The objects¶
A project holds objects, and each one is a plain Python object with arrays in it. The window shows them, and a script holds the same objects and calls the same methods. This page lists the kinds of object, what each one stores, where it comes from and what can be done with it. The API reference has the signatures; each heading below links to its page.
Two rules apply to every kind:
- Values are stored in SI once their units are known. A record whose
units were never declared keeps the file's raw numbers and says so
(
ordinate_dim == 'unknown'), and nothing is scaled by a guess. Units has the details. - A project reaches an object by its kind (
project.frf,project.time_histories), as Projects explains.project.verbs(obj)lists the processing verbs that apply to an object, each with a one-line description, andproject.selection_verbs(*names)lists the ones a selection of several objects can take together. Both lists and the acts on the window's bar are read from one table, so they always agree.
Geometry — core.geometry¶
Kind geometry. Nodes, coordinate systems, elements and element
groups, held as flat arrays: node_id, node_xyz (meters), the system
each node is placed in (node_def_cs) and measured in
(node_disp_cs), cs_matrix (three direction rows and an origin per
system), one connectivity array per element (elem_conn), and the
element group each element belongs to (elem_group) with the group
names (group_name). nodes, coordinate_systems, elements and
groups are row views onto those arrays and are what a script usually
uses; writing through a row writes the array.
geometry.place_coordinate_system(cs_id, angles=(x, y, z), origin=...)
turns or moves a coordinate system, with the angles in degrees about
the fixed X, then Y, then Z axes. It is the same call the 3-D view's
rings and arrows make when a turn or a slide ends. The coordinate
systems table shows those angles as Rotation X, Y and Z, beside the
origin, and an angle typed there turns the system. X and Z read from
-180° to 180° and Y from -90° to 90°. At a quarter turn about Y, the X
and Z turns are about the same axis, so the table gives the whole turn
as Z and shows X as zero.
There are no tracelines. A line drawn through nodes is an element
group of two-node beam elements with no properties: add_beams chains
one through the nodes, drawn_lines reads them back as the runs they
were drawn in, and the same group becomes structure once it is given a
section. An element group holds one element family (beams, triangles,
quads, tetras, wedges, hexes, points or pyramids; element_family
names the family of a type code), which is what Exodus calls an element
block. A source that mixes families in one group is split by family
when it is read.
A geometry comes from universal files, Exodus files, Nastran bulk data
and Femap neutral files, STEP and IGES, 3MF and STL meshes, sdynpy
geometry files, MATLAB files in the project layout, ESCDF files, and
.vdyn files. Its methods: plot, plot_dofs and plot_channels; add_node,
add_nodes, add_element, add_elements, add_beams, add_group
and add_coordinate_system; delete_nodes, delete_elements,
delete_groups and delete_coordinate_systems; renumber_node,
renumber_group and renumber_coordinate_system; missing_dofs
against a data object; extent; validate; save. Plates, blocks
and the other solids are added and meshed through the project
(project.add_solid_plate, project.mesh_solids and the rest),
described below.
Rigid-body modes and the default view¶
A geometry carries mass_properties: the reference point its
rigid-body modes pivot on and, when the set is to be mass-normalized,
the mass and inertia tensor about that point
(core.rigid.MassProperties).
They are stored on the geometry the same way averaging is stored on a
time history. They are set in the Modes pane (the Modes toggle on
the 3-D view's bar, offered when one geometry is selected, with
Kinematic chosen in the pane) and saved with the geometry, and suggest_mass_properties
starts the reference point at the centroid with no mass. Generate
Rigid Body Mode Shapes (project.generate_rigid_body_modes) makes
the six-mode shape set in the geometry's group, and the modes are
previewed on the model while you set the reference point.
A geometry also carries its default view, which is how it opens in
3-D (View): the direction
from the model to the eye and which way is up. There is no distance or
zoom, since every view is fitted to the model. The app opens the
geometry and everything drawn on it (shapes, an ODS, the DOF arrows) in
this view, Reset View on the 3-D view's bar returns to it, and the
report's scenes and the exported figures (plot, plot_dofs, the
animations) are drawn from it. In the app, turn the model the way you
want it and press Set Default View on the geometry's bar. From a
script:
from visualdynamics import View
project.set_view('BARC', View(eye=(1, 1, -1), up=(0, 1, 0))) # built y-up
None returns to the default, from +X+Y+Z with Z up. Only how the
model is viewed changes; its nodes are not rotated. The view is saved
with the geometry.
How a geometry is drawn¶
A solid element group is drawn as its outer skin, the faces no two of its elements share, see-through at half strength, so a bore or a pocket inside the part shows through the skin, and so does the part's far side. Plates draw as themselves, opaque from either side, and lines as lines. Nodes are drawn as points only where the point is the information: a node no element uses, the nodes of lines and point elements, and whatever is picked. The corners of plates and solids are where their mesh lines meet and are not drawn again, and a brick model's nodes, most of which are inside it, are not drawn at all. Picking the Nodes row in the tree draws every node, picking one node draws that one, and hovering over a node captions it whether it is drawn or not. The same rule draws the view, the report's scenes and every exported figure.
Element group properties¶
A geometry is also a finite element model once its element groups say what they are made of. The pencil on an element group's row in the tree opens the Element Groups table on that group. With the table open, Cmd-click (Ctrl-click elsewhere) more groups' rows in the tree to add their columns, or click a picked one off to take its column away; picking several and choosing Edit from the right-click menu opens the table on all of them. The table runs across: each group is a column, named for it, and its properties read down the column, a material (name, E, ν, ρ) and either a thickness, for a group of quads or triangles, or a section and an orientation vector, for a group of beams. A group of solid elements takes the material alone, a group of points takes a mass, ground or a stiffness, and a group of lines can take a stiffness in place of a section. A property that a group's elements do not use is blank in that group's column and takes no value: the Thickness row is live under a group of quads and blank under a group of beams, and hovering over a blank cell says why. A paste, a fill or a batch edit across several groups sets the cells that apply, skips the rest and says on the status line how many it skipped and why. A value left from before in a cell that does not apply still shows, so it can be cleared, and clearing a section's cells (its Shape, or its name) takes the section off once nothing of it is left. Meshing solids into a group that carries a section, a thickness or an orientation takes them off and keeps its material, and the status line says what went. To set one value on several groups at once, select the property's cells across their columns and batch edit, or drag the fill handle across from the group that has it; every table convention holds this way up.
A section is built from its shape: round tube, rod, rectangle,
rectangular tube, I-beam, channel or angle, picked in the Shape column.
The Dimensions cell then shows what the shape needs (D=?, t=? for a
round tube) and computes A, Iy, Iz and the torsion constant J from the
values typed. The custom shape takes those four numbers typed
directly. Every shape puts its width or flanges along the section's
local y and its depth along local z, and the orientation vector gives
local y, so for an I-beam or a channel it points across the flanges and
Iy is the strong axis. An angle's leg axes are not principal axes, so
its Iy and Iz are its principal moments, and its Dimensions cell says
where to point the orientation (45° from the long leg for an equal
angle). The shear center of a channel or an angle is off the centroid,
and the twisting that causes is not modeled. A rolled channel's tapered
flanges make its weak-axis Iz lower than the uniform-flange value given
here.
All of these values are shown and typed in the current display unit
system (psi and in⁴ in the inch system, MPa and mm⁴ in millimeters),
with the unit in the column header, and held in SI. The table follows
the unit menu while it is open. The Material cell is a drop-down over a
small library: 6061-T6, 7075-T6 and 2024-T3 aluminum; 1018, A36 and
4130 steel; 304, 316 and 17-4 PH stainless; Ti-6Al-4V; AZ31B magnesium;
C26000 brass; C11000 copper; Inconel 718; acrylic (PMMA);
polycarbonate; ABS; and nylon 6/6. Picking one fills the row with the
handbook's typical room-temperature values (fem.material(name) in a
script; fem.MATERIAL_LIBRARY carries a note for each entry). They are
typical values, not the values for your part: if you have a
certification, type its numbers over them. Any name typed into the
cell is accepted as a name.
An element group of two-node lines can instead be made rigid (massless), the last entry of the Material list. Each line is then a rigid link: its second node moves exactly as its first does (translated by the first node's rotation about it), and it adds no mass. This is how to model a bolt joining two plates whose mid-surfaces do not meet. Such a group needs no section, and its modulus, density and Poisson's ratio are blank. In the app a link is a beam element: edit the geometry's elements, switch on add mode (+), choose the beam and, in the Element group drop-down beside it, New element group. Click the two nodes of each link; every link picked goes into that new group. Then give the group rigid (massless) in the Element Groups table. The drop-down lists the element groups of the family being added to, plus a new one, and opens on the group the editing started from, so a beam is never added to a group of plates.
A bolted joint is quicker as a patch. Select the elements under the
washer (click one, Shift-click the rest) and press Tie on the bar.
Every node of the patch is linked to the nearest node of the element
group picked from its menu, or of a second patch picked next, and the
links go into the geometry's rigid element group, which is created the
first time (project.tie_elements, mesh.tie). Plates connect only
where they share nodes, so a structure built from planes is tied along
the lines where its planes meet.
An element group of point elements takes a mass alone, typed in the
Mass column, and each element in it puts that mass at its node. Use it
for a bolt, a sensor or a fitting too small to mesh
(fem.GroupProperties(mass=...) in a script). A Nastran deck's plain
CONM2 cards are read this way, one element group per distinct mass,
and a deck written back carries the masses on CONM2 cards.
A group of two-node lines can be springs instead of beams. Type a
stiffness by direction in its Stiffness cell (Kz=1e5, Kry=2e3, in the
display units, along and about the global axes) and each line becomes
a spring between its two nodes in each direction given. The two nodes
may coincide, as they do for a joint between two parts meshed to the
same point. A group of points given a stiffness is a set of springs
from each node to ground. A group of points given ground (fixed) from
the Material list holds each node in all six directions, which is a
support or the far end of a spring to ground; the Ground column can
name the directions held instead (X, Y, Z pins a node and leaves it
free to rotate; all is all six). A Nastran deck's CELAS springs and
SPC supports are read as such groups, and a deck written back carries
them as CELAS2 and SPC1 cards.
Nodes in one place are drawn as one. Hovering there captions every id
(104, 200 (2 here)), and Shift-clicking the spot again while adding
an element picks the node not picked yet, so a spring between two
coincident nodes takes two clicks. A point mass on spring lines needs
no beam at its node. The Points family is always in the tree, so the
first point can be clicked into place. In a script, use
fem.GroupProperties(stiffness=(...)) and
fem.GroupProperties(ground=True), or Model.add_spring and
Model.add_ground on a model directly.
The properties are stored in geometry.group_properties as
fem.GroupProperties and are
saved in the .vdyn file. Solve Modes (project.solve_modes) then
builds the model from the element groups (fem.Model.from_geometry)
and adds its normal modes to the geometry's group. It is in the Modes
pane: turn on Modes on the 3-D view's bar, choose Finite element
(offered once the element groups have properties), and set how far to
solve and the damping to give every mode. Solve to is either a
Number of modes, the lowest that many with the rigid-body modes
included, or a Highest frequency, every mode up to it; the status bar
says how many modes were solved and the highest frequency reached. A
script passes num_modes= or maximum_frequency=. Either way the
solve is one pass: for a frequency, the modes below it are counted
first. The pane counts the nodes, elements and
DOFs to be solved, and names any element group still without
properties. The model is free-free unless
ground groups hold it, and a free-free solution has its six rigid-body
modes at 0 Hz first. An element group with no properties, or
properties of the wrong kind for its elements, is refused by name.
Building a mesh¶
New Geometry (the + on the project row's bar) starts an empty
geometry (project.new_geometry). Its parts are built on its
Solids row and meshed with Mesh Solids, both described under
Solids below: Add Plate and Add Disk for parts meshed
into shells, Add Block and the other shapes for parts meshed
into bricks or tetrahedra. Each part becomes an element group named for
it, and the new nodes that fall on nodes already there become those
nodes. The BARC is built this way, twelve plates meshed into quads
(the finite element workflow).
In a script, mesh also builds a
mesh directly: mesh.plane meshes a rectangle of plates from a corner,
two edges and an element size, mesh.block a box of eight-node bricks,
with cylindrical holes along one of its edges, and mesh.join and
mesh.assemble put the pieces together, sharing the nodes where they
meet.
Merging and aligning meshes¶
Merge Coincident Nodes joins parts that were meshed apart. Pick the
element groups to join in the tree, one or several, and it is on their
bar. It opens a pane beside the view and marks every place where their
nodes coincide; all places are marked to begin with. Click a mark to
leave that place out and click it again to put it back; All and
None mark every place or none. The tolerance is typed in the display
unit and the marks follow it; it opens at a quarter of the groups'
finest mesh spacing. The picked groups are drawn see-through while the
pane is open, so a mark inside a solid is visible. Merge makes each
marked place one node. A rigid link, spring or beam whose nodes all
become one node no longer connects anything and is removed with them,
and the pane says so before you press Merge. The pane stays open on
the same groups afterward: the places merged are drawn as blue squares
and are no longer marks, the places left out are marked again for the
next Merge, and the pane reports what the last merge did, until you
press Close. Only the nodes the picked groups' elements use are
candidates, so a part left out stays separate even where it touches;
the geometry's own row does not offer the act. From a script,
project.merge_coincident_nodes(name, tolerance, groups=[...],
exclude=[...]), where exclude names the nodes of the places left out
(Geometry.coincident_spots lists the places). Without groups it
merges the whole geometry.
Align Meshes, beside it on the same bar, is the step before a merge
when parts meshed apart do not match. A wing meshed at an eighth of an
inch on a frame meshed at a twelfth has no coincident nodes to merge.
Align Meshes moves each node of the coarser mesh that lies within its
reach of the finer mesh's outside onto the finer mesh's nearest node
there. No node moves more than about half an element plus any gap
between the parts, and each moved node is then a place to merge. Its
pane is the same as the merge's, with a reach in place of the tolerance
(opening at half the coarsest mesh's spacing), a mark and a line for
each move, a click to leave one out, and an Align button. A move that
would turn an element inside out is refused before the button is
pressed. The nodes moved are drawn as blue squares, ready for Merge
Coincident Nodes. From a script, project.align_meshes(name, reach,
groups=[...], exclude=[...]) (Geometry.align_moves lists the moves,
each a node and the node it moves onto).
Mate Surfaces is for parts whose meshes meet face to face, matched or not. Pick two element groups or more in the tree, plates or solids, and it is on the bar. Its pane finds every patch where one group's outside lies on another's and faces it, within the tolerance, and lists them, one entry per connected patch, so four legs standing on a table top are four entries. The first side of a patch is the finer mesh; its nodes are tied to the second side's surface.
To change a patch, pick it and pick the side with the two buttons. Only that side's nodes are drawn, so coincident nodes of the two sides are never confused: the patch's nodes large, the side's nodes in the other patches small, and its other nodes that can be picked small in a muted color. A node the two groups share, where the mesher or a merge made the meshes one node, is a square on either side: it is joined already, tighter than any tie, and is never tied or picked. A node can be picked only within the Pick within distance of the other side's surface, and the node under the cursor lights up. A click adds the node to the side or takes it away.
How the sides are held is set twice, once along the surface's normal and once in its plane (the shear): Rigid, Stiffness (per node, in the display units) or Free. Rigid in both ties the surfaces together; rigid along the normal and free in the plane lets them slide; a stiffness in both is a joint to tune until the model's modes match the measured ones. Each node of the first side is tied to the point of the second side's surface it lies on, moving with the corners around that point, and along the surface's normal there. On a curved surface, a shaft in its bore, each node has its own normal, so a shaft held rigidly along the normal and free in the plane turns and slides in its bore and nothing else. When the model is built, each tied node is put on the point it is tied to, which it is already within the tolerance. Keep adds the picked patches to the geometry's Mated Surfaces row, one set each, named post on base or as typed, and the pane stays open on the patches left.
A set of mated surfaces holds no elements. Its ties are made when a
model is built, so the set can be changed at any time. Its row's pencil
opens the pane on it, to change its nodes, how it is held or its name,
and Save. Delete removes a set, or every set when the Mated
Surfaces row itself is picked. A set follows its nodes when they are
renumbered or merged, and goes with its element group. To make the
meshes one where their nodes coincide, use Merge Coincident Nodes
instead. From a script, project.mate_surfaces(name, ['post', 'base'])
keeps every patch found, rigid in both unless normal_mode and
shear_mode say otherwise; project.detect_mated_surfaces lists the
patches, and project.add_mated_surfaces, edit_mated_surfaces and
delete_mated_surfaces work on one set, stiffness in N/m.
Solids¶
Solids are the shapes a part is built from before it is meshed. They are listed on a geometry's Solids row, which is there before the first solid is added. Add Block, Add Cylinder, Add Cone and Add Sphere on that row open the add pane on a solid centered on the origin. A block is a center, three widths, three angles and an optional corner radius, which rounds its four edges along its own Z so that a window cut with it has fillets. A cylinder is a center, a radius, a length along its own Z and three angles. A cone is a frustum: a center, a base radius at its own -Z end, a top radius at its +Z end, a height and three angles, with either radius zero for a point. A sphere is a center and a radius. Each takes a name. The pane draws the shape as you type, and the rings and arrows turn and slide it. Add Section adds an I-beam, a channel, a tee, an angle, a rectangular tube or a round tube, run a length along its own Z and sized by the same dimensions the beam element's sections take (a tee takes an I-beam's). Each of these is one solid, and its pencil changes its dimensions.
A hole is a cylinder subtracted from a part, or two cylinders for a counterbore. Projects made with the hole solid that was once on this row still open with their holes, which draw, mesh and edit as before: a hole's pencil sets its depth, or Through, and its Counterbore.
Pick two parts or more in the tree and the bar offers Union, Subtract and Intersect. Subtract takes the others from the one first in the tree, which its tooltip names, so a plate with holes is the plate added first, its holes after, all of them picked, and Subtract. Drag a solid's row up or down among the rows beside it to change the order: the parts among the parts before a boolean is made, or a boolean's own solids under its row afterward, which changes what an existing subtraction cuts. A blue line shows where the row will land; a row only moves among its own siblings. A boolean lists the solids it is made of under its own row; one picked there is drawn over it, so a hole's cylinder shows inside the plate. Pattern, on picked solids, makes copies of them in rows, columns and layers: how many along X, Y and Z and how far apart, up to 10,000 copies. The result is one solid with the originals under it, and the copies follow any change to the originals. A pattern can be patterned again. Take Apart undoes a boolean or a pattern. Delete removes a part whole, with the solids inside it; a solid that a boolean still uses cannot be deleted on its own.
The pencil on a solid's row opens the same pane on it, to change it after it is made: type a block's or a cylinder's numbers or drag the rings and arrows, and the change is drawn as you make it; Apply makes it. A hole changed this way is changed in the part it was subtracted from, and a patterned hole in every copy. A pattern's pencil opens Pattern on its counts and spacing. A combined part has no size of its own, so its pencil moves and turns it whole, with every solid it is made of. A mesh already made from the solids stays as it was until Mesh Solids meshes it again.
The parts are drawn see-through in their own color, and the picked
ones in the selection color. A solid is not an element, and nothing
solves or exports it until it is meshed. Solids are evaluated by the
OpenCASCADE kernel, which is installed with the package. From a script, use
project.add_solid_block, add_solid_cylinder, add_solid_section,
add_solid_hole, combine_solids, pattern_solids,
separate_solids, delete_solids, edit_solid and move_solids; the
shapes themselves, their volumes and their surfaces are in
core.solids.
Add Plate and Add Disk add flat shapes. A plate is a center, two widths in its own X-Y plane and three angles, and a disk is a center, a radius and three angles. Neither has a thickness: they are meshed into shells, and the thickness is typed for their element group in the Element Groups table. A block, a cylinder, a section or a hole subtracted from a plate cuts it where it crosses the plate's plane, so a plate less some cylinders is a plate with holes. A union is of flat shapes or of solid ones, not both, since the two mesh into different elements.
Mesh Solids¶
Mesh Solids, on the bar when parts are picked, meshes them into eight-node bricks, ten-node tetrahedra or shells, each part an element group named for it. The element type is yours to choose in the pane: Hexes for the parts that are an extrusion, Tetras for any shape, and Shells (quads) or Shells (triangles) for plates.
A plate or a disk is meshed into shells on its own plane, with its holes round, the same way bricks are rounded; with a plate or a disk among the parts, only the two shell types are offered. A solid with a volume meshed into shells is meshed on its outer surface only: the quads are the outside faces of its brick mesh, and the triangles the outside faces of its tetrahedral mesh. Triangles on a plate are its quads, each split on its shorter diagonal. Shells take a material and a thickness in the Element Groups table before the model is solved.
Bricks mesh an extrusion best: every block square to the geometry's axes, and every cylinder and rounded corner along one axis. That covers plates, bars and their holes. A cylinder along a second axis, a hole drilled in from the side, is cut from the grid and its nodes pulled round in its own plane, without a ring, so the bricks around it are uneven. The grid is cut at every flat face of every block, so flat faces are meshed exactly, and each span is divided into the whole number of bricks nearest the element size. A brick belongs to the picked part whose shape holds its center, and where parts overlap it goes to the one later in the tree.
A union that is not an extrusion is meshed in pieces, one per
operand, as deep as unions go: a union with another union among its
operands gives up that union's operands too, so a table unioned again
with a sphere is still its block, legs and rod, and the sphere. A
subtraction whose first operand is a union is split the same way, each
member less what the subtraction takes: a block and a flange unioned
and drilled through are the block less the hole and the flange less the
hole. Any other subtraction, an intersection or a pattern is one piece,
its operands being no material on their own. Each piece that is an
extrusion is swept as above, with rings about its holes, and each that
is not is fitted as below, every piece at its own size. A piece that is one block, cylinder or section turned
off the axes is swept along its own axis: a tilted rod gets rings along
its length. Where it runs into a piece before it, each line of nodes
along the sweep stops at that piece's surface and its nodes are spread
evenly back to the free end, so the last layer lies on the face it
meets and the bricks near there are sheared; the pane gives the worst
brick. A turned piece that runs through another, or meets pieces at
both ends, is fitted instead. One turned block, cylinder or section
meshed on its own is swept the same way. The pane then shows a size per piece in place of the
one box, each starting at the size the piece is likely to hold at,
and Detect Element Sizes fills every row. Where two pieces meet and
their grids match, the seam's nodes are shared, and where they do
not, the finer piece's nodes on the seam are tied rigidly to the
coarser piece as mated surfaces, one set per seam under the geometry's
Mated Surfaces, which can be given a stiffness afterward; the pane
reads both counts. Where two pieces overlap, the material is the
earlier operand's: a later piece's grid is cut at the earlier pieces'
faces and its bricks inside them are left out, so legs that run up
into a table top end at its underside. Each piece keeps its own
element group, named for its operand. This is how a part with one thin piece on a thick one
meshes: a block with 0.2 in flanges wants 0.2 in bricks on the block
and 0.067 in on the flanges, which no one grid can give. In a script,
mesh_solids(name, [part], 0.2, unit='in', sizes={flange: 0.067})
names the sizes by solid id.
A shape that is not an extrusion, a hole drilled at an angle, a cone or a sphere, is still meshed into bricks, on a grid fitted to it: the cubes whose centers lie inside are kept, a layer of bricks is laid under their skin, the skin's nodes are moved onto the shape's surface with its corners and sharp edges captured, and every node is then moved to where the worst brick around it is best. The pane says so (on a grid fitted to the shape) and reads the worst scaled Jacobian (1 for a cube, 0 for a flat brick), which comes out between about 0.15 and 0.3 where a ring mesh gives 0.5 or better. The fitting takes seconds to minutes, so the preview draws it only for a small grid. A feature only a few bricks across leaves no room to fit: a fit has held with five or more bricks across the smallest round feature's radius on most shapes measured and folded with four or fewer on all of them; where a bore leaves a surface at a shallow angle, the feather edge there can fold a few bricks at any size. Detect Element Size writes the five-across size into the box (the smallest radius over five, or the thinnest wall over three; for an extrusion, half the thinnest feature; for tetrahedra, the radius over three), and Mesh on a size under four and a half across, or under two and a half through the thinnest wall, asks first, with the size likely to hold as the default, before the minutes are spent. Where the size likely to hold would itself be a grid past the brick limit, the part wants a finer size on its thin piece than on the rest, which one fit cannot give, and the question offers tetrahedra instead. A fit that folds anyway is refused with the count, and the pane says to use a smaller size or Tetras.
Holes, bosses and inserts are meshed round. About each circle with room around it the grid is replaced by a ring mesh, with the circle's nodes evenly spaced on it, layers of bricks out to the grid, and a square core in the middle where the circle is filled. Circles about one center, such as a washer about a hole, make one ring. The ring's outline is a rectangle of the grid's cells where one fits, and steps around whatever is in the way where none does (a hole nearly as wide as a table's top, beside its legs). Where there is no room (a hole close to another hole or to a face), and at a rounded corner, the grid's nodes on the rim are pulled onto the circle instead; a pull that would turn a brick inside out is made as far as it can be.
Tets mesh any shape the solids describe, a hole at an angle included, from the shape alone. Points are spread through the part and relaxed until the edges between them are even, points pushed out of the part are put back on its surface, and the sharp edges and corners of the part are held by points placed along them, so nothing is rounded off. The elements are ten-node tetrahedra, their midside nodes on the curved walls, which the solver takes alongside bricks; the four-node tetrahedron is far too stiff in bending and is not offered. The pane reads the count, the worst radius ratio (1 for a regular tetrahedron, 0 for a flat one) and how many are under 0.3. A tetrahedral mesh takes longer than a brick mesh of the same size, seconds for a hundred thousand elements, and the preview draws it only up to a few thousand; past that it says the count and Mesh makes them with the progress bar up. Where both kinds can mesh a part, bricks are the better element for the same count, and a brick mesh of a plate or a bar should be preferred.
Parts meshed together share nodes where they touch (a frame and the
inserts in its holes). Keep apart from other groups lands the bricks
only on their own groups' nodes. With two
parts or more picked, Keep the parts apart from each other meshes
them on one grid with each part keeping its own nodes where it touches
another, so parts to be bolted lie node on node, ready for Merge
Coincident Nodes (the BARC's box, channels and beam are meshed this
way). The pane opens on an element size of half the thinnest feature,
draws the bricks as the size is typed, and reports how many there are
and the shortest edge; a size that would make more than 2,000,000
bricks is refused. The count is the parts' volume over a brick's, so a
part filling a small share of its box is held to the bricks it will
have, not to its box. The grid a mesher lays over the box is held to
10,000,000 cells, which is about 3 GB of memory while it is laid. Mesh adds them and closes the pane. The solids
stay, to be meshed again or deleted. When a part is meshed again it
replaces its earlier mesh: the bricks of the element group named for it
are removed, with the nodes only they used (unless data is measured or
solved there), and the group keeps its material. The pane says how
many bricks will be replaced before you press Mesh. From a script,
project.mesh_solids(name, ids, size, unit=..., apart=...,
parts_apart=...).
Photos — core.photos¶
Kind photos. Setup photographs as they arrived (names, formats
and the encoded images), never re-encoded: a report embeds them, and
a second JPEG generation would only lose quality. Methods: add_file,
rename, delete_photos, plot.
Channel table — core.channel_table¶
Kind channel_table. One frame, with a row per channel and a fixed
set of typed columns. It comes from a controller run, a spreadsheet or
a project file. Methods: dof_strings, roles, controls, types,
sensitivities, ranges, units_for, set_cell, rename_dof,
delete_channels, save. The channel table has
its rules.
The data arrays — core.data¶
Every measured or computed curve is a DataArray subclass, and one
object holds many records sharing one abscissa: abscissa (the x
axis, in seconds or hertz), ordinate shaped (records, samples), and
one entry per record of response_dof, reference_dof where the type
has a reference, block (which repeat), ordinate_dim and
ordinate_unit (the quantity and its SI unit), reference_unit for a
ratio, dimension_hint (what a file claimed without giving its scale)
and comment. Uneven and unsorted abscissas are accepted on import;
anything that needs an even step checks for it when it is used.
Every data array has plot, plot_waterfall, save_plot and save;
define_units and undefine_units; delete_records and rename_dof;
display_ordinate and display_abscissa in a chosen unit system; and
num_records and record_label.
The rows of a data object's grid in the project tree are its
coordinates, and the columns of a matrix are coordinates too. A channel
assigned to the wrong point at the instrument is corrected in the grid:
double-click the row or column label and type the coordinate. The
change applies to that channel, meaning that coordinate and the
quantity of that row or column, wherever it appears in the object. A
CPSD's accelerometer is on both sides of its cross terms and moves as
one sensor, while an FRF's drive-point accelerometer (a row) and load
cell (a column) are two channels, and moving one leaves the other to be
moved separately. Everything derived from the object follows, because
a PSD computed from a mislabeled channel is mislabeled the same way
(project.rename_dof; without a quantity it moves every channel at the
point). A rename that would give two records the same coordinate and
quantity is refused: a load cell and an accelerometer can share a
point, two accelerometers cannot.
A channel table's row coordinate is its node and direction. Type over the row in the grid and the two cells change; type a node or a direction in the table view and the row's coordinate follows. A channel table imported with the data it describes is linked with it (one file, one group), but it is otherwise its own object: a coordinate corrected on the time history is not corrected on the table, or the reverse.
| kind | class | what it is | what it adds |
|---|---|---|---|
time_history |
TimeHistory |
the record as acquired, against time; carries its averaging, shocks, roles, truncation and filtering settings so every result computed from it reads one description |
compute_spectra, compute_psds, compute_cpsds, compute_frfs, compute_multiple_coherence, compute_srs, integrate, differentiate, filter, truncate, animate, split_into_frames, sample_rate, drive_dofs |
transient_specification |
TransientSpecification |
a target waveform: what a transient test was controlled to, sample by sample | everything a time history has |
spectrum |
Spectrum |
the complex average of a record's frames, amplitude and phase per line | animate |
psd |
Psd |
the power average: real autospectra, complex cross spectra; bin_widths when the bins are not even |
area, to_octave, bin_bounds, coherence, principal_shapes, as_specification, animate |
specification |
Specification |
a PSD with its band: the target and the warning and abort limits on either side, as arrays beside the ordinate | limit, has_limits, as_psd |
frf |
Frf |
response per unit reference, complex, one reference per record | plot_cmif, animate; the input to a modal fit |
coherence |
Coherence, MultipleCoherence |
how much of a response one reference explains, or all of them together; bounded 0 to 1 | plot_map |
srs |
Srs |
a shock response spectrum: the peak an oscillator of each natural frequency reached, laid out in octaves | damping |
shock_specification |
ShockSpecification |
an SRS with its band, conventionally +6 dB and −3 dB | limit, has_limits |
Writing and editing a specification¶
A specification can also be written in the app, on a sheet that opens two ways. Create Specification on the table bar of a single channel table starts one at the table's control channels: the channels with Control checked, or every motion channel when none is. With rows picked in the table's grid it starts at those rows instead, whatever their role, so a force CPSD is written at the reference channels. Edit on the plot bar of a specification opens the specification itself, with all of its channels or only the ones whose records are picked in the tree. Several specifications opened at once share one sheet, with a column per channel under its specification's name and cross terms within each. Opened on a channel table, the sheet first makes the specification beside it, in the table's object group, and edits that.
A specification at a shape set's modal coordinates, such as a virtual
point's target, is written from a script:
core.author.SpecificationDraft.at_modal_coordinates(shapes, modes=...) starts the
sheet, using every shape or only the ones named (a virtual point's
three translations, with the rotations left out), and
project.author_specification(name, draft) makes it.
The sheet sits beside the plot. It holds the breakpoints and a level per channel, each pair's coherence and phase (a pair left unstated is absent, and independence is a statement too), Add breakpoint and Remove breakpoint, Scale selected with a box that raises or lowers the selected levels by a number of decibels, and an All pairs row that states one coherence and phase for every pair. Enter: Levels or Slopes chooses how the levels are typed: a level at every breakpoint, or a level at the first and a slope in decibels per octave into each one after it, the level there computed. Areas and running rms writes each segment's area on the plot, draws the rms accumulated from the low end under it, and reads both out under the breakpoints; both are offered on the breakpoints form (Writing a random specification by slope). While the sheet is open the plot is the 2-D one, since every editing gesture happens there, and the 3-D stage is off until the sheet closes. Selecting another object in the tree closes it, the channel table it was made from included; coming back to the specification shows it drawn, with Edit to open the sheet again.
The warning and abort bands are not on the sheet: they are on the plot, as the shaded zones. While the sheet is open each edge of each band has a drag handle. There is one handle over the whole range while the channel is Uniform; with Uniform off there is one per linear section of the requirement (each segment between breakpoints, or each run of one power law in the interpolated form), and each is moved on its own. Drag one up or down; it snaps to quarter decibels and its label shows the value. When you let go, that edge moves to that value on every channel the sheet holds in that frequency range, which is the whole specification or the channels picked in the tree. A specification with no limits opens with the defaults, ±3 dB warning and ±6 dB abort, shown on the plot to drag; the sheet says they are not on the object yet, and the first edit writes them. Two constraints, after Bands: under the form buttons, apply to every channel of the specification the same way: Symmetric keeps the band above the target equal to the band below, and Uniform keeps every segment at one band. Each box opens checked when every channel's own bands meet that constraint.
Both grids are the application's ordinary tables. A column header selects a channel, a row header a breakpoint, and Cmd-click adds cells; copy, paste, Delete to clear, Batch Edit and the fill handle work as they do in every table (Editing a table), so a level dragged across the channels and down the breakpoints sets them all. A frequency typed between two others re-sorts the breakpoints. There is no Apply button: every edit is written to the specification as it is made, so switching to another object never leaves an edit behind.
A sheet holding every channel rewrites the object in the sheet's own
form: fold a controller's target to its breakpoints and the object
becomes the breakpoints. A sheet holding a picked subset of channels
merges back at the object's own lines and leaves the other channels
unchanged, so the object's name, links and place in every report stay
the same (project.author_specification with a
core.author.SpecificationDraft;
replace=True, and a list of names for a sheet covering several). A
pair left unstated is absent from the specification, not assumed. A
cross term that varies with frequency opens unstated, and the sheet
says so.
A sheet has two forms, chosen by the pair of buttons at its top and applied to the whole specification whichever channels the sheet is open on. Breakpoints is the few points a requirement is written from. Interpolated is the same requirement read onto evenly spaced frequency lines, the way a controller writes its target. A controller's target opens as lines and folds to its breakpoints exactly, since its lines were computed from them, and editing is done on the few rows. A specification with no power-law structure keeps every line and says so. The line spacing is the specification's own, otherwise a time history's averaging (sample rate over frame length), otherwise the value typed into the box beside the buttons; nothing is guessed. A specification written at modal coordinates and expanded through the set is an exact control-channel target with every cross term.
Save As offers a specification as Rattlesnake random specification
(.npz), the target file the controller's Random environment loads
before a test. It holds the frequency lines, the whole cross-spectral
matrix at each line, the four band edges, and, when every channel is a
node and a direction, the node and direction of each channel so the
controller can put the matrix in its own channel order. Most random
tests run on autospectra alone, and the controller's form of that is a
matrix with zeros off the diagonal. So a pair the specification does
not hold is written as a zero, and a held mask records that it was a
placeholder rather than a statement of independence. The values are
written in the unit system on display, g included, because the
controller reads the target in the unit of each of its own channels
(usually g for an accelerometer). Choose the system that matches the
test's channel table before saving. The file cannot record units, so
the status line names the system. The same file imports
again, with held cross terms kept and placeholders left out. A target
file written by the controller or by sdynpy imports too, with an
off-diagonal that is all zero or NaN read as the placeholder for
autospectra alone.
Sine — core.sine¶
Two kinds that are not data arrays, because each tone sweeps its own
frequencies on its own clock, and different abscissas cannot share one
array. sine_sweep_specification (SineSweepSpecification) is what a
sine test was controlled to: the tones, each with its breakpoints,
sweep law, bands and start time, over the control DOFs. sine_levels
(SineLevelSet) is one extraction: the per-tone levels a joint
Vold-Kalman solve read out of a recording, grouped the way the
specification groups its tones. Each level carries the noise floor
beside every value (floor) and where the tone was below it
(below_floor, the value then reported at the floor). The set carries
the smoothing it was read with (cycles), and a level whose sweep
clock was corrected says by how much (drift_hz).
Shapes — core.shapes¶
Kind shapes. Mode shapes over a shared set of DOFs: frequency and
damping per mode, shape_matrix shaped (modes, dofs) with
coordinate naming each column, modal_mass, modal_damping and
mass_unit where a source carried them, a description per mode, and
unscaled when the fit had no drive point to set the scale. A fitted
set is also the record of its fit, which is what Edit Fit reopens. A
geometry's rigid-body set (three translations and three rotations about
its reference point, with frequency exactly zero) is also unscaled
unless mass and inertia were given, in which case it is mass-normalized
about the principal axes of the inertia.
Any shape set can carry data through itself. project.transform fits a
record's motions to the modes (q = Φ⁺u) and projects its forces
(Φᵀf), giving one record per mode and quantity at the modal
coordinates M1 … Mn. The name is the letter M and the mode's index,
so it cannot be mistaken for a node, and it is the same for every set;
the object's provenance says which set it came through.
project.expand carries modal responses back to every DOF the set
covers. Each kind of data is transformed in its own form. A time
history or spectrum is transformed row by row. A CPSD or a
specification is transformed as the matrix, S_qq = Φ⁺ S_uu Φ⁺ᴴ,
which needs every cross term between the shared channels. Autospectra
alone are refused rather than filled in with a guess, so compute the
CPSDs, or import the specification with the cross terms the controller
wrote. The tolerance bands are carried exactly when every channel has
the same one. An FRF is transformed on its response rows and, when the
set covers the drives, on its reference columns too. A shock response
spectrum or a coherence does not transform, since one is a maximum and
the other a ratio: transform the time history and compute it again.
The expansion uses every mode for the motion of the structure, or only
the modes picked in the tree for their contribution alone, u = φₖqₖ,
and the result is named for them (records= in a script). Both results
go into the group with the set and the record. A modal object is attached
to the shape set it came through, not to a geometry, and works with
any set that has every mode it names. Both carry the record's
averaging frames and shock windows, which fall on the same instants.
The unit rule is [q] = [u]/[Φ]: unit rigid shapes give the virtual
point's rotations in rad/s² and its moments in lbf·in, mass-normalized
shapes give the half-power mass units (modal_acceleration,
in/s²·slinch½), and a set with no mass unit gives responses whose units
are left to declare. In the window, select the record and the set
together and press Transform to Modal Coordinates on the bar (or
Expand to Physical Responses, for a modal record such as the
modal responses computed from forces). The object is made
at once, since a transform has no settings, and the status line reports
the DOFs shared, the DOFs left out and the residual the fit leaves. The
same report is kept on the object as its transform_report
(core.transform). The
matrix itself, with its conditioning and the residual it leaves against
frequency, is a Transformation (The transformation to a
point).
A shape set and the channel table it was projected onto can be written
as a modal state-space model, the file Rattlesnake's state-space virtual
hardware loads in place of a real test article. In the app, select the
set and the table together and press Export State-Space Model on the bar.
A pane beside the plot takes the maximum and rigid frequencies, says how
many modes are kept, moved up and left out, and draws the model's FRF at
each drive point over the whole set's synthesized FRF, dashed, so the
effect of each setting can be seen before Export writes the file. From
a script:
project.export_state_space(shapes, table, path, maximum_frequency=4096)
(core.state_space). The
table's reference rows are the inputs, each a force at its DOF, and every
row of the table is an output in table order, since the controller
checks the file against its channel table row for row. A response row
reads the modes at its DOF as its channel type says: displacement,
velocity or acceleration. A reference row reads back its own input, as
a force gauge reads the force applied. Each row is in its channel's own
unit, g or lbf for example, because the controller applies no
sensitivity to a simulated channel; a blank unit cell takes the unit
system's unit. Modes at or above maximum_frequency are left out. Set it
to the controller's Nyquist frequency, since the hardware integrates the
model and keeps every n-th sample with no filter first, and a mode above
Nyquist would alias into the band. Modes below rigid_frequency (1 Hz
unless set) are moved up to it, because a rigid-body mode at 0 Hz is a
double integrator whose displacement drifts through a long random run;
above a few hertz its accelerance is unchanged. The set has to be real
and mass-normalized with a mass unit. The model's frequency response,
C (iωI − A)⁻¹ B + D, is the set's own synthesize_frf at the same
DOFs, in the same units.
Methods: plot, animate, animate_pair, plot_mac, auto_mac,
synthesize_frf, covers, delete_modes, save.
Matched modes — core.matches¶
Kind matches. Pairs committed on a cross-MAC between two shape sets:
first and second name the sets, pairs the modes, and macs the
value each pair had when it was committed. Methods: add,
delete_matches.
Report — core.report¶
Kind report. An ordered list of blocks, each a plain dict, bound to
project objects symbolically by default (@basis:Frf) or by a literal
name. The blocks are text, plot, scene, table, photo, bars, the
pass/fail box (verdict), and the matched-modes pairs and their
overlay. Methods: add, remove, move, unbound.
Reports explains the bindings.
What can be done with what¶
The processing verbs are on the project, so a result is added, named and linked to its source in one call:
| on | verbs |
|---|---|
| a time history | filter_data, truncate_data, detect_shocks, compute_spectra, compute_psds, compute_cpsds, compute_srs; compute_frfs and compute_multiple_coherence when it has both reference and response channels; extract_sine when the project holds a sine sweep specification; integrate and differentiate when the quantity allows; transform through a shape set whose DOFs it is measured on, and expand back when it holds that set's modal responses |
| a geometry | generate_rigid_body_modes; set_view; add_solid_block, add_solid_cylinder, add_solid_cone, add_solid_sphere, add_solid_section, add_solid_hole, add_solid_plate and add_solid_disk, then combine_solids, pattern_solids and mesh_solids; tie_elements, a patch of elements tied rigidly to an element group or a second patch; merge_coincident_nodes and align_meshes once it has elements, for the whole geometry or the element groups named by groups=; merge_groups, element groups of one element type and the same properties made one; solve_modes once its element groups carry their properties (a material and a thickness or a section per group in the Element Groups table, a material alone for a group of solids), which builds the finite element model and solves it |
| the project itself | new_geometry, an empty geometry to build in; new_channel_table, an empty channel table to fill in; generate_report |
| a channel table | add_channels, blank channels numbered on from its highest |
| a PSD, CPSD or specification | compute_octave, with a specification's warning and abort limits banded along with it; convert_to_specification for a PSD that is a requirement, and convert_to_psd for a specification, its limits left out |
| a shape set, specification or channel table | author_specification |
| an FRF | fit_modes |
| two shape sets | project_onto_basis, match_modes |
| a shape set and a channel table on another geometry | project_onto_basis, the modes at the table's channels; channels= takes some of its rows |
| a shape set and a channel table | export_state_space, the pair written as a Rattlesnake state-space model, a file rather than an object |
| any object with a sibling of its type | merge |
Every object also works with the whole-project verbs (add, remove,
rename, duplicate, link, unlink, place, set_basis,
export, save, generate_report, export_report, refresh), and
project.verbs() with no argument lists all of the processing verbs
with their descriptions. The API page for
project has every signature.