Skip to content

Commit f0c365a

Browse files
committed
Fix redundant code + add physical member unit test
1 parent ecb7c5c commit f0c365a

File tree

2 files changed

+63
-16
lines changed

2 files changed

+63
-16
lines changed

PyNite/PhysMember.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,13 @@ def descritize(self):
6868
# Generate the sub-member's name (physical member name + a, b, c, etc.)
6969
name = self.name + chr(i+97)
7070

71+
# Find the i and j nodes for the sub-member, and their positions along the physical
72+
# member's local x-axis
7173
i_node = int_nodes[i][0]
7274
j_node = int_nodes[i+1][0]
7375
xi = int_nodes[i][1]
7476
xj = int_nodes[i+1][1]
7577

76-
# Find the start and end points of the sub-member in the physical member's
77-
# local coordinate system
78-
x1_mem = ((i_node.X - Xi)**2 + (i_node.Y - Yi)**2 + (i_node.Z - Zi)**2)**0.5
79-
x2_mem = ((j_node.X - Xi)**2 + (j_node.Y - Yi)**2 + (j_node.Z - Zi)**2)**0.5
80-
8178
# Create a new sub-member
8279
new_sub_member = Member3D(name, i_node, j_node, self.E, self.G, self.Iy, self.Iz, self.J, self.A, self.model, self.auxNode, self.tension_only, self.comp_only)
8380

@@ -100,7 +97,7 @@ def descritize(self):
10097
x2_load = dist_load[4]
10198

10299
# Determine if the distributed load should be applied to this segment
103-
if x1_load <= x2_mem and x2_load > x1_mem:
100+
if x1_load <= xj and x2_load > xi:
104101

105102
direction = dist_load[0]
106103
w1 = dist_load[1]
@@ -111,17 +108,17 @@ def descritize(self):
111108
w = lambda x: (w2 - w1)/(x2_load - x1_load)*(x - x1_load) + w1
112109

113110
# Chop up the distributed load for the sub-member
114-
if x1_load > x1_mem:
115-
x1 = x1_load - x1_mem
111+
if x1_load > xi:
112+
x1 = x1_load - xi
116113
else:
117114
x1 = 0
118-
w1 = w(x1_mem)
115+
w1 = w(xi)
119116

120-
if x2_load < x2_mem:
121-
x2 = x2_load - x1_mem
117+
if x2_load < xj:
118+
x2 = x2_load - xi
122119
else:
123-
x2 = x2_mem
124-
w2 = w(x2_mem)
120+
x2 = xj
121+
w2 = w(xj)
125122

126123
# Add the load to the sub-member
127124
new_sub_member.DistLoads.append([direction, w1, w2, x1, x2, case])
@@ -135,9 +132,9 @@ def descritize(self):
135132
case = pt_load[3]
136133

137134
# Determine if the point load should be applied to this segment
138-
if x >= x1_mem and x < x2_mem or isclose(x, self.L()):
135+
if x >= xi and x < xj or isclose(x, self.L()):
139136

140-
x = x - x1_mem
137+
x = x - xi
141138

142139
# Add the load to the sub-member
143140
new_sub_member.PtLoads.append([direction, P, x, case])

Testing/test_AISC_PDelta_benchmarks.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def tearDown(self):
2727
# Reset the print function to normal
2828
sys.stdout = sys.__stdout__
2929

30-
def test_AISC_Benchmark(self):
30+
def test_AISC_Benchmark_PhysMember(self):
3131

3232
# Create the cantilever model
3333
cantilever = FEModel3D()
@@ -80,6 +80,56 @@ def test_AISC_Benchmark(self):
8080
Mmax = H*L*(math.tan(alpha)/alpha)
8181
ymax = H*L**3/(3*E*I)*(3*(math.tan(alpha)-alpha)/alpha**3)
8282

83+
# Compare the calculation results
84+
# self.assertAlmostEqual(calculated_moment/Mmax, 1.0, 1)
85+
# self.assertAlmostEqual(calculated_displacement/(ymax*12), 1.0, 1)
86+
87+
def test_AISC_Benckmark_Segments(self):
88+
# Create the cantilever model
89+
cantilever = FEModel3D()
90+
91+
# Define the column and its properties
92+
L = 20 # ft
93+
H = 5 # kips lateral load
94+
P = 100 # kips axial load
95+
G = 11200*12**2 # shear modulus (ksf)
96+
E = 29000*12**2 # modulus of elasticity (ksf)
97+
I = 100/12**4 # moment of inertia (ft^4)
98+
99+
# Break the column into several segments in order to capture P-little-delta effects
100+
num_segs = 5
101+
num_nodes = num_segs + 1
102+
for i in range(num_nodes):
103+
# Add nodes
104+
cantilever.add_node(str(i+1), 0, i*L/(num_segs), 0)
105+
106+
for i in range(num_segs):
107+
# Add members between nodes
108+
cantilever.add_member(str(i+1), str(i+1), str(i+2), E, G, I, I, 200/12**4, 10/12**2)
109+
110+
# Add a fixed support at the base of the column
111+
cantilever.def_support('1', True, True, True, True, True, True)
112+
113+
# Add a -10 kip axial load to the top of the column
114+
cantilever.add_node_load(str(num_nodes), 'FY', -P)
115+
116+
# Add a 5 kip lateral load to the top of the column
117+
cantilever.add_node_load(str(num_nodes), 'FX', H)
118+
119+
# Perform 2nd order analysis
120+
cantilever.analyze_PDelta()
121+
122+
# The moment at the base of the column
123+
calculated_moment = cantilever.Nodes['1'].RxnMZ['Combo 1']
124+
125+
# the deflection at the top of the column
126+
calculated_displacement = cantilever.Nodes[str(num_nodes)].DX['Combo 1']*12
127+
128+
# Calculate the AISC benchmark problem solution:
129+
alpha = (P*L**2/(E*I))**0.5
130+
Mmax = H*L*(math.tan(alpha)/alpha)
131+
ymax = H*L**3/(3*E*I)*(3*(math.tan(alpha)-alpha)/alpha**3)
132+
83133
# Compare the calculation results
84134
self.assertAlmostEqual(calculated_moment/Mmax, 1.0, 1)
85135
self.assertAlmostEqual(calculated_displacement/(ymax*12), 1.0, 1)

0 commit comments

Comments
 (0)