PREPROCESSING METHODS

Contents

PREPROCESSING METHODS#

class sstatics.core.preprocessing.bar.Bar(node_i, node_j, cross_section, material, hinge_u_i=False, hinge_w_i=False, hinge_phi_i=False, hinge_u_j=False, hinge_w_j=False, hinge_phi_j=False, deformations=('moment', 'normal'), line_loads=(), temp=<factory>, point_loads=())#

Bases: object

Create a bar for a statical system.

Parameters:
node_iNode

Node at the start of the bar.

node_jNode

Node at the end of the bar.

cross_sectionCrossSection

Cross-sectional properties of the bar.

materialMaterial

Material properties of the bar.

hinge_u_ibool, default=False

Normal hinge at the start of the bar.

hinge_w_ibool, default=False

Shear hinge at the start of the bar.

hinge_phi_ibool, default=False

Moment hinge at the start of the bar.

hinge_u_jbool, default=False

Normal hinge at the end of the bar.

hinge_w_jbool, default=False

Shear hinge at the end of the bar.

hinge_phi_jbool, default=False

Moment hinge at the end of the bar.

deformationstuple | list, default=(‘moment’, ‘normal’)

Deformation components considered in the calculation. Valid options: “moment”, “normal”, “shear”.

line_loadstuple | list, default=()

Distributed loads acting on the bar.

tempBarTemp, default=(BarTemp(0, 0))

Temperature loads acting on the bar.

point_loadstuple | list, default=()

Point loads acting on the bar.

Raises:
ValueError

node_i and node_j need to have different locations.

ValueError

There has to be at least one deformation component.

ValueError

Valid deformation keywords are “moment”, “normal” and “shear”.

property EA#

Alias of axial_rigidity.

property EI#

Alias of flexural_stiffness.

property GA_s#

Alias of shear_stiffness.

property axial_rigidity#

Calculates the axial rigidity (\(EA\)) of the bar.

The axial rigidity is defined as the product of the Young’s modulus (\(E\)) and the area (\(A\)).

Returns:
float

The axial rigidity \(EA\).

Notes

The axial rigidity is given by:

\[EA = E \cdot A\]

If the axial deformation component is not to be considered in the calculation (deformations does not include ‘normal’), the axial rigidity of the bar is scaled to reduce the deformation component so that the axial deformation becomes negligibly small.

\[EA = 1000 \cdot E \cdot A\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'normal'])
>>> b.axial_rigidity
1613640.0
>>> b = Bar(n1, n2, cross, mat, deformations=['moment'])
>>> b.axial_rigidity
1613640000.0
f0(hinge_modification=True, to_node_coord=True)#

Represents the vector of internal forces at the beam element ends in the load-deformation state (LDS).

Due to external loads acting on the beam element, internal forces develop at the element ends. These internal forces are assembled in the vector \(f^{(0)'}\).

Parameters:
hinge_modificationbool, default=True

Modifies the load vector and the element stiffness matrix to account for hinges.

to_node_coordbool, default=True

Transforms the load vector into the nodal coordinate system.

Returns:
numpy.array

The 6x1 vector of internal forces at the beam element ends due to external loads.

Notes

The beam element can be subjected to distributed loads and point loads. In statically indeterminate systems, internal forces may also arise due to temperature effects and support deformations. These loading cases are collected within the algorithm.

If hinges are present in the beam, it is necessary to modify the stiffness matrix and load vector to account for discontinuities in deformations at hinge locations.

Finally, the load vector may be transformed into the nodal coordinate system if required.

property f0_displacement#

Calculates the internal forces due to support stresses related to the local bar coordinate system.

Returns:
numpy.array

6x1 vector of the internal forces due to support stresses.

Notes

The support displacements of the initial and end nodes are combined into a 6x1 vector. By multiplying the stiffness matrix with the acting support displacements, the resulting internal forces are obtained. Since the support displacements are given in the node coordinate system, a transformation using the transformation matrix is required to obtain the internal forces in the bar coordinate system.

The vector is calculated using the following mathematical equations:

\[f^{0'} = k^{'} \cdot \Delta^{'}\]

Including the transformation matrix, the following equation is used:

\[\begin{split}f^{0'} = k^{'} \cdot T \cdot \left\lbrace\begin{array}{c} u_i \\ w_i \\ \varphi_i \\ u_j \\ w_j \\ \varphi_j \end{array}\right\rbrace\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> from sstatics.core.preprocessing.dof import NodeDisplacement
>>> displace = NodeDisplacement(0, 0.005, 0)
>>> n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')
>>> n2 = Node(4, 0, w='fixed', displacements=displace)
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 1.2e-5)
>>> b = Bar(n1, n2, cross, mat)
>>> b.f0_displacement
array([[0], [-5.45146875], [10.9029375], [0], [5.45146875],
[10.9029375]])
property f0_line#

Calculates the internal forces due to external line loads related to the local bar coordinate system.

Returns:
numpy.array

6x1 vector of the internal forces due to external loads

Notes

In the calculation of the deformation method, the load deformation state (LDS) of the bar element is considered in addition to unit deformation state (UDS) of the unloaded bar. For common loading conditions, internal forces are tabulated in engineering handbooks. The implemented vector for internal forces due to distributed loads assumes a trapezoidal load distribution. The vector also takes shear deformations into account.

The vector is calculated using the following mathematical equations:

\[\begin{split}f^{0'} = \left\lbrace\begin{array}{c} f_{x,i}^{(0)'} \\\\ f_{z,i}^{(0)'} \\\\ f_{M,i}^{(0)'} \\\\ f_{x,j}^{(0)'} \\\\ f_{z,j}^{(0)'} \\\\ f_{M,j}^{(0)'} \end{array}\right\rbrace = \left\lbrace\begin{array}{c} \dfrac{(7n_i + 3 n_j) \ell}{20} \\\\ \dfrac{(40EIp_j + 80EIp_i + 3GA_s \ell^2 p_j + 7 G A_s \ell^2 p_i) \ell}{240 EI + 20 GA_s \ell^2} \\\\ -\dfrac{(30 EI p_j + 30 EI p_i + 2 GA_s \ell p_j + 3 GA_s \ell^2 p_i) \ell^2}{720EI + 60 GA_s \ell^2} \\\\ -\dfrac{(3n_i + 7 n_j) \ell}{20} \\\\ -\dfrac{(80EIp_j + 40EIp_i + 7GA_s \ell^2 p_j + 3 G A_s \ell^2 p_i) \ell}{240 EI + 20 GA_s \ell^2} \\\\ -\dfrac{(30 EI p_j + 30 EI p_i + 3 GA_s \ell p_j + 2 GA_s \ell^2 p_i) \ell^2}{720EI + 60 GA_s \ell^2} \end{array}\right\rbrace\end{split}\]
property f0_point#

Calculates the internal forces due to point loads related to the local bar coordinate system.

The method rotates the point load components from the system coordination system into the bar coordination system. Only point load componants at the beginning (position = 0) and at the end (position = 1) of the beam are included.

Returns:
numpy.array

6x1 vector of the rotated point load components.

Notes

The transformation is performed using the following rotation matrix:

\[\begin{split}f^{0'}= \begin{bmatrix} \cos(\alpha- \beta_i) & \sin(\alpha - \beta_i) & 0 & 0 & 0 & 0\\ -\sin(\alpha - \beta_i) & \cos(\alpha - \beta_i) & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & \cos(\alpha- \beta_j) & \sin(\alpha - \beta_j) & 0 \\ 0 & 0 & 0 & -\sin(\alpha - \beta_j) & \cos(\alpha - \beta_j) & 0\\ 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}^{T} \cdot f^{0}_{load}\end{split}\]
property f0_temp#

Calculates the internal forces due to temperature loads related to the local bar coordinate system.

Returns:
numpy.array

6x1 vector of the internal forces due to temperature loads.

Notes

The vector is calculated by the following mathmatical equations:

\[\begin{split}f^{0'} = \left\lbrace\begin{array}{c} \alpha_T \cdot T \cdot E \cdot A \\ 0 \\ \dfrac{\alpha_T \cdot \Delta T \cdot E \cdot I}{h} \\ - \alpha_T \cdot T \cdot E \cdot A \\ 0 \\ - \dfrac{\alpha_T \cdot \Delta T \cdot E \cdot I}{h} \end{array}\right\rbrace\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> from sstatics.core.preprocessing.temperature import BarTemp
>>> n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')
>>> n2 = Node(4, 0, u='fixed', w='fixed', phi='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 1.2e-5)
>>> temp = BarTemp(15, 30)
>>> b = Bar(n1, n2, cross, mat, temp=temp)
>>> b.f0_temp
array([[435.6828], [0], [5.23341], [-435.6828], [0], [-5.23341]])
property flexural_stiffness#

Calculates the flexural stiffness (\(EI\)) of the element.

The flexural stiffness is defined as the product of the Young’s modulus (\(E\)) and the second moment of area (moment of inertia, \(I\)) of the cross-section.

Returns:
float

The flexural stiffness \(EI\).

Notes

The flexural stiffness is given by:

\[EI = E \cdot I\]

If the bending deformation component is not to be considered in the calculation (deformations does not include ‘moment’), the flexural stiffness of the bar is scaled to reduce the deformation component so that the bending deformation becomes negligibly small.

\[EI = 1000 \cdot E \cdot I\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'normal'])
>>> b.flexural_stiffness
5814.900000000001
>>> b = Bar(n1, n2, cross, mat, deformations=['normal'])
>>> b.flexural_stiffness
5814900.000000001
property hinge#

Creates a tuple containing bar hinges at both ends of a structural element.

This method assembles and returns the hinge conditions of a bar at its start node (i) and end node (j). Hinges define how the bar is allowed to move or rotate at its ends.

The tuple consists of six elements representing the hinges at each node:

Returns:
tuple
A 6-tuple containing the hinge parameters in the following order:
  • hinge_u_i (bool): Normal hinge at node i.

  • hinge_w_i (bool): Shear hinge at node i.

  • hinge_phi_i (bool): Moment hinge at node i.

  • hinge_u_j (bool): Normal at node j.

  • hinge_w_j (bool): Shear hinge at node j.

  • hinge_phi_j (bool): Moment at node j.

Notes

A value of True indicates the presence of a hinge, while False indicates a rigid connection at that degree of freedom.

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')
>>> n2 = Node(4, 0, u='fixed', w='fixed', phi='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, hinge_w_i=True, hinge_phi_j=True)
>>> b.hinge
(False, True, False, False, False, True)
property inclination#

Calculates the inclination of the beam in relation to the node coordinates.

Returns:
float

Angle of inclination in rad.

Notes

The inclination is calcultated by using the following equation:

\[\alpha = \arctan \frac{(-z_2 + z_1)}{(x_2 - x_1)}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(0, 0)
>>> node_2 = Node(4, -2)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> bar_1 = Bar(node_1, node_2, cross_sec, material)
>>> bar_1.inclination
0.7853981634
property length#

Calculates the distance between two nodes that define the bar element.

Returns:
float

Length of bar element.

Notes

The length is calcultated by using the following equation:

\[L = \sqrt{(x_2 - x_1)^2 + (z_2 - z_1)^2}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(2, 5)
>>> node_2 = Node(10, 6)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> bar_1 = Bar(node_1, node_2, cross_sec, material)
>>> bar_1.length
8.06225774829855
property line_load#

The overall line load on a bar element as a 6x1 vector.

Returns:
numpy.array

Sum of all line loads specified in line_loads.

See also

BarLineLoad

Notes

If no line loads are specified, then a 6x1 zero vector is returned. The load components are rotated by the inclination of the beam.

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(0, 0)
>>> node_2 = Node(3, -4)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> Bar(node_1, node_2, cross_sec, material).line_load
array([[0], [0], [0], [0], [0], [0]])
>>> from sstatics.core.preprocessing.loads import BarLineLoad
>>> line_loads = (BarLineLoad(1, 1, 'z', 'bar', 'exact'),
>>>               BarLineLoad(2, 3, 'x', 'system', 'proj'))
>>> Bar(node_1, node_2, cross_sec, material,
>>>     line_loads=line_loads).line_load
array([[0.96], [2.28], [0], [1.44], [2.92], [0]])
property phi#

Calculates the stiffness contributions of shear deformation.

Returns:
float

Stiffness contributions of shear deformation.

Notes

\[\phi = \dfrac{12 \cdot E \cdot I}{GA_s \cdot \ell^2}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat)
>>> b.phi
0.0007499999999999999
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'shear'])
>>> b.phi
0.011165837860598733
property point_load#

The overall point load on a bar element as a 6x1 vector.

Returns:
numpy.array

Sum of all point loads specified in point_loads.

See also

BarPointLoad

Notes

If no point loads are specified, then a 6x1 zero vector is returned.

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(0, 0)
>>> node_2 = Node(3, 0)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> Bar(node_1, node_2, cross_sec, material).point_load
array([[0], [0], [0], [0], [0], [0]])
>>> from sstatics.core.preprocessing.loads import BarPointLoad
    >>> import numpy
>>> point_loads = (BarPointLoad(1, 0, 0),
>>>                BarPointLoad(0, 2, numpy.pi/4, position=1))
>>> Bar(node_1, node_2, cross_sec, material,
>>>     point_loads=point_loads).point_load
array([[1], [0], [0], [1.41421356], [1.41421356], [0]])
property shear_stiffness#

Calculates the shear stiffness (\(GA_s\)) of the bar.

The shear stiffness is calculated using the shear modulus (\(G\)) and the shear area (\(A_s\)). The modification of the shear area (\(A_s\)) compared to the cross-sectional area (\(A\)) is taken into account using the shear correction factor (\(\kappa\)).

Returns:
float

The shear stiffness \(GA_s\).

Notes

The shear stiffness is given by:

\[GA_s = G \cdot A \cdot \kappa\]

If the shear deformation component is not to be considered in the calculation (deformations does not include ‘shear’), the flexural stiffness of the bar is scaled to reduce the deformation component so that the shear deformation becomes negligibly small.

\[GA_s = 1000 \cdot EI\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'normal'])
>>> b.shear_stiffness
5814900.000000001
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'shear'])
>>> b.shear_stiffness
390581.97463079996
stiffness_matrix(hinge_modification=True, to_node_coord=True)#

Represents the element stiffness matrix for the beam element \(k^{'}\).

The element stiffness matrix defines the relationship between nodal displacements and rotations of a beam element and the resulting internal forces at its ends.

Parameters:
hinge_modificationbool, default=True

Modifies the element stiffness matrix to account for hinges.

to_node_coordbool, default=True

Transforms the element stiffness matrix into the nodal coordinate system.

Returns:
numpy.array

The 6x6 matrix representing the element stiffness matrix.

Notes

The element stiffness matrix is symmetric and depends on the order of calculation and the applied approach. If the beam is shear-flexible, the shear component is included in the matrix.

The general form of the element stiffness matrix \(k^{'}\) for a shear-rigid beam is:

\[\begin{split}k^{'} = \left[\begin{array}{rrr|rrr} \dfrac{EA}{\ell} & 0 & 0 & -\dfrac{EA}{\ell} & 0 & 0 \\ 0 & \dfrac{12EI}{\ell^3} & -\dfrac{6EI}{\ell^2} & 0 & -\dfrac{12EI}{\ell^3} & -\dfrac{6EI}{\ell^2} \\ 0 & -\dfrac{6EI}{\ell^2} & \dfrac{4EI}{\ell} & 0 & \dfrac{6EI}{\ell^2} & \dfrac{2EI}{\ell} \\ \hline -\dfrac{EA}{\ell} & 0 & 0 & \dfrac{EA}{\ell} & 0 & 0 \\ 0 & -\dfrac{12EI}{\ell^3} & \dfrac{6EI}{\ell^2} & 0 & \dfrac{12EI}{\ell^3} & \dfrac{6EI}{\ell^2} \\ 0 & -\dfrac{6EI}{\ell^2} & \dfrac{2EI}{\ell} & 0 & \dfrac{6EI}{\ell^2} & \dfrac{4EI}{\ell} \\ \end{array}\right]\end{split}\]

If hinges are present in the beam, it is necessary to modify the stiffness matrix to account for discontinuities in deformations at hinge locations.

Finally, the stiffness matrix may be transformed into the nodal coordinate system if required.

property stiffness_shear_force#

Computes the element stiffness matrix considering shear effects.

Returns:
numpy.array

A 6x6 matrix representing the element stiffness matrix according to first-order theory, including shear effects.

Notes

The element stiffness matrix accounts for the deformation components of the beam due to axial force, bending, and shear. The factor phi describes the influence of shear deformation.

The general form of the element stiffness matrix \(k^{'}\) is given by:

\[\begin{split}k^{'} = \left[\begin{array}{rrr|rrr} \dfrac{EA}{\ell} & 0 & 0 & -\dfrac{EA}{\ell} & 0 & 0 \\ 0 & \dfrac{12EI}{\ell^3 ( 1 + \phi)} & -\dfrac{6EI}{\ell^2 (1 + \phi)} & 0 & -\dfrac{12EI}{\ell^3(1 + \phi)} & - \dfrac{6EI}{\ell^2(1 + \phi)} \\ 0 & -\dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(4 + \phi)}{\ell (1 + \phi)} & 0 & \dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(2 - \phi)}{\ell(1 + \phi)} \\ \hline -\dfrac{EA}{\ell} & 0 & 0 & \dfrac{EA}{\ell} & 0 & 0 \\ 0 & -\dfrac{12EI}{\ell^3(1 + \phi)} & \dfrac{6EI}{\ell^2(1 + \phi)} & 0 & \dfrac{12EI}{\ell^3(1 + \phi)} & \dfrac{6EI} {\ell^2(1 + \phi)} \\ 0 & -\dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(2 - \phi)}{\ell (1 + \phi)} & 0 & \dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(4 + \phi)}{\ell(1 + \phi)} \\ \end{array}\right]\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> from sstatics.core.preprocessing.loads import BarLineLoad
>>> n1, n2 = Node(0, 0), Node(0, -4)
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> deform = ['moment', 'normal', 'shear']
>>> b = Bar(n1, n2, cross, material, deformations=deform)
>>> b.stiffness_shear_force
array([[1, 0, 0, 1, 0, 0],
     [0, 0.9889574613, 0.9889574613, 0, 0.9889574613, 0.9889574613],
     [0, 0.9889574613, 0.991718096,  0, 0.9889574613, 0.983436192],
     [1, 0, 0, 1, 0, 0],
     [0, 0.9889574613, 0.9889574613, 0, 0.9889574613, 0.9889574613],
     [0, 0.9889574613, 0.983436192,  0, 0.9889574613, 0.991718096]])
transformation_matrix(to_node_coord=True)#

Create a 6x6 rotation matrix based on the bar’s inclination and node components.

Parameters:
to_node_coordbool, default=True

Determines whether a transformation into the node coordinate system takes place. True if transformation to the node coordinate system is applied. False if the transformation is not applied.

Returns:
numpy.array

A 6x6 matrix for rotating 6x1 vectors.

Notes

If the transformation to the node coordinate system is not applied, the rotation angle is determined solely by the inclination of the bar: alpha = bar.inclination.

If the transformation to the node coordinate system is applied, the rotation is calculated by subtracting the node rotations from the bar inclination: alpha_i = bar.inclination - bar.node_i.rotation alpha_j = bar.inclination - bar.node_j.rotation

The resulting matrix has the form

\[\begin{split}\left[\begin{array}{cccccc} \cos(\alpha_i) & \sin(\alpha_i) & 0 & 0 & 0 & 0\\ -\sin(\alpha_i) & \cos(\alpha_i) & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & \cos(\alpha_j) & \sin(\alpha_j) & 0 \\ 0 & 0 & 0 & -\sin(\alpha_j) & \cos(\alpha_j) & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \end{array}\right]\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
    >>> import numpy
>>> node_1 = Node(0, 0, rotation=numpy.pi/4)
>>> node_2 = Node(4, -3)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> bar = Bar(node_1, node_2, cross_sec, material)
>>> bar.transformation_matrix()
array([[0.98994949, -0.14142136, 0., 0., 0., 0.],
[0.14142136, 0.98994949, 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0.8, 0.6, 0.],
[0., 0., 0., -0.6, 0.8, 0.],
[0., 0., 0., 0., 0., 1.]])
>>> bar.transformation_matrix(False)
array([[0.8, 0.6, 0., 0., 0., 0.],
[-0.6, 0.8, 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0.8, 0.6, 0.],
[0., 0., 0., -0.6, 0.8, 0.],
[0., 0., 0., 0., 0., 1.]])
class sstatics.core.preprocessing.bar.BarSecond(node_i, node_j, cross_section, material, hinge_u_i=False, hinge_w_i=False, hinge_phi_i=False, hinge_u_j=False, hinge_w_j=False, hinge_phi_j=False, deformations=('moment', 'normal'), line_loads=(), temp=<factory>, point_loads=(), approach='analytic', f_axial=0)#

Bases: Bar

Create a bar for a statical system for the second order matrix approach.

Parameters:
node_iNode

Node at the start of the bar.

node_jNode

Node at the end of the bar.

cross_sectionCrossSection

Cross-sectional properties of the bar.

materialMaterial

Material properties of the bar.

hinge_u_ibool, default=False

Normal hinge at the start of the bar.

hinge_w_ibool, default=False

Shear hinge at the start of the bar.

hinge_phi_ibool, default=False

Moment hinge at the start of the bar.

hinge_u_jbool, default=False

Normal hinge at the end of the bar.

hinge_w_jbool, default=False

Shear hinge at the end of the bar.

hinge_phi_jbool, default=False

Moment hinge at the end of the bar.

deformationstuple | list, default=(‘moment’, ‘normal’)

Deformation components considered in the calculation. Valid options: “moment”, “normal”, “shear”.

line_loadstuple | list, default=()

Distributed loads acting on the bar.

tempBarTemp, default=(BarTemp(0, 0))

Temperature loads acting on the bar.

point_loadstuple | list, default=()

Point loads acting on the bar.

approach{‘analytic’, ‘taylor’, ‘p_delta’}, default=’analytic’

Selects the second-order formulation for the modified stiffness:

  • 'analytic' Closed-form exact geometric stiffness effects.

  • 'p_delta' P–Δ geometric stiffness formulation.

  • 'taylor' Taylor-series expansion

f_axial:any`float`, default=0

The axial force (\(L\)) applied to the beam element, which is obtained from the internal force results of the first-order theory.

Raises:
ValueError

node_i and node_j need to have different locations.

ValueError

There has to be at least one deformation component.

ValueError

Valid deformation keywords are “moment”, “normal” and “shear”.

property B_s#

Alias of modified_flexural_stiffness.

property EA#
property EI#
property GA_s#
property axial_rigidity#

Calculates the axial rigidity (\(EA\)) of the bar.

The axial rigidity is defined as the product of the Young’s modulus (\(E\)) and the area (\(A\)).

Returns:
float

The axial rigidity \(EA\).

Notes

The axial rigidity is given by:

\[EA = E \cdot A\]

If the axial deformation component is not to be considered in the calculation (deformations does not include ‘normal’), the axial rigidity of the bar is scaled to reduce the deformation component so that the axial deformation becomes negligibly small.

\[EA = 1000 \cdot E \cdot A\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'normal'])
>>> b.axial_rigidity
1613640.0
>>> b = Bar(n1, n2, cross, mat, deformations=['moment'])
>>> b.axial_rigidity
1613640000.0
property characteristic_number#

Returns the characteristic number \(\mu\) of the beam element.

This dimensionless characteristic number integrates both the bending and shear stiffness as well as the axial force in the beam. It is used in the correction functions applied in the calculation of the load vector and stiffness matrix based on the analytical approach of second-order theory.

Returns:
float

The dimensionless characteristic number \(\mu\).

Notes

It should be noted that the correction functions are not defined at \(\mu = 0\), which may lead to numerical instabilities in this range.

The characteristic number is defined by the following equation:

\[\mu = \sqrt{\dfrac{\mid L \mid}{B_s}} \cdot \ell\]
f0(hinge_modification=True, to_node_coord=True)#

Represents the vector of internal forces at the beam element ends in the load-deformation state (LDS).

Due to external loads acting on the beam element, internal forces develop at the element ends. These internal forces are assembled in the vector \(f^{(0)'}\).

Parameters:
hinge_modificationbool, default=True

Modifies the load vector and the element stiffness matrix to account for hinges.

to_node_coordbool, default=True

Transforms the load vector into the nodal coordinate system.

Returns:
numpy.array

The 6x1 vector of internal forces at the beam element ends due to external loads.

Notes

The beam element can be subjected to distributed loads and point loads. In statically indeterminate systems, internal forces may also arise due to temperature effects and support deformations. These loading cases are collected within the algorithm.

If hinges are present in the beam, it is necessary to modify the stiffness matrix and load vector to account for discontinuities in deformations at hinge locations.

Finally, the load vector may be transformed into the nodal coordinate system if required.

property f0_displacement#

Calculates the internal forces due to support stresses related to the local bar coordinate system.

Returns:
numpy.array

6x1 vector of the internal forces due to support stresses.

Notes

The support displacements of the initial and end nodes are combined into a 6x1 vector. By multiplying the stiffness matrix with the acting support displacements, the resulting internal forces are obtained. Since the support displacements are given in the node coordinate system, a transformation using the transformation matrix is required to obtain the internal forces in the bar coordinate system.

The vector is calculated using the following mathematical equations:

\[f^{0'} = k^{'} \cdot \Delta^{'}\]

Including the transformation matrix, the following equation is used:

\[\begin{split}f^{0'} = k^{'} \cdot T \cdot \left\lbrace\begin{array}{c} u_i \\ w_i \\ \varphi_i \\ u_j \\ w_j \\ \varphi_j \end{array}\right\rbrace\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> from sstatics.core.preprocessing.dof import NodeDisplacement
>>> displace = NodeDisplacement(0, 0.005, 0)
>>> n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')
>>> n2 = Node(4, 0, w='fixed', displacements=displace)
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 1.2e-5)
>>> b = Bar(n1, n2, cross, mat)
>>> b.f0_displacement
array([[0], [-5.45146875], [10.9029375], [0], [5.45146875],
[10.9029375]])
property f0_line#

Calculates the internal forces due to external line loads related to the local bar coordinate system.

This method computes the load vector associated with external line loads and adjusts it according to the selected second-order analysis approach. If a second-order method is selected but the axial force f_axial is zero, the modified stiffness terms cannot be evaluated and the load vector from first-order theory is returned instead.

If the selected analysis approach requires f_axial but it is undefined or set to zero, the method falls back to the first-order load vector, since second-order effects cannot be computed in that case.

Returns:
numpy.array

6x1 vector of the internal forces due to external loads

property f0_line_analytic#

Calculates the internal forces due to external line loads related to the local bar coordinate system for the analytical solution of the second-order theory.

To calculate the internal forces for the second-order theory, this function considers the particular solution while taking into account the axial force \(L\) in the beam element.

Returns:
numpy.array

6x1 vector of the internal forces due to external loads for the analytical solution of the second-order theory.

Notes

The application of continuous element loads can generate full constraint forces in the base element. This function calculates the particular solution of the deformation line according to the second-order theory. The particular solution is determined separately for positive and negative axial forces \(L\), which are evaluated based on the input parameter.

For negative axial forces, the internal forces are given by:

\[\begin{split}f^{0'} = \left\lbrace\begin{array}{c} -\dfrac{(7n_i + 3 n_j) \ell}{20} \\ -\dfrac{B_s \mu^2}{\ell^2} \cdot c_2 - [\dfrac{\ell}{\mu^2} + \dfrac{EI}{GA_s \ell}] (p_j - p_i) \\ \dfrac{B_s \mu^2}{\ell^2} \cdot c_3 - [\dfrac{\ell^2}{\mu^2} + \dfrac{EI}{GA_s}] \cdot p_i \\ \dfrac{(3n_i + 7 n_j) \ell}{20} \\ -\dfrac{B_s \mu^2}{\ell^2} \cdot c_2 - p_i \cdot \ell - [\dfrac{\ell}{\mu^2} + \dfrac{EI}{GA_s \ell} + \dfrac{\ell}{2}] (p_j - p_i) \\ \dfrac{B_s \mu^2}{\ell^2} [c_3 \cdot \cos (\mu) + c_4 \cdot \sin ( \mu)] - [\dfrac{\ell^2}{\mu^2} + \dfrac{EI}{GA_s}] \cdot p_j \end{array}\right\rbrace\end{split}\]

with the coefficients:

\[\begin{split}\begin{array}{ll} c_1 = \dfrac{\ell^2}{6 B_s \mu^3} \cdot & \bigg(\dfrac{3 \big[ GA_s \ell^4 + 2 B_s \ell^2 \mu^2 + \frac{B_{s}^2}{GA_s} \mu^4 \big] \sinh (\mu) (p_i + p_j)} {GA_s \ell^2 \mu \sin (\mu) + 2 [GA_s \ell^2 + B_s \mu^2] (\cos ( \mu) - 1)}\\\\ & + \dfrac{6 EI \ell^2 \mu (1- \cos ( \mu)) (p_i - p_j)}{GA_s \ell^2 \mu \sin (\mu) + 2 [GA_s \ell^2 + B_s \mu^2] (\cos ( \mu) - 1)} \\\\ & + \dfrac{[B_s \ell^2 \mu^3 + GA_s \ell^4 \mu] [p_i + 2 p_j + (2 p_i + p_j) \cos (\mu)]}{GA_s \ell^2 \mu \sin (\mu) + 2 [GA_s \ell^2 + B_s \mu^2] (\cos ( \mu) - 1)}\bigg) \end{array}\end{split}\]
\[\begin{split}\begin{array}{ll} c_2 = -\dfrac{\ell^3}{6 B_s \mu^3} \cdot & \bigg(\dfrac{12 EI ( 1- \cos ( \mu)) (p_i - p_j) + GA_s \ell^2 \mu \sin (\mu) (2 p_i + p_j)} {GA_s \ell^2 \mu \sin (\mu) + 2 [GA_s \ell^2 + B_s \mu^2] (\cos ( \mu) - 1)}\\\\ & - \dfrac{3 (GA_s \ell^2 + B_s \mu^2) (1 - \cos ( \mu)) (p_i + p_j)}{GA_s \ell^2 \mu \sin (\mu) + 2 [GA_s \ell^2 + B_s \mu^2] (\cos ( \mu) - 1))}\bigg) \end{array}\end{split}\]
\[c_3 = - c_1\]
\[c_4 = -\bigg[ \dfrac{B_s \mu}{G A_s \ell} + \dfrac{\ell}{\mu} \bigg] \cdot c_2 - \dfrac{EI \ell^2 ( p_j - p_i)}{B_s GA_s \mu^3}\]

For positive axial forces, the internal forces are given by:

\[\begin{split}f^{0'} = \left\lbrace\begin{array}{c} -\dfrac{(7n_i + 3 n_j) \ell}{20} \\ \dfrac{B_s \mu^2}{\ell^2} \cdot c_2 + [\dfrac{\ell}{\mu^2} - \dfrac{EI}{GA_s \ell}] (p_j - p_i) \\ -\dfrac{B_s \mu^2}{\ell^2} \cdot c_3 + [\dfrac{\ell^2}{\mu^2} - \dfrac{EI}{GA_s}] \cdot p_i \\ \dfrac{(3n_i + 7 n_j) \ell}{20} \\ -\dfrac{B_s \mu^2}{\ell^2} \cdot c_2 - \dfrac{(p_j + p_i) \ell}{2} + [\dfrac{\ell}{\mu^2} + \dfrac{EI}{GA_s \ell}] (p_j - p_i) \\ -B_s \cdot [c_3 \cdot \dfrac{\mu^2}{\ell^2} \cosh (\mu) + c_4 \cdot \dfrac{\mu^2}{\ell^2} \sinh ( \mu)] + [\dfrac{\ell^2} {\mu^2} - \dfrac{EI}{GA_s}] \cdot p_j \end{array}\right\rbrace\end{split}\]

with the coefficients:

\[\begin{split}\begin{array}{ll} c_1 = \dfrac{\ell^2}{6 B_s \mu^3} \cdot & \bigg(\dfrac{3 \big[GA_s \ell^4 - 2 B_s \ell^2 \mu^2 + \frac{B_{s}^2}{GA_s} \mu^4 \big] \sinh (\mu) (p_i + p_j)}{2 [GA_s \ell^2 - B_s \mu^2] (1- \cosh (\mu)) + GA_s \ell^2 \mu \sinh(\mu)}\\\\ & + \dfrac{6 EI \ell^2 \mu (1- \cosh ( \mu)) (p_i - p_j)}{2 [GA_s \ell^2 - B_s \mu^2] (1- \cosh (\mu)) + GA_s \ell^2 \mu \sinh(\mu)} \\\\ & + \dfrac{[B_s \ell^2 \mu^3 - GA_s \ell^4 \mu] [p_i + 2 p_j + (2 p_i + p_j) \cosh (\mu)]}{2 [GA_s \ell^2 - B_s \mu^2] (1- \cosh (\mu)) + GA_s \ell^2 \mu \sinh(\mu)}\bigg) \end{array}\end{split}\]
\[\begin{split}\begin{array}{ll} c_2 = -\dfrac{\ell^3}{6 B_s \mu^3} \cdot & \bigg(\dfrac{12 EI ( 1- \cosh ( \mu)) (p_i - p_j) - GA_s \ell^2 \mu \sinh (\mu) (2 p_i + p_j)} {2 [GA_s \ell^2 - B_s \mu^2] (1- \cosh (\mu)) + GA_s \ell^2 \mu \sinh(\mu)}\\\\ & - \dfrac{3 (GA_s \ell^2 - B_s \mu^2) (1 - \cosh ( \mu)) (p_i + p_j)}{2 [GA_s \ell^2 - B_s \mu^2] (1- \cosh (\mu)) + GA_s \ell^2 \mu \sinh(\mu)}\bigg) \end{array}\end{split}\]
\[c_3 = - c_1\]
\[c_4 = \bigg[ \dfrac{B_s \mu}{G A_s \ell} - \dfrac{\ell}{\mu} \bigg] \cdot c_2 + \dfrac{EI \ell^2 ( p_j - p_i)}{B_s GA_s \mu^3}\]
property f0_line_taylor#

Calculates the internal forces due to external line loads related to the local bar coordinate system for the Taylor series expansion of the second-order theory.

To calculate the internal forces for the second-order theory, this function considers the Taylor series expansion while taking into account the axial force \(L\) in the beam element.

Returns:
numpy.array

6x1 vector of the internal forces due to external loads for the Taylor series expansion of the second-order theory.

Notes

The application of continuous element loads can generate full constraint forces in the base element. This function calculates the internal forces by using a Taylor series expansion according to the second-order theory.

The vector is calculated by the following mathmatical equations:

\[\begin{split}\begin{array}{ll} f_{z,i}^{(0)'} = \dfrac{\ell}{20} \cdot & \bigg(\dfrac{720 B_{s}^2 (p_j + p_i) - 4 EIGA_s \ell^2 (p_j - p_i) + 20 B_s GA_s \ell^2 ( 5 p_j + 7 p_i)}{(12 B_s + GA_s \ell^2)^2}\\\\ & \dfrac{(GA_s)^2 \ell^4 (3 p_j + 7 p_i)}{(12 B_s + GA_s \ell^2)^2} - \dfrac{EI (p_j - p_i)}{GA_s \ell} - \dfrac{12 B_s}{L \ell} \cdot \dfrac{(EI - B_s) (p_j - p_i)}{(12 B_s + GA_s \ell^2)}\bigg) \end{array}\end{split}\]
\[\begin{split}\begin{array}{ll} f_{M,i}^{(0)'} = & \dfrac{4320 B_{s}^3(p_j + p_i) + 6 EI (GA_s)^2 \ell^4 (p_j- p_i) + 60 B_s GA_s \ell^2 (12B_s p_i - GA_s \ell^2 p_j)}{60 GA_s (12 B_s + GA_s \ell^2)^2}\\\\ & - \dfrac{(GA_s)^3 \ell^6 (2p_j + 3 p_i)}{60 GA_s (12 B_s + GA_s \ell^2)^2} - \dfrac{EI}{GA_s} \cdot p_i + \dfrac{6 B_s}{L} \cdot \dfrac{(EI - B_s) ( p_j - p_i)} {(12 B_s + GA_s \ell^2)} \end{array}\end{split}\]
\[f_{z,j}^{(0)'} = f_{z,i}^{(0)'} - \dfrac{(p_j + p_i) \cdot \ell}{2}\]
\[\begin{split}\begin{array}{ll} f_{M,j}^{(0)'} = & \dfrac{4320 B_{s}^3(p_j + p_i) - 6 EI (GA_s)^2 \ell^4 (p_j- p_i) + 60 B_s GA_s \ell^2 (12B_s p_j - GA_s \ell^2 p_i)}{60 GA_s (12 B_s + GA_s \ell^2)^2}\\\\ & - \dfrac{(GA_s)^3 \ell^6 (3p_j + 2 p_i)}{60 GA_s (12 B_s + GA_s \ell^2)^2} - \dfrac{EI}{GA_s} \cdot p_j - \dfrac{6 B_s} {L} \cdot \dfrac{(EI - B_s) ( p_j - p_i)}{(12 B_s + GA_s \ell^2)} \end{array}\end{split}\]
\[\begin{split}f^{0'} = \left\lbrace\begin{array}{c} -\dfrac{(7n_i + 3 n_j) \ell}{20} \\\\ -f_{z,i}^{(0)'} \\\\ -f_{M,i}^{(0)'} \\\\ -\dfrac{(3n_i + 7 n_j) \ell}{20}\\\\ f_{z,j}^{(0)'}\\\\ f_{M,j}^{(0)'} \end{array}\right\rbrace\end{split}\]
property f0_point#

Calculates the internal forces due to point loads related to the local bar coordinate system.

The method rotates the point load components from the system coordination system into the bar coordination system. Only point load componants at the beginning (position = 0) and at the end (position = 1) of the beam are included.

Returns:
numpy.array

6x1 vector of the rotated point load components.

Notes

The transformation is performed using the following rotation matrix:

\[\begin{split}f^{0'}= \begin{bmatrix} \cos(\alpha- \beta_i) & \sin(\alpha - \beta_i) & 0 & 0 & 0 & 0\\ -\sin(\alpha - \beta_i) & \cos(\alpha - \beta_i) & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & \cos(\alpha- \beta_j) & \sin(\alpha - \beta_j) & 0 \\ 0 & 0 & 0 & -\sin(\alpha - \beta_j) & \cos(\alpha - \beta_j) & 0\\ 0 & 0 & 0 & 0 & 0 & 1 \end{bmatrix}^{T} \cdot f^{0}_{load}\end{split}\]
property f0_temp#

Calculates the internal forces due to temperature loads related to the local bar coordinate system.

Returns:
numpy.array

6x1 vector of the internal forces due to temperature loads.

Notes

The vector is calculated by the following mathmatical equations:

\[\begin{split}f^{0'} = \left\lbrace\begin{array}{c} \alpha_T \cdot T \cdot E \cdot A \\ 0 \\ \dfrac{\alpha_T \cdot \Delta T \cdot E \cdot I}{h} \\ - \alpha_T \cdot T \cdot E \cdot A \\ 0 \\ - \dfrac{\alpha_T \cdot \Delta T \cdot E \cdot I}{h} \end{array}\right\rbrace\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> from sstatics.core.preprocessing.temperature import BarTemp
>>> n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')
>>> n2 = Node(4, 0, u='fixed', w='fixed', phi='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 1.2e-5)
>>> temp = BarTemp(15, 30)
>>> b = Bar(n1, n2, cross, mat, temp=temp)
>>> b.f0_temp
array([[435.6828], [0], [5.23341], [-435.6828], [0], [-5.23341]])
property flexural_stiffness#

Calculates the flexural stiffness (\(EI\)) of the element.

The flexural stiffness is defined as the product of the Young’s modulus (\(E\)) and the second moment of area (moment of inertia, \(I\)) of the cross-section.

Returns:
float

The flexural stiffness \(EI\).

Notes

The flexural stiffness is given by:

\[EI = E \cdot I\]

If the bending deformation component is not to be considered in the calculation (deformations does not include ‘moment’), the flexural stiffness of the bar is scaled to reduce the deformation component so that the bending deformation becomes negligibly small.

\[EI = 1000 \cdot E \cdot I\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'normal'])
>>> b.flexural_stiffness
5814.900000000001
>>> b = Bar(n1, n2, cross, mat, deformations=['normal'])
>>> b.flexural_stiffness
5814900.000000001
property hinge#

Creates a tuple containing bar hinges at both ends of a structural element.

This method assembles and returns the hinge conditions of a bar at its start node (i) and end node (j). Hinges define how the bar is allowed to move or rotate at its ends.

The tuple consists of six elements representing the hinges at each node:

Returns:
tuple
A 6-tuple containing the hinge parameters in the following order:
  • hinge_u_i (bool): Normal hinge at node i.

  • hinge_w_i (bool): Shear hinge at node i.

  • hinge_phi_i (bool): Moment hinge at node i.

  • hinge_u_j (bool): Normal at node j.

  • hinge_w_j (bool): Shear hinge at node j.

  • hinge_phi_j (bool): Moment at node j.

Notes

A value of True indicates the presence of a hinge, while False indicates a rigid connection at that degree of freedom.

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')
>>> n2 = Node(4, 0, u='fixed', w='fixed', phi='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, hinge_w_i=True, hinge_phi_j=True)
>>> b.hinge
(False, True, False, False, False, True)
property inclination#

Calculates the inclination of the beam in relation to the node coordinates.

Returns:
float

Angle of inclination in rad.

Notes

The inclination is calcultated by using the following equation:

\[\alpha = \arctan \frac{(-z_2 + z_1)}{(x_2 - x_1)}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(0, 0)
>>> node_2 = Node(4, -2)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> bar_1 = Bar(node_1, node_2, cross_sec, material)
>>> bar_1.inclination
0.7853981634
property length#

Calculates the distance between two nodes that define the bar element.

Returns:
float

Length of bar element.

Notes

The length is calcultated by using the following equation:

\[L = \sqrt{(x_2 - x_1)^2 + (z_2 - z_1)^2}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(2, 5)
>>> node_2 = Node(10, 6)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> bar_1 = Bar(node_1, node_2, cross_sec, material)
>>> bar_1.length
8.06225774829855
property line_load#

The overall line load on a bar element as a 6x1 vector.

Returns:
numpy.array

Sum of all line loads specified in line_loads.

See also

BarLineLoad

Notes

If no line loads are specified, then a 6x1 zero vector is returned. The load components are rotated by the inclination of the beam.

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(0, 0)
>>> node_2 = Node(3, -4)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> Bar(node_1, node_2, cross_sec, material).line_load
array([[0], [0], [0], [0], [0], [0]])
>>> from sstatics.core.preprocessing.loads import BarLineLoad
>>> line_loads = (BarLineLoad(1, 1, 'z', 'bar', 'exact'),
>>>               BarLineLoad(2, 3, 'x', 'system', 'proj'))
>>> Bar(node_1, node_2, cross_sec, material,
>>>     line_loads=line_loads).line_load
array([[0.96], [2.28], [0], [1.44], [2.92], [0]])
property modified_flexural_stiffness#

Computes the modified flexural stiffness (\(B_s\)) based on second-order theory , considering both shear deformations and axial force effects.

The modified flexural stiffness \(B_s\) accounts for shear deformations and the influence of axial force on the beam element.

Returns:
float

The modified flexural stiffness \(B_s\).

Notes

The modified flexural stiffness is calculated [1] :

\[B_s = EI \cdot ( 1 + \dfrac{L}{GA_s})\]

References

[1]

Spura, Christian: Einführung in die Balkentheorie nach Timoshenko und Euler-Bernoulli. Springer Vieweg, 2019 https://doi.org/10.1007/978-3-658-25216-8

property phi#

Calculates the stiffness contributions of shear deformation.

Returns:
float

Stiffness contributions of shear deformation.

Notes

\[\phi = \dfrac{12 \cdot E \cdot I}{GA_s \cdot \ell^2}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat)
>>> b.phi
0.0007499999999999999
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'shear'])
>>> b.phi
0.011165837860598733
property point_load#

The overall point load on a bar element as a 6x1 vector.

Returns:
numpy.array

Sum of all point loads specified in point_loads.

See also

BarPointLoad

Notes

If no point loads are specified, then a 6x1 zero vector is returned.

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> node_1 = Node(0, 0)
>>> node_2 = Node(3, 0)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> Bar(node_1, node_2, cross_sec, material).point_load
array([[0], [0], [0], [0], [0], [0]])
>>> from sstatics.core.preprocessing.loads import BarPointLoad
    >>> import numpy
>>> point_loads = (BarPointLoad(1, 0, 0),
>>>                BarPointLoad(0, 2, numpy.pi/4, position=1))
>>> Bar(node_1, node_2, cross_sec, material,
>>>     point_loads=point_loads).point_load
array([[1], [0], [0], [1.41421356], [1.41421356], [0]])
property shear_stiffness#

Calculates the shear stiffness (\(GA_s\)) of the bar.

The shear stiffness is calculated using the shear modulus (\(G\)) and the shear area (\(A_s\)). The modification of the shear area (\(A_s\)) compared to the cross-sectional area (\(A\)) is taken into account using the shear correction factor (\(\kappa\)).

Returns:
float

The shear stiffness \(GA_s\).

Notes

The shear stiffness is given by:

\[GA_s = G \cdot A \cdot \kappa\]

If the shear deformation component is not to be considered in the calculation (deformations does not include ‘shear’), the flexural stiffness of the bar is scaled to reduce the deformation component so that the shear deformation becomes negligibly small.

\[GA_s = 1000 \cdot EI\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> n1 = Node(0, 0, u='fixed', w='fixed')
>>> n2 = Node(4, 0, w='fixed')
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> mat = Material(210000000, 0.1, 81000000, 0.1)
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'normal'])
>>> b.shear_stiffness
5814900.000000001
>>> b = Bar(n1, n2, cross, mat, deformations=['moment', 'shear'])
>>> b.shear_stiffness
390581.97463079996
stiffness_matrix(hinge_modification=True, to_node_coord=True)#

Return the modified element stiffness matrix \(k'\) of the beam element.

This method constructs the element stiffness matrix that relates nodal displacements and rotations to the corresponding internal forces at the element ends. Depending on the chosen analysis approach, the matrix may include shear flexibility effects, second-order (P–Δ) modifications and hinge adjustments.

Parameters:
hinge_modificationbool, default=True

If True, the stiffness matrix is adjusted to account for hinges at one or both ends of the element.

to_node_coordbool, default=True

If True, the stiffness matrix is transformed from the local bar coordinate system into the global nodal coordinate system.

Returns:
numpy.ndarray

The 6×6 modified element stiffness matrix.

Notes

The element stiffness matrix is symmetric and depends on the order of calculation and the applied approach. If the beam is shear-flexible, the shear component is included in the matrix.

The general form of the element stiffness matrix \(k^{'}\) for a shear-rigid beam is:

\[\begin{split}k^{'} = \left[\begin{array}{rrr|rrr} \dfrac{EA}{\ell} & 0 & 0 & -\dfrac{EA}{\ell} & 0 & 0 \\ 0 & \dfrac{12EI}{\ell^3} & -\dfrac{6EI}{\ell^2} & 0 & -\dfrac{12EI}{\ell^3} & -\dfrac{6EI}{\ell^2} \\ 0 & -\dfrac{6EI}{\ell^2} & \dfrac{4EI}{\ell} & 0 & \dfrac{6EI}{\ell^2} & \dfrac{2EI}{\ell} \\ \hline -\dfrac{EA}{\ell} & 0 & 0 & \dfrac{EA}{\ell} & 0 & 0 \\ 0 & -\dfrac{12EI}{\ell^3} & \dfrac{6EI}{\ell^2} & 0 & \dfrac{12EI}{\ell^3} & \dfrac{6EI}{\ell^2} \\ 0 & -\dfrac{6EI}{\ell^2} & \dfrac{2EI}{\ell} & 0 & \dfrac{6EI}{\ell^2} & \dfrac{4EI}{\ell} \\ \end{array}\right]\end{split}\]

For second-order theory, the modified stiffness contributions are applied element-wise to this general form.

If hinges are present in the beam, it is necessary to modify the stiffness matrix to account for discontinuities in deformations at hinge locations.

Finally, the stiffness matrix may be transformed into the nodal coordinate system if required.

property stiffness_matrix_analytic#
Creates the element stiffness matrix according to second-order

theory for the analytical solution.

To establish the stiffness matrix based on second-order theory, four correction functions must be calculated, which account for the influence of the axial force (\(L\)).

Returns:
numpy.array

A 6x6 matrix representing the theoretically exact element stiffness matrix according to second-order theory for a shear-flexible and bending-flexible beam under constant negative or positive axial force.

Notes

The correction functions are computed depending on the sign of the axial force. The functions are also dependent on the characteristic_number, which is defined by the equation:

\[\mu = \sqrt{\dfrac{\mid L \mid}{B_s}} \cdot \ell\]

For a negative axial force, the following equations apply:

\[f_1(\mu) = - \dfrac{B_s}{12EI} \cdot \dfrac{\mu^3 \cdot \sin ( \mu)}{2 [\frac{B_s}{GA_s \ell^2} \mu^2 + 1] (\cos (\mu) - 1) + \mu \cdot \sin ( \mu)}\]
\[f_2(\mu) = \dfrac{B_s}{6EI} \cdot \dfrac{(\cos (\mu) - 1) \cdot \mu^2}{2 [\frac{B_s}{GA_s \ell^2} \mu^2 + 1] (\cos (\mu) - 1) + \mu \cdot \sin ( \mu)}\]
\[f_3(\mu) = -\dfrac{B_s}{4EI} \cdot \dfrac{\big([\frac{B_s}{GA_s \ell^2} \mu^2 + 1] \sin ( \mu) - \mu \cdot \cos( \mu ) \big) \cdot \mu}{2 [\frac{B_s}{GA_s \ell^2} \mu^2 + 1] (\cos (\mu) - 1) + \mu \cdot \sin ( \mu)}\]
\[f_4(\mu) = \dfrac{B_s}{2EI} \cdot \dfrac{\big([\frac{B_s}{GA_s \ell^2} \mu^2 + 1] \sin ( \mu) - \mu \big) \cdot \mu}{2 [\frac {B_s}{GA_s \ell^2} \mu^2 + 1] (\cos (\mu) - 1) + \mu \cdot \sin ( \mu)}\]

For a positive axial force, the equations are as follows:

\[f_1(\mu) = \dfrac{B_s}{12EI} \cdot \dfrac{\mu^3 \cdot \sinh ( \mu)}{2 [\frac{B_s}{GA_s \ell^2} \mu^2 + 1] (\cosh (\mu) - 1) + \mu \cdot \sinh ( \mu)}\]
\[f_2(\mu) = \dfrac{B_s}{6EI} \cdot \dfrac{(\cosh (\mu) - 1) \cdot \mu^2}{2 [\frac{B_s}{GA_s \ell^2} \mu^2 + 1] (\cosh (\mu) - 1) + \mu \cdot \sinh ( \mu)}\]
\[f_3(\mu) = \dfrac{B_s}{4EI} \cdot \dfrac{\big([\frac{B_s}{GA_s \ell^2} \mu^2 + 1] \sinh ( \mu) - \mu \cdot \cosh( \mu ) \big) \cdot \mu}{2 [\frac{B_s}{GA_s \ell^2} \mu^2 + 1] (\cosh (\mu) - 1) + \mu \cdot \sinh ( \mu)}\]
\[f_4(\mu) = \dfrac{B_s}{2EI} \cdot \dfrac{\big([\frac{B_s}{GA_s \ell^2} \mu^2 + 1] \sinh ( \mu) - \mu \big) \cdot \mu}{2 [ \frac{B_s}{GA_s \ell^2} \mu^2 + 1] (\cosh (\mu) - 1) + \mu \cdot \sinh ( \mu)}\]

Which leads to the element stiffness matrix:

\[\begin{split}k^{'} = \left[\begin{array}{rrr|rrr} \dfrac{EA}{\ell} & 0 & 0 & -\dfrac{EA}{\ell} & 0 & 0 \\ 0 & \dfrac{12EI}{\ell^3} \cdot f_1 & -\dfrac{6EI}{\ell^2} \cdot f_2 & 0 & -\dfrac{12EI}{\ell^3}\cdot f_1 & -\dfrac{6EI} {\ell^2}\cdot f_2 \\ 0 & -\dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{4EI}{\ell}\cdot f_3 & 0 & \dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{2EI}{\ell}\cdot f_4 \\ \hline -\dfrac{EA}{\ell} & 0 & 0 & \dfrac{EA}{\ell} & 0 & 0 \\ 0 & -\dfrac{12EI}{\ell^3}\cdot f_1 & \dfrac{6EI}{\ell^2}\cdot f_2 & 0 & \dfrac{12EI}{\ell^3}\cdot f_1 & \dfrac{6EI}{\ell^2} \cdot f_2 \\ 0 & -\dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{2EI}{\ell}\cdot f_4 & 0 & \dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{4EI}{\ell}\cdot f_3 \end{array}\right]\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import BarSecond
 >>> from sstatics.core.preprocessing.cross_section import CrossSection
 >>> from sstatics.core.preprocessing.material import Material
 >>> from sstatics.core.preprocessing.node import Node
 >>> from sstatics.core.preprocessing.loads import NodePointLoad
 >>> n_load = NodePointLoad(0, 182, 0, rotation=0)
 >>> n1 = Node(0, 0, u='fixed', w='fixed', phi='fixed')
 >>> n2 = Node(0, -4, loads=n_load)
 >>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
 >>> material = Material(210000000, 0.1, 81000000, 0.1)
 >>> line_load = BarLineLoad(1, 1.5, 'z', 'bar', 'exact')
 >>> force = -181.99971053936605
 >>> b = BarSecond(n1, n2, cross, material, line_loads=line_load)
 >>> b.stiffness_matrix_analytic
 array([[1, 0, 0, 1, 0, 0],
      [0, 0.9491546296, 0.9908554233, 0, 0.9491546296, 0.9908554233],
      [0, 0.9908554233, 0.9826126598,  0, 0.9908554233, 1.0073409503],
      [1, 0, 0, 1, 0, 0],
      [0, 0.9491546296, 0.9908554233, 0, 0.9491546296, 0.9908554233],
      [0, 0.9908554233, 1.0073409503,  0, 0.9908554233, 0.9826126598]])
property stiffness_matrix_p_delta#

Creates the geometric stiffness matrix \(k_{G}^{'}\)

The geometric stiffness matrix describes the relationship between beam forces and displacements. It represents the transverse forces resulting from the moment offset of axial forces (\(L\)) according to second-order theory.

Returns:
numpy.array

A 6x6 matrix representing the geometric stiffness matrix according to second-order theory for the P- \(\Delta\) -effect.

Notes

To obtain the approximate solution considering the P-Delta effect, a geometric stiffness matrix is added to the element stiffness matrix from first-order theory.

\[k^{'} = k_{0}^{'} + k_{G}^{'}\]

The geometric stiffness matrix is given by:

\[\begin{split}k_{G}^{'} = \left[\begin{array}{ccc|ccc} 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & \dfrac{L}{\ell} & 0 & 0 & -\dfrac{L}{\ell} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \\ \hline 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & -\dfrac{L}{\ell} & 0 & 0 & \dfrac{L}{\ell} & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \\ \end{array}\right]\end{split}\]
property stiffness_matrix_taylor#

Creates the element stiffness matrix according to second-order theory for a Taylor series.

To establish the stiffness matrix based on second-order theory, four correction functions must be calculated, which account for the influence of the axial force (\(L\)).

Returns:
numpy.array

A 6x6 matrix representing the theoretically exact element stiffness matrix according to second-order theory for a shear-flexible and bending-flexible beam under constant negative or positive axial force.

Notes

The correction function are calculated by the following equations:

\[f_1= \dfrac{B_s}{12EI ( \frac{B_s}{GA_s \ell^2}+ \frac{1}{12})} + \dfrac{L \ell^2}{144 EI} \cdot \Bigg(\dfrac{\frac{B_s}{GA_s \ell^2} + \frac{1}{10}}{(\frac{B_s}{GA_s \ell^2} + \frac{1} {12})^2}\Bigg)\]
\[f_2= \dfrac{B_s}{12EI ( \frac{B_s}{GA_s \ell^2}+ \frac{1}{12})} + \dfrac{L \ell^2}{8640 EI} \cdot \Bigg(\dfrac{1}{(\frac{B_s} {GA_s \ell^2} + \frac{1}{12})^2}\Bigg)\]
\[f_3= \dfrac{B_s ( \frac{B_s}{GA_s \ell^2}+ \frac{1}{3})}{4EI ( \frac{B_s}{GA_s \ell^2}+ \frac{1}{12})} + \dfrac{L \ell^2} {48 EI} \cdot \Bigg(\dfrac{1}{240(\frac{B_s}{GA_s \ell^2} + \frac{1}{12})^2} + 1\Bigg)\]
\[f_4= -\dfrac{B_s ( \frac{B_s}{GA_s \ell^2}- \frac{1}{6})}{2EI ( \frac{B_s}{GA_s \ell^2}+ \frac{1}{12})} + \dfrac{L \ell^2} {24 EI} \cdot \Bigg(\dfrac{1}{240(\frac{B_s}{GA_s \ell^2} + \frac{1}{12})^2} - 1\Bigg)\]

Which leads to the element stiffness matrix:

\[\begin{split}k^{'} = \left[\begin{array}{rrr|rrr} \dfrac{EA}{\ell} & 0 & 0 & -\dfrac{EA}{\ell} & 0 & 0 \\ 0 & \dfrac{12EI}{\ell^3} \cdot f_1 & -\dfrac{6EI}{\ell^2} \cdot f_2 & 0 & -\dfrac{12EI}{\ell^3}\cdot f_1 & -\dfrac{6EI} {\ell^2}\cdot f_2 \\ 0 & -\dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{4EI}{\ell}\cdot f_3 & 0 & \dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{2EI}{\ell}\cdot f_4 \\ \hline -\dfrac{EA}{\ell} & 0 & 0 & \dfrac{EA}{\ell} & 0 & 0 \\ 0 & -\dfrac{12EI}{\ell^3}\cdot f_1 & \dfrac{6EI}{\ell^2}\cdot f_2 & 0 & \dfrac{12EI}{\ell^3}\cdot f_1 & \dfrac{6EI}{\ell^2} \cdot f_2 \\ 0 & -\dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{2EI}{\ell}\cdot f_4 & 0 & \dfrac{6EI}{\ell^2}\cdot f_2 & \dfrac{4EI}{\ell}\cdot f_3 \end{array}\right]\end{split}\]
property stiffness_shear_force#

Computes the element stiffness matrix considering shear effects.

Returns:
numpy.array

A 6x6 matrix representing the element stiffness matrix according to first-order theory, including shear effects.

Notes

The element stiffness matrix accounts for the deformation components of the beam due to axial force, bending, and shear. The factor phi describes the influence of shear deformation.

The general form of the element stiffness matrix \(k^{'}\) is given by:

\[\begin{split}k^{'} = \left[\begin{array}{rrr|rrr} \dfrac{EA}{\ell} & 0 & 0 & -\dfrac{EA}{\ell} & 0 & 0 \\ 0 & \dfrac{12EI}{\ell^3 ( 1 + \phi)} & -\dfrac{6EI}{\ell^2 (1 + \phi)} & 0 & -\dfrac{12EI}{\ell^3(1 + \phi)} & - \dfrac{6EI}{\ell^2(1 + \phi)} \\ 0 & -\dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(4 + \phi)}{\ell (1 + \phi)} & 0 & \dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(2 - \phi)}{\ell(1 + \phi)} \\ \hline -\dfrac{EA}{\ell} & 0 & 0 & \dfrac{EA}{\ell} & 0 & 0 \\ 0 & -\dfrac{12EI}{\ell^3(1 + \phi)} & \dfrac{6EI}{\ell^2(1 + \phi)} & 0 & \dfrac{12EI}{\ell^3(1 + \phi)} & \dfrac{6EI} {\ell^2(1 + \phi)} \\ 0 & -\dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(2 - \phi)}{\ell (1 + \phi)} & 0 & \dfrac{6EI}{\ell^2(1 + \phi)} & \dfrac{EI(4 + \phi)}{\ell(1 + \phi)} \\ \end{array}\right]\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
>>> from sstatics.core.preprocessing.loads import BarLineLoad
>>> n1, n2 = Node(0, 0), Node(0, -4)
>>> cross = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> deform = ['moment', 'normal', 'shear']
>>> b = Bar(n1, n2, cross, material, deformations=deform)
>>> b.stiffness_shear_force
array([[1, 0, 0, 1, 0, 0],
     [0, 0.9889574613, 0.9889574613, 0, 0.9889574613, 0.9889574613],
     [0, 0.9889574613, 0.991718096,  0, 0.9889574613, 0.983436192],
     [1, 0, 0, 1, 0, 0],
     [0, 0.9889574613, 0.9889574613, 0, 0.9889574613, 0.9889574613],
     [0, 0.9889574613, 0.983436192,  0, 0.9889574613, 0.991718096]])
transformation_matrix(to_node_coord=True)#

Create a 6x6 rotation matrix based on the bar’s inclination and node components.

Parameters:
to_node_coordbool, default=True

Determines whether a transformation into the node coordinate system takes place. True if transformation to the node coordinate system is applied. False if the transformation is not applied.

Returns:
numpy.array

A 6x6 matrix for rotating 6x1 vectors.

Notes

If the transformation to the node coordinate system is not applied, the rotation angle is determined solely by the inclination of the bar: alpha = bar.inclination.

If the transformation to the node coordinate system is applied, the rotation is calculated by subtracting the node rotations from the bar inclination: alpha_i = bar.inclination - bar.node_i.rotation alpha_j = bar.inclination - bar.node_j.rotation

The resulting matrix has the form

\[\begin{split}\left[\begin{array}{cccccc} \cos(\alpha_i) & \sin(\alpha_i) & 0 & 0 & 0 & 0\\ -\sin(\alpha_i) & \cos(\alpha_i) & 0 & 0 & 0 & 0\\ 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & \cos(\alpha_j) & \sin(\alpha_j) & 0 \\ 0 & 0 & 0 & -\sin(\alpha_j) & \cos(\alpha_j) & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \end{array}\right]\end{split}\]

Examples

>>> from sstatics.core.preprocessing.bar import Bar
>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> from sstatics.core.preprocessing.material import Material
>>> from sstatics.core.preprocessing.node import Node
    >>> import numpy
>>> node_1 = Node(0, 0, rotation=numpy.pi/4)
>>> node_2 = Node(4, -3)
>>> cross_sec = CrossSection(0.00002769, 0.007684, 0.2, 0.2, 0.6275377)
>>> material = Material(210000000, 0.1, 81000000, 0.1)
>>> bar = Bar(node_1, node_2, cross_sec, material)
>>> bar.transformation_matrix()
array([[0.98994949, -0.14142136, 0., 0., 0., 0.],
[0.14142136, 0.98994949, 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0.8, 0.6, 0.],
[0., 0., 0., -0.6, 0.8, 0.],
[0., 0., 0., 0., 0., 1.]])
>>> bar.transformation_matrix(False)
array([[0.8, 0.6, 0., 0., 0., 0.],
[-0.6, 0.8, 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 0., 0., 0.8, 0.6, 0.],
[0., 0., 0., -0.6, 0.8, 0.],
[0., 0., 0., 0., 0., 1.]])
class sstatics.core.preprocessing.cross_section.CrossSection(*a, **k)#

Bases: LoggerMixin

property area#

Returns the cross-sectional area.

Returns:
float

Cross-sectional area.

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> geo = [Polygon(points=[(0, 0), (2, 0), (2, 1),  (0, 1), (0, 0)])]
>>> cs = CrossSection(geometry=geo)
>>> cs.area
2.0
boundary()#

Determines the overall geometric boundaries of the cross-section in both the y- and z-directions.

Returns:
tuple of list of float

([y_min, y_max], [z_min, z_max]) representing the horizontal and vertical extents of the cross-section.

Notes

  • The boundaries are computed based on all geometric components (polygon and circular sectors) that make up the cross-section.

  • If a polygon is present, its vertex coordinates are included directly.

  • For each circular sector, the corresponding boundary extents are obtained from its boundary() method.

  • Only circular sectors marked as positive (i.e., material present) are considered for determining the outer limits.

  • If neither polygons nor circular sectors are defined, the method returns zero boundaries.

property center_of_mass_y#

Returns the y-coordinate of the centroid of the cross-section.

Returns:
float

Centroid y-coordinate (\(c_y\)).

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> geo = [Polygon(points=[(0, 0), (2, 0), (2, 1),  (0, 1), (0, 0)])]
>>> cs = CrossSection(geometry=geo)
>>> cs.center_of_mass_y
1
property center_of_mass_z#

Returns the z-coordinate of the centroid of the cross-section.

Returns:
float

Centroid z-coordinate (\(c_z\)).

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> geo = [Polygon(points=[(0, 0), (2, 0), (2, 1),  (0, 1), (0, 0)])]
>>> cs = CrossSection(geometry=geo)
>>> cs.center_of_mass_z
0.5
property height#

Returns the height of the cross-section.

Returns:
float

Cross-section height.

Notes

Calculated from polygon and circular sector geometry.

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> geo = [Polygon(points=[(0, 0), (2, 0), (2, 1),  (0, 1), (0, 0)])]
>>> cs = CrossSection(geometry=geo)
>>> cs.height
1.0
property logger#

Returns the logger instance associated with this object.

Returns:
logging.Logger

The configured logger.

property mom_of_int#

Returns the moment of inertia of the cross-section.

Returns:
float

Moment of inertia (\(I_{yy}\)), either from input or calculated.

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> geo = [Polygon(points=[(0, 0), (2, 0), (2, 1), (0, 1), (0, 0)])]
>>> cs = CrossSection(geometry=geo)
>>> cs.mom_of_int
0.16666666666666663
property shear_cor#

Returns the shear correction factor.

Returns:
float

Shear correction factor (default 1.0).

Notes

Currently a fixed value; automatic calculation is not implemented.

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> I = 0.000405
>>> A = 0.054
>>> h = 0.3
>>> w = 0.18
>>> cs = CrossSection(I, A, h, w, shear_cor=0.85)
>>> cs.shear_cor
float(0.85)
property static_moment#

Returns the static moments (first moments of area) about y and z axes if a geometry is defined.

Returns:
tuple of float

(\(S_y\), \(S_z\)) static moments.

Notes

Includes contributions from polygons and circular sectors.

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> geo = [Polygon(points=[(0, 0), (2, 0), (2, 1),  (0, 1), (0, 0)])]
>>> cs = CrossSection(geometry=geo)
>>> sz, sy = cs.static_moment
(np.float64(1.0), np.float64(2.0))
property width#

Returns the width of the cross-section.

Returns:
float

Cross-section width.

Notes

Calculated from polygon and circular sector geometry.

Examples

>>> from sstatics.core.preprocessing.cross_section import CrossSection
>>> geo = [Polygon(points=[(0, 0), (2, 0), (2, 1),  (0, 1), (0, 0)])]
>>> cs = CrossSection(geometry=geo)
>>> cs.width
2.0
class sstatics.core.preprocessing.dof.DegreesOfFreedom(x=0.0, z=0.0, phi=0.0)#

Bases: object

Represents the degrees of freedom in a 2D space with translation along x, z, and rotation phi.

Parameters:
xfloat

The displacement or force along the x-axis.

zfloat

The displacement or force along the z-axis.

phifloat

The rotational displacement (angle) or moment around the origin.

property vector#

Returns the degrees of freedom as a 3x1 vector.

Returns:
numpy.array

A 3x1 vector representing [x, z, phi].

sstatics.core.preprocessing.dof.NodeDisplacement#

Alias of DegreesOfFreedom to make clear that this class has the purpose to shift nodes.

class sstatics.core.preprocessing.loads.BarLineLoad(pi, pj, direction='z', coord='bar', length='exact')#

Bases: object

Create a distributed line load applied to a structural bar element.

Parameters:
pifloat

The force at the start of the bar element.

pjfloat

The force at the end of the bar element.

direction{‘x’, ‘z’}, default=’z’
The direction in which the load acts. Can be either:
  • 'x' : Load acts in the global/local x-direction.

  • 'z' : Load acts in the global/local z-direction.

coord{‘bar’, ‘system’}, default=’bar’
Specifies the coordinate system in which the load is defined. Can be either:
  • 'bar' : The load is applied in the local coordinate system of the bar.

  • 'system' : The load is applied in the global coordinate system.

length{‘exact’, ‘proj’}, default=’exact’
Defines how the length of the load is considered. Can be either:
  • 'exact' : The exact length of the bar is used.

  • 'proj' : The projection of the bar length onto the global coordinate system is used.

Raises:
ValueError

direction has to be either 'x' or 'z'

ValueError

coord has to be either 'bar' or 'system'

ValueError

length has to be either 'exact' or 'proj'

rotate(rotation)#

Rotates the load vector if the coordinate system is global.

Parameters:
rotationfloat

The rotation angle in rad.

Returns:
numpy.array

The rotated load vector.

Notes

  • If the load is defined in the local bar coordinate system, no rotation is applied.

  • If the load is defined in the global coordinate system, the transformation matrix accounts for rotation and projection effects.

Examples

>>> from sstatics.core.preprocessing.loads import BarLineLoad
>>> BarLineLoad(1, 1, 'z', 'bar', 'exact').rotate(0)
array([[0], [1], [0], [0], [1], [0]])
>>> from sstatics.core.preprocessing.loads import BarLineLoad
>>> import numpy as np
>>> BarLineLoad(1, 1, 'z', 'system', 'proj').rotate(np.deg2rad(30))
array([[-0.4330127], [0.75], [0], [-0.4330127], [0.75], [0]])
property vector#

Computes the load vector for the bar element.

Returns:
numpy.array

A 6x1 vector representing the distributed load at the bar element.

Notes

  • The force at the start of the bar (pi) is assigned to index 0 (x) or 1 (z).

  • The force at the end of the bar (pj) is assigned to index 3 (x) or 4 (z).

  • If pi and pj are zero, then a 6x1 zero vector is returned.

class sstatics.core.preprocessing.loads.BarPointLoad(x=0.0, z=0.0, phi=0.0, rotation=0.0, position=0.0)#

Bases: PointLoad

Create a point load applied at a specific position along a bar.

Parameters:
xfloat

The force component in the x-direction.

zfloat

The force component in the z-direction.

phifloat

The moment applied along the beam.

rotationfloat, default=0.0

The rotation of the load components in rad.

positionfloat, default=0.0

Describes the relative position of the load along the bar. A value of 0 indicates the start of the bar, and 1 indicates the end of the bar.

Raises:
ValueError

position has to be a value between 0 and 1.

Notes

This class models a point load applied to a bar (or beam) at a specific position. The load is applied in the x and z directions and includes a moment (phi) along the beam. The position is a normalized value between 0 and 1, where 0 corresponds to the start of the bar and 1 corresponds to the end of the bar.

rotate()#

Rotates the load vector based on its relative position.

Returns:
numpy.array

A 6x1 array representing the rotated load vector.

Notes

  • If position == 0, the load is placed at the start of the bar.

  • If position == 1, the load is placed at the end of the bar.

  • For intermediate positions (0 < position < 1), the load contribution is considered elsewhere in the calculation and does not appear directly in this vector. A 6x1 zero vector is returned.

Examples

>>> from sstatics.core.preprocessing.loads import BarPointLoad
>>> load = BarPointLoad(x=5.0, z=0.0, phi=0.0, position=0.0)
>>> load.rotate()
array([[5.], [0.], [0.], [0.], [0.], [0.]])
property vector#

Returns the degrees of freedom as a 3x1 vector.

Returns:
numpy.array

A 3x1 vector representing [x, z, phi].

sstatics.core.preprocessing.loads.NodePointLoad#

Alias of PointLoad to make the use case of this class more clear.

class sstatics.core.preprocessing.loads.PointLoad(x=0.0, z=0.0, phi=0.0, rotation=0.0)#

Bases: DegreesOfFreedom

Create a point load applied to a statical system.

This class is used to model a point load at a specific location, which can represent either a load applied at a node or along a bar. It includes force components in the x and z directions, as well as a rotational component (\(\phi\)), which can represent a moment applied to either a node or a bar.

Parameters:
xfloat

The force component in the x-direction. Represents the magnitude of the force along the x-axis.

zfloat

The force component in the z-direction. Represents the magnitude of the force along the z-axis.

phifloat

The moment or rotational force applied at the load location. This can represent a torque at a node or a rotational component along a bar.

rotationfloat, default=0.0

The rotation of the load components, default is 0.0. This value specifies the initial angle (in rad) of the load’s vector relative to a reference orientation.

Notes

This class serves as the base class for modeling point loads.

rotate(rotation)#

Rotates the point load by a given angle and applies the rotation to the load vector.

Parameters:
rotationfloat

The amount of rotation to apply, in radians. This is the angle by which the load vector is rotated relative to its current orientation.

Returns:
numpy.array

The 3x1 transformed load vector after applying the rotation.

Notes

The rotation is performed by multiplying the transformation matrix with the load vector. The angle for the transformation matrix is calculated by subtracting the rotation of the point load from the input rotation: alpha = load.rotation - rotation

\[\begin{split}\left(\begin{array}{ccc} \cos(\alpha) & \sin(\alpha) & 0 \\ -\sin(\alpha) & \cos(\alpha) & 0 \\ 0 & 0 & 1 \end{array}\right) \cdot \left(\begin{array}{c} x \\ z \\ \varphi \end{array}\right)\end{split}\]
property vector#

Returns the degrees of freedom as a 3x1 vector.

Returns:
numpy.array

A 3x1 vector representing [x, z, phi].

class sstatics.core.preprocessing.material.Material(young_mod, poisson, shear_mod, therm_exp_coeff)#

Bases: object

Create a material for a statical system.

Parameters:
young_modfloat

Young’s modulus (\(E\)), a measure of the material’s stiffness.

poissonfloat

Poisson’s ratio (\(\nu\)), the negative ratio of transverse to axial strain.

shear_modfloat

Shear modulus (\(G\)), a measure of the material’s response to shear stress.

therm_exp_coefffloat

Thermal expansion coefficient (\(\alpha_T\)), describing how the material’s dimensions change with temperature (in 1/K).

Raises:
ValueError

young_mod, poisson, shear_mod, and therm_exp_coeff have to be greater than zero.

class sstatics.core.preprocessing.modifier.SystemModifier(system)#

Bases: object

Modifies a given structural system by tracking and applying changes such as support modifications, bar hinge insertions, load deletions, and more.

This class maintains a mapping between original and modified components (bars and nodes), making it possible to incrementally update the system while preserving references to the original configuration. It is especially useful in structural mechanics for performing operations like virtual force methods or stepwise modifications for influence line generation.

Parameters:
systemSystem

The structural system to be modified. This must include bars and nodes as fundamental elements, potentially with loads, supports, and other mechanical properties.

Attributes:
bar_mapdict[Bar, Optional[Bar]]

A mapping from the original bars to their current (potentially modified) versions. This ensures that modifications can always refer back to the original structure. If a bar has been deleted, it is mapped to None.

This is essential for managing modifications over time without losing the relationship between system states.

node_mapdict[Node, Node]

Maps original nodes to the current (possibly modified) versions. Used to consistently track changes in node-based properties like displacements, loads, and support conditions. The original node always remains the key.

This map ensures that new system configurations reflect changes such as support removals or load applications, while maintaining link to the original nodes.

memory_modificationlist[tuple[Union[Bar, Node], str]]

Stores a log of all applied structural modifications. Each entry consists of an object (either a Bar or Node) and a string that describes what degree of freedom was modified (e.g., ‘u’, ‘w’, ‘phi’, or ‘hinge_phi_i’).

This is especially useful when constructing related systems later, for example when using the principle of virtual forces to create unit load systems corresponding to removed constraints.

memory_bar_point_loaddict[Bar, list[float]]

Records bars that have point loads acting at positions strictly between 0 and 1 (non-endpoint). The list of floats denotes the relative position of each such load along the bar.

This is used to ensure that when systems are later subdivided or aligned (e.g., for assembling superposition systems or plotting influence lines), bars can be split consistently at these key locations.

The positions are automatically collected in __post_init__ and updated when new point loads are added via modification methods.

create_uls_systems()#

Creates systems for unit load states.

After a modified system has been created, all modifications to bars or nodes are stored in the memory_modification list.

This method generates new systems representing unit load states, which are used in the force method. Unit loads are applied at the modified locations according to the type of modification:

  • Bar modifications (hinges) – A hinge modification requires applying a load pair (equal magnitude, opposite direction). The negativ load is applied to the modified bar at the hinge location, and the positiv load is applied to a connected bar without a hinge in the same degree of freedom. If all connected bars have a hinge, the first connected bar is used.

  • Node modifications (supports) – For a released degree of freedom, a unit load is applied directly to the node in the corresponding direction (horizontal, vertical, or rotational).

  • Bar deletion - For the removed bar unit loads are applied, at the connection points of the now deleted bar.

Returns:
list of System

A list of systems, each containing a single unit load state.

delete_bar(bar_obj)#

Removes a bar from the system.

Updates the internal bar_map to mark the bar as deleted and reconstructs the system without the specified bar.

Parameters:
bar_objBar

The bar to be removed.

Returns:
System

The system without the specified bar.

Raises:
ValueError

If the bar has already been deleted or cannot be found.

delete_loads()#

Removes all loads from the current system.

This includes both nodal and bar loads (point and line loads) as well as thermal effects. It preserves the topology and geometry of the system, but clears external influences.

The system is reconstructed with the cleared nodes and bars. Also updates the internal mappings accordingly.

Returns:
System

The updated system with all loads removed.

division_positions_for(system)#

Return a division map for the given system based on the stored point load positions (memory_bar_point_load) of this modifier.

Each bar in the target system is matched to the corresponding bar of the modifier using the node coordinates. If matching bars are found and division positions exist, these positions are assigned to the new bar.

Parameters:
systemSystem

The structural system for which the division map should be created.

Returns:
dict[Bar, list[float]]

A dictionary mapping each matching bar in the given system to its division positions along the bar length.

division_positions_mesh()#

Returns a dictionary mapping each bar to a list of relative positions (0 < pos < 1) where point loads exist. This is compatible with the user_divisions argument of Mesh.

Returns:
dict[Bar, list[float]]

A dictionary where keys are Bar objects and values are lists of division positions on that bar.

insert_hinge(bar_obj, hinge)#

Inserts a hinge at a specific end and direction of a bar.

Modifies the selected bar by enabling a hinge for axial (u), shear (w), or moment (phi) behavior at the start (_i) or end (_j). Updates the system and internal memory for reconstruction or analysis.

Parameters:
bar_objBar

The target bar to modify.

hingestr

The type and location of hinge, chosen from: ‘hinge_u_i’, ‘hinge_w_i’, ‘hinge_phi_i’, ‘hinge_u_j’, ‘hinge_w_j’, ‘hinge_phi_j’.

Returns:
System

The updated system with the hinge applied.

Raises:
ValueError

If the hinge is already present on the bar.

modify_bar_force_vir(obj, force, virt_force=1, position=0)#

Applies a virtual point load to a bar.

Useful for virtual force methods to calculate internal forces (e.g., to determine internal actions). The load is placed at the specified relative position along the bar.

Parameters:
objBar

The bar where the virtual load is applied.

force{‘fx’, ‘fz’, ‘fm’}

Direction/type of load: ‘fx’ = axial, ‘fz’ = transverse, ‘fm’ = moment.

positionfloat, optional

Relative position along the bar (0 to 1), default is 0.

virt_forcefloat, optional

Magnitude of the virtual force, default is 1.

Returns:
System

Updated system with the virtual bar load.

modify_node_force_vir(obj, force, virt_force=1)#

Applies a virtual load to a node.

This is used for virtual work or energy methods (e.g., to compute displacements). It modifies the node by assigning a virtual point load in the specified direction.

Parameters:
objNode

The node to which the virtual load is applied.

force{‘fx’, ‘fz’, ‘fm’}

Type of force: ‘fx’ = horizontal, ‘fz’ = vertical, ‘fm’ = moment.

virt_forcefloat, optional

Magnitude of the virtual force (default is 1.0).

Returns:
System

Updated system with the virtual load applied to the node.

modify_support(node_obj, support)#

Frees a specific degree of freedom (support) at a given node.

Modifies the boundary condition of the node, turning the specified support direction into a free (unconstrained) one. The system is updated accordingly, and all bars connected to the node are reconstructed.

Parameters:
node_objNode

The node whose support is being modified.

support{‘u’, ‘w’, ‘phi’}

Direction of the support to release: ‘u’ for horizontal, ‘w’ for vertical, ‘phi’ for rotational.

Returns:
System

The system with the updated boundary condition.

Raises:
ValueError

If the selected support is already free.

class sstatics.core.preprocessing.node.Node(x, z, rotation=0.0, u='free', w='free', phi='free', displacements=(), loads=(), debug=False)#

Bases: LoggerMixin

Create a node for a statical system.

Parameters:
x, zfloat

Coordinates of the node in the x and z directions.

rotationfloat, default=0.0

Initial rotation of the node in radiant.

u, w, phi{‘free’, ‘fixed’} or float, default=’free’
Boundary conditions (supports) for the node:
  • 'free': no constraint

  • 'fixed': fully constrained

  • float: represents a spring support with a specific stiffness value (nib width).

displacementstuple, default=()

Prescribed displacements acting on the node. hese should be instances of the NodeDisplacement.

loadstuple, default=()

Point loads acting on the node. These should be instances of the NodePointLoad.

Raises:
ValueError

u, w and phi have to be either 'free', 'fixed' or a real number.

ValueError

u, w or phi are set to zero. A spring with a nib width of zero behaves like a free fixture and therefore the value need to be set to 'free'.

property displacement#

The overall node displacement as a 3x1 vector.

Returns:
numpy.array

Sum of all displacements specified in displacements.

See also

NodeDisplacement

Notes

If no displacements were specified, then a 3x1 zero vector is returned.

Examples

>>> from sstatics.core.preprocessing.node import Node
>>> Node(1, 2).displacement
array([[0], [0], [0]])
>>> from sstatics.core.preprocessing.dof import NodeDisplacement
>>> displacements = (NodeDisplacement(1.5, 2, 0.5),
>>>                  NodeDisplacement(-2, 3, -0.3))
>>> Node(-1, 3, displacements=displacements).displacement
array([[-0.5], [5], [0.2]])
property elastic_support#

Sets the stiffness values from the support conditions on the diagonal of the matrix.

To account for the elastic support of nodes, the support conditions of u, w, and phi are considered and placed on the diagonal of a zero matrix.

Returns:
numpy.array

A 3x3 zero matrix with the diagonal populated by the values of u, w and phi.

Notes

If an attribute is a string, its value is set to zero.

\[\begin{split}\begin{bmatrix} u & 0 & 0 \\ 0 & w & 0 \\ 0 & 0 & \varphi \\ \end{bmatrix}\end{split}\]

Examples

>>> from sstatics.core.preprocessing.node import Node
>>> Node(0, 0, u='fixed', w='fixed', phi='free').elastic_support
array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
>>> Node(0, 0, u=100, w=200, phi=1000).elastic_support
array([[100, 0, 0], [0, 200, 0], [0, 0, 1000]])
property load#

Rotate the node loads.

Every load from loads is rotated by the node’s rotation by calling PointLoad.rotate. So the resulting rotation angle is calculated by alpha = load.rotation - node.rotation. Thus each rotated load is computed by

\[\begin{split}\left(\begin{array}{c} \cos(\alpha) & \sin(\alpha) & 0 \\ -\sin(\alpha) & \cos(\alpha) & 0 \\ 0 & 0 & 1 \end{array}\right) \cdot \left(\begin{array}{c} x \\ z \\ \varphi \end{array}\right)\end{split}\]

and summed up afterward.

Returns:
numpy.array

Sum of all loads specified in loads.

See also

NodePointLoad

Notes

If no loads were specified, then a 3x1 zero vector is returned.

Examples

>>> from sstatics.core.preprocessing.node import Node
>>> from sstatics.core.preprocessing.loads import NodePointLoad
    >>> import numpy
>>> load = NodePointLoad(1, 2, 0.5, rotation=2 * numpy.pi)
>>> Node(6, 5, rotation=numpy.pi, loads=(load,)).load
array([[-1], [-2], [0.5]])
property logger#

Returns the logger instance associated with this object.

Returns:
logging.Logger

The configured logger.

same_location(other)#

Determine if two nodes have exactly the same x- and z-coordinates.

Parameters:
otherNode

Second node to compare coordinates to.

Returns:
bool

True if the nodes have exactly the same coordinates, False otherwise.

Examples

>>> from sstatics.core.preprocessing.node import Node
>>> node = Node(1, 2)
>>> node.same_location(Node(1, 2))
True
>>> node.same_location(Node(1, -2))
False
class sstatics.core.preprocessing.system.Mesh(bars, user_divisions=None)#

Bases: object

Represents a mesh of bars.

Attributes:
barsList[Bar | BarSecond]

A list of bars to be meshed.

user_divisionsOptional[Dict[Bar, List[float]]]

Optional user-defined divisions for each bar.

Notes

The user_divisions dictionary maps each bar to a list of positions where the bar should be divided.

bar_of(mesh_segment)#

Gets the original bar corresponding to a given mesh segment.

Parameters:
mesh_segmentBar | BarSecond

The mesh segment for which to retrieve the original bar.

Returns:
Bar | BarSecond

The original bar corresponding to the given mesh segment.

generate()#

Generates the mesh based on the input bars and user divisions.

This method populates the mesh and user properties.

Returns:
None

Notes

The mesh generation process involves splitting the input bars into segments based on user-defined divisions and point loads.

property mesh#

Gets the generated mesh.

Returns:
List[Bar | BarSecond]

The list of bars in the mesh.

mesh_segments_of(bar)#

Gets the mesh segments corresponding to a given bar.

Parameters:
barBar | BarSecond

The bar for which to retrieve mesh segments.

Returns:
List[Bar | BarSecond]

The list of mesh segments corresponding to the given bar.

property user#

Gets the user-defined mesh.

Returns:
List[Bar | BarSecond]

The list of bars in the user-defined mesh.

user_segments_of(bar)#

Gets the user-defined segments corresponding to a given bar.

Parameters:
barBar | BarSecond

The bar for which to retrieve user-defined segments.

Returns:
List[Bar | BarSecond]

The list of user-defined segments corresponding to the given bar.

class sstatics.core.preprocessing.system.System(bars, user_divisions=None)#

Bases: object

Represents a statical system composed of interconnected bars.

This class models a mechanical system made up of interconnected bars, where each bar connects two nodes.

Parameters:
barstuple[ Bar, …] | list[ Bar] | tuple[ BarSecond, …] | list[BarSecond]

A list or tuple of bars that define the structure of the statical system. The bars must be provided in a consecutive order, as they represent a connected structure.

Attributes:
meshtuple[Bar, …] | tuple[BarSecond, …]

Returns the generated mesh bars.

Raises:
ValueError

Raised if any of the following conditions are met:

  • The list of bars is empty.

  • Two or more bars share the same geometric location.

  • Two distinct node instances occupy the same spatial position.

  • The system’s connectivity graph is not fully connected.

bar_of(mesh_segment)#

Returns the original bar of a given mesh segment.

Parameters:
mesh_segmentBar | BarSecond

A bar segment from the generated mesh.

Returns:
Bar | BarSecond

The original bar from which the mesh segment was created.

create_mesh(user_divisions=None)#

Creates the mesh for the current system.

Parameters:
user_divisionsdict, optional

A dictionary mapping bars to lists of relative positions at which the bars should be divided.

Returns:
None

Notes

This method initializes and generates a Mesh object based on the system bars and optional user-defined divisions.

property degree_of_static_indeterminacy#

Calculates the degree of static indeterminacy of the system.

This function checks the static determinacy of the currently modified system. A system is statically determinate if n = 0. It is statically indeterminate if n > 0 and statically unstable if n < 0.

Returns:
int

The number of redundant constraints in the system.

property mesh#

Returns the generated mesh bars.

Returns:
List[Bar | BarSecond]

The list of bars representing the generated mesh.

mesh_segments_of(bar)#

Returns the mesh segments corresponding to a given bar.

Parameters:
barBar | BarSecond

The original bar.

Returns:
List[Bar | BarSecond]

The list of mesh segments derived from the given bar.

property user_mesh#

Returns the user-defined mesh bars.

Returns:
List[Bar | BarSecond]

The list of bars resulting from user-defined divisions.

user_segments_of(bar)#

Returns the user-defined segments of a given bar.

Parameters:
barBar | BarSecond

The original bar.

Returns:
List[Bar | BarSecond]

The list of user-defined segments of the bar.

class sstatics.core.preprocessing.temperature.BarTemp(temp_o, temp_u)#

Bases: object

Create a temperature load case for a statical system.

Parameters:
temp_ofloat

Temperature change above the neutral axis [K].

temp_ufloat

Temperature change below the neutral axis [K].

Raises:
ValueError

temp_o, temp_u have to be greater than or equal to zero since its unit is Kelvin.

property temp_delta#

Calculates the non-uniform temperature change in the unit Kelvin.

Returns:
float

The temperature difference between the upper and lower side of the neutral axis, indicating the non-uniform temperature change in Kelvin.

Notes

The non-uniform temperature change is given by:

\[\Delta T = T_u - T_o\]

Examples

>>> from sstatics.core.preprocessing.temperature import BarTemp
>>> temp_diff = BarTemp(10, 20).temp_delta
10.0
property temp_s#

Calculates the uniform temperature change in the unit Kelvin.

Returns:
float

Averaged value of temperature changes above and below the neutral axis in Kelvin.

Notes

The uniform temperature change is given by:

\[T = \dfrac{(T_o + T_u)}{2}\]

Examples

>>> from sstatics.core.preprocessing.temperature import BarTemp
>>> temp = BarTemp(15, 30).temp_s
22.5
class sstatics.core.preprocessing.geometry.objects.CircularSector(center, radius, angle=0, start_angle=0, positive=True)#

Bases: object

Represents a two-dimensional circular sector defined by a center point, radius, angular span and a starting angle.

Parameters:
centertuple of float

The (y_0, z_0) coordinates of the center of the circular sector.

radiusfloat

The radius of the sector. Must be a positive value.

anglefloat

The angular span of the sector in radians. Must be a non-zero number and lie within the range ± 2π.

start_anglefloat

The angle (in radians) where the sector arc begins, measured clockwise from the positive y’-axis.

positivebool, optional

Specifies whether the sector is a partial or cutout area of the total cross-section. If “True,” the sector contributes positively to calculations (e.g., area and moment). If “False,” it is treated as a ‘cutout’ and its contributions are subtracted. The default value is “True.”

Notes

The constructor validates input to ensure that the circular sector is well-defined: - The center must be a 2D coordinate tuple of numeric values. - The radius must be greater than zero. - The angle must not be zero and must be in the range (-2π <= angle <= 2π). - Start angle must be a number (in radians).” - The ‘positive’ attribute must be a boolean value.

The sector is internally represented with geometric formulas for properties such as area, centroid, and moments of inertia. Optionally, the sector can be discretized into a polygon via the convert_to_polygon() method.

Examples

Create a circular sector in the first quadrant:

>>> from sstatics.core.preprocessing.geometry.objects import CircularSector
>>> import numpy as np
>>> c = CircularSector(center = (0,0), radius = 1, angle = np.pi/4,
>>>                    start_angle = np.pi/8, positive = True
>>>                    )

Creates the same circular sector with a negative angle range:

>>> c = CircularSector(center = (0,0), radius = 1, angle = -np.pi/4,
>>>                    start_angle = 3*np.pi/8, positive = True
>>>                    )

Access area and centroid:

>>> round(c.area, 2)
0.39
>>> round(c.center_of_mass_y, 2), round(c.center_of_mass_z, 2)
(0.46, 0.46)
property area#

Computes the area of the circular sector.

Returns:
float

The area of the circular sector.

Notes

The area of a circular sector is computed using the formula:

\[A = \frac{1}{2} \cdot r^2 \cdot \mid \varphi_M \mid\]

where

  • \(r\) is the radius of circular sector

  • \(\varphi_M\) is the angular span of the sector in radians

Examples

>>> from sstatics.core.preprocessing.geometry.objects import
>>>     CircularSector
>>> import numpy as np
>>> c = CircularSector(center = (0,0), radius = 1, angle = np.pi/4,
>>>                    start_angle = np.pi/8, positive = True
>>>                    )
>>> round(c.area, 3)
0.393
boundary()#

Computes the minimum and maximum boundaries of the circular sector in both the y- and z-directions.

Returns:
tuple of list of float or np.float64

A tuple containing two lists:

  • The first list is [y_min, y_max], representing the horizontal extent.

  • The second list is [z_min, z_max], representing the vertical extent.

Notes

This method determines the spatial boundaries of the circular sector by evaluating the coordinates of:

  • The two arc endpoints (start and end angles),

  • The circle center,

  • And optionally the extreme values (i.e., if the local \(y'\)- or \(z'\)-axis lies between the start and end points of the circle sector).

The method checks whether those extreme values within the angular range of the circular sector using _angle_in_sector, and includes them if applicable. This ensures the correct bounding box even for partial sectors that span multiple quadrants.

These boundary values are used to compute the overall width and height of the sector geometry.

Examples

>>> from sstatics.core.preprocessing.geometry import CircularSector
>>> import numpy as np
>>> c = CircularSector(center = (0,0), radius = 1, angle = np.pi/2,
>>>                    start_angle = np.pi/4, positive = True
>>>                    )
>>> c.boundary()
([-0.707, 0.707], [0.0, 1.0])
property center_of_mass_y#

Computes the y-coordinate of the centroid (center of mass).

Returns:
np.float64

The centroid’s y-coordinate.

Notes

The centroid represents the geometric center of the circular sector. It is used to compute the statics moments.

\[y_c = \frac{2 \cdot r}{3 \cdot \varphi_M} \cdot (sin(\varphi_2) - sin(\varphi_1)) + y_0\]

where

  • \(r\) is the radius of circular sector

  • \(\varphi_M\) is the angular span of the sector in radians

  • \(\varphi_1\) is the starting angle

  • \(\varphi_2\) is the ending angle

  • \(y_0\) is the y-coordinate of the center of the circular sector

This assumes uniform density and thickness.

property center_of_mass_z#

Computes the z-coordinate of the centroid (center of mass).

Returns:
np.float64

The centroid’s z-coordinate.

Notes

The centroid represents the geometric center of the circular sector. It is used to compute the statics moments.

\[z_c = \frac{2 \cdot r}{3 \cdot \varphi_M} \cdot (cos(\varphi_1) - cos(\varphi_2)) + z_0\]

where

  • \(r\) is the radius of circular sector

  • \(\varphi_M\) is the angular span of the sector in radians

  • \(\varphi_1\) is the starting angle

  • \(\varphi_2\) is the ending angle

  • \(z_0\) is the z-coordinate of the center of the circular sector

This assumes uniform density and thickness.

convert_to_polygon(num_points=500)#

Converts the circular sector into an approximate polygon representation.

Parameters:
num_pointsint, optional

Number of points used to discretize the arc of the sector. Higher values yield a finer approximation. Default is 500.

Returns:
Polygon

A polygonal approximation of the circular sector, represented by a Polygon object.

Notes

The polygon is constructed by sampling num_points points along the arc defined by the sector’s start angle \(\varphi_1\), opening angle \(\varphi_M\), and radius \(r\). These points are connected together with the center point of the sector to form a closed polygonal shape.

  • The starting point of the arc is determined by start_angle.

  • Points are sampled at equidistant angles along the arc.

  • The last arc point is explicitly added (if not already present), to avoid floating point errors.

  • The center point is both the first and last point in the polygon to ensure proper closure.

The resulting polygon can be used for geometric computations such as area, static moments, and moment of inertia using existing polygon-based methods.

property height#

Computes the height of the circular sector in the local z-direction.

Returns:
np.float64

Height of the circular sector (i.e., the range of z-coordinates).

Notes

The height is defined as:

\[h = z_{\text{max}} - z_{\text{min}}\]

where \(z_{\text{max}}\) and \(z_{\text{min}}\) are the maximum and minimum vertical coordinates of the sectors’s boundary

mom_of_int_steiner(distance)#

Applies the parallel axis theorem (Steiner’s theorem) to compute the moment of inertia about a shifted axis.

Parameters:
distancefloat

The perpendicular distance from the centroid to the desired axis (in the same units as the circular sector coordinates).

Returns:
float

The additional moment of inertia due to the axis shift, i.e. \(I_{\text{shift}} = A \cdot d^2\), where \(A\) is the area and \(d\) is the distance to the new axis.

Notes

This is used to shift the moment of inertia from one axis to another parallel axis according to the parallel axis theorem:

\[I = I_c + A \cdot d^2\]
property mom_of_int_y#

Computes the second moment of area \(I_{\bar{y}}\) about the bar{y}-axis, referenced to the centroid coordinate system.

Returns:
np.float64

The second moment of area \(I_{\bar{y}}\), in units of length⁴.

Notes

The components are initially computed relative to the center of the circular sector \((y_0, z_0)\) and then shifted to the centroid using the parallel axis theorem:

\[ \begin{align}\begin{aligned}I_{y'} = \frac{r^4}{8} \cdot [|\varphi_M| - \frac{1}{2} \cdot (sin(2\varphi_2) - sin(2\varphi_1))]\\I_{\bar{y}} = I_{y'} - A \cdot (z_c - z_0)^2\end{aligned}\end{align} \]

where

  • \(r\) is the radius of circular sector

  • \(\varphi_M\) is the angular span of the sector in radians

  • \(\varphi_1\) is the starting angle

  • \(\varphi_2\) is the ending angle

  • \(z_c\) is the z-coordinate of the centroid of the circular sector

  • \(z_0\) is the z-coordinate of the center of the circular sector

property mom_of_int_z#

Computes the second moment of area \(I_{\bar{z}}\) about the bar{z}-axis, referenced to the centroid coordinate system.

Returns:
np.float64

The second moment of area \(I_{\bar{z}}\), in units of length⁴.

Notes

The components are initially computed relative to the center of the circular sector \((y_0, z_0)\) and then shifted to the centroid using the parallel axis theorem:

\[ \begin{align}\begin{aligned}I_{z'} = \frac{r^4}{8} \cdot [|\varphi_M| + \frac{1}{2} \cdot (sin(2\varphi_2) - sin(2\varphi_1))]\\I_{\bar{z}} = I_{z'} - A \cdot (y_c - y_0)^2\end{aligned}\end{align} \]

where

  • \(r\) is the radius of circular sector

  • \(\varphi_M\) is the angular span of the sector in radians

  • \(\varphi_1\) is the starting angle

  • \(\varphi_2\) is the ending angle

  • \(y_c\) is the z-coordinate of the centroid of the circular sector

  • \(y_0\) is the z-coordinate of the center of the circular sector

property static_moment#

Computes the static moments \(S_y\) and \(S_z\) of the circular sector with respect to the coordinate axes.

Returns:
tuple of np.float64

The static moments (S_y, S_z) of the circular sector.

Notes

The static moments (also called first moments of area) are used to compute the centroid of the entire composite cross-section (see class CrossSection).

\[S_y = A \cdot z_c\]
\[S_z = A \cdot y_c\]

Examples

>>> from sstatics.core.preprocessing.geometry.objects import
>>> CircularSector
>>> import numpy as np
>>> c = CircularSector(center = (0,0), radius = 1, angle = np.pi/2,
>>>                    start_angle = 0, positive = True
>>>                    )
>>> round(c.static_moment[0], 3)
0.333
>>> round(c.static_moment[1], 3)
0.333
property width#

Computes the width of the circular sector in the local y-direction.

Returns:
np.float64

Width of the circular sector (i.e., the range of y-coordinates).

Notes

The width is defined as:

\[w = y_{\text{max}} - y_{\text{min}}\]

where \(y_{\text{max}}\) and \(y_{\text{min}}\) are the maximum and minimum horizontal coordinates of the sectors’s boundary

class sstatics.core.preprocessing.geometry.objects.Polygon(points, holes=<factory>, positive=True)#

Bases: object

Represents a two-dimensional polygon with optional interior holes, defined by a sequence of (y, z) coordinate tuples.

Parameters:
pointslist of tuple of float

A list of 2D coordinates defining the exterior boundary of the polygon. The polygon must be closed; i.e., the first and last point must be identical. A minimum of three distinct points (excluding the closing point) is required.

holeslist of tuple of float, optional

A list of holes, where each hole is defined by a list of coordinate tuples similar to the outer boundary. Each hole must also be closed. Default is an empty list (no holes).

positivebool, optional

Specifies whether the polygon should be oriented positively (counterclockwise). This affects the internal construction of the Shapely polygon. Default is True.

Notes

The constructor validates the input geometry to ensure that the polygon is well-defined: - At least three distinct points are required to define a polygon. - The first and last point of the outer boundary (and any hole) must be the same to ensure closure. - All coordinate entries must be tuples of two numeric values. - No two consecutive points may be identical.

Internally, the polygon is represented using a Shapely Polygon object and re-oriented if necessary. The coordinate arrays self.y and self.z are extracted for further geometric computations, such as area, centroid, and static moments.

Examples

Create a rectangular polygon with no holes:

>>> from sstatics.core.preprocessing.geometry.objects import Polygon
>>> outer = [(0, 0), (4, 0), (4, 2), (0, 2), (0, 0)]
>>> p = Polygon(points=outer)

Create a polygon with one rectangular hole:

>>> hole = [[(1, 0.5), (3, 0.5), (3, 1.5), (1, 1.5), (1, 0.5)]]
>>> p = Polygon(points=outer, holes=hole)

Access area and centroid:

>>> round(p.area, 2)
6.0
>>> round(p.center_of_mass_y, 2), round(p.center_of_mass_z, 2)
(2.0, 1.0)
property area#

Computes the signed area of the polygon, including all interior holes.

Returns:
float

The signed area of the polygon. A positive value indicates counterclockwise orientation (positive geometry), while a negative value indicates clockwise orientation.

Notes

The area is computed using the shoelace formula:

\[ \begin{align}\begin{aligned}A = \frac{1}{2} \left| \sum_{i=1}^{n} y_i \cdot z_{(i+1)} - y_{ (i+1)} \cdot z_i \right|\\where\end{aligned}\end{align} \]
\[(y_i, z_i)\]

are the coordinates of the vertices.

Examples

>>> from sstatics.core.preprocessing.geometry.objects import Polygon
>>> outer = [(0, 0), (4, 0), (4, 2), (0, 2), (0, 0)]
>>> hole = [[(1, 0.5), (3, 0.5), (3, 1.5), (1, 1.5), (1, 0.5)]]
>>> p = Polygon(points=outer, holes=hole)
>>> round(p.area, 3)
6.0
property center_of_mass_y#

Computes the y-coordinate of the centroid (center of mass).

Returns:
np.float64

The centroid’s y-coordinate.

Notes

The centroid represents the geometric center of the polygon. It is computed as the ratio of the first moment of area about the z-axis to the total area.

\[\bar{y} = \frac{S_y}{A}\]

where

  • \(S_y\) is the static moment about the z-axis

  • \(A\) is the total area of the polygon

This assumes uniform density and thickness.

property center_of_mass_z#

Computes the z-coordinate of the centroid (center of mass).

Returns:
np.float64

The centroid’s z-coordinate.

Notes

The centroid represents the geometric center of the polygon. It is computed as the ratio of the first moment of area about the y-axis to the total area.

\[\bar{z} = \frac{S_z}{A}\]

where

  • \(S_z\) is the static moment about the y-axis

  • \(A\) is the total area of the polygon

This assumes uniform density and thickness.

property height#

Computes the height of the polygon in the local z-direction.

Returns:
np.float64

The height of the polygon (i.e., the range of z-coordinates).

Notes

The height is defined as:

\[h = z_\text{max} - z_\text{min}\]

where \(z_\text{max}\) and \(z_\text{min}\) are the maximum and minimum vertical coordinates of the polygon’s boundary, including holes.

property iyy#

Returns the second moment of area about the y-axis.

Returns:
float

Moment of inertia \(I_{yy}\) about the y-axis, relative to the centroidal coordinate system, in units of length⁴.

Notes

This value is extracted from the full second moment of inertia tensor and reflects the resistance of the shape to bending about the y-axis.

property iyz#

Returns the product moment of inertia.

Returns:
float

Product moment of inertia \(I_{yz}\) relative to the centroidal coordinate system, in units of length⁴.

Notes

A nonzero product moment of inertia indicates that the principal axes of the shape are rotated relative to the coordinate system. This value is symmetric, i.e., \(I_{yz} = I_{zy}\).

property izz#

Returns the second moment of area about the z-axis.

Returns:
float

Moment of inertia \(I_{zz}\) about the z-axis, relative to the centroidal coordinate system, in units of length⁴.

Notes

This quantity indicates the resistance of the shape to bending about the z-axis and is derived from the inertia tensor.

mom_of_int_steiner(center)#

Applies the parallel axis theorem (Steiner’s theorem) to compute the moment of inertia about a shifted axis.

Parameters:
centerfloat

The perpendicular distance from the centroid to the desired axis (in the same units as the polygon coordinates).

Returns:
float

The additional moment of inertia due to the axis shift, i.e. \(I_{\text{shift}} = A \cdot d^2\), where \(A\) is the area and \(d\) is the distance to the new axis.

Notes

This is used to shift the moment of inertia from the centroidal axis to another parallel axis according to the parallel axis theorem:

\[I = I_c + A \cdot d^2\]
property moments_of_inertia_tensor#

Computes the second moment of area tensor (also known as the area moment of inertia tensor) relative to the centroid of the polygon.

Returns:
ndarray

A 2×2 symmetric numpy array representing the inertia tensor:

\[\begin{split}\begin{bmatrix} I_{yy} & I_{yz} \\ I_{zy} & I_{zz} \end{bmatrix}\end{split}\]

All entries are in units of length⁴.

Notes

The components are initially computed relative to the origin and then shifted to the centroid using the parallel axis theorem:

\[\begin{split}I_{yy}^{\text{centroid}} = I_{yy}^0 - A \cdot z_c^2 \\ I_{zz}^{\text{centroid}} = I_{zz}^0 - A \cdot y_c^2 \\ I_{yz}^{\text{centroid}} = I_{yz}^0 - A \cdot y_c z_c\end{split}\]
where:
  • \(A\) is the area,

  • \((y_c, z_c)\) is the centroid.

This tensor is useful for calculating principal axes and moments, and for evaluating bending behavior in 2D beam cross-sections.

property static_moment#

Computes the static moments \(S_z\) and \(S_y\) with respect to the coordinate axes.

Returns:
tuple of float or np.float64

The static moments (S_z, S_y) of the polygon.

Notes

The static moments (also called first moments of area) are used to compute the centroid of the polygon.

\[S_z = -\frac{1}{6} \sum (y_i z_{i-1} - y_{i-1} z_i) (z_i + z_{i-1})\]
\[S_y = -\frac{1}{6} \sum (y_i z_{i-1} - y_{i-1} z_i) (y_i + y_{i-1})\]

These are discrete approximations of the first moments:

\[S_z = \int_A z \, \mathrm{d}A, \quad S_y = \int_A y \, \mathrm{d}A\]

Examples

Without holes:

>>> from sstatics.core.preprocessing.geometry.objects import Polygon
>>> outer = [(0, 0), (4, 0), (4, 2), (0, 2), (0, 0)]
>>> p = Polygon(points=outer)
>>> sz, sy = p.static_moment
>>> round(sz, 2)
10.67
>>> round(sy, 2)
21.33
property width#

Computes the width of the polygon in the local y-direction.

Returns:
np.float64

The width of the polygon (i.e., the range of y-coordinates).

Notes

The width is defined as:

\[w = y_\text{max} - y_\text{min}\]

where \(y_\text{max}\) and \(y_\text{min}\) are the maximum and minimum horizontal coordinates of the polygon’s boundary, including holes.

class sstatics.core.preprocessing.geometry.operation.PolygonMerge(*a, **k)#

Bases: LoggerMixin

Represents a combination of multiple positive and negative polygons, and provides methods to compute their geometric difference.

This class is used to merge a list of “positive” polygons and subtract one or more “negative” polygons (holes or cut-outs) from the result. Internally, it uses geometric union and difference operations based on Shapely.

Parameters:
positivelist of Polygon, optional

A list of polygons that define the base area to be merged. At least one polygon must be provided. All elements must be instances of the custom Polygon class.

negativelist of Polygon, optional

A list of polygons to be subtracted (cut out) from the merged positive geometry. These are treated as holes or exclusions. Defaults to an empty list.

Attributes:
positivelist of Polygon

The list of input polygons to be merged.

negativelist of Polygon

The list of polygons to subtract from the merged positive area.

unary_posshapely.geometry.Polygon or MultiPolygon

Union geometry of all positive polygons.

unary_negshapely.geometry.Polygon or MultiPolygon or None

Union geometry of all negative polygons, or None if empty.

Raises:
ValueError

If the positive list is empty.

TypeError

If any element of positive or negative is not an instance of Polygon.

difference()#

Computes the geometric difference between the union of the positive polygons and the union of the negative polygons.

Returns:
Polygon

A new Polygon instance representing the result of the difference operation.

Raises:
NotImplementedError

If the resulting geometry is a MultiPolygon, which is currently not supported.

property logger#

Returns the logger instance associated with this object.

Returns:
logging.Logger

The configured logger.

class sstatics.core.preprocessing.geometry.operation.SectorToPolygonHandler(*a, **k)#

Bases: LoggerMixin

Handles the interaction between regular polygons and circular sectors.

This class is responsible for checking overlaps between circular sectors and existing polygons. If an overlap is detected, the circular sector is converted into a polygon and added to the list of polygons. Otherwise, it is kept as a remaining circular sector.

Parameters:
polygonslist of Polygon

A list of existing polygonal shapes. Each element must be an instance of the custom Polygon class.

circularlist of CircularSector

A list of circular sectors to be tested against the polygons. Each element must be an instance of CircularSector.

Attributes:
polygonslist of Polygon

The original list of polygon shapes.

circular_sectorlist of CircularSector

The original list of circular sectors to be tested and potentially converted.

Raises:
TypeError

If any element in polygons is not a Polygon, or any element in circular is not a CircularSector.

static bounding_boxes_overlap(a, b)#

Checks whether the bounding boxes of two Shapely polygons overlap.

Parameters:
ashapely.geometry.Polygon

First polygon.

bshapely.geometry.Polygon

Second polygon.

Returns:
bool

True if the bounding boxes overlap, False otherwise.

execute()#

Converts intersecting circular sectors to polygons and separates non-intersecting ones.

Each circular sector is checked for intersection with the existing polygons. If it intersects any polygon (based on bounding box and area of geometric intersection), it is converted to a polygon and added to the polygon list. Otherwise, it remains as a circular sector.

Returns:
tuple of (list of Polygon, list of CircularSector)
  • A list of polygons including the original ones and those converted from intersecting sectors.

  • A list of circular sectors that did not intersect any polygon.

property logger#

Returns the logger instance associated with this object.

Returns:
logging.Logger

The configured logger.