PyNiteFEA 2.0.2__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pynitefea-2.0.2/PyNiteFEA.egg-info → pynitefea-2.1.0}/PKG-INFO +22 -3
- pynitefea-2.0.2/README.md → pynitefea-2.1.0/PyNiteFEA.egg-info/PKG-INFO +69 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/PyNiteFEA.egg-info/requires.txt +1 -1
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Analysis.py +41 -36
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/FEModel3D.py +418 -504
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Member3D.py +69 -69
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Mesh.py +78 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Rendering.py +201 -155
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/ShearWall.py +4 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Visualization.py +226 -112
- pynitefea-2.1.0/Pynite/__init__.py +12 -0
- pynitefea-2.0.2/PKG-INFO → pynitefea-2.1.0/README.md +16 -50
- {pynitefea-2.0.2 → pynitefea-2.1.0}/setup.py +6 -3
- pynitefea-2.0.2/Pynite/__init__.py +0 -12
- {pynitefea-2.0.2 → pynitefea-2.1.0}/LICENSE +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/PyNiteFEA.egg-info/SOURCES.txt +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/PyNiteFEA.egg-info/dependency_links.txt +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/PyNiteFEA.egg-info/top_level.txt +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/BeamSegY.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/BeamSegZ.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/FixedEndReactions.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/LoadCombo.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/MainStyleSheet.css +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/MatFoundation.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Material.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Node3D.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/PhysMember.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Plate3D.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Quad3D.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Report_Template.html +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Reporting.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Section.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Spring3D.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/Tri3D.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/Pynite/VTKWriter.py +0 -0
- {pynitefea-2.0.2 → pynitefea-2.1.0}/setup.cfg +0 -0
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyNiteFEA
|
|
3
|
-
Version: 2.0
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: A simple elastic 3D structural finite element library for Python.
|
|
5
5
|
Home-page: https://github.com/JWock82/Pynite.git
|
|
6
6
|
Author: D. Craig Brinck, PE, SE
|
|
7
7
|
Author-email: Building.Code@outlook.com
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
9
12
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
13
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.
|
|
14
|
+
Requires-Python: >=3.11
|
|
12
15
|
Description-Content-Type: text/markdown
|
|
13
16
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: numpy
|
|
17
|
+
Requires-Dist: numpy>=2.4.0
|
|
15
18
|
Requires-Dist: PrettyTable
|
|
16
19
|
Requires-Dist: scipy
|
|
17
20
|
Requires-Dist: matplotlib
|
|
@@ -56,6 +59,7 @@ Dynamic: summary
|
|
|
56
59
|
|
|
57
60
|

|
|
58
61
|
[](https://codecov.io/gh/JWock82/Pynite)
|
|
62
|
+

|
|
59
63
|

|
|
60
64
|
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/JWock82/Pynite">
|
|
61
65
|

|
|
@@ -117,10 +121,25 @@ Here's a list of projects that use Pynite:
|
|
|
117
121
|
* Phaenotyp (https://github.com/bewegende-Architektur/Phaenotyp) (https://youtu.be/shloSw9HjVI)
|
|
118
122
|
|
|
119
123
|
# What's New?
|
|
124
|
+
v2.1.0
|
|
125
|
+
* Major speed boost and leaner memory usage: the global stiffness/mass assembly plus the nodal load and fixed-end reaction builders now use block-based vectorized writes instead of Python loops, which keeps data in contiguous NumPy buffers rather than thousands of temporary Python objects. The dense solver sees ~15-25% faster `K`/`M` builds in our targeted benchmarks, while sparse solver runs see ~30% faster stiffness assembly in our benchmarks.
|
|
126
|
+
* Meshes can now be regenerated with the `FEModel3D.meshes[mesh_name].generate()` command. This command removes the old mesh and replaces it with an updated one. The mesh will not remove nodes needed by other elements outside the mesh. Note that any loads applied to the old mesh will be lost when its elements and nodes are deleted. This makes meshes truly parametric.
|
|
127
|
+
* Added `FEModel3D.delete_mesh()` to help deleting old meshes properly.
|
|
128
|
+
* Renderers now automatically set the annotation size as 5% of the minimum distance between nodes. You still have the option of overiding this by setting the annotation size manually.
|
|
129
|
+
* Added load case/combo identification to VTK rendering.
|
|
130
|
+
* Dropped support for Python version 3.10, which is not compatible with Numpy 2.4.
|
|
131
|
+
* Removed unecessary checks for Scipy. Scipy has been a required dependency for some time now.
|
|
132
|
+
* Cleaned up whitespace to conform to PEP8 style guide.
|
|
133
|
+
|
|
134
|
+
v2.0.3
|
|
135
|
+
* Numpy >= 2.4 is now a requirement. This ensures the VTK renderer will handle plate results arrays properly.
|
|
136
|
+
* `pip` now installs dependencies during build testing. Pynite's testing suite now runs against the correct version of each dependency.
|
|
137
|
+
|
|
120
138
|
v2.0.2
|
|
121
139
|
* Added docstrings to the VTK `Renderer` class to help the user.
|
|
122
140
|
* Enforced use of properties instead of attributes in the VTK `Renderer` and added docstrings to properties help the user make decisions.
|
|
123
141
|
* Removed the VTK `Renderer`'s properties that began with "set_". These were redundant and caused confusion. The prefix "set_" is no longer used to access or set any of the `Renderer`'s properties.
|
|
142
|
+
* Made the VTK `Renderer` compatible with the latest version of `numpy`.
|
|
124
143
|
|
|
125
144
|
v2.0.1
|
|
126
145
|
* Pynite no longer struggles rendering load cases and combinations when no loads are present. This is especially helpful for rendering modal load combinations, which don't have loads (only masses).
|
|
@@ -1,3 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PyNiteFEA
|
|
3
|
+
Version: 2.1.0
|
|
4
|
+
Summary: A simple elastic 3D structural finite element library for Python.
|
|
5
|
+
Home-page: https://github.com/JWock82/Pynite.git
|
|
6
|
+
Author: D. Craig Brinck, PE, SE
|
|
7
|
+
Author-email: Building.Code@outlook.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: numpy>=2.4.0
|
|
18
|
+
Requires-Dist: PrettyTable
|
|
19
|
+
Requires-Dist: scipy
|
|
20
|
+
Requires-Dist: matplotlib
|
|
21
|
+
Provides-Extra: all
|
|
22
|
+
Requires-Dist: Ipython; extra == "all"
|
|
23
|
+
Requires-Dist: vtk>=9.3.0; extra == "all"
|
|
24
|
+
Requires-Dist: pyvista[all,trame]>=0.43.4; extra == "all"
|
|
25
|
+
Requires-Dist: trame_jupyter_extension; extra == "all"
|
|
26
|
+
Requires-Dist: ipywidgets; extra == "all"
|
|
27
|
+
Requires-Dist: pdfkit; extra == "all"
|
|
28
|
+
Requires-Dist: Jinja2; extra == "all"
|
|
29
|
+
Provides-Extra: vtk
|
|
30
|
+
Requires-Dist: IPython; extra == "vtk"
|
|
31
|
+
Requires-Dist: vtk>=9.3.0; extra == "vtk"
|
|
32
|
+
Provides-Extra: pyvista
|
|
33
|
+
Requires-Dist: pyvista[all,trame]>=0.43.4; extra == "pyvista"
|
|
34
|
+
Requires-Dist: trame_jupyter_extension; extra == "pyvista"
|
|
35
|
+
Requires-Dist: ipywidgets; extra == "pyvista"
|
|
36
|
+
Provides-Extra: reporting
|
|
37
|
+
Requires-Dist: pdfkit; extra == "reporting"
|
|
38
|
+
Requires-Dist: Jinja2; extra == "reporting"
|
|
39
|
+
Provides-Extra: derivations
|
|
40
|
+
Requires-Dist: jupyterlab; extra == "derivations"
|
|
41
|
+
Requires-Dist: sympy; extra == "derivations"
|
|
42
|
+
Dynamic: author
|
|
43
|
+
Dynamic: author-email
|
|
44
|
+
Dynamic: classifier
|
|
45
|
+
Dynamic: description
|
|
46
|
+
Dynamic: description-content-type
|
|
47
|
+
Dynamic: home-page
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
Dynamic: provides-extra
|
|
50
|
+
Dynamic: requires-dist
|
|
51
|
+
Dynamic: requires-python
|
|
52
|
+
Dynamic: summary
|
|
53
|
+
|
|
1
54
|
<div align="center">
|
|
2
55
|
<img src="https://github.com/JWock82/Pynite/raw/main/Resources/Full Logo No Buffer.png" width=40% align="center"/>
|
|
3
56
|
<br>
|
|
@@ -6,6 +59,7 @@
|
|
|
6
59
|
|
|
7
60
|

|
|
8
61
|
[](https://codecov.io/gh/JWock82/Pynite)
|
|
62
|
+

|
|
9
63
|

|
|
10
64
|
<img alt="GitHub code size in bytes" src="https://img.shields.io/github/languages/code-size/JWock82/Pynite">
|
|
11
65
|

|
|
@@ -67,10 +121,25 @@ Here's a list of projects that use Pynite:
|
|
|
67
121
|
* Phaenotyp (https://github.com/bewegende-Architektur/Phaenotyp) (https://youtu.be/shloSw9HjVI)
|
|
68
122
|
|
|
69
123
|
# What's New?
|
|
124
|
+
v2.1.0
|
|
125
|
+
* Major speed boost and leaner memory usage: the global stiffness/mass assembly plus the nodal load and fixed-end reaction builders now use block-based vectorized writes instead of Python loops, which keeps data in contiguous NumPy buffers rather than thousands of temporary Python objects. The dense solver sees ~15-25% faster `K`/`M` builds in our targeted benchmarks, while sparse solver runs see ~30% faster stiffness assembly in our benchmarks.
|
|
126
|
+
* Meshes can now be regenerated with the `FEModel3D.meshes[mesh_name].generate()` command. This command removes the old mesh and replaces it with an updated one. The mesh will not remove nodes needed by other elements outside the mesh. Note that any loads applied to the old mesh will be lost when its elements and nodes are deleted. This makes meshes truly parametric.
|
|
127
|
+
* Added `FEModel3D.delete_mesh()` to help deleting old meshes properly.
|
|
128
|
+
* Renderers now automatically set the annotation size as 5% of the minimum distance between nodes. You still have the option of overiding this by setting the annotation size manually.
|
|
129
|
+
* Added load case/combo identification to VTK rendering.
|
|
130
|
+
* Dropped support for Python version 3.10, which is not compatible with Numpy 2.4.
|
|
131
|
+
* Removed unecessary checks for Scipy. Scipy has been a required dependency for some time now.
|
|
132
|
+
* Cleaned up whitespace to conform to PEP8 style guide.
|
|
133
|
+
|
|
134
|
+
v2.0.3
|
|
135
|
+
* Numpy >= 2.4 is now a requirement. This ensures the VTK renderer will handle plate results arrays properly.
|
|
136
|
+
* `pip` now installs dependencies during build testing. Pynite's testing suite now runs against the correct version of each dependency.
|
|
137
|
+
|
|
70
138
|
v2.0.2
|
|
71
139
|
* Added docstrings to the VTK `Renderer` class to help the user.
|
|
72
140
|
* Enforced use of properties instead of attributes in the VTK `Renderer` and added docstrings to properties help the user make decisions.
|
|
73
141
|
* Removed the VTK `Renderer`'s properties that began with "set_". These were redundant and caused confusion. The prefix "set_" is no longer used to access or set any of the `Renderer`'s properties.
|
|
142
|
+
* Made the VTK `Renderer` compatible with the latest version of `numpy`.
|
|
74
143
|
|
|
75
144
|
v2.0.1
|
|
76
145
|
* Pynite no longer struggles rendering load cases and combinations when no loads are present. This is especially helpful for rendering modal load combinations, which don't have loads (only masses).
|
|
@@ -48,18 +48,20 @@ def _prepare_model(model: FEModel3D, n_modes: int = 0) -> None:
|
|
|
48
48
|
for i in range(n_modes):
|
|
49
49
|
model.add_load_combo(f'Mode {i + 1}', {}, ['modal'])
|
|
50
50
|
|
|
51
|
-
# Generate all basic meshes
|
|
51
|
+
# Generate all basic meshes that haven't been generated yet
|
|
52
52
|
for mesh in model.meshes.values():
|
|
53
|
-
if mesh.is_generated
|
|
53
|
+
if not mesh.is_generated:
|
|
54
54
|
mesh.generate()
|
|
55
55
|
|
|
56
|
-
# Generate all shear wall meshes
|
|
56
|
+
# Generate all shear wall meshes that haven't been generated yet
|
|
57
57
|
for shear_wall in model.shear_walls.values():
|
|
58
|
-
shear_wall.
|
|
58
|
+
if not shear_wall.is_generated:
|
|
59
|
+
shear_wall.generate()
|
|
59
60
|
|
|
60
|
-
# Generate all mat foundation meshes
|
|
61
|
+
# Generate all mat foundation meshes that haven't been generated yet
|
|
61
62
|
for mat in model.mats.values():
|
|
62
|
-
mat.
|
|
63
|
+
if not mat.is_generated:
|
|
64
|
+
mat.generate()
|
|
63
65
|
|
|
64
66
|
# Activate all springs and members for all load combinations
|
|
65
67
|
for spring in model.springs.values():
|
|
@@ -217,9 +219,9 @@ def _PDelta(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1: NDArr
|
|
|
217
219
|
# Calculate the partitioned initial stiffness matrices. These matrices must be recalculated on each T/C iteration due to tension/compression-only members deactivating or reactivating.
|
|
218
220
|
if log:
|
|
219
221
|
print('- Calculating initial stiffness matrix')
|
|
220
|
-
K11, K12, K21, K22 = _partition(model, model.K(combo_name, log, check_stability, sparse)
|
|
222
|
+
K11, K12, K21, K22 = _partition(model, model.K(combo_name, log, check_stability, sparse), D1_indices, D2_indices)
|
|
221
223
|
|
|
222
|
-
# The initial stiffness matrices are
|
|
224
|
+
# The initial stiffness matrices are in `coo` format from construction. They will be converted to `csr` format for efficient mathematical operations.
|
|
223
225
|
K11 = K11.tocsr()
|
|
224
226
|
K12 = K12.tocsr()
|
|
225
227
|
K21 = K21.tocsr()
|
|
@@ -232,7 +234,7 @@ def _PDelta(model: FEModel3D, combo_name: str, P1: NDArray[float64], FER1: NDArr
|
|
|
232
234
|
if log: print('- Calculating geometric stiffness matrix')
|
|
233
235
|
Kg11, Kg12, Kg21, Kg22 = _partition(model, model.Kg(combo_name, log, sparse, False), D1_indices, D2_indices)
|
|
234
236
|
|
|
235
|
-
# The Kg stiffness matrices are
|
|
237
|
+
# The Kg stiffness matrices are in `coo` format from construction. They will be converted to `csr` format for efficient addition. Note that the `+` operator performs matrix addition on `csr` matrices.
|
|
236
238
|
if log: print('- Summing initial & geometric stiffness matrices')
|
|
237
239
|
K11 = K11 + Kg11.tocsr()
|
|
238
240
|
K12 = K12 + Kg12.tocsr()
|
|
@@ -325,21 +327,20 @@ def _pushover_step(model: FEModel3D, combo_name: str, push_combo: str, step_num:
|
|
|
325
327
|
|
|
326
328
|
# Calculate the initial stiffness matrix
|
|
327
329
|
if log: print('- Calculating elastic stiffness matrix [Ke]')
|
|
328
|
-
K11, K12, K21, K22 = _partition(model, model.K(combo_name, log, check_stability, sparse)
|
|
330
|
+
K11, K12, K21, K22 = _partition(model, model.K(combo_name, log, check_stability, sparse), D1_indices, D2_indices)
|
|
329
331
|
|
|
330
332
|
# Calculate the geometric stiffness matrix
|
|
331
333
|
# The `combo_name` variable in the code below is not the name of the pushover load combination. Rather it is the name of the primary combination that the pushover load will be added to. Axial loads used to develop Kg are calculated from the displacements stored in `combo_name`.
|
|
332
334
|
if log: print('- Calculating geometric stiffness matrix [Kg]')
|
|
333
|
-
Kg11, Kg12, Kg21, Kg22 = _partition(model, model.Kg(combo_name, log, sparse, False)
|
|
335
|
+
Kg11, Kg12, Kg21, Kg22 = _partition(model, model.Kg(combo_name, log, sparse, False), D1_indices, D2_indices)
|
|
334
336
|
|
|
335
337
|
# Calculate the stiffness reduction matrix
|
|
336
338
|
if log: print('- Calculating plastic reduction matrix [Km]')
|
|
337
|
-
Km11, Km12, Km21, Km22 = _partition(model, model.Km(combo_name, push_combo, step_num, log, sparse)
|
|
339
|
+
Km11, Km12, Km21, Km22 = _partition(model, model.Km(combo_name, push_combo, step_num, log, sparse), D1_indices, D2_indices)
|
|
338
340
|
|
|
339
|
-
# The stiffness matrices are
|
|
340
|
-
#
|
|
341
|
-
#
|
|
342
|
-
# matrices.
|
|
341
|
+
# The stiffness matrices are in `coo` format from construction. They will be
|
|
342
|
+
# converted to `csr` format for efficient operations. The `+` operator
|
|
343
|
+
# performs matrix addition on `csr` matrices.
|
|
343
344
|
K11 = K11.tocsr() + Kg11.tocsr() + Km11.tocsr()
|
|
344
345
|
K12 = K12.tocsr() + Kg12.tocsr() + Km12.tocsr()
|
|
345
346
|
K21 = K21.tocsr() + Kg21.tocsr() + Km21.tocsr()
|
|
@@ -718,7 +719,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
718
719
|
node.RxnMZ[combo.name] = 0.0
|
|
719
720
|
|
|
720
721
|
# Determine if the node has any supports
|
|
721
|
-
if (node.support_DX or node.support_DY or node.support_DZ
|
|
722
|
+
if (node.support_DX or node.support_DY or node.support_DZ
|
|
722
723
|
or node.support_RX or node.support_RY or node.support_RZ):
|
|
723
724
|
|
|
724
725
|
# Sum the spring end forces at the node
|
|
@@ -727,7 +728,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
727
728
|
if spring.i_node == node and spring.active[combo.name] == True:
|
|
728
729
|
|
|
729
730
|
# Get the spring's global force matrix
|
|
730
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
731
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
731
732
|
spring_F = spring.F(combo.name)
|
|
732
733
|
|
|
733
734
|
if node.support_DX: node.RxnFX[combo.name] += spring_F[0, 0]
|
|
@@ -740,7 +741,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
740
741
|
elif spring.j_node == node and spring.active[combo.name] == True:
|
|
741
742
|
|
|
742
743
|
# Get the spring's global force matrix
|
|
743
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
744
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
744
745
|
spring_F = spring.F(combo.name)
|
|
745
746
|
|
|
746
747
|
if node.support_DX: node.RxnFX[combo.name] += spring_F[6, 0]
|
|
@@ -759,7 +760,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
759
760
|
if member.i_node == node and phys_member.active[combo.name] == True:
|
|
760
761
|
|
|
761
762
|
# Get the member's global force matrix
|
|
762
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
763
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
763
764
|
member_F = member.F(combo.name)
|
|
764
765
|
|
|
765
766
|
if node.support_DX: node.RxnFX[combo.name] += member_F[0, 0]
|
|
@@ -772,7 +773,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
772
773
|
elif member.j_node == node and phys_member.active[combo.name] == True:
|
|
773
774
|
|
|
774
775
|
# Get the member's global force matrix
|
|
775
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
776
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
776
777
|
member_F = member.F(combo.name)
|
|
777
778
|
|
|
778
779
|
if node.support_DX: node.RxnFX[combo.name] += member_F[6, 0]
|
|
@@ -788,7 +789,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
788
789
|
if plate.i_node == node:
|
|
789
790
|
|
|
790
791
|
# Get the plate's global force matrix
|
|
791
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
792
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
792
793
|
plate_F = plate.F(combo.name)
|
|
793
794
|
|
|
794
795
|
if node.support_DX: node.RxnFX[combo.name] += plate_F[0, 0]
|
|
@@ -801,7 +802,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
801
802
|
elif plate.j_node == node:
|
|
802
803
|
|
|
803
804
|
# Get the plate's global force matrix
|
|
804
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
805
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
805
806
|
plate_F = plate.F(combo.name)
|
|
806
807
|
|
|
807
808
|
if node.support_DX: node.RxnFX[combo.name] += plate_F[6, 0]
|
|
@@ -814,7 +815,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
814
815
|
elif plate.m_node == node:
|
|
815
816
|
|
|
816
817
|
# Get the plate's global force matrix
|
|
817
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
818
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
818
819
|
plate_F = plate.F(combo.name)
|
|
819
820
|
|
|
820
821
|
if node.support_DX: node.RxnFX[combo.name] += plate_F[12, 0]
|
|
@@ -827,7 +828,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
827
828
|
elif plate.n_node == node:
|
|
828
829
|
|
|
829
830
|
# Get the plate's global force matrix
|
|
830
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
831
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
831
832
|
plate_F = plate.F(combo.name)
|
|
832
833
|
|
|
833
834
|
if node.support_DX: node.RxnFX[combo.name] += plate_F[18, 0]
|
|
@@ -843,7 +844,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
843
844
|
if quad.i_node == node:
|
|
844
845
|
|
|
845
846
|
# Get the quad's global force matrix
|
|
846
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
847
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
847
848
|
quad_F = quad.F(combo.name)
|
|
848
849
|
|
|
849
850
|
if node.support_DX: node.RxnFX[combo.name] += quad_F[0, 0]
|
|
@@ -856,7 +857,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
856
857
|
elif quad.j_node == node:
|
|
857
858
|
|
|
858
859
|
# Get the quad's global force matrix
|
|
859
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
860
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
860
861
|
quad_F = quad.F(combo.name)
|
|
861
862
|
|
|
862
863
|
if node.support_DX: node.RxnFX[combo.name] += quad_F[6, 0]
|
|
@@ -869,7 +870,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
869
870
|
elif quad.m_node == node:
|
|
870
871
|
|
|
871
872
|
# Get the quad's global force matrix
|
|
872
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
873
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
873
874
|
quad_F = quad.F(combo.name)
|
|
874
875
|
|
|
875
876
|
if node.support_DX: node.RxnFX[combo.name] += quad_F[12, 0]
|
|
@@ -882,7 +883,7 @@ def _calc_reactions(model: FEModel3D, log: bool = False, combo_tags: List[str] |
|
|
|
882
883
|
elif quad.n_node == node:
|
|
883
884
|
|
|
884
885
|
# Get the quad's global force matrix
|
|
885
|
-
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
886
|
+
# Storing it as a local variable eliminates the need to rebuild it every time a term is needed
|
|
886
887
|
quad_F = quad.F(combo.name)
|
|
887
888
|
|
|
888
889
|
if node.support_DX: node.RxnFX[combo.name] += quad_F[18, 0]
|
|
@@ -1020,7 +1021,7 @@ def _check_statics(model: FEModel3D, combo_tags: List[str] | None = None) -> Non
|
|
|
1020
1021
|
SumRFZ += RFZ
|
|
1021
1022
|
SumRMX += RMX - RFY*Z + RFZ*Y
|
|
1022
1023
|
SumRMY += RMY + RFX*Z - RFZ*X
|
|
1023
|
-
SumRMZ += RMZ - RFX*Y + RFY*X
|
|
1024
|
+
SumRMZ += RMZ - RFX*Y + RFY*X
|
|
1024
1025
|
|
|
1025
1026
|
# Add the results to the table
|
|
1026
1027
|
statics_table.add_row([combo.name, '{:.3g}'.format(SumFX), '{:.3g}'.format(SumRFX),
|
|
@@ -1120,10 +1121,10 @@ def _partition_D(model: FEModel3D) -> Tuple[List[int], List[int], NDArray[float6
|
|
|
1120
1121
|
else:
|
|
1121
1122
|
D2_indices.append(node.ID*6 + 5)
|
|
1122
1123
|
D2.append(0.0)
|
|
1123
|
-
|
|
1124
|
+
|
|
1124
1125
|
# Legacy code on the next line. I will leave it here until the line that follows has been proven over time.
|
|
1125
1126
|
# D2 = atleast_2d(D2)
|
|
1126
|
-
|
|
1127
|
+
|
|
1127
1128
|
# Convert D2 from a list to a matrix
|
|
1128
1129
|
D2 = array(D2, ndmin=2).T
|
|
1129
1130
|
|
|
@@ -1144,6 +1145,10 @@ def _partition(model: FEModel3D, unp_matrix: NDArray[float64] | lil_matrix, D1_i
|
|
|
1144
1145
|
:rtype: array, array, array, array
|
|
1145
1146
|
"""
|
|
1146
1147
|
|
|
1148
|
+
# Convert sparse matrices to CSR so they support efficient slicing
|
|
1149
|
+
if hasattr(unp_matrix, 'tocsr'):
|
|
1150
|
+
unp_matrix = unp_matrix.tocsr()
|
|
1151
|
+
|
|
1147
1152
|
# Determine if this is a 1D vector or a 2D matrix
|
|
1148
1153
|
|
|
1149
1154
|
# 1D vectors
|
|
@@ -1167,11 +1172,11 @@ def _renumber(model: FEModel3D) -> None:
|
|
|
1167
1172
|
Assigns node and element ID numbers to be used internally by the program. Numbers are
|
|
1168
1173
|
assigned according to the order in which they occur in each dictionary.
|
|
1169
1174
|
"""
|
|
1170
|
-
|
|
1175
|
+
|
|
1171
1176
|
# Number each node in the model
|
|
1172
1177
|
for id, node in enumerate(model.nodes.values()):
|
|
1173
1178
|
node.ID = id
|
|
1174
|
-
|
|
1179
|
+
|
|
1175
1180
|
# Number each spring in the model
|
|
1176
1181
|
for id, spring in enumerate(model.springs.values()):
|
|
1177
1182
|
spring.ID = id
|
|
@@ -1183,11 +1188,11 @@ def _renumber(model: FEModel3D) -> None:
|
|
|
1183
1188
|
for member in phys_member.sub_members.values():
|
|
1184
1189
|
member.ID = id
|
|
1185
1190
|
id += 1
|
|
1186
|
-
|
|
1191
|
+
|
|
1187
1192
|
# Number each plate in the model
|
|
1188
1193
|
for id, plate in enumerate(model.plates.values()):
|
|
1189
1194
|
plate.ID = id
|
|
1190
|
-
|
|
1195
|
+
|
|
1191
1196
|
# Number each quadrilateral in the model
|
|
1192
1197
|
for id, quad in enumerate(model.quads.values()):
|
|
1193
1198
|
quad.ID = id
|