PyNiteFEA 2.3.0__tar.gz → 2.4.1__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.3.0 → pynitefea-2.4.1}/PKG-INFO +8 -2
- {pynitefea-2.3.0 → pynitefea-2.4.1}/PyNiteFEA.egg-info/PKG-INFO +8 -2
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Member3D.py +145 -109
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/PhysMember.py +315 -81
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Visualization.py +3 -6
- {pynitefea-2.3.0 → pynitefea-2.4.1}/README.md +7 -1
- {pynitefea-2.3.0 → pynitefea-2.4.1}/setup.py +1 -1
- {pynitefea-2.3.0 → pynitefea-2.4.1}/LICENSE +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/PyNiteFEA.egg-info/SOURCES.txt +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/PyNiteFEA.egg-info/dependency_links.txt +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/PyNiteFEA.egg-info/requires.txt +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/PyNiteFEA.egg-info/top_level.txt +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Analysis.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/BeamSegY.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/BeamSegZ.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/FEModel3D.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/FixedEndReactions.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/LoadCombo.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/MainStyleSheet.css +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/MatFoundation.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Material.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Mesh.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Node3D.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Plate3D.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Quad3D.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Rendering.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Report_Template.html +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Reporting.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Section.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/ShearWall.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Spring3D.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/Tri3D.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/VTKWriter.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/Pynite/__init__.py +0 -0
- {pynitefea-2.3.0 → pynitefea-2.4.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyNiteFEA
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.1
|
|
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
|
|
@@ -121,9 +121,15 @@ Here's a list of projects that use Pynite:
|
|
|
121
121
|
* Phaenotyp (https://github.com/bewegende-Architektur/Phaenotyp) (https://youtu.be/shloSw9HjVI)
|
|
122
122
|
|
|
123
123
|
# What's New?
|
|
124
|
+
2.4.1
|
|
125
|
+
* Fixed a bug where enveloped results did not work if both tagged and untagged combos were in a model.
|
|
126
|
+
|
|
127
|
+
2.4.0
|
|
128
|
+
* Member `max` and `min` methods now return governing load combination along with the member max/min forces.
|
|
129
|
+
* Bug fix: Quadrilateral element displacements had corners swapped during VTK visualization. This was a relic from the old MITC4 formulation that has been corrected.
|
|
130
|
+
|
|
124
131
|
v2.3.0
|
|
125
132
|
* Added enveloping to member diagrams. Set `combo_name` to a list of combo tags and the member diagram will show an envelope of all the combos that have any of those tags.
|
|
126
|
-
* Bug fix: Quadrilateral element displacements had corners swapped during VTK visualization. This was a relic from the old MITC4 formulation that has been corrected.
|
|
127
133
|
* Bug fix: Added shear wall and mat foundation load cases to `FEModel3D.load_cases()`. The list of load cases was sometimes incomplete if these meshes had not yet been generated.
|
|
128
134
|
* Added bending moment end releases to visualizations.
|
|
129
135
|
* Bug fix for shear walls with flanges having an origin with their origin at Y != 0.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyNiteFEA
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.1
|
|
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
|
|
@@ -121,9 +121,15 @@ Here's a list of projects that use Pynite:
|
|
|
121
121
|
* Phaenotyp (https://github.com/bewegende-Architektur/Phaenotyp) (https://youtu.be/shloSw9HjVI)
|
|
122
122
|
|
|
123
123
|
# What's New?
|
|
124
|
+
2.4.1
|
|
125
|
+
* Fixed a bug where enveloped results did not work if both tagged and untagged combos were in a model.
|
|
126
|
+
|
|
127
|
+
2.4.0
|
|
128
|
+
* Member `max` and `min` methods now return governing load combination along with the member max/min forces.
|
|
129
|
+
* Bug fix: Quadrilateral element displacements had corners swapped during VTK visualization. This was a relic from the old MITC4 formulation that has been corrected.
|
|
130
|
+
|
|
124
131
|
v2.3.0
|
|
125
132
|
* Added enveloping to member diagrams. Set `combo_name` to a list of combo tags and the member diagram will show an envelope of all the combos that have any of those tags.
|
|
126
|
-
* Bug fix: Quadrilateral element displacements had corners swapped during VTK visualization. This was a relic from the old MITC4 formulation that has been corrected.
|
|
127
133
|
* Bug fix: Added shear wall and mat foundation load cases to `FEModel3D.load_cases()`. The list of load cases was sometimes incomplete if these meshes had not yet been generated.
|
|
128
134
|
* Added bending moment end releases to visualizations.
|
|
129
135
|
* Bug fix for shear walls with flanges having an origin with their origin at Y != 0.
|
|
@@ -1154,7 +1154,7 @@ class Member3D():
|
|
|
1154
1154
|
|
|
1155
1155
|
return 0
|
|
1156
1156
|
|
|
1157
|
-
def max_shear(self, Direction: Literal['Fy', 'Fz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
1157
|
+
def max_shear(self, Direction: Literal['Fy', 'Fz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
1158
1158
|
"""
|
|
1159
1159
|
Returns the maximum shear force in the member for the specified direction
|
|
1160
1160
|
and load combination(s).
|
|
@@ -1174,16 +1174,10 @@ class Member3D():
|
|
|
1174
1174
|
|
|
1175
1175
|
Returns
|
|
1176
1176
|
-------
|
|
1177
|
-
float
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
Notes
|
|
1183
|
-
-----
|
|
1184
|
-
- Unlike moments, shear does not depend on P-Delta effects.
|
|
1185
|
-
- Automatically segments the member if it has not yet been segmented
|
|
1186
|
-
for a load combination.
|
|
1177
|
+
float or tuple of (float, str)
|
|
1178
|
+
If a single combo name is provided, returns the maximum shear value.
|
|
1179
|
+
If a list of tags is provided, returns a tuple of the maximum shear
|
|
1180
|
+
value and the name of the governing load combination.
|
|
1187
1181
|
"""
|
|
1188
1182
|
# Normalize input: single name vs list of tags
|
|
1189
1183
|
if isinstance(combo_tags, str):
|
|
@@ -1192,10 +1186,11 @@ class Member3D():
|
|
|
1192
1186
|
# Filter combos that contain *any* of the given tags
|
|
1193
1187
|
combo_names = [
|
|
1194
1188
|
name for name, combo in self.model.load_combos.items()
|
|
1195
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
1189
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
1196
1190
|
]
|
|
1197
1191
|
|
|
1198
1192
|
Vmax_global = None # will store the global maximum across combos
|
|
1193
|
+
governing_combo = None
|
|
1199
1194
|
|
|
1200
1195
|
for combo_name in combo_names:
|
|
1201
1196
|
# Skip inactive combos
|
|
@@ -1219,11 +1214,16 @@ class Member3D():
|
|
|
1219
1214
|
# Update global maximum
|
|
1220
1215
|
if Vmax_global is None or Vmax > Vmax_global:
|
|
1221
1216
|
Vmax_global = Vmax
|
|
1217
|
+
governing_combo = combo_name
|
|
1222
1218
|
|
|
1223
|
-
# Return
|
|
1224
|
-
|
|
1219
|
+
# Return result
|
|
1220
|
+
if Vmax_global is None:
|
|
1221
|
+
Vmax_global = 0
|
|
1222
|
+
if isinstance(combo_tags, list):
|
|
1223
|
+
return (Vmax_global, governing_combo)
|
|
1224
|
+
return Vmax_global
|
|
1225
1225
|
|
|
1226
|
-
def min_shear(self, Direction: Literal['Fy', 'Fz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
1226
|
+
def min_shear(self, Direction: Literal['Fy', 'Fz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
1227
1227
|
"""
|
|
1228
1228
|
Returns the minimum shear force in the member for the specified direction
|
|
1229
1229
|
and load combination(s).
|
|
@@ -1243,16 +1243,10 @@ class Member3D():
|
|
|
1243
1243
|
|
|
1244
1244
|
Returns
|
|
1245
1245
|
-------
|
|
1246
|
-
float
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
Notes
|
|
1252
|
-
-----
|
|
1253
|
-
- Unlike moments, shear does not depend on P-Delta effects.
|
|
1254
|
-
- Automatically segments the member if it has not yet been segmented
|
|
1255
|
-
for a load combination.
|
|
1246
|
+
float or tuple of (float, str)
|
|
1247
|
+
If a single combo name is provided, returns the minimum shear value.
|
|
1248
|
+
If a list of tags is provided, returns a tuple of the minimum shear
|
|
1249
|
+
value and the name of the governing load combination.
|
|
1256
1250
|
"""
|
|
1257
1251
|
# Normalize input: single name vs list of tags
|
|
1258
1252
|
if isinstance(combo_tags, str):
|
|
@@ -1261,10 +1255,11 @@ class Member3D():
|
|
|
1261
1255
|
# Filter combos that contain *any* of the given tags
|
|
1262
1256
|
combo_names = [
|
|
1263
1257
|
name for name, combo in self.model.load_combos.items()
|
|
1264
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
1258
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
1265
1259
|
]
|
|
1266
1260
|
|
|
1267
1261
|
Vmin_global = None # will store the global minimum across combos
|
|
1262
|
+
governing_combo = None
|
|
1268
1263
|
|
|
1269
1264
|
for combo_name in combo_names:
|
|
1270
1265
|
# Skip inactive combos
|
|
@@ -1288,9 +1283,14 @@ class Member3D():
|
|
|
1288
1283
|
# Update global minimum
|
|
1289
1284
|
if Vmin_global is None or Vmin < Vmin_global:
|
|
1290
1285
|
Vmin_global = Vmin
|
|
1286
|
+
governing_combo = combo_name
|
|
1291
1287
|
|
|
1292
|
-
# Return
|
|
1293
|
-
|
|
1288
|
+
# Return result
|
|
1289
|
+
if Vmin_global is None:
|
|
1290
|
+
Vmin_global = 0
|
|
1291
|
+
if isinstance(combo_tags, list):
|
|
1292
|
+
return (Vmin_global, governing_combo)
|
|
1293
|
+
return Vmin_global
|
|
1294
1294
|
|
|
1295
1295
|
def plot_shear(self, Direction: Literal['Fy', 'Fz'], combo_name: Union[str, List[str]] = 'Combo 1', n_points: int = 20) -> None:
|
|
1296
1296
|
"""
|
|
@@ -1319,7 +1319,7 @@ class Member3D():
|
|
|
1319
1319
|
combo_names = [combo_name]
|
|
1320
1320
|
else:
|
|
1321
1321
|
combo_names = [name for name, combo in self.model.load_combos.items()
|
|
1322
|
-
if any(tag in combo.combo_tags for tag in combo_name)]
|
|
1322
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_name)]
|
|
1323
1323
|
|
|
1324
1324
|
fig, ax = Member3D.__plt.subplots()
|
|
1325
1325
|
ax.axhline(0, color='black', lw=1)
|
|
@@ -1456,7 +1456,7 @@ class Member3D():
|
|
|
1456
1456
|
|
|
1457
1457
|
return 0
|
|
1458
1458
|
|
|
1459
|
-
def max_moment(self, Direction: Literal['My', 'Mz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
1459
|
+
def max_moment(self, Direction: Literal['My', 'Mz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
1460
1460
|
"""
|
|
1461
1461
|
Returns the maximum bending moment in the member for the specified direction
|
|
1462
1462
|
and load combination(s).
|
|
@@ -1476,16 +1476,10 @@ class Member3D():
|
|
|
1476
1476
|
|
|
1477
1477
|
Returns
|
|
1478
1478
|
-------
|
|
1479
|
-
float
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
Notes
|
|
1485
|
-
-----
|
|
1486
|
-
- Includes P-Delta effects if the model's solution is 'P-Delta' or 'Pushover'.
|
|
1487
|
-
- Automatically segments the member if it has not yet been segmented
|
|
1488
|
-
for a load combination.
|
|
1479
|
+
float or tuple of (float, str)
|
|
1480
|
+
If a single combo name is provided, returns the maximum moment value.
|
|
1481
|
+
If a list of tags is provided, returns a tuple of the maximum moment
|
|
1482
|
+
value and the name of the governing load combination.
|
|
1489
1483
|
"""
|
|
1490
1484
|
# Normalize input: single name vs list of tags
|
|
1491
1485
|
if isinstance(combo_tags, str):
|
|
@@ -1494,10 +1488,11 @@ class Member3D():
|
|
|
1494
1488
|
# Filter combos that contain *any* of the given tags
|
|
1495
1489
|
combo_names = [
|
|
1496
1490
|
name for name, combo in self.model.load_combos.items()
|
|
1497
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
1491
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
1498
1492
|
]
|
|
1499
1493
|
|
|
1500
1494
|
Mmax_global = None # will store the global maximum across combos
|
|
1495
|
+
governing_combo = None
|
|
1501
1496
|
|
|
1502
1497
|
for combo_name in combo_names:
|
|
1503
1498
|
# Skip inactive combos
|
|
@@ -1524,11 +1519,16 @@ class Member3D():
|
|
|
1524
1519
|
# Update global maximum
|
|
1525
1520
|
if Mmax_global is None or Mmax > Mmax_global:
|
|
1526
1521
|
Mmax_global = Mmax
|
|
1522
|
+
governing_combo = combo_name
|
|
1527
1523
|
|
|
1528
|
-
# Return
|
|
1529
|
-
|
|
1524
|
+
# Return result
|
|
1525
|
+
if Mmax_global is None:
|
|
1526
|
+
Mmax_global = 0
|
|
1527
|
+
if isinstance(combo_tags, list):
|
|
1528
|
+
return (Mmax_global, governing_combo)
|
|
1529
|
+
return Mmax_global
|
|
1530
1530
|
|
|
1531
|
-
def min_moment(self, Direction: Literal['My', 'Mz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
1531
|
+
def min_moment(self, Direction: Literal['My', 'Mz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
1532
1532
|
"""
|
|
1533
1533
|
Returns the minimum bending moment in the member for the specified direction
|
|
1534
1534
|
and load combination(s).
|
|
@@ -1548,16 +1548,10 @@ class Member3D():
|
|
|
1548
1548
|
|
|
1549
1549
|
Returns
|
|
1550
1550
|
-------
|
|
1551
|
-
float
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
Notes
|
|
1557
|
-
-----
|
|
1558
|
-
- Includes P-Delta effects if the model's solution is 'P-Delta' or 'Pushover'.
|
|
1559
|
-
- Automatically segments the member if it has not yet been segmented
|
|
1560
|
-
for a load combination.
|
|
1551
|
+
float or tuple of (float, str)
|
|
1552
|
+
If a single combo name is provided, returns the minimum moment value.
|
|
1553
|
+
If a list of tags is provided, returns a tuple of the minimum moment
|
|
1554
|
+
value and the name of the governing load combination.
|
|
1561
1555
|
"""
|
|
1562
1556
|
# Normalize input: single name vs list of tags
|
|
1563
1557
|
if isinstance(combo_tags, str):
|
|
@@ -1566,10 +1560,11 @@ class Member3D():
|
|
|
1566
1560
|
# Filter combos that contain *any* of the given tags
|
|
1567
1561
|
combo_names = [
|
|
1568
1562
|
name for name, combo in self.model.load_combos.items()
|
|
1569
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
1563
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
1570
1564
|
]
|
|
1571
1565
|
|
|
1572
1566
|
Mmin_global = None # will store the global minimum across combos
|
|
1567
|
+
governing_combo = None
|
|
1573
1568
|
|
|
1574
1569
|
for combo_name in combo_names:
|
|
1575
1570
|
# Skip inactive combos
|
|
@@ -1596,9 +1591,14 @@ class Member3D():
|
|
|
1596
1591
|
# Update global minimum
|
|
1597
1592
|
if Mmin_global is None or Mmin < Mmin_global:
|
|
1598
1593
|
Mmin_global = Mmin
|
|
1594
|
+
governing_combo = combo_name
|
|
1599
1595
|
|
|
1600
|
-
# Return
|
|
1601
|
-
|
|
1596
|
+
# Return result
|
|
1597
|
+
if Mmin_global is None:
|
|
1598
|
+
Mmin_global = 0
|
|
1599
|
+
if isinstance(combo_tags, list):
|
|
1600
|
+
return (Mmin_global, governing_combo)
|
|
1601
|
+
return Mmin_global
|
|
1602
1602
|
|
|
1603
1603
|
|
|
1604
1604
|
def plot_moment(self, Direction: Literal['My', 'Mz'], combo_name: Union[str, List[str]] = 'Combo 1', n_points: int = 20) -> None:
|
|
@@ -1628,7 +1628,7 @@ class Member3D():
|
|
|
1628
1628
|
combo_names = [combo_name]
|
|
1629
1629
|
else:
|
|
1630
1630
|
combo_names = [name for name, combo in self.model.load_combos.items()
|
|
1631
|
-
if any(tag in combo.combo_tags for tag in combo_name)]
|
|
1631
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_name)]
|
|
1632
1632
|
|
|
1633
1633
|
fig, ax = Member3D.__plt.subplots()
|
|
1634
1634
|
ax.axhline(0, color='black', lw=1)
|
|
@@ -1747,7 +1747,7 @@ class Member3D():
|
|
|
1747
1747
|
|
|
1748
1748
|
return 0
|
|
1749
1749
|
|
|
1750
|
-
def max_torque(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
1750
|
+
def max_torque(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
1751
1751
|
"""
|
|
1752
1752
|
Returns the maximum torsional moment in the member across the
|
|
1753
1753
|
specified load combination(s).
|
|
@@ -1763,10 +1763,10 @@ class Member3D():
|
|
|
1763
1763
|
|
|
1764
1764
|
Returns
|
|
1765
1765
|
-------
|
|
1766
|
-
float
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1766
|
+
float or tuple of (float, str)
|
|
1767
|
+
If a single combo name is provided, returns the maximum torsion value.
|
|
1768
|
+
If a list of tags is provided, returns a tuple of the maximum torsion
|
|
1769
|
+
value and the name of the governing load combination.
|
|
1770
1770
|
"""
|
|
1771
1771
|
# Normalize input: single combo name or list of tags
|
|
1772
1772
|
if isinstance(combo_tags, str):
|
|
@@ -1774,11 +1774,12 @@ class Member3D():
|
|
|
1774
1774
|
else:
|
|
1775
1775
|
combo_names = [
|
|
1776
1776
|
name for name, combo in self.model.load_combos.items()
|
|
1777
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
1777
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
1778
1778
|
]
|
|
1779
1779
|
|
|
1780
1780
|
# Track global maximum torsion across all combos
|
|
1781
1781
|
Tmax_global = None
|
|
1782
|
+
governing_combo = None
|
|
1782
1783
|
|
|
1783
1784
|
# Loop through each candidate combo
|
|
1784
1785
|
for combo_name in combo_names:
|
|
@@ -1801,12 +1802,17 @@ class Member3D():
|
|
|
1801
1802
|
# Update global maximum
|
|
1802
1803
|
if Tmax_global is None or Tmax > Tmax_global:
|
|
1803
1804
|
Tmax_global = Tmax
|
|
1805
|
+
governing_combo = combo_name
|
|
1804
1806
|
|
|
1805
|
-
# Return
|
|
1806
|
-
|
|
1807
|
+
# Return result
|
|
1808
|
+
if Tmax_global is None:
|
|
1809
|
+
Tmax_global = 0
|
|
1810
|
+
if isinstance(combo_tags, list):
|
|
1811
|
+
return (Tmax_global, governing_combo)
|
|
1812
|
+
return Tmax_global
|
|
1807
1813
|
|
|
1808
1814
|
|
|
1809
|
-
def min_torque(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
1815
|
+
def min_torque(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
1810
1816
|
"""
|
|
1811
1817
|
Returns the minimum torsional moment in the member across the
|
|
1812
1818
|
specified load combination(s).
|
|
@@ -1822,10 +1828,10 @@ class Member3D():
|
|
|
1822
1828
|
|
|
1823
1829
|
Returns
|
|
1824
1830
|
-------
|
|
1825
|
-
float
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1831
|
+
float or tuple of (float, str)
|
|
1832
|
+
If a single combo name is provided, returns the minimum torsion value.
|
|
1833
|
+
If a list of tags is provided, returns a tuple of the minimum torsion
|
|
1834
|
+
value and the name of the governing load combination.
|
|
1829
1835
|
"""
|
|
1830
1836
|
# Normalize input: single combo name or list of tags
|
|
1831
1837
|
if isinstance(combo_tags, str):
|
|
@@ -1833,11 +1839,12 @@ class Member3D():
|
|
|
1833
1839
|
else:
|
|
1834
1840
|
combo_names = [
|
|
1835
1841
|
name for name, combo in self.model.load_combos.items()
|
|
1836
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
1842
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
1837
1843
|
]
|
|
1838
1844
|
|
|
1839
1845
|
# Track global minimum torsion across all combos
|
|
1840
1846
|
Tmin_global = None
|
|
1847
|
+
governing_combo = None
|
|
1841
1848
|
|
|
1842
1849
|
# Loop through each candidate combo
|
|
1843
1850
|
for combo_name in combo_names:
|
|
@@ -1860,9 +1867,14 @@ class Member3D():
|
|
|
1860
1867
|
# Update global minimum
|
|
1861
1868
|
if Tmin_global is None or Tmin < Tmin_global:
|
|
1862
1869
|
Tmin_global = Tmin
|
|
1870
|
+
governing_combo = combo_name
|
|
1863
1871
|
|
|
1864
|
-
# Return
|
|
1865
|
-
|
|
1872
|
+
# Return result
|
|
1873
|
+
if Tmin_global is None:
|
|
1874
|
+
Tmin_global = 0
|
|
1875
|
+
if isinstance(combo_tags, list):
|
|
1876
|
+
return (Tmin_global, governing_combo)
|
|
1877
|
+
return Tmin_global
|
|
1866
1878
|
|
|
1867
1879
|
def plot_torque(self, combo_name: Union[str, List[str]] = 'Combo 1', n_points: int = 20) -> None:
|
|
1868
1880
|
"""
|
|
@@ -1887,7 +1899,7 @@ class Member3D():
|
|
|
1887
1899
|
combo_names = [combo_name]
|
|
1888
1900
|
else:
|
|
1889
1901
|
combo_names = [name for name, combo in self.model.load_combos.items()
|
|
1890
|
-
if any(tag in combo.combo_tags for tag in combo_name)]
|
|
1902
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_name)]
|
|
1891
1903
|
|
|
1892
1904
|
fig, ax = Member3D.__plt.subplots()
|
|
1893
1905
|
ax.axhline(0, color='black', lw=1)
|
|
@@ -1980,7 +1992,7 @@ class Member3D():
|
|
|
1980
1992
|
|
|
1981
1993
|
return 0
|
|
1982
1994
|
|
|
1983
|
-
def max_axial(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
1995
|
+
def max_axial(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
1984
1996
|
"""
|
|
1985
1997
|
Returns the maximum axial force in the member across the specified
|
|
1986
1998
|
load combination(s).
|
|
@@ -1996,10 +2008,10 @@ class Member3D():
|
|
|
1996
2008
|
|
|
1997
2009
|
Returns
|
|
1998
2010
|
-------
|
|
1999
|
-
float
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2011
|
+
float or tuple of (float, str)
|
|
2012
|
+
If a single combo name is provided, returns the maximum axial value.
|
|
2013
|
+
If a list of tags is provided, returns a tuple of the maximum axial
|
|
2014
|
+
value and the name of the governing load combination.
|
|
2003
2015
|
"""
|
|
2004
2016
|
# Normalize input: if a string is passed, treat it as a single combo name
|
|
2005
2017
|
if isinstance(combo_tags, str):
|
|
@@ -2008,11 +2020,12 @@ class Member3D():
|
|
|
2008
2020
|
# If tags are provided, gather all combos that match ANY of the tags
|
|
2009
2021
|
combo_names = [
|
|
2010
2022
|
name for name, combo in self.model.load_combos.items()
|
|
2011
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
2023
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
2012
2024
|
]
|
|
2013
2025
|
|
|
2014
2026
|
# Track the global maximum axial force across all combos
|
|
2015
2027
|
Pmax_global = None
|
|
2028
|
+
governing_combo = None
|
|
2016
2029
|
|
|
2017
2030
|
# Loop through each candidate combo
|
|
2018
2031
|
for combo_name in combo_names:
|
|
@@ -2035,11 +2048,16 @@ class Member3D():
|
|
|
2035
2048
|
# Update the global maximum
|
|
2036
2049
|
if Pmax_global is None or Pmax > Pmax_global:
|
|
2037
2050
|
Pmax_global = Pmax
|
|
2051
|
+
governing_combo = combo_name
|
|
2038
2052
|
|
|
2039
|
-
# Return
|
|
2040
|
-
|
|
2053
|
+
# Return result
|
|
2054
|
+
if Pmax_global is None:
|
|
2055
|
+
Pmax_global = 0
|
|
2056
|
+
if isinstance(combo_tags, list):
|
|
2057
|
+
return (Pmax_global, governing_combo)
|
|
2058
|
+
return Pmax_global
|
|
2041
2059
|
|
|
2042
|
-
def min_axial(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
2060
|
+
def min_axial(self, combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
2043
2061
|
"""
|
|
2044
2062
|
Returns the minimum axial force in the member across the specified
|
|
2045
2063
|
load combination(s).
|
|
@@ -2055,10 +2073,10 @@ class Member3D():
|
|
|
2055
2073
|
|
|
2056
2074
|
Returns
|
|
2057
2075
|
-------
|
|
2058
|
-
float
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2076
|
+
float or tuple of (float, str)
|
|
2077
|
+
If a single combo name is provided, returns the minimum axial value.
|
|
2078
|
+
If a list of tags is provided, returns a tuple of the minimum axial
|
|
2079
|
+
value and the name of the governing load combination.
|
|
2062
2080
|
"""
|
|
2063
2081
|
# Normalize input: if a string is passed, treat it as a single combo name
|
|
2064
2082
|
if isinstance(combo_tags, str):
|
|
@@ -2067,11 +2085,12 @@ class Member3D():
|
|
|
2067
2085
|
# If tags are provided, gather all combos that match ANY of the tags
|
|
2068
2086
|
combo_names = [
|
|
2069
2087
|
name for name, combo in self.model.load_combos.items()
|
|
2070
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
2088
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
2071
2089
|
]
|
|
2072
2090
|
|
|
2073
2091
|
# Track the global minimum axial force across all combos
|
|
2074
2092
|
Pmin_global = None
|
|
2093
|
+
governing_combo = None
|
|
2075
2094
|
|
|
2076
2095
|
# Loop through each candidate combo
|
|
2077
2096
|
for combo_name in combo_names:
|
|
@@ -2094,9 +2113,14 @@ class Member3D():
|
|
|
2094
2113
|
# Update the global minimum
|
|
2095
2114
|
if Pmin_global is None or Pmin < Pmin_global:
|
|
2096
2115
|
Pmin_global = Pmin
|
|
2116
|
+
governing_combo = combo_name
|
|
2097
2117
|
|
|
2098
|
-
# Return
|
|
2099
|
-
|
|
2118
|
+
# Return result
|
|
2119
|
+
if Pmin_global is None:
|
|
2120
|
+
Pmin_global = 0
|
|
2121
|
+
if isinstance(combo_tags, list):
|
|
2122
|
+
return (Pmin_global, governing_combo)
|
|
2123
|
+
return Pmin_global
|
|
2100
2124
|
|
|
2101
2125
|
def plot_axial(self, combo_name: Union[str, List[str]] = 'Combo 1', n_points: int = 20) -> None:
|
|
2102
2126
|
"""
|
|
@@ -2121,7 +2145,7 @@ class Member3D():
|
|
|
2121
2145
|
combo_names = [combo_name]
|
|
2122
2146
|
else:
|
|
2123
2147
|
combo_names = [name for name, combo in self.model.load_combos.items()
|
|
2124
|
-
if any(tag in combo.combo_tags for tag in combo_name)]
|
|
2148
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_name)]
|
|
2125
2149
|
|
|
2126
2150
|
fig, ax = Member3D.__plt.subplots()
|
|
2127
2151
|
ax.axhline(0, color='black', lw=1)
|
|
@@ -2257,7 +2281,7 @@ class Member3D():
|
|
|
2257
2281
|
|
|
2258
2282
|
return 0
|
|
2259
2283
|
|
|
2260
|
-
def max_deflection(self, Direction: Literal['dx', 'dy', 'dz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
2284
|
+
def max_deflection(self, Direction: Literal['dx', 'dy', 'dz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
2261
2285
|
"""
|
|
2262
2286
|
Returns the maximum deflection in the member across the specified
|
|
2263
2287
|
load combination(s).
|
|
@@ -2278,10 +2302,10 @@ class Member3D():
|
|
|
2278
2302
|
|
|
2279
2303
|
Returns
|
|
2280
2304
|
-------
|
|
2281
|
-
float
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2305
|
+
float or tuple of (float, str)
|
|
2306
|
+
If a single combo name is provided, returns the maximum deflection.
|
|
2307
|
+
If a list of tags is provided, returns a tuple of the maximum
|
|
2308
|
+
deflection and the name of the governing load combination.
|
|
2285
2309
|
"""
|
|
2286
2310
|
# Normalize input: single name or list of tags
|
|
2287
2311
|
if isinstance(combo_tags, str):
|
|
@@ -2289,11 +2313,12 @@ class Member3D():
|
|
|
2289
2313
|
else:
|
|
2290
2314
|
combo_names = [
|
|
2291
2315
|
name for name, combo in self.model.load_combos.items()
|
|
2292
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
2316
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
2293
2317
|
]
|
|
2294
2318
|
|
|
2295
2319
|
# Track global maximum deflection across all combos
|
|
2296
2320
|
dmax_global = None
|
|
2321
|
+
governing_combo = None
|
|
2297
2322
|
|
|
2298
2323
|
# Loop through each candidate combo
|
|
2299
2324
|
for combo_name in combo_names:
|
|
@@ -2318,12 +2343,17 @@ class Member3D():
|
|
|
2318
2343
|
# Update global maximum
|
|
2319
2344
|
if dmax_global is None or dmax > dmax_global:
|
|
2320
2345
|
dmax_global = dmax
|
|
2346
|
+
governing_combo = combo_name
|
|
2321
2347
|
|
|
2322
|
-
# Return
|
|
2323
|
-
|
|
2348
|
+
# Return result
|
|
2349
|
+
if dmax_global is None:
|
|
2350
|
+
dmax_global = 0
|
|
2351
|
+
if isinstance(combo_tags, list):
|
|
2352
|
+
return (dmax_global, governing_combo)
|
|
2353
|
+
return dmax_global
|
|
2324
2354
|
|
|
2325
2355
|
|
|
2326
|
-
def min_deflection(self, Direction: Literal['dx', 'dy', 'dz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> float:
|
|
2356
|
+
def min_deflection(self, Direction: Literal['dx', 'dy', 'dz'], combo_tags: Union[str, List[str]] = 'Combo 1') -> Union[float, tuple[float, str]]:
|
|
2327
2357
|
"""
|
|
2328
2358
|
Returns the minimum deflection in the member across the specified
|
|
2329
2359
|
load combination(s).
|
|
@@ -2344,10 +2374,10 @@ class Member3D():
|
|
|
2344
2374
|
|
|
2345
2375
|
Returns
|
|
2346
2376
|
-------
|
|
2347
|
-
float
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2377
|
+
float or tuple of (float, str)
|
|
2378
|
+
If a single combo name is provided, returns the minimum deflection.
|
|
2379
|
+
If a list of tags is provided, returns a tuple of the minimum
|
|
2380
|
+
deflection and the name of the governing load combination.
|
|
2351
2381
|
"""
|
|
2352
2382
|
# Normalize input: single name or list of tags
|
|
2353
2383
|
if isinstance(combo_tags, str):
|
|
@@ -2355,11 +2385,12 @@ class Member3D():
|
|
|
2355
2385
|
else:
|
|
2356
2386
|
combo_names = [
|
|
2357
2387
|
name for name, combo in self.model.load_combos.items()
|
|
2358
|
-
if any(tag in combo.combo_tags for tag in combo_tags)
|
|
2388
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_tags)
|
|
2359
2389
|
]
|
|
2360
2390
|
|
|
2361
2391
|
# Track global minimum deflection across all combos
|
|
2362
2392
|
dmin_global = None
|
|
2393
|
+
governing_combo = None
|
|
2363
2394
|
|
|
2364
2395
|
# Loop through each candidate combo
|
|
2365
2396
|
for combo_name in combo_names:
|
|
@@ -2384,9 +2415,14 @@ class Member3D():
|
|
|
2384
2415
|
# Update global minimum
|
|
2385
2416
|
if dmin_global is None or dmin < dmin_global:
|
|
2386
2417
|
dmin_global = dmin
|
|
2418
|
+
governing_combo = combo_name
|
|
2387
2419
|
|
|
2388
|
-
# Return
|
|
2389
|
-
|
|
2420
|
+
# Return result
|
|
2421
|
+
if dmin_global is None:
|
|
2422
|
+
dmin_global = 0
|
|
2423
|
+
if isinstance(combo_tags, list):
|
|
2424
|
+
return (dmin_global, governing_combo)
|
|
2425
|
+
return dmin_global
|
|
2390
2426
|
|
|
2391
2427
|
def plot_deflection(self, Direction: Literal['dx', 'dy', 'dz'], combo_name: Union[str, List[str]] = 'Combo 1', n_points: int = 20) -> None:
|
|
2392
2428
|
"""
|
|
@@ -2416,7 +2452,7 @@ class Member3D():
|
|
|
2416
2452
|
combo_names = [combo_name]
|
|
2417
2453
|
else:
|
|
2418
2454
|
combo_names = [name for name, combo in self.model.load_combos.items()
|
|
2419
|
-
if any(tag in combo.combo_tags for tag in combo_name)]
|
|
2455
|
+
if combo.combo_tags is not None and any(tag in combo.combo_tags for tag in combo_name)]
|
|
2420
2456
|
|
|
2421
2457
|
fig, ax = Member3D.__plt.subplots()
|
|
2422
2458
|
ax.axhline(0, color='black', lw=1)
|