Modules
tnsgrt.prism
- class tnsgrt.prism.Prism(p: int = 3, top_radius: float = 1, bottom_radius: float = 1, height: float = 1, alpha: float | None = None, calculate_equilibrium=True, equilibrium_method=typing.Literal['analytic', 'numeric'], **kwargs)
Constructs a Snelson prism with
pbars- Parameters:
p – number of bars
top_radius – the top radius
bottom_radius – the bottom radius
height – the radius of the prism
alpha – the twist angle
calculate_equilibrium – if
Truecalculates equilibriumequilibrium_method – choice of method for computing equilibrium
**kwargs – See below
- Keyword Arguments:
bar (
bool=True) – ifTrueadd barsbottom (
bool=True) – ifTrueadd bottom stringstop (
bool=True) – ifTrueadd top stringsvertical (
bool=True) – ifTrueadd vertical stringsdiagonal (
bool=False) – ifTrueadd diagonal strings
Notes:
Unloaded equilibrium is possible only if
\[\frac{\pi}{2} - \frac{\pi}{p} \leq \alpha \leq \frac{\pi}{2}\]when both vertical and diagonal strings are present
If diagonal strings are not present, then unloaded equilibrium is possible only if
\[\alpha = \frac{\pi}{2} - \frac{\pi}{p}\]This is the default prism configuration
If vertical strings are not present, then unloaded equilibrium is possible only if
\[\alpha = \frac{\pi}{2}\]Additional keyword arguments are passed to
tnsgrt.structure.Structure
tnsgrt.michell
- class tnsgrt.michell.Michell(n: int = 6, beta: float = 0.7853981633974483, q: int = 4, radius: float = 1, **kwargs)
Constructs a circular Michell truss with
nsides andqlayers- Parameters:
n – the number of sides
beta – the angle between the radius and the outermost bar
q – the number of layers
radius – the radius of the structure
**kwargs – See below
- Keyword Arguments:
spiral (
bool=True) – ifTrueadd spiral membersradial (
bool=True) – ifTrueadd radial membersouter (
bool=True) – ifTrueadd outer membersinner (
bool=True) – ifTrueadd inner memberscenter (
bool=True) – ifTrueadd center members
Notes:
If \(\rho\) is equal to
radius, then the radii as a function of the layer number i is
\[r(i) = \rho \, a^i, \qquad a = \frac{\beta}{\sin(\beta + \pi)}\]The radii are convergent only if \(a < 1\), that is
\[\beta < \frac{\pi}{2} - \frac{\pi}{2 n}\]The default \(\beta = \pi/4\) leads to convergent designs for all \(n > 2\).
Additional keyword arguments are passed to
tnsgrt.structure.Structure
tnsgrt.structure
- class tnsgrt.structure.Property
Base class for storing properties
Derived classes should implement
dataclassfromdataclasses
- class tnsgrt.structure.Structure(nodes: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] = array([], shape=(3, 0), dtype=float64), members: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] = array([], shape=(2, 0), dtype=int64), number_of_strings: int = 0, node_tags: Dict[str, ndarray[Any, dtype[int64]]] | None = None, member_tags: Dict[str, ndarray[Any, dtype[int64]]] | None = None, label: str = None)
A
Structureobject- Parameters:
nodes – a 3 x n array representing the
Structure’s nodesmembers – a 3 x m array representing the
Structure’s membersnumber_of_strings – the number of strings in
Structurenode_tags – a dictionary with the node tags
member_tags – a dictionary with the member tags
label – the
Structure’s label
- class MemberProperty(lambda_: float = 0.0, force: float = 0.0, stiffness: float = 0.0, volume: float = 0.0, radius: float = 0.01, inner_radius: float = 0, mass: float = 1.0, rest_length: float = 0.0, yld: float = 250000000.0, density: float = 7850.0, modulus: float = 200000000000.0, visible: bool = True, facecolor: object = (1, 0, 0), edgecolor: object = (1, 0, 0), linewidth: int = 2, linestyle: str = '-')
Subclass representing properties of members
- class NodeProperty(radius: float = 0.002, visible: bool = True, constraint: object = None, facecolor: object = (0, 0.447, 0.741), edgecolor: object = (0, 0.447, 0.741))
Subclass representing properties of nodes
- add_member_tag(tag: str, indices: int | ndarray[Any, dtype[int64]]) None
Add members with indices in
indicesto the member tagtagCreate tag if it does not already exist
- Parameters:
tag – the member tag
indices – the member indices
- add_members(members: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes], number_of_strings: int | None = None, member_tags: Dict[str, ndarray[Any, dtype[int64]]] | None = None) None
Add members and tags to current structure
- Parameters:
members – the members to be added
number_of_strings – the number of strings; if not
None, then the first number_of_strings members are tagged as ‘strings’ and the remaining members as ‘bars’member_tags – the new members’ tags
- add_node_tag(tag: str, indices: ndarray[Any, dtype[int64]]) None
Add nodes with indices in
indicesto the node tagtagCreate tag if it does not already exist
- Parameters:
tag – the node tag
indices – the node indices
- add_nodes(nodes: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes], node_tags: Dict[str, ndarray[Any, dtype[int64]]] | None = None) None
Add nodes to the
Structure- Parameters:
nodes – the nodes to add
node_tags – the node tags to add
- delete_member_tag(tag: str) None
Delete member tag
tag- Parameters:
tag – the member tag to be deleted
- delete_node_tag(tag: str) None
Delete node tag
tag- Parameters:
tag – the node tag to be deleted
- equilibrium(force: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None = None, lambda_bar: float | None = None, equalities: List[_SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes]] | None = None, epsilon: float = 1e-07) ndarray[Any, dtype[ScalarType]]
Solves for the set of internal forces that ensures the equilibrium of the current
Structurein response to the vector of external forcesforcesSolve the force equilibrium equation
\[A \lambda = f, \quad \lambda \in \Lambda\]in which:
\(A\): is a matrix representing the element vectors
\(f\): is the vector of external forces
\(\lambda\): is the vector of force coefficients
- \(\Lambda\): is a set of constraints on the force coefficients
(see Notes below)
- Parameters:
force – a 3 x n array of external forces or
Nonelambda_bar – the normalizing factor
equalities – a list of lists of member indices which are constrained to have the same force coefficient
epsilon – numerical accuracy
Notes:
If the \(i\) th element is a string then
\[\Lambda = \{ \lambda : \qquad \lambda_i \geq 0 \quad \text{ if } i\text{th element is a string} \}\]All elements in
equalitiesare set equal. For example, if:equalities = [[0, 1, 3], [2, 4]]
then the constraints
\[\lambda_0 = \lambda_1 = \lambda_3, \qquad \lambda_2 = \lambda_4\]are added to the constraint set \(\Lambda\).
If
force=Nonethen the sum of the bar force coefficients equalslambda_bar. That is, the following modified problem is solved:\[A \lambda = 0, \quad \mathbf{e}^T \lambda = \bar{\lambda}, \quad \lambda \in \Lambda\]in which \(\mathbf{e}\) is a vector that has 1 for bars and 0 for strings.
If
forceis notNoneandlambda_baris also notNonethen the following problem is solved\[A \lambda = f, \quad \mathbf{e}^T \lambda = \bar{\lambda}, \quad \lambda \in \Lambda\]WARNING: This problem may not be feasible for all \(\bar{\lambda} > 0\)!
- get_center_of_mass() ndarray[Any, dtype[float64]]
- Returns:
the
Structure’s center of mass
- get_centroid() ndarray[Any, dtype[float64]]
- Returns:
the
Structure’s geometric center or centroid
- get_close_nodes(radius=1e-06) Tuple[Set[int], ndarray[Any, dtype[ScalarType]]]
Returns the set of nodes that lie within
radiusdistance to other nodes inStructureand the corresponding mapFor example, if:
close_nodes, close_nodes_map = s.get_close_nodes()
is such that:
close_nodes = {1, 3} close_nodes_map = [0,0,2,2,4]
then node
1is close to node0and node3is close to node2.- Parameters:
radius – the proximity radius
- Returns:
tuple with
close_nodesandclose_nodes_map
- get_colinear_nodes(epsilon: float = 1e-08, return_members: bool = False) ndarray[Any, dtype[int64]] | Tuple[ndarray[Any, dtype[int64]], ndarray[Any, dtype[int64]]]
- Params epsilon:
accuracy of co-linearity test
- Params return_members:
if
Truereturns tuple of member indices as well- Returns:
an array with the indices of the co-linear nodes or tuple with an array with the indices of the co-linear nodes and an array with the member indices
Notes:
Co-linear nodes are nodes that have only 2 co-linear members connected to them
- get_member_length() ndarray[Any, dtype[float64]]
- Returns:
an array with the
Structure’s member lengths
- get_member_properties(index: int | Sequence[int] | slice, *labels: str) DataFrame
Retrieve member properties
- Parameters:
index – the member index
*labels – the member property labels
- Returns:
datafrome with the selected properties
WARNING:
tnsgrt.structure.Structure.get_member_properties()uses pandas’ loc method that includes the last element of slices; See pandas documentation for details
- get_member_tags(index: int) List[str]
A list with the tags for the member with index
index- Parameters:
index – the index of the member
- Returns:
list of tags
- get_member_vectors() ndarray[Any, dtype[float64]]
- Returns:
a 3 x m array with the
Structure’s members
- get_members_by_tag(*tag: str) ndarray[Any, dtype[int64]]
Return a list of member indices that have given tags
- Parameters:
*tag – the tag
- Returns:
list of member indices
- get_members_per_node() ndarray[Any, dtype[ScalarType]]
- Returns:
number of members connected to each node
- get_node_properties(index: int | Sequence[int] | slice, *labels: str) DataFrame
Retrieve node properties
- Parameters:
index – the node index
*labels – the node property labels
- Returns:
datafrome with the selected properties
WARNING:
tnsgrt.structure.Structure.get_node_properties()uses pandas’ loc method that includes the last element of slices; See pandas documentation for details
- get_node_values(index: int | Sequence[int] | slice) ndarray[Any, dtype[ScalarType]]
Get node values
- Parameters:
index – the index of the nodes to get; can be a slice, integer, or sequence
- Returns:
the node values
- get_nodes_by_tag(*tag: str) ndarray[Any, dtype[int64]]
Return a list of node indices that have given tags
- Parameters:
*tag – the tag
- Returns:
list of node indices
- get_number_of_members() int
- Returns:
the number of members in
Structure
- get_number_of_members_by_tag(tag: str) int
Return the number of members with tag
tag- Parameters:
tag – the tags
- Returns:
the number of members
- get_number_of_nodes() int
- Returns:
the number of nodes in
Structure
- get_number_of_nodes_by_tag(tag: str) int
Return the number of members with tag
tag- Parameters:
tag – the tags
- Returns:
the number of members
- get_slack_members(epsilon: bool = 1e-08) Index
- Returns:
the index of members with small force coefficients
- get_unused_nodes() ndarray[Any, dtype[int64]]
- Returns:
an array with the indices of the unused nodes
- has_member_tag(index: int, tag: str) bool
Return
Trueif member with indexindexhas tagtag- Parameters:
index – the index of the member
tag – the tag
- Returns:
TrueorFalse
- has_unused_nodes() bool
- Returns:
Trueif there are no unused nodes
- merge_close_nodes(radius: float = 1e-06, verbose: bool = False) None
Merge then remove all nodes in
Structurewhich lie withinradius- Parameters:
radius – the proximity radius
verbose – if
Trueissues a warning with number of nodes removed after the merge
- merge_colinear_nodes(epsilon: float = 1e-08) None
Merge members in co-linear nodes
See
tnsgrt.structure.Structure.get_colinear_nodes()- Parameters:
epsilon – accuracy of co-linearity test
Notes:
If the co-linear members are a bar and a string, the node and members are skipped
New member inherit all tag from co-linear members
All dependent nodes are removed and co-linear members are replaced
- merge_overlapping_members(verbose: bool = False) None
Merge overlapping members in structure
Notes:
Overlapping members are members that share the same set of nodes
The properties ‘lambda_’, ‘force’, ‘mass’, and ‘volume’ are summed on the merged member
The remaining member has as tags the union of all tags in the merged members
- reflect(v: ndarray[Any, dtype[ScalarType]], p: ndarray[Any, dtype[ScalarType]] | None = None) Structure
Reflects the structure about a plane normal to the vector v, passing through the point p. If no point is given, it defaults to the origin.
- Parameters:
v – the 3D normal vector
p – the 3D origin vector
- Returns:
self
- remove_member_tag(tag: str, indices: ndarray[Any, dtype[int64]]) None
Remove members with indices in
indicesfrom the existing member tagtag- Parameters:
tag – the member tag
indices – the member indices
- remove_members(members_to_be_deleted: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None = None, verbose: bool = False)
Remove members from
Structure- Parameters:
members_to_be_deleted – the indices of the members to be deleted
verbose – if
Truewarns of the members to be deleted
- Returns:
- remove_node_tag(tag: str, indices: ndarray[Any, dtype[int64]]) None
Remove nodes with indices in
indicesfrom the existing node tagtag- Parameters:
tag – the node tag
indices – the node indices
- remove_nodes(nodes_to_be_removed: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None = None, verify_if_unused: bool = True, verbose: bool = False) None
Remove nodes from structure
- Parameters:
nodes_to_be_removed – the indices of the nodes to be deleted; if
None, delete all currently unused nodesverify_if_unused – if
Trueverifies if the nodes to be deleted are not in useverbose – if
Truewarns of the nodes to be deleted
- rotate(v: ndarray[Any, dtype[ScalarType]]) Structure
Rotate all nodes of the
Structureby the 3D vectorv- Parameters:
v – the 3D rotation vector
- Returns:
self
Notes:
See
scipy.spatial.transform.Rotation.from_rotvec()for details
- set_member_properties(index: int | Sequence[int] | slice, labels: str | Sequence[str], values: Any, *vargs, scalar: bool = True) None
Set member properties
See
tnsgrt.structure.Structure._set_dataframe()- Parameters:
index – the element index
labels – the property label(s)
values – the values to set to
*vargs – label/values pairs
scalar – if
True,valueis set to an array of len(index)
- set_node_properties(index: int | Sequence[int] | slice, labels: str | Sequence[str], values: Any, *vargs, scalar: bool = True) None
Set node properties
See
tnsgrt.structure.Structure._set_dataframe()- Parameters:
index – the element index
labels – the property label(s)
values – the values to set to
*vargs – label/values pairs
scalar – if
True,valueis set to an array of len(index)
- set_node_values(index: int | Sequence[int] | slice, nodes: ndarray[Any, dtype[ScalarType]]) None
Set node values
- Parameters:
index – the index of the nodes to set; can be a slice, integer, or sequence
nodes – the values to set
- set_nodes(nodes: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes]) None
Set nodes of the
Structure- Parameters:
nodes – the nodes
- stiffness(force: _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None = None, epsilon: float = 1e-06, storage: str = 'sparse', apply_rigid_body_constraint: bool = False, apply_planar_constraint: bool = False)
Computes
normal: potential energy (1 x 1)
F: force vectors (3 x n)
K: stiffness matrix (3 n x 3 n)
M: mass matrix (n x 1)
for the current
Structure. The mass and stiffness matrices are returned in the form of an object of the classtnsgrt.stiffness.Stiffness- Parameters:
epsilon – numerical accuracy
storage – if
sparsestores the resulting stiffness and mass matrices in sparse csr formatapply_rigid_body_constraint – if
Trueapply 3D rigid body constraintsapply_planar_constraint – if
Trueapply 2D constraints
- Returns:
tuple (S, F, normal)
- translate(v: ndarray[Any, dtype[ScalarType]]) Structure
Translate all nodes of the
Structureby the 3D vectornormal- Parameters:
v – the 3D translation vector
- Returns:
self
- update_member_properties(property_name: str | Iterable[str] | None = None) None
Update
Structure’s member propertiesIf property_name is
‘stiffness’: calculate
stiffnessandrest_lengthbased onmodulus,radius,inner_radiusandlambda_‘mass’: calculate
massandvolumebased onradiusanddensity‘force’: calculate
forcebased onlambda_
- Parameters:
property_name – the property name to update; if
None, update all properties
- tnsgrt.structure.merge(*s: Structure) Structure
Returns a new structure in which all structures given in s are merged
- Parameters:
*s – the structures to merge
- Returns:
the merged structure
- tnsgrt.structure.reflect(s: Structure, v: ndarray[Any, dtype[ScalarType]], p: ndarray[Any, dtype[ScalarType]]) Structure
Returns a copy of
sin which all nodes are reflected about a plane normal to the vector v, passing through the point p.If no point is given, it defaults to the origin.
- Parameters:
s – the structure to reflect
v – the 3D normal vector
p – the 3D origin vector
- Returns:
the reflected structure
- tnsgrt.structure.rotate(s: Structure, v: ndarray[Any, dtype[ScalarType]]) Structure
Returns a copy of
sin which all nodes are rotated around the 3D vectorv- Parameters:
s – the structure to rotate
v – the 3D rotation vector
- Returns:
the rotated structure
Notes:
See
scipy.spatial.transform.Rotation.from_rotvec()for details
tnsgrt.plotter
- class tnsgrt.plotter.plotter.Plotter
Base class for structure plotters
- static cone(node1: ndarray[Any, dtype[ScalarType]], node2: ndarray[Any, dtype[ScalarType]], base_radius: float = 0.01, n: int = 12) Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]]
Return xyz grid points for cylinder with center aligned with the vector defined by
node1andnode2- Parameters:
node1 – center of the base of the cylinder
node2 – center of the top of the cylinder
base_radius – radius of the cylinder, ignore if volume is positive
n – number of sides
- Returns:
tuple with x, y, and z points
- static cylinder(node1: ndarray[Any, dtype[ScalarType]], node2: ndarray[Any, dtype[ScalarType]], radius: float = 0.01, n: int = 12) Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]]
Return xyz grid points for cylinder with center aligned with the vector defined by
node1andnode2- Parameters:
node1 – center of the base of the cylinder
node2 – center of the top of the cylinder
radius – radius of the cylinder, ignore if volume is positive
n – number of sides
- Returns:
tuple with x, y, and z points
- plot(*s: Structure, **kwargs) None
Plot structure
- Parameters:
*s – the structure or sequence of structures
**kwargs – additional keyword arguments
- static truncated_cylinder(node1: ndarray[Any, dtype[ScalarType]], node2: ndarray[Any, dtype[ScalarType]], base_radius: float = 0.01, top_radius: float = 0.01, n: int = 12) Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]]
Return xyz grid points for cylinder with center aligned with the vector defined by
node1andnode2- Parameters:
node1 – center of the base of the cylinder
node2 – center of the top of the cylinder
base_radius – radius of the cylinder base
top_radius – radius of the cylinder top
n – number of sides
- Returns:
tuple with x, y, and z points
- static unit_cylinder(n: int = 10, radius: float = 1, height: float = 1) Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]]
Return xyz grid points for solid cylinder centered at the origin
- Parameters:
n – number of sides
radius – radius of cylinder
height – height of cylinder
- Returns:
tuple with x, y, and z points
- static unit_sphere(n: int = 10, radius: float = 1) Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]]
Return xyz grid points for solid sphere centered at the origin
- Parameters:
n – number of sides
radius – radius of sphere
- Returns:
tuple with x, y, and z points
- static unit_truncated_cylinder(n: int = 10, base_radius: float = 1, top_radius: float = 1, height: float = 1) Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]]
Return xyz grid points for solid truncated cylinder centered at the origin
- Parameters:
n – number of sides
base_radius – radius of the cylinder base
top_radius – radius of the cylinder top
height – height of cylinder
- Returns:
tuple with x, y, and z points
- class tnsgrt.plotter.matplotlib.MatplotlibPlotter(plotter: MatplotlibPlotter | None = None, fig: Figure | None = None, ax: Axes | None = None)
Matplotlib based structure plotter
- Parameters:
plotter –
tnsgrt.plotter.matplotlib.Matplotlibobjectfig –
matplotlib.figureobjectax –
matplotlib.pyplot.axisobject
- get_handles() Tuple[Figure, Axes]
- Returns:
tuple with matplotlib figure and axis
- plot(*s: Structure, **kwargs) None
Plot structure
- Parameters:
*s – the structure or sequence of structures
**kwargs – additional keyword arguments
- view_init(elev=0, azim=0, roll=0) None
Set view
- Parameters:
elev – elevation
azim – azimuth
roll – roll
tnsgrt.stiffness
- class tnsgrt.stiffness.NodeConstraint(constraint: ndarray[Any, dtype[ScalarType]] | None = None, displacement: ndarray[Any, dtype[ScalarType]] | None = None, epsilon: float = 1e-08)
Object representing a node constraint
- Parameters:
constraint – the constraint coefficient array
epsilon – precision used to assess numerical rank
Notes:
If \(x\) is the node coordinate and \(A\) is the constraint coefficient then
\[A x = 0\]then the equivalent constraint and its null space
\[R \, x = 0, \quad x = T \, y, \quad R R^T = I, \quad T^T T = I\]are constructed using
tnsgrt.utils.orthogonalize()
- static node_constraint(nodes: ndarray[Any, dtype[ScalarType]], constraints: Sequence[NodeConstraint], storage: Literal['sparse', 'dense'] = 'sparse') Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]] | Tuple[csr_array, csr_array]
Construct the constraint associated with the given nodes and node constraints
The resulting tuple is compatible with
apply_constraint()- Parameters:
nodes – 3 x n array of nodes
constraints – list with n constraints
storage – if
sparse, returns sparse arrays
- Returns:
tuple with the constraint matrix, and its null space
- static planar_constraint(nodes: ndarray[Any, dtype[ScalarType]], normal: ndarray[Any, dtype[ScalarType]] | None = None, epsilon: float = 1e-08, storage='sparse')
Construct the planar constraint associated with the given nodes and normal vector
The resulting tuple is compatible with
apply_constraint()- Parameters:
nodes – 3 x n array of nodes
normal – list with n constraints
epsilon – accuracy
storage – if
sparse, returns sparse arrays
- Returns:
tuple with the constraint matrix, and its null space
- static rigid_body_constraint(nodes: ndarray[Any, dtype[ScalarType]], epsilon: float = 1e-08) Tuple[ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]]
Construct rigid-body constraint associated with the given nodes
The resulting tuple is compatible with
apply_constraint()- Parameters:
nodes – 3 x n array of nodes
epsilon – precision used to assess numerical rank
- Returns:
tuple with the constraint matrix, and its null space
- static rigid_body_three_point_constraint(nodes: ndarray[Any, dtype[ScalarType]], epsilon: float = 1e-08) Tuple[NodeConstraint, NodeConstraint, NodeConstraint]
Return three constraints on three given nodes to prevent rigid motion.
- Parameters:
nodes – 3 x 3 array of nodes (column oriented)
epsilon – accuracy to assess co-linearity
- Returns:
tuple with 3 node constraints
Notes:
The constraints are as follows: - Node 0 is fixed - Node 1 is allowed to move in the line 0-1 - Node 2 is allowed to move in the plane 0-1-2
- class tnsgrt.stiffness.Stiffness(K: ndarray[Any, dtype[ScalarType]] | csr_matrix, M: ndarray[Any, dtype[ScalarType]] | csr_matrix | None = None)
Model for a constrained mechanical system consisting of
\(K\): the stiffness matrix
\(M\): the mass matrix
\(R\): a matrix representing node displacement constraints
\(T\): a matrix representing allowed node displacements
such that
\[V = \frac{1}{2} y^T K y + \frac{1}{2} \ddot{y}^T M \ddot{y}, \qquad R \, x = 0, \qquad x = T y\]Constructor parameters:
- Parameters:
K – the stiffness matrix
M – the mass matrix
Notes:
The stiffness and mass matrices are stored in the reduced coordinates \(y\)
In global coordinates
\[V = \frac{1}{2} x^T K_x x + \frac{1}{2} \ddot{x}^T M_x \ddot{x}\]in which
\[K_x = T^T K T, \qquad M_x = T^T M T\]Use
tnsgrt.stiffness.Stiffness.apply_constraint()to apply constraints to the modelNode constraints are enforced to be orthogonal so that
\[R \, x = 0, \quad x = T y, \qquad R R^T = I, \quad T^T T = I, \quad R \, T = 0\]
- apply_constraint(R: ndarray[Any, dtype[ScalarType]] | csr_matrix, T: ndarray[Any, dtype[ScalarType]] | csr_matrix | None = None, local: bool = True, verbose: bool = True, epsilon: float = 1e-08)
Apply the constraint
\[R \, y = 0, \qquad y = T z\]to the current or the global
Stiffnessobject coordinate- Parameters:
R – the constraint coefficient matrix
T – the allowed node displacements; if
Noneconstraint is normalizedlocal – if
Truethe constraint is appliedverbose – if
Trueprint warningsepsilon – precision used to assess numerical rank
- Returns:
Notes:
If
local = Trueand the current constraints are\[R_y \, x = 0, \quad x = T_y \, y, \qquad R^{}_y R_y^T = I, \quad T_y^T T^{}_y = I, \quad R_y T_y = 0\]then after applying the new constraints
\[R \, y = R \, T_y^T x = R_z x = 0, \qquad x = T_y \, y = T_y T z = T_z z,\]in which
\[R_z = R \, T_y^T, \qquad T_z = T_y T\]and
\[V = \frac{1}{2} z^T K_z \, z + \frac{1}{2} \ddot{z}^T M_z \, \ddot{z}, \qquad R_z x = 0, \quad x = R_z \, z,\]in which
\[K_z = T^T K T, \qquad M_z = T^T M T\]If
local = Falseand the constraints are interpreted as\[R \, x = 0, \quad x = T \, z\]which is first converted to the local constraint
\[R \, x = R \, T_y y = \tilde{R} y = 0, \qquad \tilde{R} = R \, T_y,\]before applying
- displacements(f: ndarray[Any, dtype[ScalarType]])
Calculate displacements due to the application of a global force
- Parameters:
f – 3 x m array of forces
- Returns:
the displacements
Notes:
The displacements are calculated in global coordinates
\[x = T K^{-1} T^T f\]
- eigs(k: int = 12, which: Literal['LM', 'SM', 'LR', 'SR', 'LI', 'SI'] = 'SM')
Compute the eigenvalues and eigenvectors of the stiffness matrix
If the stiffness matrix is stored as a sparse array, return only the first k eigenvalue/eigenvector pairs
- Parameters:
k – the number of eigenvalues
which – which eigenvalues to compute; see
scipy.sparse.linalg.eigsh()for details
- Returns:
tuple with eigenvalues, and eigenvectors
Notes:
The eigenvalues and eigenvectors are calculated by solving the eigenvalue problem
\[K y = \lambda \, y, \qquad x = T \, y\]
- modes(k: int = 12, units='Hz', which: Literal['LM', 'SM'] = 'SM')
Compute the natural frequencies [rad/s] and mode vectors
- Parameters:
k – the number of eigenvalues
which – which eigenvalues to compute; see
scipy.sparse.linalg.eigsh()for detailsunits – return frequencies in Hz if
units = 'Hz'
- Returns:
tuple with eigenvalues, and eigenvectors
Notes:
The natural frequencies and mode vectors are calculated by solving the generalized eigenvalue problem
\[K y = \omega^2 M y, \qquad x = T \, y\]
tnsgrt.utils
- class tnsgrt.utils.Colors(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
Default colors
- BLUE = (0, 0.447, 0.741)
- BROWN = (0.635, 0.078, 0.184)
- GREEN = (0.466, 0.674, 0.188)
- LIGHT_BLUE = (0.301, 0.745, 0.933)
- ORANGE = (0.85, 0.325, 0.098)
- PURPLE = (0.494, 0.184, 0.556)
- YELLOW = (0.929, 0.694, 0.125)
- tnsgrt.utils.is_colinear(a: ndarray[Any, dtype[ScalarType]], b: ndarray[Any, dtype[ScalarType]], epsilon: float = 1e-08) bool
Two vectors are colinear if their orthogonal projection is small
- Parameters:
a – first vector
b – second vector
epsilon – accuracy
- Returns:
Trueif colinear
- tnsgrt.utils.norm(a: ndarray[Any, dtype[ScalarType]] | csr_matrix) float
- Parameters:
a – the array
- Returns:
the 2-norm of the array
- tnsgrt.utils.orthogonalize(a: ndarray[Any, dtype[ScalarType]] | csr_matrix, epsilon: float = 1e-08, mode: Literal['reduced', 'complete'] = 'reduced') Tuple[int, ndarray[Any, dtype[ScalarType]], ndarray[Any, dtype[ScalarType]]] | Tuple[int, ndarray[Any, dtype[ScalarType]]]
Ortoghonalize the constraint
\[A^T \, x = 0\]- Parameters:
a – the coefficient array \(A\)
epsilon – the accuracy with which to evaluate the rank
mode – ‘complete’ or ‘reduced’
- Returns:
tuple with rank, the orthogonalized coefficient array, and its null space if mode is ‘complete’
Notes:
If
mode = 'reduced'the constraint coefficient is normalized at the constructor by calculating the reduced SVD decomposition\[A = V S U^T, \quad V^T V = I, \quad U^T U = I, \quad S \text{ is diagonal}\]Assuming that \(A\) is full rank, the equivalent orthogonal constraint
\[A^T x = U S V^T x = 0 \quad \Leftrightarrow \quad V^T x = 0\]is obtained in which the coefficient is the orthogonal matrix \(V\)
If
mode = 'complete'the constraint coefficient is normalized at the constructor by calculating the complete SVD decomposition\[A = \tilde{V} \tilde{S} \tilde{U}^T, \quad \tilde{V}^T \tilde{V} = \tilde{V} \tilde{V}^T = I, \quad \tilde{U}^T \tilde{U} = \tilde{U} \tilde{U}^T = I, \quad \tilde{S} \text{ is diagonal}\]Assuming that \(A\) is full rank, partition
\[\begin{split}\begin{bmatrix} V & T \end{bmatrix} = \tilde{V}, \qquad \begin{bmatrix} U & Q \end{bmatrix} = \tilde{U}, \qquad \tilde{S} = \begin{bmatrix} S \\ 0 \end{bmatrix}, \quad S \text{ is diagonal}\end{split}\]to obtain the equivalent orthogonal constraint and its solution
\[A^T x = U S V^T x = 0 \quad \Leftrightarrow \quad V^T x = 0, \qquad x = T \, y\]The matrix \(T\) is an orthogonal basis for the constraint null space
The above factorizations are modified to take into account the numerical rank of \(A\) when it is rank-deficient
- tnsgrt.utils.rotation_2d(phi: float) ndarray[Any, dtype[ScalarType]]
Return a 2D rotation matrix
- Parameters:
phi – the rotation angle in radians
- Returns:
the rotation matrix
- tnsgrt.utils.rotation_3d(v: ndarray[Any, dtype[ScalarType]]) ndarray[Any, dtype[ScalarType]]
Return a 3D rotation matrix
- Parameters:
v – the vector around which to rotate; its norm is the angle to rotate
- Returns:
the rotation matrix
Notes:
See
scipy.spatial.transform.Rotation.from_rotvec()for details