def get_properties(): # build the lists of points, facets, holes and control points points = request.json['points'] facets = request.json['facets'] holes = request.json['holes'] control_points = request.json['controls'] # create the custom geometry object geometry = sections.CustomSection(points, facets, holes, control_points) geometry.clean_geometry() # clean the geometry # create the mesh - use a smaller refinement for the angle region mesh = geometry.create_mesh(mesh_sizes=[0.0005, 0.001]) # create a CrossSection object section = CrossSection(geometry, mesh) # perform a geometric, warping and plastic analysis section.calculate_geometric_properties() section.calculate_warping_properties() section.calculate_plastic_properties() properties = section.display_results() return jsonify({'properties': properties})
def _analyze_common_structural_geometry(step, geometry, mesh_sizes, N, Vx, Vy, Mxx, Myy, Mzz): mesh = geometry.create_mesh(mesh_sizes=[mesh_sizes]) section = CrossSection(geometry, mesh) finite_elements_number = len(section.mesh_elements) if finite_elements_number > MAX_FINITE_ELEMENTS_NUMBER: return False, None, None, None, None, None, None, None, None, None, None elif finite_elements_number < MAX_FINITE_ELEMENTS_NUMBER and step == 'checking': return True, None, None, None, None, None, None, None, None, None, None else: section.calculate_geometric_properties() section.calculate_warping_properties() loadcase = section.calculate_stress(N=N, Vx=Vx, Vy=Vy, Mxx=Mxx, Myy=Myy, Mzz=Mzz) nodes = section.mesh_nodes stresses = loadcase.get_stress()[0] area = section.get_area() ixx_c, iyy_c, ixy_c = section.get_ic() torsion_constant = section.get_j() warping_constant = section.get_gamma() elastic_centroid = section.get_c() centroidal_shear_center = section.get_sc() return True, nodes, stresses, area, ixx_c, iyy_c, ixy_c, torsion_constant, warping_constant, \ elastic_centroid, centroidal_shear_center
def calculate(self, loadProfileFromDB): '''Se ejecuta el calculo de las propiedades de la seccion. Referencia ---------- rx, ry : radio de giro del miembro | sqrt(I/A) c_i : coordenada del centroide de la seccion sc_i : coordenada del centro de corte A : Area de la seccion Cw : Constante torsional de warping de la seccion J : Constante de torsion de St. Venant Si : modulo elastico j : mitad de la constante monociclica a compresion en eje -y- (beta22-) ''' if loadProfileFromDB: try: self.load() except: loadProfileFromDB = False pass if not loadProfileFromDB: ## CALCULO PROPIEDADES A PARTIR DEL PAQUETE sectionproperties geometry = sections.CeeSection(d=self.H, b=self.B+self.r_out, l=self.r_out, t=self.t, r_out=self.r_out, n_r=8) # corto los labios y el radio p1 = geometry.add_point([self.B, 0]) p2 = geometry.add_point([self.B, self.t]) p3 = geometry.add_point([self.B, self.H]) p4 = geometry.add_point([self.B, self.H-self.t]) geometry.add_facet([p1, p2]) geometry.add_facet([p3, p4]) geometry.add_hole([self.B+self.r_out/10, self.t/2]) # add hole geometry.add_hole([self.B+self.r_out/10, self.H-self.t/2]) # add hole geometry.clean_geometry() # clean the geometry # create mesh mesh = geometry.create_mesh(mesh_sizes=[self.t/4.0]) # creo la seccion section = CrossSection(geometry, mesh) # calculo las propiedades section.calculate_geometric_properties() section.calculate_warping_properties() (self.c_x, self.c_y) = section.get_c() # centroides (self.sc_x, self.sc_y) = section.get_sc() # shear center self.Cw = section.get_gamma() # warping (self.rx, self.ry) = section.get_rc() # radios de giro self.J = section.get_j() self.A = section.get_area() self.Ae = section.get_area() (self.Ix, self.Iy, _) = section.get_ic() (self.Sx, _, _, _) = section.get_z() # modulo elastico self.j = section.get_beta_p()[3]/2.0 self.save(section) self.section = section
def calculate(self, loadProfileFromDB): '''Se ejecuta el calculo de las propiedades de la seccion. Parameters ---------- loadProfileFromDB: bool indica si se debe intentar cargar el perfil desde la base de datos Referencia ---------- rx, ry : radio de giro del miembro | sqrt(I/A) c_i : coordenada del centroide de la seccion sc_i : coordenada del centro de corte A : Area de la seccion Cw : Constante torsional de warping de la seccion J : Constante de torsion de St. Venant Si : modulo elastico j : mitad de la constante monociclica a compresion en eje -y- (beta22-) ''' if loadProfileFromDB: try: self.load() except: loadProfileFromDB = False pass if not loadProfileFromDB: ## CALCULO PROPIEDADES A PARTIR DEL PAQUETE sectionproperties geometry = sections.CeeSection(d=self.H, b=self.B, l=self.D, t=self.t, r_out=self.r_out, n_r=8) # create mesh mesh = geometry.create_mesh(mesh_sizes=[self.t/4.0]) # creo la seccion section = CrossSection(geometry, mesh) # calculo las propiedades section.calculate_geometric_properties() section.calculate_warping_properties() (self.c_x, self.c_y) = section.get_c() # centroides (self.sc_x, self.sc_y) = section.get_sc() # shear center self.Cw = section.get_gamma() # warping (self.rx, self.ry) = section.get_rc() # radios de giro self.J = section.get_j() # St Venant self.A = section.get_area() self.Ae = section.get_area() (self.Ix, self.Iy, _) = section.get_ic() (self.Sx, _, _, _) = section.get_z() # modulo elastico self.j = section.get_beta_p()[3]/2.0 self.save(section) self.section = section
geometry.plot_geometry() # plot the geometry # create a mesh - use a mesh size of 5 for the UB, 20 for the panel mesh = geometry.create_mesh(mesh_sizes=[5, 20]) # create a CrossSection object - take care to list the materials in the same order as entered into # the MergedSection section = CrossSection(geometry, mesh, materials=[steel, timber]) section.display_mesh_info() # display the mesh information # plot the mesh with coloured materials and a line transparency of 0.5 section.plot_mesh(materials=True, alpha=0.5) # perform a geometric, warping and plastic analysis section.calculate_geometric_properties(time_info=True) section.calculate_warping_properties(time_info=True) section.calculate_plastic_properties(time_info=True, verbose=True) # perform a stress analysis with N = 100 kN, Mxx = 120 kN.m and Vy = 75 kN stress_post = section.calculate_stress(N=-100e3, Mxx=-120e6, Vy=-75e3, time_info=True) # print the results to the terminal section.display_results() # plot the centroids section.plot_centroids() stress_post.plot_stress_n_zz(pause=False) # plot the axial stress
def calculate(self, loadProfileFromDB): '''Se ejecuta el calculo de las propiedades de la seccion. Referencia ---------- rx, ry : radio de giro de la seccion | sqrt(I/A) ri : radio de giro en -y- de un solo perfil c c_x, c_y : coordenada del centroide de la seccion sc_x, sc_y : coordenada del centro de corte A : Area de la seccion Cw : Constante torsional de warping de la seccion J : Constante de torsion de St. Venant Si : modulo elastico j : mitad de la constante monociclica a compresion en eje -y- (beta22-) ''' if loadProfileFromDB: try: self.load() except: loadProfileFromDB = False pass if not loadProfileFromDB: c0 = c_profile(H= self.H, B= self. B, t= self.t, r_out= self.r_out) c0.calculate(loadProfileFromDB) c1 = sections.CeeSection(d=self.H, b=self.B+self.r_out, l=self.r_out, t=self.t, r_out=self.r_out, n_r=8) c2 = deepcopy(c1) # corto los labios y el radio c1 p1 = c1.add_point([self.B, 0]) p2 = c1.add_point([self.B, self.t]) p3 = c1.add_point([self.B, self.H]) p4 = c1.add_point([self.B, self.H-self.t]) c1.add_facet([p1, p2]) c1.add_facet([p3, p4]) c1.add_hole([self.B+self.r_out/10, self.t/2]) # add hole c1.add_hole([self.B+self.r_out/10, self.H-self.t/2]) # add hole c1.clean_geometry() # clean the geometry c2 = deepcopy(c1) c2.mirror_section(axis= 'y', mirror_point=[0, 0]) if self.s: c1.shift = [self.s/2, 0] c1.shift_section() c2.shift = [-self.s/2, 0] c2.shift_section() # soldadura en los extremos del alma if self.wld: h = self.wld*self.r_out # weld length a = self.wld*self.r_out*2 + self.s # base de la soldadura weld1 = sections.CustomSection( points=[[a/2,0], [-a/2, 0], [0, h]], facets=[[0,1], [1,2], [2,0]], holes=[], control_points=[[h / 3, h / 3]] ) weld2 = deepcopy(weld1) weld2.mirror_section(axis= 'x', mirror_point=[0, 0]) weld2.shift = [0, self.H] weld2.shift_section() geometry = sections.MergedSection([c1, c2, weld1, weld2]) geometry.clean_geometry(verbose= False) if self.s: geometry.add_hole([0, self.H/2]) mesh = geometry.create_mesh(mesh_sizes=[self.mesh_size, self.mesh_size, self.mesh_size, self.mesh_size]) else: geometry = sections.MergedSection([c1, c2]) geometry.clean_geometry() mesh = geometry.create_mesh(mesh_sizes=[self.mesh_size, self.mesh_size]) section = CrossSection(geometry, mesh) #mesh_c1 = c1.create_mesh(mesh_sizes=[self.mesh_size]) #section_c1 = CrossSection(c1, mesh_c1) #section_c1.calculate_geometric_properties() #section_c1.calculate_warping_properties() section.calculate_geometric_properties() section.calculate_warping_properties() (self.c_x, self.c_y) = section.get_c() # centroides (self.sc_x, self.sc_y) = section.get_sc() # shear center self.Cw = section.get_gamma() # warping (self.rx, self.ry) = section.get_rc() # radios de giro self.J = section.get_j() self.A = section.get_area() self.Ae = self.A self.ri = c0.ry # radios de giro y de c1 (self.Ix, self.Iy, _) = section.get_ic() (self.Sx, _, _, _) = section.get_z() # modulo elastico self.j = section.get_beta_p()[3]/2.0 self.save(section) self.section = section
def test_angle(self): """Section properties are validated against results from the Strand7 beam section utility.""" geometry = sections.AngleSection(d=150, b=90, t=12, r_r=10, r_t=5, n_r=8) mesh = geometry.create_mesh(mesh_sizes=[2.5]) section = CrossSection(geometry, mesh) val_list = [] val_list.append({"prop": "area", "val": 2746.73, "tol": 2e-4}) val_list.append({"prop": "perimeter", "val": 471, "tol": 1e-3}) val_list.append({"prop": "cx", "val": 21.2255, "tol": 2e-4}) val_list.append({"prop": "cy", "val": 50.9893, "tol": 2e-4}) val_list.append({"prop": "ixx_g", "val": 1.3428e7, "tol": 2e-4}) val_list.append({"prop": "iyy_g", "val": 2.95629e6, "tol": 2e-4}) val_list.append({"prop": "ixy_g", "val": 1.08669e6, "tol": 2e-4}) val_list.append({"prop": "ixx_c", "val": 6.28678e6, "tol": 2e-4}) val_list.append({"prop": "iyy_c", "val": 1.71882e6, "tol": 3e-4}) val_list.append({"prop": "ixy_c", "val": -1.88603e6, "tol": 3e-4}) val_list.append({"prop": "zxx_plus", "val": 63496.0, "tol": 2e-4}) val_list.append({"prop": "zxx_minus", "val": 123296, "tol": 2e-4}) val_list.append({"prop": "zyy_plus", "val": 24992.1, "tol": 3e-4}) val_list.append({"prop": "zyy_minus", "val": 80979.0, "tol": 2e-4}) val_list.append({"prop": "rx", "val": 47.8416, "tol": 2e-4}) val_list.append({"prop": "ry", "val": 25.0154, "tol": 2e-4}) val_list.append({"prop": "i11_c", "val": 6.96484e6, "tol": 2e-4}) val_list.append({"prop": "i22_c", "val": 1.04076e6, "tol": 2e-4}) val_list.append({"prop": "phi", "val": 19.7744 - 180, "tol": 2e-4}) val_list.append({"prop": "z11_plus", "val": 97751.9, "tol": 2e-4}) val_list.append({"prop": "z11_minus", "val": 69403.3, "tol": 2e-4}) val_list.append({"prop": "z22_plus", "val": 27959.0, "tol": 2e-4}) val_list.append({"prop": "z22_minus", "val": 20761.6, "tol": 3e-4}) val_list.append({"prop": "r11", "val": 50.3556, "tol": 2e-4}) val_list.append({"prop": "r22", "val": 19.4656, "tol": 2e-4}) val_list.append({"prop": "sxx", "val": 113541, "tol": 2e-4}) val_list.append({"prop": "syy", "val": 45724.6, "tol": 2e-4}) val_list.append({ "prop": "sf_xx_plus", "val": 113541 / 63496.0, "tol": 2e-4 }) val_list.append({ "prop": "sf_xx_minus", "val": 113541 / 123296, "tol": 2e-4 }) val_list.append({ "prop": "sf_yy_plus", "val": 45724.6 / 24992.1, "tol": 3e-4 }) val_list.append({ "prop": "sf_yy_minus", "val": 45724.6 / 80979.0, "tol": 2e-4 }) val_list.append({"prop": "s11", "val": 121030, "tol": 2e-4}) val_list.append({"prop": "s22", "val": 43760.6, "tol": 2e-4}) val_list.append({ "prop": "sf_11_plus", "val": 121030 / 97751.9, "tol": 2e-4 }) val_list.append({ "prop": "sf_11_minus", "val": 121030 / 69403.3, "tol": 2e-4 }) val_list.append({ "prop": "sf_22_plus", "val": 43760.6 / 27959.0, "tol": 2e-4 }) val_list.append({ "prop": "sf_22_minus", "val": 43760.6 / 20761.6, "tol": 3e-4 }) val_list.append({"prop": "j", "val": 135333, "tol": 1e-3}) val_list.append({"prop": "gamma", "val": 1.62288e8, "tol": 5e-4}) val_list.append({"prop": "A_s11", "val": 885.444, "tol": 2e-4}) val_list.append({"prop": "A_s22", "val": 1459.72, "tol": 4e-4}) val_list.append({"prop": "x11_se", "val": 28.719, "tol": 1e-3}) val_list.append({"prop": "y22_se", "val": 35.2348, "tol": 5e-4}) section.calculate_geometric_properties() section.calculate_plastic_properties() section.calculate_warping_properties() validate_properties(self, val_list, section)
def test_custom(self): """Section properties are validated against results from the Strand7 beam section utility.""" points = [[-10, 0], [110, 0], [100, 10], [55, 10], [55, 90], [100, 90], [110, 100], [110, 110], [-10, 110], [-10, 100], [0, 90], [45, 90], [45, 10], [-10, 10]] facets = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10], [10, 11], [11, 12], [12, 13], [13, 0]] holes = [] control_points = [[0, 5]] geometry = sections.CustomSection(points, facets, holes, control_points) mesh = geometry.create_mesh(mesh_sizes=[5]) section = CrossSection(geometry, mesh) val_list = [] val_list.append({"prop": "area", "val": 4250, "tol": None}) val_list.append({"prop": "cx", "val": 49.3333, "tol": None}) val_list.append({"prop": "cy", "val": 65.0196, "tol": None}) val_list.append({"prop": "ixx_g", "val": 2.56725e7, "tol": None}) val_list.append({"prop": "iyy_g", "val": 1.41858e7, "tol": None}) val_list.append({"prop": "ixy_g", "val": 1.37979e7, "tol": None}) val_list.append({"prop": "ixx_c", "val": 7.70542e6, "tol": None}) val_list.append({"prop": "iyy_c", "val": 3.84228e6, "tol": None}) val_list.append({"prop": "ixy_c", "val": 165472, "tol": None}) val_list.append({"prop": "zxx_plus", "val": 171306, "tol": None}) val_list.append({"prop": "zxx_minus", "val": 118509, "tol": None}) val_list.append({"prop": "zyy_plus", "val": 63334.2, "tol": None}) val_list.append({"prop": "zyy_minus", "val": 64757.5, "tol": None}) val_list.append({"prop": "rx", "val": 42.5798, "tol": None}) val_list.append({"prop": "ry", "val": 30.0677, "tol": None}) val_list.append({"prop": "phi", "val": 177.552 - 180, "tol": 1e-4}) val_list.append({"prop": "i11_c", "val": 7.71249e6, "tol": None}) val_list.append({"prop": "i22_c", "val": 3.8352e6, "tol": None}) val_list.append({"prop": "z11_plus", "val": 162263, "tol": None}) val_list.append({"prop": "z11_minus", "val": 114268, "tol": None}) val_list.append({"prop": "z22_plus", "val": 60503.0, "tol": None}) val_list.append({"prop": "z22_minus", "val": 62666.1, "tol": None}) val_list.append({"prop": "r11", "val": 42.5993, "tol": None}) val_list.append({"prop": "r22", "val": 30.04, "tol": None}) val_list.append({"prop": "sxx", "val": 153196, "tol": None}) val_list.append({"prop": "syy", "val": 101494, "tol": None}) val_list.append({ "prop": "sf_xx_plus", "val": 153196 / 171306, "tol": None }) val_list.append({ "prop": "sf_xx_minus", "val": 153196 / 118509, "tol": None }) val_list.append({ "prop": "sf_yy_plus", "val": 101494 / 63334.2, "tol": None }) val_list.append({ "prop": "sf_yy_minus", "val": 101494 / 64757.5, "tol": None }) val_list.append({"prop": "s11", "val": 153347, "tol": None}) val_list.append({"prop": "s22", "val": 101501, "tol": None}) val_list.append({ "prop": "sf_11_plus", "val": 153347 / 162263, "tol": None }) val_list.append({ "prop": "sf_11_minus", "val": 153347 / 114268, "tol": None }) val_list.append({ "prop": "sf_22_plus", "val": 101501 / 60503.0, "tol": None }) val_list.append({ "prop": "sf_22_minus", "val": 101501 / 62666.1, "tol": None }) val_list.append({"prop": "j", "val": 347040, "tol": 5e-3}) val_list.append({"prop": "gamma", "val": 7.53539e9, "tol": 1e-3}) val_list.append({"prop": "A_s11", "val": 2945.53, "tol": 5e-4}) val_list.append({"prop": "A_s22", "val": 956.014, "tol": 5e-4}) val_list.append({"prop": "x11_se", "val": 1.9134, "tol": 5e-3}) val_list.append({"prop": "y22_se", "val": 3.02028, "tol": 5e-3}) section.calculate_geometric_properties() section.calculate_plastic_properties() section.calculate_warping_properties() validate_properties(self, val_list, section)
class TestRectangle(unittest.TestCase): """Section properties are mostly validated against hand calcs. Results from Strand7 and Roark's Formulas for Stress and Strain are used for some warping properties.""" def setUp(self): self.geometry = sections.RectangularSection(d=100, b=50) self.mesh = self.geometry.create_mesh(mesh_sizes=[10]) self.section = CrossSection(self.geometry, self.mesh) def test_geometric(self): self.section.calculate_geometric_properties() val_list = [] val_list.append({"prop": "area", "val": 100 * 50, "tol": None}) val_list.append({ "prop": "perimeter", "val": 100 * 2 + 50 * 2, "tol": None }) val_list.append({"prop": "ea", "val": 1 * 100 * 50, "tol": None}) val_list.append({"prop": "qx", "val": 100 * 50 * 50, "tol": None}) val_list.append({"prop": "qy", "val": 100 * 50 * 25, "tol": None}) val_list.append({"prop": "ixx_g", "val": 50 * 100**3 / 3, "tol": None}) val_list.append({"prop": "iyy_g", "val": 100 * 50**3 / 3, "tol": None}) val_list.append({ "prop": "ixy_g", "val": 100 * 50 * 50 * 25, "tol": None }) val_list.append({"prop": "cx", "val": 50 / 2, "tol": None}) val_list.append({"prop": "cy", "val": 100 / 2, "tol": None}) val_list.append({ "prop": "ixx_c", "val": 50 * 100**3 / 12, "tol": None }) val_list.append({ "prop": "iyy_c", "val": 100 * 50**3 / 12, "tol": None }) val_list.append({"prop": "ixy_c", "val": 0, "tol": None}) val_list.append({ "prop": "zxx_plus", "val": 50 * 100**2 / 6, "tol": None }) val_list.append({ "prop": "zxx_minus", "val": 50 * 100**2 / 6, "tol": None }) val_list.append({ "prop": "zyy_plus", "val": 100 * 50**2 / 6, "tol": None }) val_list.append({ "prop": "zyy_minus", "val": 100 * 50**2 / 6, "tol": None }) val_list.append({ "prop": "rx", "val": (50 * 100**3 / 12 / 100 / 50)**0.5, "tol": None }) val_list.append({ "prop": "ry", "val": (100 * 50**3 / 12 / 100 / 50)**0.5, "tol": None }) val_list.append({ "prop": "i11_c", "val": 50 * 100**3 / 12, "tol": None }) val_list.append({ "prop": "i22_c", "val": 100 * 50**3 / 12, "tol": None }) val_list.append({"prop": "phi", "val": 0, "tol": None}) val_list.append({ "prop": "z11_plus", "val": 50 * 100**2 / 6, "tol": None }) val_list.append({ "prop": "z11_minus", "val": 50 * 100**2 / 6, "tol": None }) val_list.append({ "prop": "z22_plus", "val": 100 * 50**2 / 6, "tol": None }) val_list.append({ "prop": "z22_minus", "val": 100 * 50**2 / 6, "tol": None }) val_list.append({ "prop": "r11", "val": (50 * 100**3 / 12 / 100 / 50)**0.5, "tol": None }) val_list.append({ "prop": "r22", "val": (100 * 50**3 / 12 / 100 / 50)**0.5, "tol": None }) validate_properties(self, val_list, self.section) def test_plastic(self): self.section.calculate_geometric_properties() self.section.calculate_plastic_properties() val_list = [] val_list.append({"prop": "x_pc", "val": 50 / 2, "tol": None}) val_list.append({"prop": "y_pc", "val": 100 / 2, "tol": None}) val_list.append({"prop": "x11_pc", "val": 50 / 2, "tol": None}) val_list.append({"prop": "y22_pc", "val": 100 / 2, "tol": None}) val_list.append({"prop": "sxx", "val": 50 * 100**2 / 4, "tol": None}) val_list.append({"prop": "syy", "val": 100 * 50**2 / 4, "tol": None}) val_list.append({"prop": "s11", "val": 50 * 100**2 / 4, "tol": None}) val_list.append({"prop": "s22", "val": 100 * 50**2 / 4, "tol": None}) val_list.append({"prop": "sf_xx_plus", "val": 1.5, "tol": None}) val_list.append({"prop": "sf_xx_minus", "val": 1.5, "tol": None}) val_list.append({"prop": "sf_yy_plus", "val": 1.5, "tol": None}) val_list.append({"prop": "sf_yy_minus", "val": 1.5, "tol": None}) val_list.append({"prop": "sf_11_plus", "val": 1.5, "tol": None}) val_list.append({"prop": "sf_11_minus", "val": 1.5, "tol": None}) val_list.append({"prop": "sf_22_plus", "val": 1.5, "tol": None}) val_list.append({"prop": "sf_22_minus", "val": 1.5, "tol": None}) validate_properties(self, val_list, self.section) def test_warping(self): self.section.calculate_geometric_properties() self.section.calculate_warping_properties() val_list = [] val_list.append({"prop": "j", "val": 2861002, "tol": 0.04}) # roark's val_list.append({"prop": "j", "val": 2.85852e6, "tol": 2e-5}) # st7 val_list.append({ "prop": "gamma", "val": 3.17542e8, "tol": None }) # st7 val_list.append({"prop": "x_se", "val": 50 / 2, "tol": None}) val_list.append({"prop": "y_se", "val": 100 / 2, "tol": None}) val_list.append({"prop": "x11_se", "val": 0, "tol": None}) val_list.append({"prop": "y22_se", "val": 0, "tol": None}) val_list.append({"prop": "x_st", "val": 50 / 2, "tol": None}) val_list.append({"prop": "y_st", "val": 100 / 2, "tol": None}) val_list.append({"prop": "A_sx", "val": 5 / 6 * 100 * 50, "tol": None}) val_list.append({"prop": "A_sy", "val": 5 / 6 * 100 * 50, "tol": None}) val_list.append({ "prop": "A_s11", "val": 5 / 6 * 100 * 50, "tol": None }) val_list.append({ "prop": "A_s22", "val": 5 / 6 * 100 * 50, "tol": None })
class Beam(Component): '''Beam is a wrapper for emergent useful properties of the structure''' structure = attr.ib() #parent structure, will be in its _beams name = attr.ib() material = attr.ib(validator=attr.validators.instance_of(SolidMaterial)) section = attr.ib(validator=attr.validators.instance_of(( sectionproperties.pre.sections.Geometry, ottgeo.Profile2D, type(None)))) mesh_size = attr.ib(default=3) in_Iy = attr.ib(default=None, validator=attr.validators.instance_of( (int, float, nonetype))) in_Ix = attr.ib(default=None, validator=attr.validators.instance_of( (int, float, nonetype))) in_J = attr.ib(default=None, validator=attr.validators.instance_of( (int, float, nonetype))) in_A = attr.ib(default=None, validator=attr.validators.instance_of( (int, float, nonetype))) _L = None _section_properties = None _ITensor = None min_stress_xy = None #set to true or false def __on_init__(self): self.info('initalizing...') self._skip_attr = ['mesh_size', 'in_Iy', 'in_Ix', 'in_J', 'in_A'] self.update_section(self.section) def update_section(self, section): self.section = section self.debug(f'determining {section} properties...') if isinstance(self.section, sectionproperties.pre.sections.Geometry): self.debug(f'determining mesh {section} properties...') mesh = self.section.create_mesh([self.mesh_size]) self._section_properties = CrossSection(self.section, mesh) #no material here self._section_properties.calculate_geometric_properties() self._section_properties.calculate_warping_properties() elif isinstance(self.section, ottgeo.Profile2D): self.debug(f'determining profile {section} properties...') self._section_properties = self.section else: self.debug(f'checking input values') assert all([ val is not None for val in (self.in_Iy, self.in_Ix, self.in_J, self.in_A) ]) def apply_pt_load(self, gFx, gFy, gFz, x, case='Case 1'): '''add a force in a global orientation''' Fvec = numpy.array([gFx, gFy, gFz]) self.debug(f'adding pt load {Fvec}') Floc = self.ReverseRotationMatrix.dot(Fvec) Flx = Floc[0] Fly = Floc[1] Flz = Floc[2] for Fkey, Fval in [('Fx', Flx), ('Fy', Fly), ('Fz', Flz)]: if Fval: self.debug(f'adding {Fkey}={Fval}') self.structure.frame.AddMemberPtLoad(self.member.Name, Fkey, Fval, x)
import sectionproperties.pre.sections as sections from sectionproperties.analysis.cross_section import CrossSection # create a 150x100x6 RHS on its side geometry = sections.Rhs(d=100, b=150, t=6, r_out=15, n_r=8) # create a mesh with a maximum area of 2 mesh = geometry.create_mesh(mesh_sizes=[2]) # create a CrossSection object section = CrossSection(geometry, mesh) # perform a geometry and warping analysis section.calculate_geometric_properties() section.calculate_warping_properties() # perform a stress analysis with Mx = 5 kN.m; Vx = 10 kN and Mzz = 3 kN.m case1 = section.calculate_stress(Mxx=5e6, Vx=10e3, Mzz=3e6) # perform a stress analysis with My = 15 kN.m; Vy = 30 kN and Mzz = 1.5 kN.m case2 = section.calculate_stress(Myy=15e6, Vy=30e3, Mzz=1.5e6) case1.plot_stress_m_zz(pause=False) # plot the bending stress for case1 case1.plot_vector_mzz_zxy(pause=False) # plot the torsion vectors for case1 case2.plot_stress_v_zxy(pause=False) # plot the shear stress for case1 case1.plot_stress_vm(pause=False) # plot the von mises stress for case1 case2.plot_stress_vm() # plot the von mises stress for case2
def process_geometry(geometry, mesh_sizes, loadcases): # update this to receive the geometry, mesh info, material and loads # generate a finite element mesh mesh = geometry.create_mesh(mesh_sizes=mesh_sizes) # generate material - can be overwritten if needed --all in N and cm # create a CrossSection object for analysis section = CrossSection(geometry, mesh) # calculate various cross-section properties section.calculate_geometric_properties() section.calculate_warping_properties() section.calculate_plastic_properties() # Area area = section.get_area() sheararea = section.get_As() asx = sheararea[0] asy = sheararea[1] # Second Moment of Area about centroid (ixx, iyy, ixy) = section.get_ic() # Centroid (xg, yg) = section.get_c() # Radii of Gyration (rxx, ryy) = section.get_rc() # Principal bending axis angle phi = section.get_phi() # St. Venant torsion constant ipp = section.get_j() # Warping Constant cw = section.get_gamma() # Elastic Section Moduli (welx_top, welx_bottom, wely_top, wely_bottom) = section.get_z() # Plastic Section Moduli (wplx, wply) = section.get_s() # plot centroid to image section.plot_centroids(pause=False) buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight') buf.seek(0) plot_centroid = base64.b64encode(buf.getvalue()).decode() plt.close() # calculate torsion resistance from stress and torque #from the below can also return torsional stress if wanted stress_post = section.calculate_stress(Mzz=10) unit_mzz_zxy = [] maxstress = [] for group in stress_post.material_groups: maxstress.append(max(group.stress_result.sig_zxy_mzz)) unit_mzz_zxy.append(group.stress_result.sig_zxy_mzz.tolist()) #there should be only one maxstress value therefore: wt = 10 / maxstress[0] #plot this image stress_post.plot_stress_mzz_zxy(pause=False) buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight') buf.seek(0) plot_unittorsionstress = base64.b64encode(buf.getvalue()).decode() plt.close() #foreach load case submitted calculate vm stress state and create image vmStressImages = {} vmStressStates = {} for loadcase in loadcases: lc_name = loadcase[0] s_n = loadcase[1] s_vx = loadcase[2] s_vy = loadcase[3] s_mxx = loadcase[4] s_myy = loadcase[5] s_mzz = loadcase[6] stress_post = section.calculate_stress(N=s_n, Vx=s_vx, Vy=s_vy, Mxx=s_mxx, Myy=s_myy, Mzz=s_mzz) stress_state = [] for group in stress_post.material_groups: stress_state.append(group.stress_result.sig_vm.tolist()) vmStressStates['lc_' + str(lc_name) + '_vm_stress'] = stress_state #plot this image stress_post.plot_stress_vm(pause=False) buf = io.BytesIO() plt.savefig(buf, format='png', bbox_inches='tight') buf.seek(0) vmStressImages['lc_' + str(lc_name) + '_vm_stress'] = base64.b64encode( buf.getvalue()).decode() plt.close() # create rhino mesh rmesh = rhino_mesh_from_meshpy(mesh) # return send_file(path, as_attachment=True) # get some of the calculated section properties return_data = {} return_data['properties'] = { 'area': area, 'Avx': asx, 'Avy': asy, 'xg': xg, 'yg': yg, 'rxx': rxx, 'ryy': ryy, 'phi': phi, 'ixx': ixx, 'iyy': iyy, 'ipp': ipp, 'cw': cw, 'welx+': welx_top, 'welx-': welx_bottom, 'wely+': wely_top, 'wely-': wely_bottom, 'wplx': wplx, 'wply': wply, 'wt': wt, } return_data['geometry'] = { 'mesh': rhino.CommonObject.Encode(rmesh), } return_data['images'] = { 'centroids': plot_centroid, 'unittorsion_vxy_stress': plot_unittorsionstress, } return_data['images'].update(vmStressImages) return_data['stress_results'] = { 'unittorsion_vxy_stress': unit_mzz_zxy, } return_data['stress_results'].update(vmStressStates) return return_data
class OneSec: """表示一个截面""" def __init__(self, pls): """ 单独截面 :param pls: 多条 cad 多段线对象组成的列表,其中应有一根指示控制点的线 """ # 原始线和控制点 self.pls_origin = [] self.points = [] for i in pls: if i.area == 0: self.points = i.id else: self.pls_origin.append(i) # 对线段进行排序,得到分离节点和完整节点 self.areas = np.array([i.area for i in self.pls_origin]) self.pls = np.array(self.pls_origin)[np.argsort(self.areas)][::-1] self.ids_sep = [i.id for i in self.pls] self.ids = [j.tolist() for i in self.ids_sep for j in i] # 获取节点连接方式 self.faces = [] id_num = 0 for i in self.ids_sep: id_num_0 = id_num for j in i: connect = [ id_num, id_num_0 ] if id_num + 1 == id_num_0 + len(i) else [id_num, id_num + 1] self.faces.append(connect) id_num += 1 # 定义其他所需值 self.geo = 0 self.mesh = 0 self.sec = 0 self.prop = {} self.stress = 0 self.corner = [] self.ids_to_c = [] def sec_cal(self, mesh=0.01, d=0.03): """ 对单个截面进行属性计算 :param mesh: 截面划分单元尺寸 :param d: 截取形心附近应力范围 :return: 无 """ self.geo = sections.CustomSection(self.ids, self.faces, self.points[1:], [self.points[0]]) self.mesh = self.geo.create_mesh(mesh_sizes=[mesh]) self.sec = CrossSection(self.geo, self.mesh) self.sec.plot_mesh() self.sec.calculate_geometric_properties() self.sec.calculate_warping_properties() # 获取截面属性 prop = self.sec.section_props self.prop['center'] = self.sec.get_c() self.ids_to_c = [i - self.prop['center'] for i in self.ids_sep] self.prop['area'] = prop.area self.prop['as'] = [prop.A_s22, prop.A_s11] self.prop['i'] = [prop.j, prop.ixx_c, prop.iyy_c] pts = np.array(self.ids) left = prop.cx - pts[:, 0].min() right = pts[:, 0].max() - prop.cx top = pts[:, 1].max() - prop.cy bot = prop.cy - pts[:, 1].min() self.prop['c'] = [right, left, top, bot] self.stress = self.sec.calculate_stress(Vx=1, Vy=1) stresses = self.stress.get_stress() dy = self.sec.get_c()[1] - self.sec.mesh_nodes[:, 1] dx = self.sec.get_c()[0] - self.sec.mesh_nodes[:, 0] qyb = stresses[0]['sig_zy_vy'][dx < d].max() * prop.ixx_c qzb = stresses[0]['sig_zx_vx'][dy < d].max() * prop.iyy_c self.prop['q'] = [qyb, qzb] self.prop['p'] = [ self.pls[0].length, sum([i.length for i in self.pls[1:]]) ] # 获取角点 pt_all = self.ids_to_c[0] pt_1 = pt_all[(pt_all[:, 0] < 0) & (pt_all[:, 1] > 0)] pt_2 = pt_all[(pt_all[:, 0] > 0) & (pt_all[:, 1] > 0)] pt_3 = pt_all[(pt_all[:, 0] < 0) & (pt_all[:, 1] < 0)] pt_4 = pt_all[(pt_all[:, 0] > 0) & (pt_all[:, 1] < 0)] pt_1 = find_pt(pt_1, relation='max') pt_2 = find_pt(pt_2, relation='max') pt_3 = find_pt(pt_3, relation='max') pt_4 = find_pt(pt_4, relation='max') self.corner = [pt_1, pt_2, pt_4, pt_3]