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.
Files changed (35) hide show
  1. {pynitefea-3.1.0 → pynitefea-3.2.0}/PKG-INFO +7 -1
  2. {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/PKG-INFO +7 -1
  3. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/ShearWall.py +181 -57
  4. {pynitefea-3.1.0 → pynitefea-3.2.0}/README.md +6 -0
  5. {pynitefea-3.1.0 → pynitefea-3.2.0}/pyproject.toml +1 -1
  6. {pynitefea-3.1.0 → pynitefea-3.2.0}/LICENSE +0 -0
  7. {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/SOURCES.txt +0 -0
  8. {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/dependency_links.txt +0 -0
  9. {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/requires.txt +0 -0
  10. {pynitefea-3.1.0 → pynitefea-3.2.0}/PyNiteFEA.egg-info/top_level.txt +0 -0
  11. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Analysis.py +0 -0
  12. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/BeamSegY.py +0 -0
  13. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/BeamSegZ.py +0 -0
  14. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/FEModel3D.py +0 -0
  15. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/FixedEndReactions.py +0 -0
  16. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/LoadCombo.py +0 -0
  17. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/MainStyleSheet.css +0 -0
  18. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/MatFoundation.py +0 -0
  19. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Material.py +0 -0
  20. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Member3D.py +0 -0
  21. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Mesh.py +0 -0
  22. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Node3D.py +0 -0
  23. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/PhysMember.py +0 -0
  24. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Plate3D.py +0 -0
  25. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Quad3D.py +0 -0
  26. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Rendering.py +0 -0
  27. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Report_Template.html +0 -0
  28. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Reporting.py +0 -0
  29. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Section.py +0 -0
  30. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Spring3D.py +0 -0
  31. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Tri3D.py +0 -0
  32. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/VTKWriter.py +0 -0
  33. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/Visualization.py +0 -0
  34. {pynitefea-3.1.0 → pynitefea-3.2.0}/Pynite/__init__.py +0 -0
  35. {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.1.0
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.1.0
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
- self._openings.append([name, x_start, y_start, width, height, None])
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
- """Tabulates and prints pier results for the shear wall
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
- P, M, V, M_VL = pier.sum_forces(combo_name)
860
- table.add_row([pier.name, pier.width, pier.height, M_VL, V, M, P])
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
- """Tabulates and prints coupling beam results for the shear wall
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
- P, M, V, M_VL = beam.sum_forces(combo_name)
881
- table.add_row([beam.name, beam.length, beam.height, M_VL, V, M, P])
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
- # Determine if this plate is at the bottom of the pier
964
- if isclose(yi, self.y):
1013
+ if location == 'bottom':
965
1014
 
966
- # Find and sum the axial forces in this plate
967
- Pi = plate.f(combo_name)[1][0]
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
- # Find and sum the moments about the pier's center in this plate
972
- xi_p = xi - (self.x + self.width/2)
973
- xj_p = xj - (self.x + self.width/2)
974
- Mi = plate.f(combo_name)[1][0]*xi_p
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
- # Find and sum the shear forces in this plate
979
- # Check if this is a flange plate or a web plate
980
- if isclose(xi, xj):
981
- Vi = -plate.f(combo_name)[2][0]
982
- Vj = -plate.f(combo_name)[8][0]
983
- else:
984
- Vi = -plate.f(combo_name)[0][0]
985
- Vj = -plate.f(combo_name)[6][0]
986
- V += -Vi - Vj
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
- # Determine if this plate is at the left edge of the coupling beam
1028
- if isclose(xi, self.x):
1116
+ if location == 'left':
1029
1117
 
1030
- # Check if this is a wall flange plate or a wall web plate
1031
- if isclose(xi, xj):
1118
+ # Determine if this plate is at the left edge of the coupling beam
1119
+ if isclose(xi, self.x):
1032
1120
 
1033
- # Plates that form wall flanges should not affect coupling beams, so forces will not be summed
1034
- pass
1121
+ # Check if this is a wall flange plate or a wall web plate
1122
+ if isclose(xi, xj):
1035
1123
 
1036
- else:
1124
+ # Plates that form wall flanges should not affect coupling beams, so forces will not be summed
1125
+ pass
1037
1126
 
1038
- # Find and sum the axial forces in this plate
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
- # Find and sum the moments about the coupling beam's center in this plate
1044
- xi_cb = yi - (self.y + self.height/2)
1045
- xn_cb = yn - (self.y + self.height/2)
1046
- Mi = plate.f(combo_name)[0][0]*xi_cb
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
- # Find and sum the shear forces in this plate
1051
- Vi = -plate.f(combo_name)[1][0]
1052
- Vn = -plate.f(combo_name)[19][0]
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
- V += -Vi - Vn
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.1.0"
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