def long_cantilever_500_members(): Cantilever = FEModel3D() # Adding in 1001 nodes 1ft apart, building it out from left to right for i in range(501): Cantilever.AddNode(f"N{i + 1}", i, 0, 0) # Adding in 1000 members end to end, building it out from left to right # AISC W8x31 # E = 29000 ksi, G = 11200 ksi, Iy = 37.1 in^4, Iz = 110 in^4, J = 0.536 in^4, A = 9.13 in^2 for i in range(500): Cantilever.AddMember(Name=f"M{i + 1}", iNode=f"N{i + 1}", jNode=f"N{i + 2}", E=29000, G=11200, Iy=37.1, Iz=110, J=0.536, A=9.13) # Fixed end on left end Cantilever.DefineSupport("N1", True, True, True, True, True, True) return Cantilever
def test_unstable_supports(self): # This test checks the PyNite's ability to detect unstable support conditions # Units used in this test are inches, and kips MomentFrame = FEModel3D() # Add nodes (frame is 15 ft wide x 12 ft tall) MomentFrame.AddNode("N1", 0, 0, 0) MomentFrame.AddNode("N2", 0, 12 * 12, 0) MomentFrame.AddNode("N3", 15 * 12, 12 * 12, 0) MomentFrame.AddNode("N4", 15 * 12, 0 * 12, 0) # Add columns with the following properties: # E = 29000 ksi, G = 11400 ksi, Iy = 100 in^4, Iz = 150 in^4, J = 250 in^4, A = 10 in^2 MomentFrame.AddMember("M1", "N1", "N2", 29000, 11400, 100, 150, 250, 10) MomentFrame.AddMember("M2", "N4", "N3", 29000, 11400, 100, 150, 250, 10) # Add a beam with the following properties: # E = 29000 ksi, G = 11400 ksi, Iy = 100 in^4, Iz = 250 in^4, J = 250 in^4, A = 15 in^2 MomentFrame.AddMember("M3", "N2", "N3", 29000, 11400, 100, 250, 250, 15) # Provide unstable supports (unsupported in DY) MomentFrame.DefineSupport("N1", True, False, True, True, True, True) # Add a nodal lateral load of 50 kips at the left side of the frame MomentFrame.AddNodeLoad("N2", "FX", 50) # Analyze the frame - we should see an error message that the structure is unstable with self.assertRaises(Exception): MomentFrame.Analyze()
def test_member_torque_load(self): TorqueBeam = FEModel3D() # Add nodes (14 ft = 168 in apart) TorqueBeam.add_node('N1', 0, 0, 0) TorqueBeam.add_node('N2', 168, 0, 0) # Add a beam with the following properties: TorqueBeam.add_member('M1', 'N1', 'N2', 29000, 11400, 100, 150, 250, 20) # Provide fixed supports TorqueBeam.def_support('N1', False, True, True, True, True, True) TorqueBeam.def_support('N2', True, True, True, True, True, True) # Add a point load of 5 kip-ft and 10 kip-ft at 3ft and 11 ft along the beam respectively TorqueBeam.add_member_pt_load('M1', 'Mx', 5, 3 * 12) TorqueBeam.add_member_pt_load('M1', 'Mx', 10, 11 * 12) TorqueBeam.analyze(check_statics=True) # Support reactions (around local x axis) at each end left_Rxn = TorqueBeam.Nodes['N1'].RxnMX['Combo 1'] # subTest context manager prints which portion fails, if any with self.subTest(left_Rxn=left_Rxn): self.assertAlmostEqual(left_Rxn, -6.07, 2) right_Rxn = TorqueBeam.Nodes['N2'].RxnMX['Combo 1'] with self.subTest(right_Rxn=right_Rxn): self.assertAlmostEqual(right_Rxn, -8.93, 2) # Max/min torques on the beam max_torque = TorqueBeam.Members['M1'].max_torque() with self.subTest(max_torque=max_torque): self.assertAlmostEqual(max_torque, 8.93, 2) min_torque = TorqueBeam.Members['M1'].min_torque() with self.subTest(min_torque=min_torque): self.assertAlmostEqual(min_torque, -6.07, 2)
def test_XZ_ptload(self): # A simply supported beam with a point load. # Units used in this example are inches, and kips SimpleBeam = FEModel3D() # Add nodes (14 ft = 168 in apart) SimpleBeam.AddNode("N1", 0, 0, 0) SimpleBeam.AddNode("N2", 0, 0, 168) # Add a beam with the following properties: A = 20 E = 29000 G = 11400 Iy = 100 Iz = 150 J = 250 SimpleBeam.AddMember("M1", "N1", "N2", E, G, Iy, Iz, J, A) # Provide simple supports SimpleBeam.DefineSupport("N1", True, True, True, False, False, True) SimpleBeam.DefineSupport("N2", True, True, True, False, False, False) # Add a point load of 5 kips at the midspan of the beam SimpleBeam.AddMemberPtLoad("M1", "Fy", 5, 7 * 12) # Analyze the beam SimpleBeam.Analyze(False) # Print reactions at each end of the beam correct_reactions = [('N1', -2.5), ('N2', -2.5)] for node_name, rxn in correct_reactions: with self.subTest(node=node_name): calculated_reaction = SimpleBeam.GetNode(node_name).RxnFY['Combo 1'] # Two decimal place accuracy requires +/-0.5% accuracy # one decimal place requires +/-5% self.assertAlmostEqual(calculated_reaction/rxn, 1.0, 2)
def test_hydrostatic_plate(self): # Establish problem parameters t = 1 # ft E = 57000 * math.sqrt(4500) * 12**2 # psf nu = 1 / 6 mesh_size = 1 # ft a = 10 # ft b = 15 # ft # Generate the mesh of plates plate_mesh = RectangleMesh(mesh_size, a, b, t, E, nu, kx_mod=1, ky_mod=1, element_type='Rect') plate_mesh.generate() # Create the model and add the plates plate_model = FEModel3D() plate_model.add_mesh(plate_mesh) # Add supports to the sides and base of the wall for node in plate_model.Nodes.values(): if node.X == 0 or node.X == a or node.Y == 0: plate_model.def_support(node.name, True, True, True, True, True, True) # Add hydrostatic loads to the elements for element in plate_model.Plates.values(): Yavg = (element.i_node.Y + element.j_node.Y + element.m_node.Y + element.n_node.Y) / 4 p = 62.4 * (b - Yavg) plate_model.add_plate_surface_pressure(element.name, p, 'Hydrostatic') # Add a load combination to the model plate_model.add_load_combo('F', {'Hydrostatic': 1.0}) # Analyze the model plate_model.analyze() # Get the maximum deflection in the model at the top of the wall DZ_calcd = max([ node.DZ['F'] for node in plate_model.Nodes.values() if node.Y == b ]) # Find the maximum deflection at the top of the wall from Timoshenko's Table 45 q = 62.4 * b D = E * t**3 / (12 * (1 - nu**2)) DZ_expected = 0.00042 * q * a**4 / D # Check that the PyNite calculated values are within 15% of the Timoshenko calculated # values. self.assertLess(abs(DZ_calcd / DZ_expected - 1), 0.15, 'Failed Timoshenko rectangle hydrostatic test.')
def test_XY_member_ptload(self): frame = FEModel3D() # Add nodes frame.AddNode('N1', 0, 0, 0) # ft frame.AddNode('N2', 0, 7.667, 0) # ft frame.AddNode('N3', 7.75, 7.667, 0) # ft frame.AddNode('N4', 7.75, 0, 0) # ft # Add supports frame.DefineSupport('N1', True, True, True, True, True, False) frame.DefineSupport('N4', True, True, True, True, True, False) # Define material and section properties for a W8x24 E = 29000*12**2 # ksf G = 1111200*12**2 # ksf Iy = 18.3/12**4 # ft^4 Iz = 82.7/12**4 # ft^4 J = 0.346/12**4 # ft^4 A = 5.26/12**2 # in^2 # Define members frame.AddMember('M1', 'N1', 'N2', E, G, Iy, Iz, J, A) frame.AddMember('M2', 'N2', 'N3', E, G, Iy, Iz, J, A) frame.AddMember('M3', 'N4', 'N3', E, G, Iy, Iz, J, A) # Add loads to the frame frame.AddMemberPtLoad('M2', 'Fy', -5, 7.75/2) # 5 kips @ midspan frame.AddMemberDistLoad('M2', 'Fy', -0.024, -0.024) # W8x24 self-weight # Analyze the frame frame.Analyze() calculated_RZ = frame.GetNode('N1').RZ['Combo 1'] # Update the expected value to an appropriate precision expected_RZ = 0.00022794540510395617 self.assertAlmostEqual(calculated_RZ/expected_RZ, 1.0, 2)
def pin_fixed_beam(length): PinFixBeam = FEModel3D() # Add nodes (14 ft = 168 in apart) PinFixBeam.AddNode("N1", 0, 0, 0) PinFixBeam.AddNode("N2", length, 0, 0) # Add a beam with the following properties: # E = 29000 ksi, G = 11200 ksi, Iy = 100 in^4, Iz = 150 in^4, J = 250 in^4, A = 20 in^2 PinFixBeam.AddMember("M1", "N1", "N2", E=29000, G=11200, Iy=100, Iz=150, J=250, A=20) # Supports: Pin, Fixed PinFixBeam.DefineSupport("N1", SupportDX=True, SupportDY=True, SupportDZ=True, SupportRX=True) PinFixBeam.DefineSupport("N2", SupportDX=True, SupportDY=True, SupportDZ=True, SupportRX=True, SupportRZ=True) return PinFixBeam
def test_axial_distributed_load(self): # Units N e m Beam = FEModel3D() L = 5 # m # Nodes Beam.add_node("N1", 0, 0, 0) Beam.add_node("N2", L, 0, 0) # Beams (30x50 cm) E = 2.1e11 # N/m^2 G = 1 Iy = 0.001125 # m^4 Iz = 0.003125 # m^4 J = 1 A = 0.15 # m^2 Beam.add_member("M1", "N1", "N2", E, G, Iy, Iz, J, A) # Supports Beam.def_support("N1", True, True, True, True, True, True) Beam.def_support("N2", True, True, True, False, True, True) # Load Beam.add_member_dist_load("M1", "Fx", 10, 10, 0, 5) # Analyze Beam.analyze() # Member fixed end reaction vector # print('M1 Displacement Vector: ', Beam.Members['M1'].d()) # print('M1 Fixed End Reaction Vector: ', Beam.Members['M1'].fer()) # Reactions for node_name in ('N1', 'N2'): with self.subTest(node=node_name): rxn = Beam.Nodes[node_name].RxnFX['Combo 1'] self.assertAlmostEqual(rxn / -25.0, 1.0, 2)
def __init__(self, width, height, thickness, E=3824, nu=0.3, mesh_size=1, bot_support='Pinned', top_support='Pinned', left_support='Free', right_support='Free'): self.width = width self.height = height self.thickness = thickness self.mesh_size = mesh_size self.E = E self.nu = nu self.fem = FEModel3D() # A finite element model for the wall self.loads = [] # A list of surface loads applied to the wall panel self.nodes = [] # A list of nodes that make up the wall panel self.plates = [] # A list of plates that make up the wall panel self.bot_support = bot_support self.top_support = top_support self.left_support = left_support self.right_support = right_support self.__analyzed = False
def test_support_settlement(self): # Create a new beam beam = FEModel3D() # Add nodes beam.AddNode('A', 0, 0, 0) beam.AddNode('B', 20 * 12, 0, 0) beam.AddNode('C', 40 * 12, 0, 0) beam.AddNode('D', 60 * 12, 0, 0) # Add members A = 20 E = 29000 G = 11400 Iy = 1000 Iz = 7800 J = 8800 beam.AddMember('AB', 'A', 'B', E, G, Iy, Iz, J, A) beam.AddMember('BC', 'B', 'C', E, G, Iy, Iz, J, A) beam.AddMember('CD', 'C', 'D', E, G, Iy, Iz, J, A) # Provide supports beam.DefineSupport('A', True, True, True, True, False, False) beam.DefineSupport('B', False, True, True, False, False, False) beam.DefineSupport('C', False, True, True, False, False, False) beam.DefineSupport('D', False, True, True, False, False, False) # Add a uniform load to the beam beam.AddMemberDistLoad('AB', 'Fy', -2 / 12, -2 / 12) beam.AddMemberDistLoad('BC', 'Fy', -2 / 12, -2 / 12) beam.AddMemberDistLoad('CD', 'Fy', -2 / 12, -2 / 12) # Add support settlements beam.AddNodeDisplacement('B', 'DY', -5 / 8) beam.AddNodeDisplacement('C', 'DY', -1.5) beam.AddNodeDisplacement('D', 'DY', -0.75) # Analyze the beam beam.Analyze() # Below are the textbook reactions given in the back of the textbook textbook_rxns = [('A', -1.098), ('B', 122.373), ('C', -61.451), ('D', 60.176)] # Check each textbook value against the PyNite calculated value for name, text_rxn in textbook_rxns: # The `subTest` context manager prints which, if any, of the nodes fail the test with self.subTest(node=name): # Get the reaction at the node PyNite_rxn = beam.Nodes[name].RxnFY['Combo 1'] # There are some known rounding errors in the "textbook values" listed above. These # rounding errors cause up to a 7.6% difference from the theoretical solution. # Check that the PyNite reactions are within 7.6% of the textbook values self.assertLess(abs(PyNite_rxn / text_rxn - 1), 0.076)
def analyse(self): self.frame = FEModel3D() # Add nodes for i in range(0, self.Nt): nname = self.__create_name('N', i) self.frame.AddNode(nname, self.node[i,0], self.node[i,1], self.node[i,2]) self.frame.AddNodeLoad(nname, 'FX', self.node[i,3]) self.frame.AddNodeLoad(nname, 'FY', self.node[i,4]) self.frame.AddNodeLoad(nname, 'FZ', self.node[i,5]) # Fix outer ring of nodes for n in range(1, self.Nn + 1): r, n, index = self.RNI(self.Nr, n) nname = self.__create_name('N', index) self.frame.DefineSupport(nname, True, True, True, True, True, True) for e in self.edge: r0, n0, i0 = e['node0'] r1, n1, i1 = e['node1'] mname = e['mname'] nname0 = self.__create_name('N', i0) nname1 = self.__create_name('N', i1) group = self.group[e['gname']] sectype = group['sec_type'] secindex = group['sec_index'] material = group['material'] area = sectype.get(secindex, 'area') Iyy = sectype.get(secindex, 'Iyy') Izz = sectype.get(secindex, 'Izz') J = sectype.get(secindex, 'J') E = material['Young'] G = material['Shear'] self.frame.AddMember(mname, nname0, nname1, E, G, Iyy, Izz, J, area, self.dome_origin) if self.verbose: print('Setup complete. Analysing...') self.frame.Analyze() if self.verbose: print('Done.') max_deflection = 0 for i in range(0, self.Nt): Ni = self.frame.GetNode(self.__create_name('N', i)) deflection = np.linalg.norm(np.asarray([Ni.DX, Ni.DY, Ni.DZ])) if max_deflection < deflection: max_deflection = deflection return self.dome_mass, self.__maximum_bending_stress(), max_deflection
def test_hydrostatic_quad(self): # Establish problem parameters t = 1 # ft E = 57000 * math.sqrt(4500) * 12**2 # psf nu = 1 / 6 mesh_size = 1 # ft a = 10 # ft b = 15 # ft # Generate the mesh of plates plate_mesh = RectangleMesh(t, E, nu, mesh_size, a, b, element_type='Quad') # Create the model and add the plates plate_model = FEModel3D() plate_model.AddMesh(plate_mesh) # Add supports to the sides and base of the wall for node in plate_model.Nodes.values(): if node.X == 0 or node.X == a or node.Y == 0: plate_model.DefineSupport(node.Name, True, True, True, True, True, True) # Add hydrostatic loads to the elements for element in plate_model.Quads.values(): Yavg = (element.iNode.Y + element.jNode.Y + element.mNode.Y + element.nNode.Y) / 4 p = 62.4 * (b - Yavg) plate_model.AddQuadSurfacePressure(element.Name, p, 'Hydrostatic') # Add a load combination to the model plate_model.AddLoadCombo('F', {'Hydrostatic': 1.0}) # Analyze the model plate_model.Analyze() # Find the maximum deflection in the model dz_calcd = max([ node.DZ['F'] for node in plate_model.Nodes.values() if node.Y == b ]) q = 62.4 * b D = E * t**3 / (12 * (1 - nu**2)) dz_expected = 0.00042 * q * a**4 / D # Check that the PyNite calculated values are within 15% of the Timoshenko calculated # values. self.assertLess(abs(dz_calcd / dz_expected - 1), 0.15, 'Failed Timoshenko quadrilateral hydrostatic test.')
def test_plate_displacement(self): """ # A First Course in the Finite Element Method, 4th Edition # Daryl L. Logan # Example 12.1 # Units for this model are pounds and inches """ plModel = FEModel3D() plModel.add_node('N1', 0, 0, 0) plModel.add_node('N2', 10, 0, 0) plModel.add_node('N3', 20, 0, 0) plModel.add_node('N4', 0, 10, 0) plModel.add_node('N5', 10, 10, 0) plModel.add_node('N6', 20, 10, 0) plModel.add_node('N7', 0, 20, 0) plModel.add_node('N8', 10, 20, 0) plModel.add_node('N9', 20, 20, 0) plModel.add_plate('P1', 'N1', 'N2', 'N5', 'N4', 0.1, 30000000, 0.3) plModel.add_plate('P2', 'N2', 'N3', 'N6', 'N5', 0.1, 30000000, 0.3) plModel.add_plate('P3', 'N4', 'N5', 'N8', 'N7', 0.1, 30000000, 0.3) plModel.add_plate('P4', 'N5', 'N6', 'N9', 'N8', 0.1, 30000000, 0.3) plModel.add_node_load('N5', 'FZ', -100) plModel.def_support('N1', True, True, True, True, True, True) plModel.def_support('N2', True, True, True, True, True, True) plModel.def_support('N3', True, True, True, True, True, True) plModel.def_support('N4', True, True, True, True, True, True) plModel.def_support('N6', True, True, True, True, True, True) plModel.def_support('N7', True, True, True, True, True, True) plModel.def_support('N8', True, True, True, True, True, True) plModel.def_support('N9', True, True, True, True, True, True) plModel.def_support('N5', True, True, False, False, False, True) # Check to see if the stiffness matrix for each plate is symmetric # print(allclose(plModel.Plates[0].K(), plModel.Plates[0].K().T)) # print(allclose(plModel.Plates[1].K(), plModel.Plates[1].K().T)) # print(allclose(plModel.Plates[2].K(), plModel.Plates[2].K().T)) # print(allclose(plModel.Plates[3].K(), plModel.Plates[3].K().T)) # Check to see if the global stiffness matrix is symmetric # print(allclose(plModel.K(Renumber=True), plModel.K(Renumber=False).T)) plModel.analyze(check_statics=True, sparse=False) # Test: displacement of N5 in Z direction calculated_displacement = plModel.Nodes['N5'].DZ['Combo 1'] expected_displacement = -0.0861742424242424 self.assertAlmostEqual(calculated_displacement / expected_displacement, 1.0, 2)
def test_AISC_Benckmark(self): # Create the cantilever model cantilever = FEModel3D() # Define the column and its properties L = 20 # ft H = 5 # kips lateral load P = 100 # kips axial load G = 11200 * 12**2 # shear modulus (ksf) E = 29000 * 12**2 # modulus of elasticity (ksf) I = 100 / 12**4 # moment of inertia (ft^4) # Break the column into several segments in order to capture P-little-delta effects num_segs = 5 num_nodes = num_segs + 1 for i in range(num_nodes): # Add nodes cantilever.add_node(str(i + 1), 0, i * L / (num_segs), 0) for i in range(num_segs): # Add members between nodes cantilever.add_member(str(i + 1), str(i + 1), str(i + 2), E, G, I, I, 200 / 12**4, 10 / 12**2) # Add a fixed support at the base of the column cantilever.def_support('1', True, True, True, True, True, True) # Add a -10 kip axial load to the top of the column cantilever.add_node_load(str(num_nodes), 'FY', -P) # Add a 5 kip lateral load to the top of the column cantilever.add_node_load(str(num_nodes), 'FX', H) # Perform 2nd order analysis cantilever.analyze_PDelta() # The moment at the base of the column calculated_moment = cantilever.Nodes['1'].RxnMZ['Combo 1'] # the deflection at the top of the column calculated_displacement = cantilever.Nodes[str( num_nodes)].DX['Combo 1'] * 12 # Calculate the AISC benchmark problem solution: alpha = (P * L**2 / (E * I))**0.5 Mmax = H * L * (math.tan(alpha) / alpha) ymax = H * L**3 / (3 * E * I) * (3 * (math.tan(alpha) - alpha) / alpha**3) # Compare the calculation results self.assertAlmostEqual(calculated_moment / Mmax, 1.0, 1) self.assertAlmostEqual(calculated_displacement / (ymax * 12), 1.0, 1)
def __init__(self, file, default_behavior='bonded'): self.igs = IGES_Object(file) self.model = FEModel3D() self.highest = [-np.inf, -np.inf, -np.inf] self.lowest = [+np.inf, +np.inf, +np.inf] # "Big picture" members and nodes... the ones that really matter. self.members = [] for i, entity in enumerate(self.igs.toplevel_entities): self.loadEntity(str(i + 1), entity) print("Bounding box: ", self.lowest, self.highest)
def test_beam_on_elastic_foundation(self): ''' Matrix Structural Analysis, 2nd Edition William McGuire, Richard H. Gallagher, Ronald D. Ziemian Example 4.15 Units for this model are kips and inches ''' # Create a new model boef = FEModel3D() # Define nodes for i in range(17): # Add nodes spaced at 15" boef.add_node('N' + str(i + 1), i*15, 0, 0) # Add supports to the nodes if i == 0 or i == 16: boef.def_support('N' + str(i + 1), True, True, True, True, False, False) else: boef.def_support_spring('N' + str(i + 1), 'DY', 22.5, '-') # Define member material properties E = 29000 # ksi G = 11200 # ksi A = 10.3 # in^2 Iz = 128.5 # in^4 (strong axis) Iy = 42.6 # in^4 (weak axis) J = 0.769 # in^4 # Define members for i in range(16): # Add the members boef.add_member('M' + str(i + 1), 'N' + str(i + 1), 'N' + str(i + 2), E, G, Iy, Iz, J, A) # Add a point load at midspan boef.add_node_load('N9', 'FY', -40) # Analyze the model boef.analyze(sparse=False) print(boef.Members['M8'].min_moment('Mz')) print(boef.Members['M8'].max_moment('Mz')) # Check that results are within 5% of the expected answer self.assertLess(boef.Nodes['N9'].DY['Combo 1']/(-0.238) - 1, 0.05, 'Failed beam on elastic foundation test.') self.assertLess(-boef.Members['M8'].min_moment('Mz')/547 - 1, 0.05, 'Failed beam on elastic foundation test.')
def test_XY_gravity_load(self): # A First Course in the Finite Element Method, 4th Edition # Daryl L. Logan # Problem 5.30 # Units for this model are kips and inches frame = FEModel3D() # Define the nodes frame.AddNode('N1', 0, 0, 0) frame.AddNode('N2', 0, 30*12, 0) frame.AddNode('N3', 15*12, 40*12, 0) frame.AddNode('N4', 35*12, 40*12, 0) frame.AddNode('N5', 50*12, 30*12, 0) frame.AddNode('N6', 50*12, 0, 0) # Define the supports frame.DefineSupport('N1', True, True, True, True, True, True) frame.DefineSupport('N6', True, True, True, True, True, True) # Create members (all members will have the same properties in this example) J = 250 Iy = 250 Iz = 200 E = 30000 G = 250 A = 12 frame.AddMember('M1', 'N1', 'N2', E, G, Iy, Iz, J, A) frame.AddMember('M2', 'N2', 'N3', E, G, Iy, Iz, J, A) frame.AddMember('M3', 'N3', 'N4', E, G, Iy, Iz, J, A) frame.AddMember('M4', 'N4', 'N5', E, G, Iy, Iz, J, A) frame.AddMember('M5', 'N5', 'N6', E, G, Iy, Iz, J, A) # Add nodal loads frame.AddNodeLoad('N3', 'FY', -30) frame.AddNodeLoad('N4', 'FY', -30) # Analyze the model frame.Analyze() # subTest context manager prints which portion fails, if any correct_values = [('N1', {'RxnFX': 11.6877, 'RxnFY': 30, 'RxnMZ': -1810.0745}), ('N6', {'RxnFX': -11.6877, 'RxnFY': 30, 'RxnMZ': 1810.0745})] for name, values in correct_values: with self.subTest(node=name): node = frame.GetNode(name) # Two decimal place accuracy requires +/-0.5% accuracy # one decimal place requires +/-5% self.assertAlmostEqual(node.RxnFX['Combo 1']/values['RxnFX'], 1.0, 2) self.assertAlmostEqual(node.RxnFY['Combo 1']/values['RxnFY'], 1.0, 2) self.assertAlmostEqual(node.RxnMZ['Combo 1']/values['RxnMZ'], 1.0, 2)
def two_span_beam(length): TwoSpanBeam = FEModel3D() # Add nodes (14 ft = 168 in apart) TwoSpanBeam.AddNode("N1", 0, 0, 0) TwoSpanBeam.AddNode("N2", length, 0, 0) TwoSpanBeam.AddNode("N3", length * 2, 0, 0) # Add a beam with the following properties: # E = 29000 ksi, G = 11200 ksi, Iy = 100 in^4, Iz = 150 in^4, J = 250 in^4, A = 20 in^2 TwoSpanBeam.AddMember("M1", "N1", "N2", E=29000, G=11200, Iy=100, Iz=150, J=250, A=20) TwoSpanBeam.AddMember("M2", "N2", "N3", E=29000, G=11200, Iy=100, Iz=150, J=250, A=20) # Supports: Pin, Roller, Roller TwoSpanBeam.DefineSupport("N1", SupportDX=True, SupportDY=True, SupportDZ=True, SupportRX=True) TwoSpanBeam.DefineSupport("N2", SupportDX=False, SupportDY=True, SupportDZ=True, SupportRX=True) TwoSpanBeam.DefineSupport("N3", SupportDX=False, SupportDY=True, SupportDZ=True, SupportRX=True) return TwoSpanBeam
def three_member_frame_1(): MomentFrame = FEModel3D() # Add nodes (frame is 15 ft wide x 12 ft tall) MomentFrame.AddNode("N1", 0, 0, 0) MomentFrame.AddNode("N2", 0, 12 * 12, 0) MomentFrame.AddNode("N3", 15 * 12, 12 * 12, 0) MomentFrame.AddNode("N4", 15 * 12, 0 * 12, 0) # Add columns with the following properties: # AISC W8x31 # E = 29000 ksi, G = 11200 ksi, Iy = 37.1 in^4, Iz = 110 in^4, J = 0.536 in^4, A = 9.13 in^2 MomentFrame.AddMember("M1", "N1", "N2", E=29000, G=11200, Iy=37.1, Iz=110, J=0.536, A=9.13) MomentFrame.AddMember("M2", "N4", "N3", E=29000, G=11200, Iy=37.1, Iz=110, J=0.536, A=9.13) MomentFrame.AddMember("M3", "N2", "N3", E=29000, G=11200, Iy=37.1, Iz=110, J=0.536, A=9.13) # Provide fixed supports at the bases of the columns MomentFrame.DefineSupport("N1", True, True, True, True, True, True) MomentFrame.DefineSupport("N4", True, True, True, True, True, True) return MomentFrame
def test_end_release_Rz(self): myModel = FEModel3D() # Add two supported nodes and one member myModel.AddNode('N1', 0, 0, 0) myModel.AddNode('N2', 10 * 12, 0, 0) myModel.DefineSupport('N1', True, True, True, True, True, True) myModel.DefineSupport('N2', True, True, True, True, True, True) myModel.AddMember('M1', 'N1', 'N2', 29000, 11400, 100, 150, 250, 10) # Release Rzi and Rzj on member M1 myModel.DefineReleases('M1', False, False, False, False, False, True, \ False, False, False, False, False, True) # Add a load myModel.AddMemberDistLoad('M1', 'Fy', -0.5, -0.5) myModel.Analyze() # Get the resulting moments calculated_moment = myModel.GetMember('M1').MinMoment('Mz') expected_moment = -0.5 * (10 * 12)**2 / 8 self.assertAlmostEqual(calculated_moment, expected_moment)
def test_end_release_Rz(self): myModel = FEModel3D() # Add two supported nodes and one member myModel.add_node('N1', 0, 0, 0) myModel.add_node('N2', 10 * 12, 0, 0) myModel.def_support('N1', True, True, True, True, True, True) myModel.def_support('N2', True, True, True, True, True, True) myModel.add_member('M1', 'N1', 'N2', 29000, 11400, 100, 150, 250, 10) # Release Rzi and Rzj on member M1 myModel.def_releases('M1', False, False, False, False, False, True, \ False, False, False, False, False, True) # Add a load myModel.add_member_dist_load('M1', 'Fy', -0.5, -0.5) myModel.analyze() # Get the resulting moments calculated_moment = myModel.Members['M1'].min_moment('Mz') expected_moment = -0.5 * (10 * 12)**2 / 8 self.assertAlmostEqual(calculated_moment, expected_moment)
def two_member_frame_2(): # Two member frame with sloping beam up to flat beam. Flat beam is on right. # Frame is taken from Example 16.2 in textbook "Structural Analysis" by R.C. Hibbeler (8th Ed.) Frame = FEModel3D() Frame.AddNode("N1", X=0, Y=0, Z=0) Frame.AddNode("N2", X=20 * 12, Y=15 * 12, Z=0) Frame.AddNode("N3", X=20 * 12 + 20 * 12, Y=15 * 12, Z=0) Frame.AddMember("M1", "N1", "N2", E=29000, G=11200, Iy=150, Iz=600, J=2, A=12) Frame.AddMember("M2", "N2", "N3", E=29000, G=11200, Iy=150, Iz=600, J=2, A=12) # N1: Fixed, N3: Fixed Frame.DefineSupport("N1", SupportDX=True, SupportDY=True, SupportDZ=True, SupportRX=True, SupportRZ=True) Frame.DefineSupport("N3", SupportDX=True, SupportDY=True, SupportDZ=True, SupportRX=True, SupportRZ=True) return Frame
def two_member_frame_1(): # Two member frame with one beam and one column. Column is on right. # Frame is taken from Example 16.1 in textbook "Structural Analysis" by R.C. Hibbeler (8th Ed.) Frame = FEModel3D() Frame.AddNode("N1", X=0, Y=20 * 12, Z=0) Frame.AddNode("N2", X=20 * 12, Y=20 * 12, Z=0) Frame.AddNode("N3", X=20 * 12, Y=0, Z=0) Frame.AddMember("M1", "N1", "N2", E=29000, G=11200, Iy=150, Iz=500, J=2, A=10) Frame.AddMember("M2", "N2", "N3", E=29000, G=11200, Iy=150, Iz=500, J=2, A=10) # N1: Roller, N3: Fixed Frame.DefineSupport("N1", SupportDX=False, SupportDY=True, SupportDZ=True, SupportRX=True) Frame.DefineSupport("N3", SupportDX=True, SupportDY=True, SupportDZ=True, SupportRX=True, SupportRZ=True) return Frame
def test_support_settlement(self): beam = FEModel3D() # Add nodes beam.AddNode('A', 0, 0, 0) beam.AddNode('B', 20 * 12, 0, 0) beam.AddNode('C', 40 * 12, 0, 0) beam.AddNode('D', 60 * 12, 0, 0) # Add members A = 20 E = 29000 G = 11400 Iy = 1000 Iz = 7800 J = 8800 beam.AddMember('AB', 'A', 'B', E, G, Iy, Iz, J, A) beam.AddMember('BC', 'B', 'C', E, G, Iy, Iz, J, A) beam.AddMember('CD', 'C', 'D', E, G, Iy, Iz, J, A) # Provide supports beam.DefineSupport('A', True, True, True, True, False, False) beam.DefineSupport('B', False, True, True, False, False, False) beam.DefineSupport('C', False, True, True, False, False, False) beam.DefineSupport('D', False, True, True, False, False, False) # Add a uniform load to the beam beam.AddMemberDistLoad('AB', 'Fy', -2 / 12, -2 / 12) beam.AddMemberDistLoad('BC', 'Fy', -2 / 12, -2 / 12) beam.AddMemberDistLoad('CD', 'Fy', -2 / 12, -2 / 12) # Add support settlements beam.AddNodeDisplacement('B', 'DY', -5 / 8) beam.AddNodeDisplacement('C', 'DY', -1.5) beam.AddNodeDisplacement('D', 'DY', -0.75) # Analyze the beam beam.Analyze() # subTest context manager prints which portion fails, if any correct_values = [('A', -1.098), ('B', 122.373), ('C', -61.451), ('D', 60.176)] for name, value in correct_values: with self.subTest(node=name): calculated_Rxn = beam.GetNode(name).RxnFY['Combo 1'] # Two decimal place accuracy requires +/-0.5% accuracy # one decimal place requires +/-5% self.assertAlmostEqual(calculated_Rxn / value, 1.0, 2)
def test_spring_elements(self): # A First Course in the Finite Element Method, 4th Edition # Daryl L. Logan # Example 2.1 # Units for this model are pounds and inches system = FEModel3D() system.add_node('1', 0, 0, 0) system.add_node('2', 30, 0, 0) system.add_node('3', 10, 0, 0) system.add_node('4', 20, 0, 0) # Add spring members system.add_spring('S1', '1', '3', 1000) system.add_spring('S2', '3', '4', 2000) system.add_spring('S3', '4', '2', 3000) # Define supports system.def_support('1', True, True, True, True, True, True) system.def_support('2', True, True, True, True, True, True) system.def_support('3', False, True, True, True, True, True) system.def_support('4', False, True, True, True, True, True) # Add node loads system.add_node_load('4', 'FX', 5000) system.analyze(True) # Check results # correct_values = [('3', 0.9090909090909092), # ('4', 1.3636363636363638), # ('1', -909.0909090909091), # ('2', -4090.9090909090914)] n3_DX = system.Nodes['3'].DX['Combo 1'] self.assertAlmostEqual(n3_DX/ 0.9090909090909092, 1.0, 2) n4_DX = system.Nodes['4'].DX['Combo 1'] self.assertAlmostEqual(n4_DX/1.3636363636363638, 1.0, 2) n1_rxn = system.Nodes['1'].RxnFX['Combo 1'] self.assertAlmostEqual(n1_rxn/-909.0909090909091, 1.0, 2) n2_rxn = system.Nodes['2'].RxnFX['Combo 1'] self.assertAlmostEqual(n2_rxn/-4090.9090909090914, 1.0, 2)
def test_cracked_rect_shear_wall(self): sw = FEModel3D() E = 57000*(4000)**0.5/1000*12**2 nu = 0.17 G = E/(2*(1 + nu)) t = 1 L = 10 H = 20 A = L*t I = 0.35*t*L**3/12 mesh_size = 1 mesh = RectangleMesh(mesh_size, L, H, t, E, nu, ky_mod=0.35, element_type='Rect') mesh.generate() sw.add_mesh(mesh) V = 1000 for node in sw.Nodes.values(): if node.Y == 0: sw.def_support(node.name, True, True, True, True, True, True) elif node.Y == H: sw.add_node_load(node.name, 'FX', V/11) sw.analyze() # Calculated solution delta1 = max([node.DX['Combo 1'] for node in sw.Nodes.values()]) # Theoretical solution delta2 = V*H**3/(3*E*I) + 1.2*V*H/(G*A) # Check that the solution matches the theoretical solution within 2% self.assertLess(abs(1 - delta1/delta2), 0.02, 'Failed cracked rect plate shear wall test.')
# -*- coding: utf-8 -*- """ Created on Sun Sep 16 14:43:31 2018 @author: craig """ # Example of a simply supported beam with a point load. # Units used in this example are inches, and kips # Import `FEModel3D` from `PyNite` from PyNite import FEModel3D # Create a new finite element model SimpleBeam = FEModel3D() # Add nodes (14 ft = 168 in apart) SimpleBeam.AddNode("N1", 0, 0, 0) SimpleBeam.AddNode("N2", 168, 0, 0) # Add a beam with the following properties: # E = 29000 ksi, G = 11400 ksi, Iy = 100 in^4, Iz = 150 in^4, J = 250 in^4, A = 20 in^2 SimpleBeam.AddMember("M1", "N1", "N2", 29000, 11400, 100, 150, 250, 20) # Provide simple supports SimpleBeam.DefineSupport("N1", True, True, True, True, False, False) SimpleBeam.DefineSupport("N2", True, True, True, True, False, False) # Add a point load of 5 kips at the midspan of the beam SimpleBeam.AddMemberPtLoad("M1", "Fy", 5, 7 * 12) # Analyze the beam
# A First Course in the Finite Element Method, 4th Edition # Daryl L. Logan # Example 5.8 # Units for this model are kips and inches # Import 'FEModel3D' and 'Visualization' from 'PyNite' from PyNite import FEModel3D from PyNite import Visualization # Create a new model frame = FEModel3D() # Define the nodes frame.AddNode('N1', 0, 0, 0) frame.AddNode('N2', -100, 0, 0) frame.AddNode('N3', 0, 0, -100) frame.AddNode('N4', 0, -100, 0) # Define the supports frame.DefineSupport('N2', True, True, True, True, True, True) frame.DefineSupport('N3', True, True, True, True, True, True) frame.DefineSupport('N4', True, True, True, True, True, True) # Create members (all members will have the same properties in this example) J = 50 Iy = 100 Iz = 100 E = 30000 G = 10000 A = 10
# Example of a basic 2D tension-only braced frame with gravity and lateral # loads. Units used for the model in this example are inches and kips # Import `FEModel3D` from `PyNite` from PyNite import FEModel3D # Create a new finite element model BracedFrame = FEModel3D() # Add nodes (frame is 15 ft wide x 12 ft tall) BracedFrame.AddNode('N1', 0, 0, 0) BracedFrame.AddNode('N2', 0, 12 * 12, 0) BracedFrame.AddNode('N3', 15 * 12, 12 * 12, 0) BracedFrame.AddNode('N4', 15 * 12, 0 * 12, 0) # Define column properties (use W10x33 from the AISC Manual): E = 29000 # ksi G = 11400 # ksi Iy = 36.6 # in^4 Iz = 171 # in^4 J = 0.58 # in^4 A = 9.71 # in^2 # Define the columns BracedFrame.AddMember('Col1', 'N1', 'N2', E, G, Iy, Iz, J, A) BracedFrame.AddMember('Col2', 'N4', 'N3', E, G, Iy, Iz, J, A) # Define beam properties (Use W8x24) Iy = 18.3 # in^4 Iz = 82.7 # in^4 J = 0.346 # in^4
nu, kx_mod=1, ky_mod=1, origin=[0, 0, 0], plane='XY', start_node='N1', start_element='Q1', element_type='Quad') # Generate the mesh. Rectangle meshes won't generate unless you tell them to. # This allows you to add openings to them before meshing. mesh.generate() # Create a finite element model from PyNite import FEModel3D model = FEModel3D() # Add the mesh to the model model.add_mesh(mesh) # Step through each quadrilateral in the model for element in model.Quads.values(): # Add loads to the element model.add_quad_surface_pressure(element.name, load, case='W') # Add fully fixed supports on all side of the wall for node in model.Nodes.values(): if (round(node.Y, 10) == 0 or round(node.Y, 10) == height or round(node.X, 10) == 0 or round(node.X, 10) == width): model.def_support(node.name, True, True, True, True, True, True)