Skip to content

Commit 04ab074

Browse files
JWock82JWock82
authored andcommitted
Code cleanup and comment improvements
1 parent 16998a2 commit 04ab074

File tree

1 file changed

+49
-38
lines changed

1 file changed

+49
-38
lines changed

Pynite/Analysis.py

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ def _identify_combos(model: FEModel3D, combo_tags: List[str] | None = None) -> L
8080
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags):
8181
# Add the load combination to the list of load combinations to be evaluated
8282
combo_list.append(combo)
83-
83+
8484
# Return the list of load combinations to be evaluated
8585
return combo_list
8686

87+
8788
def _check_stability(model: FEModel3D, K: NDArray[float64]) -> None:
8889
"""
8990
Identifies nodal instabilities in a model's stiffness matrix.
@@ -144,11 +145,17 @@ def _check_stability(model: FEModel3D, K: NDArray[float64]) -> None:
144145
return
145146

146147

147-
def _PDelta_step(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, first_step: bool = True) -> None:
148+
def _PDelta_step(model: FEModel3D, combo_name: str, Delta_P1: NDArray[float64], Delta_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, first_step: bool = True) -> None:
148149
"""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. The analysis is iterative and takes longer to solve. 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.
149150
150-
:param combo_name: The name of the load combination to evaluate P-Delta effects for.
151+
:param model: The finite element model to be solved.
152+
:type: FEModel3D
153+
:param combo_name: The name of the load combination to evaluate.
151154
:type combo_name: string
155+
:param Delta_P1: An array of the loads to apply for the load step.
156+
:type Delta_P1: numpy array
157+
:param Delta_FER1: An array of the fixed end reactions for the load step.
158+
:type Delta_FER1: numpy array
152159
:param log: Prints updates to the console if set to True. Default is False.
153160
:type log: bool, optional
154161
:param check_stability: When set to True, checks the stiffness matrix for any unstable degrees of freedom and reports them back to the console. This does add to the solution time. Defaults to True.
@@ -173,7 +180,7 @@ def _PDelta_step(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1:
173180
iter_count_PD = 1 # Tracks P-Delta iterations
174181

175182
convergence_TC = False # Tracks tension/compression-only convergence
176-
divergence_TC = False # Tracks tension/compression-only divergence
183+
divergence_TC = False # Tracks tension/compression-only divergence
177184

178185
# Iterate until either T/C convergence or divergence occurs. Perform at least 2 iterations for the P-Delta analysis.
179186
while (convergence_TC is False and divergence_TC is False) or iter_count_PD <= 2:
@@ -185,7 +192,7 @@ def _PDelta_step(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1:
185192
# Calculate the partitioned global stiffness matrices
186193
if sparse is True:
187194

188-
# Calculate the initial stiffness matrix
195+
# Calculate the initial stiffness matrix. This matrix must be recalculated on each iteration due to tension/compression-only members deactivating or reactivating.
189196
K11, K12, K21, K22 = _partition(model, model.K(combo_name, log, check_stability, sparse).tolil(), D1_indices, D2_indices)
190197

191198
# Calculate the geometric stiffness matrix
@@ -204,7 +211,7 @@ def _PDelta_step(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1:
204211

205212
else:
206213

207-
# Initial stiffness matrix
214+
# Calculate the initial stiffness matrix. This matrix must be recalculated on each iteration due to tension/compression-only members deactivating or reactivating.
208215
K11, K12, K21, K22 = _partition(model, model.K(combo_name, log, check_stability, sparse), D1_indices, D2_indices)
209216

210217
# Geometric stiffness matrix
@@ -232,12 +239,12 @@ def _PDelta_step(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1:
232239
if sparse is True:
233240
# The partitioned stiffness matrix is already in `csr` format. The `@`
234241
# operator performs matrix multiplication on sparse matrices.
235-
Delta_D1 = spsolve(K11.tocsr(), subtract(subtract(P1, FER1), K12.tocsr() @ D2))
242+
Delta_D1 = spsolve(K11.tocsr(), subtract(subtract(Delta_P1, Delta_FER1), K12.tocsr() @ D2))
236243
Delta_D1 = Delta_D1.reshape(len(Delta_D1), 1)
237244
else:
238245
# The partitioned stiffness matrix is in `csr` format. It will be
239246
# converted to a 2D dense array for mathematical operations.
240-
Delta_D1 = solve(K11, subtract(subtract(P1, FER1), matmul(K12, D2)))
247+
Delta_D1 = solve(K11, subtract(subtract(Delta_P1, Delta_FER1), matmul(K12, D2)))
241248

242249
except:
243250
# Return out of the method if 'K' is singular and provide an error message
@@ -248,18 +255,18 @@ def _PDelta_step(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1:
248255
_store_displacements(model, Delta_D1, D2, D1_indices, D2_indices, model.load_combos[combo_name])
249256
else:
250257
_sum_displacements(model, Delta_D1, D2, D1_indices, D2_indices, model.load_combos[combo_name])
251-
258+
252259
# Check whether the tension/compression-only analysis has converged and deactivate any members that are showing forces they can't hold
253260
convergence_TC = _check_TC_convergence(model, combo_name, log)
254-
261+
255262
# Report on convergence of tension/compression only analysis
256-
if convergence_TC == False:
257-
263+
if convergence_TC is False:
264+
258265
if log:
259266
print('- Tension/compression-only analysis did not converge on this iteration')
260267
print('- Stiffness matrix will be adjusted')
261268
print('- P-Delta analysis will be restarted')
262-
269+
263270
# Increment the tension/compression-only iteration count
264271
iter_count_TC += 1
265272

@@ -268,16 +275,17 @@ def _PDelta_step(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1:
268275
iter_count_PD = 0
269276

270277
else:
271-
if log: print('- Tension/compression-only analysis converged after ' + str(iter_count_TC) + ' iteration(s)')
272-
278+
if log:
279+
print('- Tension/compression-only analysis converged after ' + str(iter_count_TC) + ' iteration(s)')
280+
273281
# Check for divergence in the tension/compression-only analysis
274282
if iter_count_TC > max_iter:
275283
divergence_TC = True
276284
raise Exception('- Model diverged during tension/compression-only analysis')
277285

278286
# Increment the P-Delta iteration count
279287
iter_count_PD += 1
280-
288+
281289
# Flag the model as solved
282290
model.solution = 'P-Delta'
283291

@@ -443,10 +451,10 @@ def _store_displacements(model: FEModel3D, D1: NDArray[float64], D2: NDArray[flo
443451
:param combo: The load combination to store the displacements for
444452
:type combo: LoadCombo
445453
"""
446-
454+
447455
# The raw results from the solver are partitioned. Unpartition them.
448456
D = _unpartition_disp(model, D1, D2, D1_indices, D2_indices)
449-
457+
450458
# Store the displacements in the model's global displacement vector
451459
model._D[combo.name] = D
452460

@@ -460,6 +468,7 @@ def _store_displacements(model: FEModel3D, D1: NDArray[float64], D2: NDArray[flo
460468
node.RY[combo.name] = D[node.ID*6 + 4, 0]
461469
node.RZ[combo.name] = D[node.ID*6 + 5, 0]
462470

471+
463472
def _sum_displacements(model: FEModel3D, Delta_D1: NDArray[float64], Delta_D2: NDArray[float64], D1_indices: List[int], D2_indices: List[int], combo: LoadCombo) -> None:
464473
"""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.
465474
@@ -476,7 +485,7 @@ def _sum_displacements(model: FEModel3D, Delta_D1: NDArray[float64], Delta_D2: N
476485
:param combo: The load combination to store the displacements for
477486
:type combo: LoadCombo
478487
"""
479-
488+
480489
# The raw results from the solver are partitioned. Unpartition them.
481490
Delta_D = _unpartition_disp(model, Delta_D1, Delta_D2, D1_indices, D2_indices)
482491

@@ -493,6 +502,7 @@ def _sum_displacements(model: FEModel3D, Delta_D1: NDArray[float64], Delta_D2: N
493502
node.RY[combo.name] += Delta_D[node.ID*6 + 4, 0]
494503
node.RZ[combo.name] += Delta_D[node.ID*6 + 5, 0]
495504

505+
496506
def _check_TC_convergence(model: FEModel3D, combo_name: str = "Combo 1", log: bool = True, spring_tolerance: float = 0, member_tolerance: float = 0) -> bool:
497507

498508
# Assume the model has converged until we find out otherwise
@@ -522,28 +532,26 @@ def _check_TC_convergence(model: FEModel3D, combo_name: str = "Combo 1", log: bo
522532
# TODO: Adjust the code below to allow elements to reactivate on subsequent iterations if deformations at element nodes indicate the member goes back into an active state. This will lead to a less conservative and more realistic analysis. Nodal springs (above) already do this.
523533

524534
# Check tension/compression-only springs
525-
if log: print('- Checking for tension/compression-only spring convergence')
535+
if log:
536+
print('- Checking for tension/compression-only spring convergence')
537+
526538
for spring in model.springs.values():
527539

528-
if spring.active[combo_name] == True:
540+
if spring.active[combo_name] is True:
541+
529542
# Check if tension-only conditions exist
530-
if (
531-
spring.tension_only == True
532-
and spring.axial(combo_name) > spring_tolerance
533-
):
543+
if (spring.tension_only is True) and (spring.axial(combo_name) > spring_tolerance):
534544
spring.active[combo_name] = False
535545
convergence = False
536546

537547
# Check if compression-only conditions exist
538-
elif (
539-
spring.comp_only == True
540-
and spring.axial(combo_name) < -spring_tolerance
541-
):
548+
elif (spring.comp_only is True) and (spring.axial(combo_name) < -spring_tolerance):
542549
spring.active[combo_name] = False
543550
convergence = False
544551

545552
# Check tension/compression only members
546-
if log: print('- Checking for tension/compression-only member convergence')
553+
if log:
554+
print('- Checking for tension/compression-only member convergence')
547555
for phys_member in model.members.values():
548556

549557
# Only run the tension/compression only check if the member is still active
@@ -571,11 +579,11 @@ def _check_TC_convergence(model: FEModel3D, combo_name: str = "Combo 1", log: bo
571579
):
572580
# Deactivate the physical member
573581
phys_member.active[combo_name] = False
574-
582+
575583
# Deactivate all the sub-members
576584
for sub_member in phys_member.sub_members.values():
577585
sub_member.active[combo_name] = False
578-
586+
579587
# Flag the analysis as not converged
580588
convergence = False
581589

@@ -585,7 +593,8 @@ def _check_TC_convergence(model: FEModel3D, combo_name: str = "Combo 1", log: bo
585593

586594
# Return whether the TC analysis has converged
587595
return convergence
588-
596+
597+
589598
def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] | None = None) -> None:
590599
"""
591600
Calculates reactions internally once the model is solved.
@@ -853,6 +862,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
853862
RZ = node.RZ[combo.name]
854863
node.RxnMZ[combo.name] += k*RZ
855864

865+
856866
def _check_statics(model: FEModel3D, combo_tags: List[str] | None = None) -> None:
857867
'''
858868
Checks static equilibrium and prints results to the console.
@@ -947,21 +957,22 @@ def _check_statics(model: FEModel3D, combo_tags: List[str] | None = None) -> Non
947957
# Print the static check table
948958
print(statics_table)
949959
print('')
950-
960+
961+
951962
def _partition_D(model: FEModel3D) -> Tuple[List[int], List[int], NDArray[float64]]:
952963
"""Builds a list with known nodal displacements and with the positions in global stiffness matrix of known and unknown nodal displacements
953964
954965
: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).
955966
:rtype: list, list, list
956967
"""
957968

958-
D1_indices = [] # A list of the indices for the unknown nodal displacements
959-
D2_indices = [] # A list of the indices for the known nodal displacements
960-
D2 = [] # A list of the values of the known nodal displacements
969+
D1_indices = [] # A list of the indices for the unknown nodal displacements
970+
D2_indices = [] # A list of the indices for the known nodal displacements
971+
D2 = [] # A list of the values of the known nodal displacements
961972

962973
# Create the auxiliary table
963974
for node in model.nodes.values():
964-
975+
965976
# Unknown displacement DX
966977
if node.support_DX == False and node.EnforcedDX == None:
967978
D1_indices.append(node.ID*6 + 0)

0 commit comments

Comments
 (0)