visualdynamics.core.mesh¶
mesh
¶
Plate meshes built from planes, and solid meshes built from blocks.
A structure made of flat plates, such as a box, a channel or a bracket,
is described most simply as the planes it is made of: each one a
rectangle at its mid-thickness, meshed into rectangular plate elements
and put in an element group of its own. plane makes one, and block
makes a box of solid bricks the same way. assemble joins the pieces
into one geometry and merges the nodes they share, so the plates are
tied along the lines where their mid-surfaces meet. Where mid-surfaces
do not meet, as with a bolted foot sitting on a wall, no node is shared,
and the two are joined by rigid links (fem.RIGID) that tie adds.
Each element group is then given a material and a thickness
(fem.GroupProperties, or the Element Groups table), and
fem.Model.from_geometry builds the model.
Nodes on a shared line coincide only because both planes divide it the same way, so planes that meet should be given the same element size.
Functions:
| Name | Description |
|---|---|
plane |
A rectangle meshed into four-node plate elements, in one element group. |
block |
A rectangular block meshed into eight-node bricks, in one element |
landing |
Which of |
join |
Put |
assemble |
One geometry from several, joined in turn by |
tie |
Tie a patch of elements rigidly to what lies under it (Tie). |
Classes¶
Functions:¶
plane
¶
plane(corner: ArrayLike, edge_a: ArrayLike, edge_b: ArrayLike, size: float, name: str = '', *, unit: str | None = 'm') -> Geometry
A rectangle meshed into four-node plate elements, in one element group.
Each edge is divided evenly into the whole number of elements nearest
size, so the elements come out close to square and close to that
size. Planes that meet along a line divide it the same way, since the
line has the same length in both, and assemble ties them there.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
corner
|
array_like
|
One corner, (x, y, z). |
required |
edge_a
|
array_like
|
The two edges from that corner, as vectors; their lengths are the rectangle's sides. They must be perpendicular, because the plate element is a rectangle, and edges that are not are refused. |
required |
edge_b
|
array_like
|
The two edges from that corner, as vectors; their lengths are the rectangle's sides. They must be perpendicular, because the plate element is a rectangle, and edges that are not are refused. |
required |
size
|
float
|
The element size aimed at, positive. |
required |
name
|
str
|
The element group's name, which is the part this plane is. |
''
|
unit
|
str or None
|
The unit every length given here is in. The geometry holds the lengths in SI, as any geometry with its units defined does, and remembers this unit; None leaves them as given, units undefined. |
'm'
|
Returns:
| Type | Description |
|---|---|
Geometry
|
Nodes numbered from 1, one element group holding every element. |
Source code in src/visualdynamics/core/mesh.py
block
¶
block(corner: ArrayLike, edge_a: ArrayLike, edge_b: ArrayLike, edge_c: ArrayLike, size: float, name: str = '', *, unit: str | None = 'm', holes: Sequence[Any] = (), hole_name: str | None = None) -> Geometry
A rectangular block meshed into eight-node bricks, in one element group.
This is plane in three dimensions: a corner and three perpendicular
edges, each divided evenly into the whole number of elements nearest
size, so the bricks come out close to cubes. Blocks that meet over a
face divide it the same way, since it is the same rectangle in both,
and assemble ties them there, so blocks that meet should be given
the same size.
A hole is a cylinder along one of the block's edges, and every brick
whose center lies within the hole's radius of its axis is taken out
of the block. A hole is given as (center, radius, axis), with the
center a point on the hole's axis and axis 0, 1 or 2 for the edge it
runs along (edge_a, edge_b or edge_c); as (center, radius, axis,
depth) for a blind hole of that depth, measured from the end face
nearer the center point; and with a fifth item naming the element
group the hole's bricks go to instead of being removed (a threaded
insert, given its own material in the Element Groups table), or None
to remove them. A hole with no fifth item uses hole_name. Holes are
applied in order, a later one over an earlier, so a through hole, then
an insert of the same radius part way down, then a void the size of
the insert's bore, is a threaded insert in a drilled hole. Every hole
must run along the same edge, because the bricks are a grid swept
along it; holes along different edges are refused.
A hole is meshed round, not stair-stepped, by the same mesher Mesh Solids uses. Where there is room around the hole, the grid there is replaced by a ring mesh with its nodes evenly spaced on the circle, and a core of bricks where an insert fills it. Where there is not room, the grid's nodes nearest the rim are moved onto the circle, sliding along the block's face where the hole breaks out. A hole whose center lies on the block's edge is a round-over and keeps its steps, because its corner brick cannot follow an arc, and its area is already within a few percent of the fillet's.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
corner
|
array_like
|
One corner, (x, y, z). |
required |
edge_a
|
array_like
|
The three edges from that corner, as vectors; their lengths are the block's sides. They must be perpendicular, and edges that are not are refused. |
required |
edge_b
|
array_like
|
The three edges from that corner, as vectors; their lengths are the block's sides. They must be perpendicular, and edges that are not are refused. |
required |
edge_c
|
array_like
|
The three edges from that corner, as vectors; their lengths are the block's sides. They must be perpendicular, and edges that are not are refused. |
required |
size
|
float
|
The element size aimed at, positive. |
required |
name
|
str
|
The element group's name, which is the part this block is. |
''
|
unit
|
str or None
|
The unit every length given here is in, as for |
'm'
|
holes
|
sequence of tuple
|
Cylindrical holes, as above, in the same unit and the same frame. |
()
|
hole_name
|
str
|
The element group the bricks of a hole that names none go to; None removes them. |
None
|
Returns:
| Type | Description |
|---|---|
Geometry
|
Nodes numbered from 1; one element group, and one more for each name the holes put bricks in. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If an edge has no length, the edges are not perpendicular, |
Source code in src/visualdynamics/core/mesh.py
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | |
landing
¶
landing(geometry: Geometry, part: Geometry, tolerance: float | None = None, apart: bool = False) -> tuple[ndarray, ndarray]
Which of part's nodes fall on a node of geometry, and on which
one.
This is the matching join does, without the join, so a reading can
say how many nodes a part would share before it is added.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Where the part would go, and the part. |
required |
part
|
Geometry
|
Where the part would go, and the part. |
required |
tolerance
|
float
|
As |
None
|
apart
|
bool
|
As |
False
|
Returns:
| Type | Description |
|---|---|
(ndarray of bool, ndarray of int)
|
Per node of the part: whether it lands, and the row in
|
Source code in src/visualdynamics/core/mesh.py
group_families
¶
group_families(geometry: Geometry, group_id: int) -> set[str]
The element families an element group of geometry holds, empty
for an element group with no elements yet.
Source code in src/visualdynamics/core/mesh.py
group_refusal
¶
Why part cannot join geometry by element group name, or None.
An element group holds one element family (Geometry.mixed_groups),
so a part whose element group has the name of one that already holds
another family is refused. This is the one rule join refuses by, and
the Add pane checks it before it offers Add.
Source code in src/visualdynamics/core/mesh.py
join
¶
join(geometry: Geometry, part: Geometry, tolerance: float | None = None, apart: bool = False) -> dict
Put part into geometry, in place.
Each of the part's nodes that falls on a node already there becomes
that node, the rest are added after the highest id, and the part's
elements follow them. The nodes already there keep their ids, because
data linked to the geometry refers to them by id, so this is how a
part is added to a model under construction (Mesh Solids) as well as
how assemble builds one. A solid element of the part that would fill
a cell already filled is left out, so the overlap of two crossing bars
is counted once.
An element group of the part with the same name as one already in the
geometry joins it, so the five planes of a box, each named 'box', are
one part and are given a material once. An unnamed element group is
always an element group of its own. A named element group holding a
different element family is refused (group_refusal), since an
element group holds one family, and so is a part whose length unit is
defined when the geometry's is not, or the other way round.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Where the part goes; changed in place. |
required |
part
|
Geometry
|
What goes in. Its coordinates must mean what the geometry's do: both SI (units defined) or both as given. |
required |
tolerance
|
float
|
How close a node must be to one already there to be it, in meters once units are defined. Defaults to a millionth of the size of the two together. |
None
|
apart
|
bool
|
Land only on the nodes of the element group the part joins by name, so a part meshed against another (a channel's foot on the box it is bolted to) keeps nodes of its own where the two touch, coincident and not joined, until Merge Coincident Nodes joins the places picked. A plane of the box still joins the box's other planes. |
False
|
Returns:
| Type | Description |
|---|---|
dict
|
'added', the number of nodes added; 'shared', the number of the part's nodes that fell on nodes already there; 'elements', the number of elements added; 'duplicates', the number of the part's solid elements left out because they were already there; 'groups', the ids of the element groups they went into. |
Source code in src/visualdynamics/core/mesh.py
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | |
assemble
¶
One geometry from several, joined in turn by join.
Nodes are numbered from 1 in the order they arrive, and a node that
falls on one already there becomes it, so planes meeting along a line
are tied there. Element groups of the same name become one element
group; unnamed element groups stay separate. Coincident nodes within
one part, which join does not look for, are merged as well (with
apart, only within each element group).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*parts
|
Geometry
|
The pieces, at least one, all in the same length unit; parts in different units are refused. |
()
|
tolerance
|
float
|
How close nodes must be to be one, in the units the geometry holds them in (meters when the length unit is defined). Defaults to a millionth of the assembly's size. |
None
|
apart
|
bool
|
Join each piece only to its own element group's nodes ( |
False
|
Returns:
| Type | Description |
|---|---|
Geometry
|
|
Source code in src/visualdynamics/core/mesh.py
links_on
¶
links_on(geometry: Geometry, elements: Any) -> list[int]
The rigid links (tie, tie_nodes) with a node among these
elements' nodes, by id: what goes when the elements are meshed
again, since a link left in holds the old node and points the new
mesh at it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Whose elements. |
required |
elements
|
sequence of int
|
Element ids. |
required |
Returns:
| Type | Description |
|---|---|
list of int
|
|
Source code in src/visualdynamics/core/mesh.py
group_skin
¶
group_skin(geometry: Geometry, group: int | str) -> list[tuple[int, ...]]
The faces on the outside of an element group, as node ids: every face of its plates, and of its solids the faces no second solid in the group shares. Lines and points have none.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Whose elements. |
required |
group
|
int or str
|
The element group, by id or name. |
required |
Returns:
| Type | Description |
|---|---|
list of tuple of int
|
|
Source code in src/visualdynamics/core/mesh.py
tie
¶
tie(geometry: Geometry, elements: Any, to: Any, group: str | None = None) -> dict
Tie a patch of elements rigidly to what lies under it (Tie).
Every node of elements is joined by a rigid, massless link to the
nearest node of to, and the links are added to a rigid element
group. The use is a bolted joint: select the elements under a washer
and tie them to the part below, one step per bolt.
A node the patch shares with the target is already joined and is left alone, and a patch whose nodes are all shared with the target is refused. Each link runs from the target's node to the patch's, so the patch follows the part it is bolted to.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Changed in place. |
required |
elements
|
sequence of int
|
The patch, by element id. |
required |
to
|
str, int or sequence of int
|
What to tie to: an element group, by name or id (its nodes nearest the patch), or a second patch, by element ids. |
required |
group
|
str
|
The element group the links go into, by name. One that is new or has no properties yet is made rigid; one with other properties is refused. Defaults to the geometry's first rigid element group, or else one named 'ties'. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
'links', how many were added; 'shared', the patch's nodes left alone because the target holds them already; 'group', the id of the element group the links went into. |
Source code in src/visualdynamics/core/mesh.py
tie_nodes
¶
tie_nodes(geometry: Geometry, followers: Any, target: Any, group: str | None = None) -> dict
Tie each of the followers nodes by a rigid, massless link to the
nearest of the target nodes, the links going into a rigid element
group as tie puts them: tie for a patch of elements, and the
seam between two pieces meshed at different sizes (solids.brick_mesh).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
Changed in place. |
required |
followers
|
sequence of int
|
The nodes tied, by id. |
required |
target
|
sequence of int
|
The nodes they may be tied to, by id. |
required |
group
|
str
|
As |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
'links', how many were added; 'group', the element group's id. |