PyNiteFEA 3.1.0__tar.gz → 3.2.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-3.1.0 → pynitefea-3.2.0}/PKG-INFO +7 -1
- {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/PKG-INFO +7 -1
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/ShearWall.py +181 -57
- {pynitefea-3.1.0 → pynitefea-3.2.0}/README.md +6 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/pyproject.toml +1 -1
- {pynitefea-3.1.0 → pynitefea-3.2.0}/LICENSE +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/SOURCES.txt +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/dependency_links.txt +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/requires.txt +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/top_level.txt +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Analysis.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/BeamSegY.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/BeamSegZ.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/FEModel3D.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/FixedEndReactions.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/LoadCombo.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/MainStyleSheet.css +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/MatFoundation.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Material.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Member3D.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Mesh.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Node3D.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/PhysMember.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Plate3D.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Quad3D.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Rendering.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Report_Template.html +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Reporting.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Section.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Spring3D.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Tri3D.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/VTKWriter.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Visualization.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/__init__.py +0 -0
- {pynitefea-3.1.0 → pynitefea-3.2.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyNiteFEA
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: A simple 3D structural finite element library for Python.
|
|
5
5
|
Author-email: "D. Craig Brinck, PE, SE" <Building.Code@outlook.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -109,6 +109,12 @@ Here's a list of projects that use Pynite:
|
|
|
109
109
|
* Phaenotyp (https://github.com/bewegende-Architektur/Phaenotyp) (https://youtu.be/shloSw9HjVI)
|
|
110
110
|
|
|
111
111
|
# What's New?
|
|
112
|
+
3.2.0
|
|
113
|
+
* Added shear wall pier top results and coupling beam right hand side results to the pier/coupling beam force results output.
|
|
114
|
+
* Adjusted shear wall pier and coupling beam internal force results sign convention to match the sign convention used for members.
|
|
115
|
+
* Added targeted testing for shear wall pier and coupling beam sign convention and load magnitudes.
|
|
116
|
+
* Added shear wall docstrings and a readthedocs documentation page.
|
|
117
|
+
|
|
112
118
|
3.1.0
|
|
113
119
|
* Improved detection of unstable structures.
|
|
114
120
|
* Bug fix for shear walls. Shear walls were erroneously tracking other plates in the model for internal pier/coupling beam force summations, rather than just the plates related to the individual shear wall.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyNiteFEA
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: A simple 3D structural finite element library for Python.
|
|
5
5
|
Author-email: "D. Craig Brinck, PE, SE" <Building.Code@outlook.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -109,6 +109,12 @@ Here's a list of projects that use Pynite:
|
|
|
109
109
|
* Phaenotyp (https://github.com/bewegende-Architektur/Phaenotyp) (https://youtu.be/shloSw9HjVI)
|
|
110
110
|
|
|
111
111
|
# What's New?
|
|
112
|
+
3.2.0
|
|
113
|
+
* Added shear wall pier top results and coupling beam right hand side results to the pier/coupling beam force results output.
|
|
114
|
+
* Adjusted shear wall pier and coupling beam internal force results sign convention to match the sign convention used for members.
|
|
115
|
+
* Added targeted testing for shear wall pier and coupling beam sign convention and load magnitudes.
|
|
116
|
+
* Added shear wall docstrings and a readthedocs documentation page.
|
|
117
|
+
|
|
112
118
|
3.1.0
|
|
113
119
|
* Improved detection of unstable structures.
|
|
114
120
|
* Bug fix for shear walls. Shear walls were erroneously tracking other plates in the model for internal pier/coupling beam force summations, rather than just the plates related to the individual shear wall.
|
|
@@ -49,6 +49,11 @@ class ShearWall():
|
|
|
49
49
|
return f"ShearWall(name={self.name!r}, length={self.L}, height={self.H})"
|
|
50
50
|
|
|
51
51
|
def asign_material(self, name: str, t: float, x_start: float | None = None, x_end: float | None = None, y_start: float | None = None, y_end: float | None = None) -> None:
|
|
52
|
+
"""Assign a material and thickness to a rectangular wall region.
|
|
53
|
+
|
|
54
|
+
Omitted extents default to the full wall. Regenerate the wall, or solve
|
|
55
|
+
the model, after changing material assignments.
|
|
56
|
+
"""
|
|
52
57
|
|
|
53
58
|
# Data validation: ensure the extents of the material fall within the wall's envelope
|
|
54
59
|
if x_start is None: x_start = 0
|
|
@@ -64,16 +69,27 @@ class ShearWall():
|
|
|
64
69
|
self.needs_update = True
|
|
65
70
|
|
|
66
71
|
def add_opening(self, name: str, x_start: float, y_start: float, width: float, height: float, tie: float | None = None) -> None:
|
|
67
|
-
|
|
72
|
+
"""Add a rectangular opening in the wall's local x-y coordinates.
|
|
73
|
+
|
|
74
|
+
``tie`` is the optional axial rigidity, EA, of a tie spanning the top
|
|
75
|
+
of the opening. This is useful for modeling collectors between wall piers.
|
|
76
|
+
"""
|
|
77
|
+
self._openings.append([name, x_start, y_start, width, height, tie])
|
|
68
78
|
if self.is_generated:
|
|
69
79
|
self.needs_update = True
|
|
70
80
|
|
|
71
81
|
def add_flange(self, thickness: float, width: float, x: float, y_start: float, y_end: float, material: str, side: Literal['+z', '-z']) -> None:
|
|
82
|
+
"""Add a wall return normal to the wall plane at local coordinate ``x``."""
|
|
72
83
|
self._flanges.append([thickness, width, x, y_start, y_end, material, side])
|
|
73
84
|
if self.is_generated:
|
|
74
85
|
self.needs_update = True
|
|
75
86
|
|
|
76
87
|
def add_support(self, elevation: float | None = None, x_start: float | None = None, x_end: float | None = None) -> None:
|
|
88
|
+
"""Add fixed supports along a horizontal segment of the wall.
|
|
89
|
+
|
|
90
|
+
Coordinates are local. Omitted values define support across the wall's
|
|
91
|
+
full base.
|
|
92
|
+
"""
|
|
77
93
|
|
|
78
94
|
# Default support settings
|
|
79
95
|
if elevation is None: elevation = 0
|
|
@@ -90,6 +106,11 @@ class ShearWall():
|
|
|
90
106
|
self.needs_update = True
|
|
91
107
|
|
|
92
108
|
def add_story(self, story_name: str, elevation: float, x_start: float | None = None, x_end: float | None = None) -> None:
|
|
109
|
+
"""Define a diaphragm level where wall shear and axial loads are applied.
|
|
110
|
+
|
|
111
|
+
The method also creates a 100-unit stiffness load combination for use
|
|
112
|
+
with :meth:`stiffness`.
|
|
113
|
+
"""
|
|
93
114
|
|
|
94
115
|
# Validate input
|
|
95
116
|
if elevation is None: elevation = self.H
|
|
@@ -108,11 +129,13 @@ class ShearWall():
|
|
|
108
129
|
self.add_shear(story_name, 100, case=story_name)
|
|
109
130
|
|
|
110
131
|
def add_shear(self, story_name: str, force: float, case: str = 'Case 1') -> None:
|
|
132
|
+
"""Apply an in-plane shear force uniformly across a defined story."""
|
|
111
133
|
self._shears.append([story_name, force, case])
|
|
112
134
|
if self.is_generated:
|
|
113
135
|
self.needs_update = True
|
|
114
136
|
|
|
115
137
|
def add_axial(self, story_name: str, force: float, case: str = 'Case 1') -> None:
|
|
138
|
+
"""Apply a downward axial force uniformly across a defined story."""
|
|
116
139
|
self._axials.append([story_name, force, case])
|
|
117
140
|
if self.is_generated:
|
|
118
141
|
self.needs_update = True
|
|
@@ -135,6 +158,10 @@ class ShearWall():
|
|
|
135
158
|
del self.model.meshes[flange_name]
|
|
136
159
|
|
|
137
160
|
def generate(self) -> None:
|
|
161
|
+
"""Generate or regenerate the wall mesh, flanges, supports, and loads.
|
|
162
|
+
|
|
163
|
+
The generated wall automatically identifies piers and coupling beams.
|
|
164
|
+
"""
|
|
138
165
|
|
|
139
166
|
# Remove shear wall elements and nodes from the model if regenerating
|
|
140
167
|
if self.is_generated:
|
|
@@ -685,6 +712,11 @@ class ShearWall():
|
|
|
685
712
|
beam.plates.append(plate)
|
|
686
713
|
|
|
687
714
|
def draw_piers(self, show: bool = False) -> None | matplotlib.figure.Figure:
|
|
715
|
+
"""Draw the automatically identified pier layout.
|
|
716
|
+
|
|
717
|
+
Set ``show=True`` to display the plot; otherwise the pyplot module is
|
|
718
|
+
returned for saving or further customization.
|
|
719
|
+
"""
|
|
688
720
|
|
|
689
721
|
fig, ax = plt.subplots()
|
|
690
722
|
|
|
@@ -704,6 +736,11 @@ class ShearWall():
|
|
|
704
736
|
else: return plt
|
|
705
737
|
|
|
706
738
|
def draw_coupling_beams(self, show: bool = False) -> None | matplotlib.figure.Figure:
|
|
739
|
+
"""Draw the automatically identified coupling-beam layout.
|
|
740
|
+
|
|
741
|
+
Set ``show=True`` to display the plot; otherwise the pyplot module is
|
|
742
|
+
returned for saving or further customization.
|
|
743
|
+
"""
|
|
707
744
|
|
|
708
745
|
fig, ax = plt.subplots()
|
|
709
746
|
|
|
@@ -761,6 +798,7 @@ class ShearWall():
|
|
|
761
798
|
self._openings[j], self._openings[j+1] = self._openings[j+1], self._openings[j]
|
|
762
799
|
|
|
763
800
|
def stiffness(self, story_name: str) -> float:
|
|
801
|
+
"""Return the in-plane stiffness at a story from its 100-unit test load."""
|
|
764
802
|
|
|
765
803
|
# Validate that the specified story exists in the shear wall
|
|
766
804
|
if not any(story[0] == story_name for story in self._stories):
|
|
@@ -802,6 +840,11 @@ class ShearWall():
|
|
|
802
840
|
return V/(d_max)
|
|
803
841
|
|
|
804
842
|
def screenshots(self, combo_name: str = 'Combo 1', dir_path: str = './', renderer_backend: Literal['vtk', 'pyvista'] = 'vtk') -> None:
|
|
843
|
+
"""Save shear contours and pier/coupling-beam layout images.
|
|
844
|
+
|
|
845
|
+
``renderer_backend`` may be ``'vtk'`` or ``'pyvista'``. Files are
|
|
846
|
+
written to ``dir_path``.
|
|
847
|
+
"""
|
|
805
848
|
|
|
806
849
|
renderer_backend = renderer_backend.lower()
|
|
807
850
|
|
|
@@ -845,19 +888,20 @@ class ShearWall():
|
|
|
845
888
|
beam_sketch.savefig(os.path.join(dir_path, 'shear_wall_coupling_beams.png'), format='png')
|
|
846
889
|
|
|
847
890
|
def print_piers(self, combo_name: str = 'Combo 1') -> None:
|
|
848
|
-
"""
|
|
849
|
-
"""
|
|
891
|
+
"""Print pier forces at both the bottom and top for a load combination."""
|
|
850
892
|
|
|
851
893
|
# Create a PrettyTable object
|
|
852
894
|
table = PrettyTable()
|
|
853
895
|
|
|
854
896
|
# Define the headers
|
|
855
|
-
table.field_names = ["ID", "Length", "Height", "M/(VL)", "V", "M", "P"]
|
|
897
|
+
table.field_names = ["ID", "Length", "Height", "Location", "M/(VL)", "V", "M", "P"]
|
|
856
898
|
|
|
857
|
-
# Add rows to the table
|
|
899
|
+
# Add rows to the table for both ends of each pier
|
|
858
900
|
for pier_id, pier in self.piers.items():
|
|
859
|
-
|
|
860
|
-
|
|
901
|
+
P_bot, M_bot, V_bot, M_VL_bot = pier.sum_forces(combo_name, 'bottom')
|
|
902
|
+
P_top, M_top, V_top, M_VL_top = pier.sum_forces(combo_name, 'top')
|
|
903
|
+
table.add_row([pier.name, pier.width, pier.height, 'Bottom', M_VL_bot, V_bot, M_bot, P_bot])
|
|
904
|
+
table.add_row([pier.name, pier.width, pier.height, 'Top', M_VL_top, V_top, M_top, P_top])
|
|
861
905
|
|
|
862
906
|
# Print the table
|
|
863
907
|
print('+-------------------+')
|
|
@@ -866,19 +910,20 @@ class ShearWall():
|
|
|
866
910
|
print(table)
|
|
867
911
|
|
|
868
912
|
def print_coupling_beams(self, combo_name: str = 'Combo 1') -> None:
|
|
869
|
-
"""
|
|
870
|
-
"""
|
|
913
|
+
"""Print coupling-beam forces at both the left and right ends."""
|
|
871
914
|
|
|
872
915
|
# Create a PrettyTable object
|
|
873
916
|
table = PrettyTable()
|
|
874
917
|
|
|
875
918
|
# Define the headers
|
|
876
|
-
table.field_names = ["ID", "Length", "Height", "M/(VH)", "V", "M", "P"]
|
|
919
|
+
table.field_names = ["ID", "Length", "Height", "Location", "M/(VH)", "V", "M", "P"]
|
|
877
920
|
|
|
878
|
-
# Add rows to the table
|
|
921
|
+
# Add rows to the table for both ends of each coupling beam
|
|
879
922
|
for beam_id, beam in self.coupling_beams.items():
|
|
880
|
-
|
|
881
|
-
|
|
923
|
+
P_left, M_left, V_left, M_VH_left = beam.sum_forces(combo_name, 'left')
|
|
924
|
+
P_right, M_right, V_right, M_VH_right = beam.sum_forces(combo_name, 'right')
|
|
925
|
+
table.add_row([beam.name, beam.length, beam.height, 'Left', M_VH_left, V_left, M_left, P_left])
|
|
926
|
+
table.add_row([beam.name, beam.length, beam.height, 'Right', M_VH_right, V_right, M_right, P_right])
|
|
882
927
|
|
|
883
928
|
# Print the table
|
|
884
929
|
print('+----------------------------+')
|
|
@@ -949,7 +994,12 @@ class Pier():
|
|
|
949
994
|
def __repr__(self) -> str:
|
|
950
995
|
return f"Pier(name={self.name!r}, width={self.width}, height={self.height})"
|
|
951
996
|
|
|
952
|
-
def sum_forces(self, combo_name: str = 'Combo 1') -> Tuple[float, float, float, float]:
|
|
997
|
+
def sum_forces(self, combo_name: str = 'Combo 1', location: Literal['bottom', 'top'] = 'bottom') -> Tuple[float, float, float, float]:
|
|
998
|
+
"""Return ``(P, M, V, M_over_VL)`` at the pier bottom or top.
|
|
999
|
+
|
|
1000
|
+
``location`` defaults to ``'bottom'`` for backward compatibility.
|
|
1001
|
+
The force signs match the internal-result convention used by members.
|
|
1002
|
+
"""
|
|
953
1003
|
|
|
954
1004
|
# Initialize the forces in the plate
|
|
955
1005
|
P, M, V = 0, 0, 0
|
|
@@ -960,30 +1010,62 @@ class Pier():
|
|
|
960
1010
|
xi, yi, zi = _global2local(plate.i_node.X, plate.i_node.Y, plate.i_node.Z, self.origin, self.plane)
|
|
961
1011
|
xj, yj, zj = _global2local(plate.j_node.X, plate.j_node.Y, plate.j_node.Z, self.origin, self.plane)
|
|
962
1012
|
|
|
963
|
-
|
|
964
|
-
if isclose(yi, self.y):
|
|
1013
|
+
if location == 'bottom':
|
|
965
1014
|
|
|
966
|
-
#
|
|
967
|
-
|
|
968
|
-
Pj = plate.f(combo_name)[7][0]
|
|
969
|
-
P += -Pi - Pj
|
|
1015
|
+
# Determine if this plate is at the bottom of the pier
|
|
1016
|
+
if isclose(yi, self.y):
|
|
970
1017
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
Mj = plate.f(combo_name)[7][0]*xj_p
|
|
976
|
-
M += -Mi - Mj
|
|
1018
|
+
# Find and sum the axial forces in this plate
|
|
1019
|
+
Pi = plate.f(combo_name)[1][0]
|
|
1020
|
+
Pj = plate.f(combo_name)[7][0]
|
|
1021
|
+
P += Pi + Pj
|
|
977
1022
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1023
|
+
# Find and sum the moments about the pier's center in this plate
|
|
1024
|
+
xi_p = xi - (self.x + self.width/2)
|
|
1025
|
+
xj_p = xj - (self.x + self.width/2)
|
|
1026
|
+
Mi = Pi*xi_p
|
|
1027
|
+
Mj = Pj*xj_p
|
|
1028
|
+
M += Mi + Mj
|
|
1029
|
+
|
|
1030
|
+
# Find and sum the shear forces in this plate
|
|
1031
|
+
# Check if this is a flange plate or a web plate
|
|
1032
|
+
if isclose(xi, xj):
|
|
1033
|
+
Vi = -plate.f(combo_name)[2][0]
|
|
1034
|
+
Vj = -plate.f(combo_name)[8][0]
|
|
1035
|
+
else:
|
|
1036
|
+
Vi = -plate.f(combo_name)[0][0]
|
|
1037
|
+
Vj = -plate.f(combo_name)[6][0]
|
|
1038
|
+
V += Vi + Vj
|
|
1039
|
+
|
|
1040
|
+
else:
|
|
1041
|
+
|
|
1042
|
+
xm, ym, zm = _global2local(plate.m_node.X, plate.m_node.Y, plate.m_node.Z, self.origin, self.plane)
|
|
1043
|
+
xn, yn, zn = _global2local(plate.n_node.X, plate.n_node.Y, plate.n_node.Z, self.origin, self.plane)
|
|
1044
|
+
|
|
1045
|
+
# Determine if this plate is at the top of the pier
|
|
1046
|
+
if isclose(ym, self.y + self.height):
|
|
1047
|
+
|
|
1048
|
+
# Find and sum the axial forces in this plate
|
|
1049
|
+
Pm = plate.f(combo_name)[13][0]
|
|
1050
|
+
Pn = plate.f(combo_name)[19][0]
|
|
1051
|
+
P += -Pm - Pn
|
|
1052
|
+
|
|
1053
|
+
# Find and sum the moments about the pier's center in this plate
|
|
1054
|
+
xm_p = xm - (self.x + self.width/2)
|
|
1055
|
+
xn_p = xn - (self.x + self.width/2)
|
|
1056
|
+
Mm = Pm*xm_p
|
|
1057
|
+
Mn = Pn*xn_p
|
|
1058
|
+
M += -Mm - Mn
|
|
1059
|
+
|
|
1060
|
+
# Find and sum the shear forces in this plate
|
|
1061
|
+
# Check if this is a flange plate or a web plate
|
|
1062
|
+
if isclose(xm, xn):
|
|
1063
|
+
Vm = -plate.f(combo_name)[14][0]
|
|
1064
|
+
Vn = -plate.f(combo_name)[20][0]
|
|
1065
|
+
else:
|
|
1066
|
+
Vm = -plate.f(combo_name)[12][0]
|
|
1067
|
+
Vn = -plate.f(combo_name)[18][0]
|
|
1068
|
+
V += -Vm - Vn
|
|
987
1069
|
|
|
988
1070
|
# Calculate the shear span ratio
|
|
989
1071
|
M_VL = M/(V*self.width)
|
|
@@ -996,6 +1078,7 @@ class Pier():
|
|
|
996
1078
|
class CouplingBeam():
|
|
997
1079
|
|
|
998
1080
|
def __init__(self, name: str, x: float, y: float, length: float, height: float, shear_wall: ShearWall) -> None:
|
|
1081
|
+
|
|
999
1082
|
self.name: str = name
|
|
1000
1083
|
self.x: float = x # The location of the left side of the coupling beam
|
|
1001
1084
|
self.y: float = y # The height to the bottom of the coupling beam
|
|
@@ -1010,9 +1093,15 @@ class CouplingBeam():
|
|
|
1010
1093
|
self.plates: List[Quad3D | Plate3D] = []
|
|
1011
1094
|
|
|
1012
1095
|
def __repr__(self) -> str:
|
|
1096
|
+
|
|
1013
1097
|
return f"CouplingBeam(name={self.name!r}, length={self.length}, height={self.height})"
|
|
1014
1098
|
|
|
1015
|
-
def sum_forces(self, combo_name: str = 'Combo 1') -> Tuple[float, float, float, float]:
|
|
1099
|
+
def sum_forces(self, combo_name: str = 'Combo 1', location: Literal['left', 'right'] = 'left') -> Tuple[float, float, float, float]:
|
|
1100
|
+
"""Return ``(P, M, V, M_over_VH)`` at the beam left or right end.
|
|
1101
|
+
|
|
1102
|
+
``location`` defaults to ``'left'`` for backward compatibility. The
|
|
1103
|
+
force signs match the internal-result convention used by members.
|
|
1104
|
+
"""
|
|
1016
1105
|
|
|
1017
1106
|
# Initialize plate forces to zero
|
|
1018
1107
|
P, M, V = 0, 0, 0
|
|
@@ -1024,34 +1113,69 @@ class CouplingBeam():
|
|
|
1024
1113
|
xj, yj, zj = _global2local(plate.j_node.X, plate.j_node.Y, plate.j_node.Z, self.origin, self.plane)
|
|
1025
1114
|
xn, yn, zn = _global2local(plate.n_node.X, plate.n_node.Y, plate.n_node.Z, self.origin, self.plane)
|
|
1026
1115
|
|
|
1027
|
-
|
|
1028
|
-
if isclose(xi, self.x):
|
|
1116
|
+
if location == 'left':
|
|
1029
1117
|
|
|
1030
|
-
#
|
|
1031
|
-
if isclose(xi,
|
|
1118
|
+
# Determine if this plate is at the left edge of the coupling beam
|
|
1119
|
+
if isclose(xi, self.x):
|
|
1032
1120
|
|
|
1033
|
-
#
|
|
1034
|
-
|
|
1121
|
+
# Check if this is a wall flange plate or a wall web plate
|
|
1122
|
+
if isclose(xi, xj):
|
|
1035
1123
|
|
|
1036
|
-
|
|
1124
|
+
# Plates that form wall flanges should not affect coupling beams, so forces will not be summed
|
|
1125
|
+
pass
|
|
1037
1126
|
|
|
1038
|
-
|
|
1039
|
-
Pi = plate.f(combo_name)[0][0]
|
|
1040
|
-
Pn = plate.f(combo_name)[18][0]
|
|
1041
|
-
P += -Pi - Pn
|
|
1127
|
+
else:
|
|
1042
1128
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
Mn = plate.f(combo_name)[18][0]*xn_cb
|
|
1048
|
-
M += -Mi - Mn
|
|
1129
|
+
# Find and sum the axial forces in this plate
|
|
1130
|
+
Pi = plate.f(combo_name)[0][0]
|
|
1131
|
+
Pn = plate.f(combo_name)[18][0]
|
|
1132
|
+
P += Pi + Pn
|
|
1049
1133
|
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1134
|
+
# Find and sum the moments about the coupling beam's center in this plate
|
|
1135
|
+
yi_cb = yi - (self.y + self.height/2)
|
|
1136
|
+
yn_cb = yn - (self.y + self.height/2)
|
|
1137
|
+
Mi = plate.f(combo_name)[0][0]*yi_cb
|
|
1138
|
+
Mn = plate.f(combo_name)[18][0]*yn_cb
|
|
1139
|
+
M += -Mi - Mn
|
|
1140
|
+
|
|
1141
|
+
# Find and sum the shear forces in this plate
|
|
1142
|
+
Vi = -plate.f(combo_name)[1][0]
|
|
1143
|
+
Vn = -plate.f(combo_name)[19][0]
|
|
1144
|
+
|
|
1145
|
+
V += -Vi - Vn
|
|
1146
|
+
|
|
1147
|
+
else:
|
|
1148
|
+
|
|
1149
|
+
xm, ym, zm = _global2local(plate.m_node.X, plate.m_node.Y, plate.m_node.Z, self.origin, self.plane)
|
|
1150
|
+
|
|
1151
|
+
# Determine if this plate is at the right edge of the coupling beam
|
|
1152
|
+
if isclose(xj, self.x + self.length):
|
|
1153
|
+
|
|
1154
|
+
# Check if this is a wall flange plate or a wall web plate
|
|
1155
|
+
if isclose(xi, xj):
|
|
1156
|
+
|
|
1157
|
+
# Plates that form wall flanges should not affect coupling beams, so forces will not be summed
|
|
1158
|
+
pass
|
|
1159
|
+
|
|
1160
|
+
else:
|
|
1161
|
+
|
|
1162
|
+
# Find and sum the axial forces in this plate
|
|
1163
|
+
Pj = plate.f(combo_name)[6][0]
|
|
1164
|
+
Pm = plate.f(combo_name)[12][0]
|
|
1165
|
+
P += -Pj - Pm
|
|
1166
|
+
|
|
1167
|
+
# Find and sum the moments about the coupling beam's center in this plate
|
|
1168
|
+
yj_cb = yj - (self.y + self.height/2)
|
|
1169
|
+
ym_cb = ym - (self.y + self.height/2)
|
|
1170
|
+
Mj = plate.f(combo_name)[6][0]*yj_cb
|
|
1171
|
+
Mm = plate.f(combo_name)[12][0]*ym_cb
|
|
1172
|
+
M += Mj + Mm
|
|
1173
|
+
|
|
1174
|
+
# Find and sum the shear forces in this plate
|
|
1175
|
+
Vj = -plate.f(combo_name)[7][0]
|
|
1176
|
+
Vm = -plate.f(combo_name)[13][0]
|
|
1053
1177
|
|
|
1054
|
-
|
|
1178
|
+
V += Vj + Vm
|
|
1055
1179
|
|
|
1056
1180
|
# Calculate the shear span ratio
|
|
1057
1181
|
M_VH = M/(V*self.height)
|
|
@@ -69,6 +69,12 @@ Here's a list of projects that use Pynite:
|
|
|
69
69
|
* Phaenotyp (https://github.com/bewegende-Architektur/Phaenotyp) (https://youtu.be/shloSw9HjVI)
|
|
70
70
|
|
|
71
71
|
# What's New?
|
|
72
|
+
3.2.0
|
|
73
|
+
* Added shear wall pier top results and coupling beam right hand side results to the pier/coupling beam force results output.
|
|
74
|
+
* Adjusted shear wall pier and coupling beam internal force results sign convention to match the sign convention used for members.
|
|
75
|
+
* Added targeted testing for shear wall pier and coupling beam sign convention and load magnitudes.
|
|
76
|
+
* Added shear wall docstrings and a readthedocs documentation page.
|
|
77
|
+
|
|
72
78
|
3.1.0
|
|
73
79
|
* Improved detection of unstable structures.
|
|
74
80
|
* Bug fix for shear walls. Shear walls were erroneously tracking other plates in the model for internal pier/coupling beam force summations, rather than just the plates related to the individual shear wall.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "PyNiteFEA"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.2.0"
|
|
8
8
|
description = "A simple 3D structural finite element library for Python."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
requires-python = ">=3.11"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|