Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.21.2
hooks:
- id: pyupgrade
args: [--py310-plus]
1 change: 0 additions & 1 deletion Examples/Beam on Elastic Foundation.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
This example shows how to generate a beam on elastic foundation by using spring supports. All units
in this model are expressed in terms of kips (force) and inches (length).
Expand Down
32 changes: 16 additions & 16 deletions Pynite/Analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def _prepare_model(model: FEModel3D, n_modes: int = 0) -> None:
_renumber(model)


def _identify_combos(model: FEModel3D, combo_tags: List[str] | None = None) -> List[LoadCombo]:
def _identify_combos(model: FEModel3D, combo_tags: list[str] | None = None) -> list[LoadCombo]:
"""Returns a list of load combinations that are to be run based on tags given by the user.

:param model: The model being analyzed.
Expand Down Expand Up @@ -164,7 +164,7 @@ def _check_stability(model: FEModel3D, K: NDArray[float64]) -> None:
return


def _PDelta(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1: NDArray[float64], D1_indices: List[int], D2_indices: List[int], D2: NDArray[float64], log: bool = True, sparse: bool = True, check_stability: bool = False, max_iter: int = 30) -> None:
def _PDelta(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1: NDArray[float64], D1_indices: list[int], D2_indices: list[int], D2: NDArray[float64], log: bool = True, sparse: bool = True, check_stability: bool = False, max_iter: int = 30) -> None:
"""Performs second order (P-Delta) analysis. This type of analysis is appropriate for most models using beams, columns and braces. Second order analysis is usually required by material-specific codes. Models with slender members and/or members with combined bending and axial loads will generally have more significant P-Delta effects. P-Delta effects in plates/quads are not considered by Pynite at this time.

:param model: The finite element model to be solved.
Expand Down Expand Up @@ -309,7 +309,7 @@ def _PDelta(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1: NDArr
model.solution = 'P-Delta'


def _pushover_step(model: FEModel3D, combo_name: str, push_combo: str, step_num: int, P1: NDArray[float64], FER1: NDArray[float64], D1_indices: List[int], D2_indices: List[int], D2: NDArray[float64], log: bool = True, sparse: bool = True, check_stability: bool = False) -> None:
def _pushover_step(model: FEModel3D, combo_name: str, push_combo: str, step_num: int, P1: NDArray[float64], FER1: NDArray[float64], D1_indices: list[int], D2_indices: list[int], D2: NDArray[float64], log: bool = True, sparse: bool = True, check_stability: bool = False) -> None:

# Run at least one iteration
run_step = True
Expand Down Expand Up @@ -434,7 +434,7 @@ def _pushover_step(model: FEModel3D, combo_name: str, push_combo: str, step_num:
_sum_displacements(model, Delta_D1, D2, D1_indices, D2_indices, model.load_combos[combo_name])


def _unpartition_disp(model: FEModel3D, D1: NDArray[float64], D2: NDArray[float64], D1_indices: List[int], D2_indices: List[int]) -> NDArray[float64]:
def _unpartition_disp(model: FEModel3D, D1: NDArray[float64], D2: NDArray[float64], D1_indices: list[int], D2_indices: list[int]) -> NDArray[float64]:
"""Unpartitions displacements from the solver and returns them as a global displacement vector

:param model: The finite element model being evaluated
Expand Down Expand Up @@ -471,7 +471,7 @@ def _unpartition_disp(model: FEModel3D, D1: NDArray[float64], D2: NDArray[float6
return D


def _store_displacements(model: FEModel3D, D1: NDArray[float64], D2: NDArray[float64], D1_indices: List[int], D2_indices: List[int], combo: LoadCombo) -> None:
def _store_displacements(model: FEModel3D, D1: NDArray[float64], D2: NDArray[float64], D1_indices: list[int], D2_indices: list[int], combo: LoadCombo) -> None:
"""Stores calculated displacements from the solver into the model's displacement vector `_D` and into each node object in the model

:param model: The finite element model being evaluated.
Expand Down Expand Up @@ -507,7 +507,7 @@ def _store_displacements(model: FEModel3D, D1: NDArray[float64], D2: NDArray[flo
node.RZ[combo.name] = D[node.ID*6 + 5, 0]


def _sum_displacements(model: FEModel3D, Delta_D1: NDArray[float64], Delta_D2: NDArray[float64], D1_indices: List[int], D2_indices: List[int], combo: LoadCombo) -> None:
def _sum_displacements(model: FEModel3D, Delta_D1: NDArray[float64], Delta_D2: NDArray[float64], D1_indices: list[int], D2_indices: list[int], combo: LoadCombo) -> None:
"""Sums calculated displacements for a load step from the solver into the model's displacement vector `_D` and into each node object in the model.

:param model: The finite element model being evaluated.
Expand Down Expand Up @@ -682,7 +682,7 @@ def _check_TC_convergence(model: FEModel3D, combo_name: str = "Combo 1", log: bo
return convergence


def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] | None = None) -> None:
def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: list[str] | None = None) -> None:
"""
Calculates reactions internally once the model is solved.

Expand Down Expand Up @@ -939,7 +939,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
node.RxnMZ[combo.name] -= k*RZ


def _check_statics(model: FEModel3D, combo_tags: List[str] | None = None) -> None:
def _check_statics(model: FEModel3D, combo_tags: list[str] | None = None) -> None:
'''
Checks static equilibrium and prints results to the console.

Expand Down Expand Up @@ -1023,19 +1023,19 @@ def _check_statics(model: FEModel3D, combo_tags: List[str] | None = None) -> Non
SumRMZ += RMZ - RFX*Y + RFY*X

# Add the results to the table
statics_table.add_row([combo.name, '{:.3g}'.format(SumFX), '{:.3g}'.format(SumRFX),
'{:.3g}'.format(SumFY), '{:.3g}'.format(SumRFY),
'{:.3g}'.format(SumFZ), '{:.3g}'.format(SumRFZ),
'{:.3g}'.format(SumMX), '{:.3g}'.format(SumRMX),
'{:.3g}'.format(SumMY), '{:.3g}'.format(SumRMY),
'{:.3g}'.format(SumMZ), '{:.3g}'.format(SumRMZ)])
statics_table.add_row([combo.name, f'{SumFX:.3g}', f'{SumRFX:.3g}',
f'{SumFY:.3g}', f'{SumRFY:.3g}',
f'{SumFZ:.3g}', f'{SumRFZ:.3g}',
f'{SumMX:.3g}', f'{SumRMX:.3g}',
f'{SumMY:.3g}', f'{SumRMY:.3g}',
f'{SumMZ:.3g}', f'{SumRMZ:.3g}'])

# Print the static check table
print(statics_table)
print('')


def _partition_D(model: FEModel3D) -> Tuple[List[int], List[int], NDArray[float64]]:
def _partition_D(model: FEModel3D) -> tuple[list[int], list[int], NDArray[float64]]:
"""Builds a list with known nodal displacements and with the positions in global stiffness matrix of known and unknown nodal displacements

:return: A list of the global matrix indices for the unknown nodal displacements (D1_indices). A list of the global matrix indices for the known nodal displacements (D2_indices). A list of the known nodal displacements (D2).
Expand Down Expand Up @@ -1131,7 +1131,7 @@ def _partition_D(model: FEModel3D) -> Tuple[List[int], List[int], NDArray[float6
return D1_indices, D2_indices, D2


def _partition(model: FEModel3D, unp_matrix: NDArray[float64] | lil_matrix, D1_indices: List[int], D2_indices: List[int]) -> Tuple[NDArray[float64], NDArray[float64]] | Tuple[NDArray[float64], NDArray[float64], NDArray[float64], NDArray[float64]]:
def _partition(model: FEModel3D, unp_matrix: NDArray[float64] | lil_matrix, D1_indices: list[int], D2_indices: list[int]) -> tuple[NDArray[float64], NDArray[float64]] | tuple[NDArray[float64], NDArray[float64], NDArray[float64], NDArray[float64]]:
"""Partitions a matrix (or vector) into submatrices (or subvectors) based on degree of freedom boundary conditions.

:param unp_matrix: The unpartitioned matrix (or vector) to be partitioned.
Expand Down
3 changes: 1 addition & 2 deletions Pynite/BeamSegZ.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 6 20:52:31 2017

Expand Down Expand Up @@ -138,7 +137,7 @@ def axial(self, x: float) -> float:

return P1 + (p2 - p1)/(2*L)*x**2 + p1*x

def Torsion(self, x: float | List[float] = 0) -> float | None | NDArray[Any]:
def Torsion(self, x: float | list[float] = 0) -> float | None | NDArray[Any]:
"""
Returns the torsional moment in the segment.
"""
Expand Down
30 changes: 15 additions & 15 deletions Pynite/FEModel3D.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,28 @@ def __init__(self) -> None:
# the data types they store, and then those types will be removed. This will give us the
# ability to get type-based hints when using the dictionaries.

self.nodes: Dict[str, Node3D] = {} # A dictionary of the model's nodes
self.materials: Dict[str, Material] = {} # A dictionary of the model's materials
self.sections: Dict[str, Section] = {} # A dictonary of the model's cross-sections
self.springs: Dict[str, Spring3D] = {} # A dictionary of the model's springs
self.members: Dict[str, PhysMember] = {} # A dictionary of the model's physical members
self.quads: Dict[str, Quad3D] = {} # A dictionary of the model's quadiralterals
self.plates: Dict[str, Plate3D] = {} # A dictionary of the model's rectangular plates
self.meshes: Dict[str, Mesh] = {} # A dictionary of the model's meshes
self.shear_walls: Dict[str, ShearWall] = {} # A dictionary of the model's shear walls
self.mats: Dict[str, MatFoundation] = {} # A dictionary of the model's mat foundations
self.load_combos: Dict[str, LoadCombo] = {} # A dictionary of the model's load combinations
self._D: Dict[str, NDArray[float64]] = {} # A dictionary of the model's nodal displacements by load combination
self.nodes: dict[str, Node3D] = {} # A dictionary of the model's nodes
self.materials: dict[str, Material] = {} # A dictionary of the model's materials
self.sections: dict[str, Section] = {} # A dictonary of the model's cross-sections
self.springs: dict[str, Spring3D] = {} # A dictionary of the model's springs
self.members: dict[str, PhysMember] = {} # A dictionary of the model's physical members
self.quads: dict[str, Quad3D] = {} # A dictionary of the model's quadiralterals
self.plates: dict[str, Plate3D] = {} # A dictionary of the model's rectangular plates
self.meshes: dict[str, Mesh] = {} # A dictionary of the model's meshes
self.shear_walls: dict[str, ShearWall] = {} # A dictionary of the model's shear walls
self.mats: dict[str, MatFoundation] = {} # A dictionary of the model's mat foundations
self.load_combos: dict[str, LoadCombo] = {} # A dictionary of the model's load combinations
self._D: dict[str, NDArray[float64]] = {} # A dictionary of the model's nodal displacements by load combination

self.solution: str | None = None # Indicates the solution type for the latest run of the model

@property
def load_cases(self) -> List[str]:
def load_cases(self) -> list[str]:
"""Returns a list of all the load cases in the model (in alphabetical order).
"""

# Create an empty list of load cases
cases: List[str] = []
cases: list[str] = []

# Step through each node
for node in self.nodes.values():
Expand Down Expand Up @@ -757,7 +757,7 @@ def add_cylinder_mesh(self, name:str, mesh_size:float, radius:float, height:floa
# Return the mesh's name
return name

def add_shear_wall(self, name: str, mesh_size: float, length: float, height: float, thickness: float, material_name: str, ky_mod: float = 0.35, plane: Literal['XY', 'YZ'] = 'XY', origin: List[float] = [0, 0, 0]):
def add_shear_wall(self, name: str, mesh_size: float, length: float, height: float, thickness: float, material_name: str, ky_mod: float = 0.35, plane: Literal['XY', 'YZ'] = 'XY', origin: list[float] = [0, 0, 0]):
"""Adds a meshed shear wall helper to the model.

The shear wall utility generates a regular mesh for a rectangular wall panel and
Expand Down
1 change: 0 additions & 1 deletion Pynite/FixedEndReactions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
Created on Fri Nov 3 20:58:03 2017

Expand Down
6 changes: 3 additions & 3 deletions Pynite/LoadCombo.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class LoadCombo():
"""A class that stores all the information necessary to define a load combination.
"""

def __init__(self, name: str, combo_tags: List[str] | None = None, factors: Dict[str, float] = {}) -> None:
def __init__(self, name: str, combo_tags: list[str] | None = None, factors: dict[str, float] = {}) -> None:
"""Initializes a new load combination.

:param name: A unique name for the load combination.
Expand All @@ -17,8 +17,8 @@ def __init__(self, name: str, combo_tags: List[str] | None = None, factors: Dict
"""

self.name: str = name # A unique user-defined name for the load combination
self.combo_tags: List[str] | None = combo_tags # Used to categorize the load combination (e.g. strength or serviceability)
self.factors: Dict[str, float] = factors # A dictionary containing each load case name and associated load factor
self.combo_tags: list[str] | None = combo_tags # Used to categorize the load combination (e.g. strength or serviceability)
self.factors: dict[str, float] = factors # A dictionary containing each load case name and associated load factor

def AddLoadCase(self, case_name: str, factor: float) -> None:
'''
Expand Down
Loading