@@ -37,6 +37,7 @@ class Forces:
3737 _N_x : Quantity = field (default = 0 * kN ) # Ensure you use the correct unit type here
3838 _V_z : Quantity = field (default = 0 * kN )
3939 _M_y : Quantity = field (default = 0 * kNm )
40+ _M_x : Quantity = field (default = 0 * kNm )
4041 unit_system : str = field (default = "metric" ) # Add unit_system as a field
4142
4243 def __init__ (
@@ -45,6 +46,7 @@ def __init__(
4546 N_x : Quantity = 0 * kN ,
4647 V_z : Quantity = 0 * kN ,
4748 M_y : Quantity = 0 * kNm ,
49+ M_x : Quantity = 0 * kNm ,
4850 unit_system : str = "metric" ,
4951 ) -> None :
5052 # Increment the class variable for the next unique ID
@@ -56,7 +58,7 @@ def __init__(
5658 self .unit_system = unit_system # Set the unit system
5759
5860 # Set the forces upon initialization
59- self .set_forces (N_x , V_z , M_y )
61+ self .set_forces (N_x , V_z , M_y , M_x )
6062
6163 @property
6264 def id (self ) -> int :
@@ -92,26 +94,43 @@ def M_y(self) -> Quantity:
9294 else :
9395 return self ._M_y .to ("ft*kip" )
9496
97+ @property
98+ def M_x (self ) -> Quantity :
99+ """Bending moment about the x-axis — used for biaxial punching shear (default is 0 kN*m)."""
100+ if self .unit_system == "metric" :
101+ return self ._M_x .to ("kN*m" )
102+ else :
103+ return self ._M_x .to ("ft*kip" )
104+
95105 def get_forces (self ) -> Dict [str , Quantity ]:
96- """Returns the forces as a dictionary with keys 'N_x', 'V_z', and 'M_y '."""
106+ """Returns the forces as a dictionary with keys 'N_x', 'V_z', 'M_y', and 'M_x '."""
97107 if self .unit_system == "metric" :
98108 return {
99109 "N_x" : self ._N_x .to ("kN" ),
100110 "V_z" : self ._V_z .to ("kN" ),
101111 "M_y" : self ._M_y .to ("kN*m" ),
112+ "M_x" : self ._M_x .to ("kN*m" ),
102113 }
103114 else :
104115 return {
105116 "N_x" : self ._N_x .to ("kip" ),
106117 "V_z" : self ._V_z .to ("kip" ),
107118 "M_y" : self ._M_y .to ("ft*kip" ),
119+ "M_x" : self ._M_x .to ("ft*kip" ),
108120 }
109121
110- def set_forces (self , N_x : Quantity = 0 * kN , V_z : Quantity = 0 * kN , M_y : Quantity = 0 * kNm ) -> None :
122+ def set_forces (
123+ self ,
124+ N_x : Quantity = 0 * kN ,
125+ V_z : Quantity = 0 * kN ,
126+ M_y : Quantity = 0 * kNm ,
127+ M_x : Quantity = 0 * kNm ,
128+ ) -> None :
111129 """Sets the forces in the object."""
112130 self ._N_x = N_x
113131 self ._V_z = V_z
114132 self ._M_y = M_y
133+ self ._M_x = M_x
115134
116135 def compare_to (self , other : "Forces" , by : str = "V_z" ) -> bool :
117136 """Compares this force with another force based on a selected attribute.
@@ -121,16 +140,19 @@ def compare_to(self, other: "Forces", by: str = "V_z") -> bool:
121140 other : Forces
122141 Another Forces instance to compare with.
123142 by : str
124- The attribute to compare by ('N_x', 'V_z', or 'M_y ').
143+ The attribute to compare by ('N_x', 'V_z', 'M_y', or 'M_x ').
125144
126145 Returns
127146 -------
128147 bool
129148 True if this force is greater than the other force by the selected attribute.
130149 """
131- if by not in ["N_x" , "V_z" , "M_y" ]:
132- raise ValueError ("Comparison attribute must be one of 'N_x', 'V_z', or 'M_y '" )
150+ if by not in ["N_x" , "V_z" , "M_y" , "M_x" ]:
151+ raise ValueError ("Comparison attribute must be one of 'N_x', 'V_z', 'M_y', or 'M_x '" )
133152 return getattr (self , by ).magnitude > getattr (other , by ).magnitude
134153
135154 def __str__ (self ) -> str :
136- return f"Force ID: { self .id } , Label: { self .label } , " f"N_x: { self .N_x } , V_z: { self .V_z } , M_y: { self .M_y } "
155+ base = f"Force ID: { self .id } , Label: { self .label } , N_x: { self .N_x } , V_z: { self .V_z } , M_y: { self .M_y } "
156+ if self ._M_x .magnitude != 0 :
157+ base += f", M_x: { self .M_x } "
158+ return base
0 commit comments