visualdynamics.core.validate¶
validate
¶
What an object will accept, in one place.
A type annotation is a claim — it tells an editor, a type checker and
the API reference what a thing is, and it does nothing at all at run
time. node_id: NDArray[np.int64] will not stop a string arriving. So
each claim needs an enforcement beside it, and the two belong in one
place or they drift: the helper here is what makes the annotation true,
and the annotation is what tells a reader the helper exists.
The failures worth catching are not the absurd ones. 'x' for a node id
already fails, loudly, inside numpy. What silently succeeds is 1.7
becoming node 1 — a mode shape drawn on the wrong node three weeks
later, with nothing in the file to say why.
Functions:
| Name | Description |
|---|---|
ids |
|
damping |
Damping as a fraction of critical: zero or more, per mode. |
frequency |
Modal frequencies in Hz: zero or more. |
modal_coordinate |
The mode index a modal coordinate names, or None for anything |
dofs |
DOF strings: a node id, then one of |
Functions:¶
ids
¶
values as ids, or a refusal saying which one was wrong.
Whole numbers only. 1.7 is not node 1 with a rounding error — it
is a caller who has computed an id, and truncating it quietly is how
that becomes somebody else's afternoon. Numeric strings are
accepted: every file format in this field writes ids as text, and a
reader that has to convert them before calling is a reader that will
convert them wrongly.
Not negative. An id is a label, and there is no meaning to give a negative one; zero is allowed, because files in the wild do number from zero and refusing them would be refusing real data.
unique where something refers to these by id — nodes, coordinate
systems and blocks. Element and traceline ids are labels nothing
refers to, and one traceline id legitimately names several polylines
(a UNV trace line that lifts the pen), so they are not held to it.
Source code in src/visualdynamics/core/validate.py
damping
¶
Damping as a fraction of critical: zero or more, per mode.
No upper bound. Above 1.0 is overdamped — a real thing to measure even if it is not a mode anyone will animate — so the rule is a floor and not a range. Below zero is a fit that has gone wrong or a sign convention nobody meant, and a negative damping synthesizes an FRF that grows without bound.
Source code in src/visualdynamics/core/validate.py
frequency
¶
Modal frequencies in Hz: zero or more.
Exactly zero is a rigid-body mode and is load-bearing — the FRF synthesis cancels its 0/0 by testing for it — so zero is not merely allowed, it is meaningful. Negative is not a frequency.
Source code in src/visualdynamics/core/validate.py
modal_coordinate
¶
The mode index a modal coordinate names, or None for anything
else — the one reader of the M<index> spelling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
A DOF string. |
required |
Returns:
| Type | Description |
|---|---|
int or None
|
The 1-based mode index, or None when the string is not a modal coordinate. |
Source code in src/visualdynamics/core/validate.py
dofs
¶
DOF strings: a node id, then one of DIRECTIONS. '101RX+'.
Or a modal coordinate, 'M3' (modal_coordinate).
A DOF is the whole vocabulary of this toolset — it is how a record finds its node on a geometry, how a shape finds its column, how a channel finds what it measures. An unparseable one does not fail where it is written; it fails as a record that quietly measures nothing, on a geometry that quietly has no such node, which is a much worse afternoon than a refusal at the door.
An unsigned direction is taken as the positive one — '101Z' is
'101Z+' — because that is how people write them by hand, and the
string is returned normalized so that everything downstream compares
like with like.
allow_unknown lets an incomplete DOF through, because a
channel table is written by people and people leave fields out. A
DOF string is the node and the direction concatenated, so whatever
was recorded is what comes out:
| node | direction | DOF |
|---|---|---|
| 101 | Z+ | 101Z+ |
| 101 | — | 101 |
| — | Z+ | Z+ |
| — | — | '' |
All four import. Refusing the file would leave the user nothing to
fix, where an imported record is visibly incompatible with any
geometry and the channel table is right there to correct it in. What
is still refused either way is a direction that is not a direction:
101Q+ is a typo, not an omission, and no amount of fixing the
channel table will make Q an axis.