visualdynamics.core.rigid¶
rigid
¶
Rigid-body mode shapes of a geometry.
Six shapes every free structure has: three translations and three rotations about a reference point. They are the start of the virtual point workflow (PLAN.md, "The virtual point arc"): responses measured at the control DOFs are transformed through them to the six motions of a point, and a specification is transformed the same way, so the two can be compared there.
The shapes are kinematic; only the reference point shapes them. A
rigid translation moves every node one unit along an axis; a rotation
of one radian about an axis e through the point c moves a node at
r by e × (r − c). No mass enters. The point is what a test
engineer calls the CG, and the geometry's centroid is the default.
Mass and inertia only scale. ShapeSet holds mass-normalised
shapes, φᵀMφ = I. A rigid body's 6×6 mass matrix about its CG is
diagonal in its principal axes — the mass three times, then the three
principal moments — so normalising divides each translation by √m
and each rotation by √I about its own axis. That is all the mass
properties do, and it is why they come as one optional group: mass
without inertia could scale three rows and not the other three, and a
set normalised by halves carries modal masses nobody can read. Without
them the set is exactly what a fit without a drive point is,
unscaled — unit shapes, modal mass a convention.
The rotation axes are the inertia's principal axes. Rotations about the global axes are mass-orthogonal only when the products of inertia vanish. With a coupled tensor the six orthonormal shapes rotate about its eigenvectors, and there is no choice about it, so the principal decomposition is always taken: a diagonal tensor's principal axes are the global axes and the user who typed three numbers gets X, Y and Z back; a coupled one gets its own axes, named in the mode descriptions. Taking the diagonal of a coupled tensor and calling the result mass-normalised is a wrong answer that looks right.
Mass normalisation is only meaningful about the CG — about any other point the rigid mass matrix couples translation to rotation and the six are not orthogonal — so the mass properties, when given, are taken to be about the point. Unscaled shapes about any point span the same six-dimensional space, which is what the later transformation wants: it builds unscaled shapes about the virtual point, an interface location and not the CG at all, through this same function.
Classes:
| Name | Description |
|---|---|
MassProperties |
The reference point, and optionally the mass and inertia about it. |
Functions:
| Name | Description |
|---|---|
is_rigid_set |
Whether a set is the six rigid-body shapes |
axis_name |
|
rigid_body_shapes |
The six rigid-body mode shapes of a geometry about a point. |
Classes¶
MassProperties
dataclass
¶
MassProperties(
point: tuple[float, float, float],
mass: float | None = None,
inertia: tuple[float, float, float, float, float, float]
| None = None,
)
The reference point, and optionally the mass and inertia about it.
point is in metres, mass in kilograms, inertia in kg·m² —
SI, like every stored value here — and the six inertia terms are
the tensor's Ixx, Iyy, Izz, Ixy, Ixz, Iyz (INERTIA_TERMS).
Frozen like Averaging and Truncation, and for the same reason:
the settings ride the geometry, the staleness fingerprint is their
fields, and a mutable setting would be a fingerprint that lies.
Validated at entry rather than at use: mass and inertia both or
neither, a positive mass, and a tensor a real body could have —
symmetric positive definite, which a typo in a product of inertia
breaks and which the triangle inequality (Ixx + Iyy ≥ Izz for a
real body) is a consequence of.
Methods:
| Name | Description |
|---|---|
tensor |
The 3×3 inertia tensor, or the identity when unscaled — |
principal_axes |
(moments, axes): the principal moments and the unit axis of |
describe |
The settings in words, for the status line and the |
Attributes:
| Name | Type | Description |
|---|---|---|
scaled |
bool
|
Whether the shapes are mass-normalised (mass and inertia |
Attributes¶
scaled
property
¶
Whether the shapes are mass-normalised (mass and inertia given) or unit shapes.
Methods:¶
tensor
¶
The 3×3 inertia tensor, or the identity when unscaled — which is what makes the unscaled rotation axes X, Y and Z.
Source code in src/visualdynamics/core/rigid.py
principal_axes
¶
(moments, axes): the principal moments and the unit axis of
each, as the rows of axes, one per rotation mode.
Ordered and signed so that mode 4 rotates about the principal axis nearest X, 5 nearest Y, 6 nearest Z, each pointed to have a positive component along its global axis — a diagonal tensor gives exactly X, Y, Z, and a lightly coupled one gives axes a reader can still call X, Y and Z. Each rotation shape is built from its own axis, so the three need not form a right-handed triad and are not forced into one.
Source code in src/visualdynamics/core/rigid.py
describe
¶
describe(
unit_system: UnitSystem | None = None,
*,
defined: bool = True,
) -> str
The settings in words, for the status line and the
staleness story alike: 'about (0.1, 0, 0.05) m, unit shapes'.
In SI by default — the journal's and the staleness story's
units — or in a unit system's display units when one is given.
defined=False says the geometry's coordinates are raw, so the
point is labelled as such rather than as metres.
Source code in src/visualdynamics/core/rigid.py
Functions:¶
is_rigid_set
¶
is_rigid_set(shapes: ShapeSet) -> bool
Whether a set is the six rigid-body shapes rigid_body_shapes
writes: six modes at exactly 0 Hz, described as such.
Read off the set rather than flagged on it, so a rigid set that travelled through a file, a copy or a script is still one.
Source code in src/visualdynamics/core/rigid.py
axis_name
¶
'X' for a global axis, else the axis's components — what a
rotation mode's description says it turns about.
Source code in src/visualdynamics/core/rigid.py
rigid_body_shapes
¶
rigid_body_shapes(
geometry: Geometry, properties: MassProperties
) -> ShapeSet
The six rigid-body mode shapes of a geometry about a point.
Three translations, then three rotations, over the three
translational DOFs of every node, each coefficient expressed in
the node's own displacement frame — deform.dof_directions is the
one owner of a DOF's global direction, so the shapes and the
animation that draws them agree by construction. Rotational DOFs
are not carried: nothing here measures them.
Frequencies are exactly 0.0, the convention the FRF synthesis relies on to recognise a rigid mode, and damping is 0.0.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
geometry
|
Geometry
|
The nodes the shapes are written over. |
required |
properties
|
MassProperties
|
The reference point and, optionally, the mass and inertia that mass-normalise the set. Mass properties on a geometry whose length unit is undeclared are refused: an inertia in kg·m² against coordinates in nothing is not a number. |
required |
Returns:
| Type | Description |
|---|---|
ShapeSet
|
Six modes over |