def create_fem_elem_from_obj(self, obj, el_type=None) -> Elem: """Converts structural object to FEM elements. Currently only BEAM is supported""" from ada.fem.shapes import ElemType if type(obj) is not Beam: raise NotImplementedError( f'Object type "{type(obj)}" is not yet supported') el_type = ElemType.LINE if el_type is None else el_type res = self.nodes.add(obj.n1) if res is not None: obj.n1 = res res = self.nodes.add(obj.n2) if res is not None: obj.n2 = res elem = self.add_elem(Elem(None, [obj.n1, obj.n2], el_type)) femset = self.add_set( FemSet(f"{obj.name}_set", [elem], FemSet.TYPES.ELSET)) self.add_section( FemSection( f"d{obj.name}_sec", ElemType.LINE, femset, obj.material, obj.section, obj.ori[1], )) return elem
def grab_beam(match): d = match.groupdict() elset = fem.elsets[d["elset"]] name = d["sec_name"] if d["sec_name"] is not None else elset.name profile = d["profile_name"] if d[ "profile_name"] is not None else elset.name ass = fem.parent.get_assembly() material = ass.materials.get_by_name(d["material"]) # material = parent.parent.materials.get_by_name(d['material']) temperature = d["temperature"] section_type = d["sec_type"] geo_props = d["line1"] sec = interpret_section(profile, section_type, geo_props) beam_y = [ float(x.strip()) for x in d["line2"].split(",") if x.strip() != "" ] metadata = dict( temperature=temperature, profile=profile.strip(), section_type=section_type, line1=geo_props, ) res = fem.parent.sections.add(sec) if res is not None: sec = res return FemSection( name.strip(), sec_type="beam", elset=elset, section=sec, local_y=beam_y, material=material, metadata=metadata, parent=fem, )
def get_shell_section(m, sh_name, fem: "FEM", a: "Assembly"): d = m.groupdict() name = next(sh_name) elset = fem.sets.get_elset_from_name(d["elset"]) material = d["material"] mat = a.materials.get_by_name(material) thickness = float(d["t"]) offset = d["offset"] if offset is not None: # TODO: update this with the latest eccentricity class logging.warning("Offset for Shell elements is not yet evaluated") for el in elset.members: el.eccentricity = Eccentricity(sh_ecc_vector=offset) int_points = d["int_points"] metadata = dict(controls=d["controls"]) return FemSection( name=name, sec_type=ElemType.SHELL, thickness=thickness, elset=elset, material=mat, int_points=int_points, parent=fem, metadata=metadata, )
def get_beam_elements(self, li, order): """ :param li: :param order: :return: """ import gmsh from ada.core.utils import make_name_fem_ready model = gmsh.model bm = self._bm_map[li] segments = model.mesh.getElements(1, li)[1][0] fem_nodes = model.mesh.getElements(1, li)[2][0] elem_types, elem_tags, elem_node_tags = gmsh.model.mesh.getElements( 1, li) face, dim, morder, numv, parv, _ = gmsh.model.mesh.getElementProperties( elem_types[0]) set_name = make_name_fem_ready(f"el{bm.name}_set") fem = self._part.fem def make_elem(j): no = [] for i in range(numv): p1 = fem_nodes[numv * j + i] p1_co = gmsh.model.mesh.getNode(p1)[0] no.append(Node(p1_co, p1)) if len(no) == 3: myorder = [0, 2, 1] no = [no[i] for i in myorder] bm_el_type = "B31" if order == 1 else "B32" return Elem(segments[j], no, bm_el_type, parent=self._part.fem) elements = list(map(make_elem, range(len(segments)))) fem_sec_name = make_name_fem_ready(f"d{bm.name}_sec") if set_name in fem.elsets.keys(): fem_set = fem.elsets[set_name] for el in elements: el.fem_sec = fem_set.members[0].fem_sec fem_set.add_members(elements) else: fem_set = FemSet(set_name, elements, "elset", parent=fem) fem.sets.add(fem_set) fem.add_section( FemSection( fem_sec_name, "beam", fem_set, bm.material, bm.section, bm.ori[2], metadata=dict(beam=bm, numel=len(elements)), )) return elements
def grab_solid(m_in): name = m_in.group(1) if m_in.group(1) is not None else next(secnames) elset = m_in.group(2) material = m_in.group(3) return FemSection( name=name, sec_type="solid", elset=elset, material=material, parent=fem, )
def test_negative_sec_contained(self): # A minor change in section box thickness sec = Section('myBG', from_str='BG800x400x20x40') mat = Material('my_mat') bm = Beam('my_beam', (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], 'B31') fem_set = FemSet('my_set', [elem], 'elset') fem_sec = FemSection('my_sec', 'beam', fem_set, mat, sec) p = get_fsec_bm_collection() self.assertFalse(fem_sec in p.fem.sections)
def get_shell_elements(self, sh, order): """ :param sh: :param order: :return: """ import gmsh pl = self._pl_map[sh] assert isinstance(pl, Plate) try: get_elems = gmsh.model.mesh.getElements(2, sh) segments = get_elems[1][0] except BaseException as e: logging.debug(e) return [] fem_nodes = gmsh.model.mesh.getElements(2, sh)[2][0] elemTypes, elemTags, elemNodeTags = gmsh.model.mesh.getElements(2, sh) face, dim, morder, numv, parv, _ = gmsh.model.mesh.getElementProperties( elemTypes[0]) elem_type = gmsh_map[face] def make_elem(j): el_id = segments[j] nonlocal elem_type nonlocal numv nonlocal fem_nodes no = [] for i in range(numv): p1 = fem_nodes[numv * j + i] p1_co = gmsh.model.mesh.getNode(p1)[0] no.append(Node(p1_co, p1)) return Elem(el_id, no, elem_type, parent=self._part.fem) elements = list(map(make_elem, range(len(segments)))) femset = FemSet(f"el{pl.name}_set", elements, "elset") self._part.fem.add_set(femset) self._part.fem.add_section( FemSection( f"sh{pl.name}_sec", "shell", femset, pl.material, local_z=pl.n, thickness=pl.t, int_points=5, metadata=dict(beam=pl, numel=len(elements)), )) return elements
def grab_solid(m_in): name = m_in.group(1) if m_in.group(1) is not None else next(secnames) elset = m_in.group(2) material = m_in.group(3) mat = a.materials.get_by_name(material) return FemSection( name=name, sec_type=ElemType.SOLID, elset=elset, material=mat, parent=fem, )
def test_negative_sec_contained(self): # A minor change in section box thickness sec = Section("myBG", from_str="BG800x400x20x40") mat = Material("my_mat") bm = Beam("my_beam", (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], "B31") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "beam", fem_set, mat, sec) p = get_fsec_bm_collection() self.assertFalse(fem_sec in p.fem.sections)
def part_with_beam(): sec = Section("myIPE", from_str="BG800x400x30x40") mat = Material("my_mat") bm = Beam("my_beam", (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], "line") p = Part("my_part") / bm fem_set = p.fem.sets.add(FemSet("my_set", [elem])) p.fem.sections.add( FemSection("my_sec", "line", fem_set, mat, sec, local_z=(0, 0, 1))) p.fem.elements.add(elem) return p
def test_negative_mat_contained(self): # A minor change in material property (S420 instead of S355) sec = Section('myBG', from_str='BG800x400x30x40') mat = Material('my_mat', CarbonSteel('S420')) bm = Beam('my_beam', (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], 'B31') fem_set = FemSet('my_set', [elem], 'elset') fem_sec = FemSection('my_sec', 'beam', fem_set, mat, sec) p = get_fsec_bm_collection() self.assertFalse(fem_sec in p.fem.sections)
def test_negative_mat_contained(self): # A minor change in material property (S420 instead of S355) sec = Section("myBG", from_str="BG800x400x30x40") mat = Material("my_mat", CarbonSteel("S420")) bm = Beam("my_beam", (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], "B31") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "beam", fem_set, mat, sec) p = get_fsec_bm_collection() self.assertFalse(fem_sec in p.fem.sections)
def test_negative_contained_shell_(part_with_shell): # Testing equal operator for change in element type mat = Material("my_mat") elem = Elem( 1, [Node((0, 0, 0)), Node((1, 0, 0)), Node((1, 1, 0)), Node((0, 1, 0))], "quad") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "shell", fem_set, mat, thickness=0.01) assert fem_sec not in part_with_shell.fem.sections
def test_negative_contained_shell_(self): # Testing equal operator for change in element type mat = Material("my_mat") elem = Elem(1, [ Node((0, 0, 0)), Node((1, 0, 0)), Node((1, 1, 0)), Node((0, 1, 0)) ], "S4") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "shell", fem_set, mat, thickness=0.01) p = get_fsec_sh_collection() self.assertFalse(fem_sec in p.fem.sections)
def test_negative_contained_shell(self): # Testing equal operator for different shell thickness mat = Material('my_mat') elem = Elem(1, [ Node((0, 0, 0)), Node((1, 0, 0)), Node((1, 1, 0)), Node((0, 1, 0)) ], 'S4R') fem_set = FemSet('my_set', [elem], 'elset') fem_sec = FemSection('my_sec', 'shell', fem_set, mat, thickness=0.02) p = get_fsec_sh_collection() self.assertFalse(fem_sec in p.fem.sections)
def get_beam_elements(self, li, order): """ :param li: :param order: :return: """ model = gmsh.model bm = self._bm_map[li] segments = model.mesh.getElements(1, li)[1][0] fem_nodes = model.mesh.getElements(1, li)[2][0] elem_types, elem_tags, elem_node_tags = gmsh.model.mesh.getElements( 1, li) face, dim, morder, numv, parv, _ = gmsh.model.mesh.getElementProperties( elem_types[0]) def make_elem(j): no = [] for i in range(numv): p1 = fem_nodes[numv * j + i] p1_co = gmsh.model.mesh.getNode(p1)[0] no.append(Node(p1_co, p1)) if len(no) == 3: myorder = [0, 2, 1] no = [no[i] for i in myorder] bm_el_type = "B31" if order == 1 else "B32" return Elem(segments[j], no, bm_el_type, parent=self._part.fem) elements = list(map(make_elem, range(len(segments)))) femset = FemSet(f"el{bm.name}_set", elements, "elset", parent=self._part.fem) self._part.fem.sets.add(femset) self._part.fem.add_section( FemSection( f"d{bm.name}_sec", "beam", femset, bm.material, bm.section, bm.ori[2], metadata=dict(beam=bm, numel=len(elements)), )) return elements
def test_negative_sec_contained(part_with_beam): # A minor change in section box thickness sec = Section("myBG", from_str="BG800x400x20x40") mat = Material("my_mat") bm = Beam("my_beam", (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], "line") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "line", fem_set, mat, sec, local_z=(0, 0, 1)) assert fem_sec not in part_with_beam.fem.sections
def read_line_section(elem: Elem, fem: FEM, mat: Material, geono, d, lcsysd, hinges_global, eccentricities): transno = str_to_int(d["transno"]) sec = fem.parent.sections.get_by_id(geono) n1, n2 = elem.nodes v = n2.p - n1.p if vector_length(v) == 0.0: xvec = [1, 0, 0] else: xvec = unit_vector(v) zvec = lcsysd[transno] crossed = np.cross(zvec, xvec) ma = max(abs(crossed)) yvec = tuple([roundoff(x / ma, 3) for x in crossed]) fix_data = str_to_int(d["fixno"]) ecc_data = str_to_int(d["eccno"]) members = None if d["members"] is not None: members = [ str_to_int(x) for x in d["members"].replace("\n", " ").split() ] if fix_data == -1: add_hinge_prop_to_elem(elem, members, hinges_global, xvec, yvec) if ecc_data == -1: add_ecc_to_elem(elem, members, eccentricities, fix_data) fem_set = FemSet(sec.name, [elem], "elset", metadata=dict(internal=True), parent=fem) fem.sets.add(fem_set, append_suffix_on_exist=True) fem_sec = FemSection( sec_id=geono, name=sec.name, sec_type=ElemType.LINE, elset=fem_set, section=sec, local_z=zvec, local_y=yvec, material=mat, parent=fem, ) return fem_sec
def read_shell_section(elem: Elem, fem: FEM, mat: Material, elno, thicknesses, geono): sec_name = f"sh{elno}" fem_set = FemSet(sec_name, [elem], "elset", parent=fem, metadata=dict(internal=True)) fem.sets.add(fem_set) fem_sec = FemSection( name=sec_name, sec_type=ElemType.SHELL, thickness=roundoff(thicknesses[geono]), elset=fem_set, material=mat, parent=fem, ) return fem_sec
def part_with_shell(): p = Part("my_part") mat = Material("my_mat") elem = Elem( 1, [Node((0, 0, 0)), Node((1, 0, 0)), Node((1, 1, 0)), Node((0, 1, 0))], "quad") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "shell", fem_set, mat, thickness=0.01) for n in elem.nodes: p.fem.nodes.add(n) p.fem.elements.add(elem) p.fem.sets.add(fem_set) p.fem.sections.add(fem_sec) return p
def get_fsec_sh_collection(): p = Part('my_part') mat = Material('my_mat') elem = Elem( 1, [Node((0, 0, 0)), Node((1, 0, 0)), Node((1, 1, 0)), Node((0, 1, 0))], 'S4R') fem_set = FemSet('my_set', [elem], 'elset') fem_sec = FemSection('my_sec', 'shell', fem_set, mat, thickness=0.01) for n in elem.nodes: p.fem.nodes.add(n) p.fem.elements.add(elem) p.fem.sets.add(fem_set) p.fem.sections.add(fem_sec) return p
def test_negative_mat_contained(part_with_beam): # A minor change in material property (S420 instead of S355) sec = Section("myBG", from_str="BG800x400x30x40") mat = Material("my_mat", CarbonSteel("S420")) bm = Beam("my_beam", (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], "line") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "line", fem_set, mat, sec, local_z=(0, 0, 1)) assert fem_sec not in part_with_beam.fem.sections
def add_shell_section( set_name, fem_sec_name, normal, thickness, elements, model_obj: Union[Beam, Plate, Pipe, Shape], fem: FEM, is_rigid=False, ): fem_set = FemSet(set_name, elements, FemSet.TYPES.ELSET) props = dict(local_z=normal, thickness=thickness, int_points=5, is_rigid=is_rigid) fem_sec = FemSection(fem_sec_name, ElemType.SHELL, fem_set, model_obj.material, **props) add_sec_to_fem(fem, fem_sec, fem_set)
def get_so_sections(model: gmsh.model, solid_object: Beam, gmsh_data: GmshData, fem: FEM): tags = [] for dim, ent in gmsh_data.entities: _, tag, _ = model.mesh.getElements(3, ent) tags += tag elements = [ fem.elements.from_id(elid) for elid in chain.from_iterable(tags) ] set_name = make_name_fem_ready(f"el{solid_object.name}_so") fem_sec_name = make_name_fem_ready(f"d{solid_object.name}_so") fem_set = FemSet(set_name, elements, FemSet.TYPES.ELSET, parent=fem) fem_sec = FemSection(fem_sec_name, ElemType.SOLID, fem_set, solid_object.material) add_sec_to_fem(fem, fem_sec, fem_set)
def get_fsec_bm_collection(): sec = Section("myIPE", from_str="BG800x400x30x40") mat = Material("my_mat") p = Part("my_part") bm = Beam("my_beam", (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], "B31") fem_set = FemSet("my_set", [elem], "elset") fem_sec = FemSection("my_sec", "beam", fem_set, mat, sec, local_z=(0, 0, 1)) p.add_beam(bm) p.fem.elements.add(elem) p.fem.sets.add(fem_set) p.fem.sections.add(fem_sec) return p
def get_fsec_bm_collection(): sec = Section('myIPE', from_str='BG800x400x30x40') mat = Material('my_mat') p = Part('my_part') bm = Beam('my_beam', (0, 0, 0), (1, 0, 0), sec, mat) elem = Elem(1, [bm.n1, bm.n2], 'B31') fem_set = FemSet('my_set', [elem], 'elset') fem_sec = FemSection('my_sec', 'beam', fem_set, mat, sec, local_z=(0, 0, 1)) p.add_beam(bm) p.fem.elements.add(elem) p.fem.sets.add(fem_set) p.fem.sections.add(fem_sec) return p
def grab_shell(m): d = m.groupdict() name = d["name"] if d["name"] is not None else next(shname) elset = fem.sets.get_elset_from_name(d["elset"]) material = d["material"] thickness = float(d["t"]) offset = d["offset"] int_points = d["int_points"] metadata = dict(controls=d["controls"]) return FemSection( name=name, sec_type="shell", thickness=thickness, elset=elset, material=material, int_points=int_points, offset=offset, parent=fem, metadata=metadata, )
def get_bm_sections(model: gmsh.model, beam: Beam, gmsh_data, fem: FEM): from ada.core.vector_utils import vector_length tags = [] for dim, ent in gmsh_data.entities: _, tag, _ = model.mesh.getElements(1, ent) tags += tag elements = [ fem.elements.from_id(elid) for elid in chain.from_iterable(tags) ] set_name = make_name_fem_ready(f"el{beam.name}_set_bm") fem_sec_name = make_name_fem_ready(f"d{beam.name}_sec_bm") fem_set = FemSet(set_name, elements, FemSet.TYPES.ELSET, parent=fem) fem_sec = FemSection(fem_sec_name, ElemType.LINE, fem_set, beam.material, beam.section, beam.ori[2], refs=[beam]) add_sec_to_fem(fem, fem_sec, fem_set) if beam.hinge_prop is None: return end1_p = beam.hinge_prop.end1.concept_node.p if beam.hinge_prop.end1 is not None else None end2_p = beam.hinge_prop.end2.concept_node.p if beam.hinge_prop.end2 is not None else None if beam.hinge_prop is not None: for el in elements: n1 = el.nodes[0] n2 = el.nodes[-1] el.hinge_prop = beam.hinge_prop if beam.hinge_prop.end1 is not None and vector_length(end1_p - n1.p) == 0.0: el.hinge_prop.end1.fem_node = n1 if beam.hinge_prop.end2 is not None and vector_length(end2_p - n2.p) == 0.0: el.hinge_prop.end2.fem_node = n2
def get_femsecs(match): d = match.groupdict() geono = str_to_int(d["geono"]) next(total_geo) transno = str_to_int(d["transno"]) elno = str_to_int(d["elno"]) elem = fem.elements.from_id(elno) matno = str_to_int(d["matno"]) # Go no further if element has no fem section if elem.type in ElemShapes.springs + ElemShapes.masses: next(importedgeom_counter) elem.metadata["matno"] = matno return None mat = fem.parent.materials.get_by_id(matno) if elem.type in ElemShapes.beam: next(importedgeom_counter) sec = fem.parent.sections.get_by_id(geono) n1, n2 = elem.nodes v = n2.p - n1.p if vector_length(v) == 0.0: xvec = [1, 0, 0] else: xvec = unit_vector(v) zvec = lcsysd[transno] crossed = np.cross(zvec, xvec) ma = max(abs(crossed)) yvec = tuple([roundoff(x / ma, 3) for x in crossed]) fix_data = str_to_int(d["fixno"]) ecc_data = str_to_int(d["eccno"]) members = None if d["members"] is not None: members = [ str_to_int(x) for x in d["members"].replace("\n", " ").split() ] hinges = None if fix_data == -1: hinges = get_hinges_from_elem(elem, members, hinges_global, lcsysd, xvec, zvec, yvec) offset = None if ecc_data == -1: offset = get_ecc_from_elem(elem, members, eccentricities, fix_data) fem_set = FemSet(sec.name, [elem], "elset", metadata=dict(internal=True), parent=fem) fem.sets.add(fem_set, append_suffix_on_exist=True) fem_sec = FemSection( name=sec.name, sec_type="beam", elset=fem_set, section=sec, local_z=zvec, local_y=yvec, material=mat, offset=offset, hinges=hinges, parent=fem, ) return fem_sec elif elem.type in ElemShapes.shell: next(importedgeom_counter) sec_name = f"sh{elno}" fem_set = FemSet(sec_name, [elem], "elset", parent=fem, metadata=dict(internal=True)) fem.sets.add(fem_set) fem_sec = FemSection( name=sec_name, sec_type="shell", thickness=roundoff(thicknesses[geono]), elset=fem_set, material=mat, parent=fem, ) return fem_sec else: raise ValueError("Section not added to conversion")
def create_beam_mesh( beam, fem, geom_repr="solid", max_size=0.1, order=1, algo=8, tol=1e-3, interactive=False, gmsh_session=None ): """ :param beam: :param gmsh_session: :param geom_repr: :param max_size: :param order: :param algo: Mesh algorithm :param tol: Maximum geometry tolerance :param interactive: :type beam: ada.Beam :type fem: ada.fem.FEM :type gmsh_session: gmsh """ if gmsh_session is None: gmsh_session = _init_gmsh_session() temp_dir = _Settings.temp_dir name = beam.name.replace("/", "") + f"_{create_guid()}" option = gmsh_session.option model = gmsh_session.model option.setNumber("Mesh.Algorithm", algo) option.setNumber("Mesh.MeshSizeFromCurvature", True) option.setNumber("Mesh.MinimumElementsPerTwoPi", 12) option.setNumber("Mesh.MeshSizeMax", max_size) option.setNumber("Mesh.ElementOrder", order) option.setNumber("Mesh.SecondOrderIncomplete", 1) option.setNumber("Mesh.Smoothing", 3) option.setNumber("Geometry.Tolerance", tol) option.setNumber("Geometry.OCCImportLabels", 1) # import colors from STEP if geom_repr == "solid": option.setNumber("Geometry.OCCMakeSolids", 1) model.add(name) if geom_repr in ["shell", "solid"]: # geom_so = beam.solid # geom_sh = beam.shell beam.to_stp(temp_dir / name, geom_repr=geom_repr) gmsh_session.open(str(temp_dir / f"{name}.stp")) else: # beam p1, p2 = beam.n1.p, beam.n2.p s = get_point(p1, gmsh_session) e = get_point(p2, gmsh_session) if len(s) == 0: s = [(0, model.geo.addPoint(*p1.tolist(), max_size))] if len(e) == 0: e = [(0, model.geo.addPoint(*p2.tolist(), max_size))] # line = model.geo.addLine(s[0][1], e[0][1]) model.geo.synchronize() model.mesh.setRecombine(3, 1) model.mesh.generate(3) model.mesh.removeDuplicateNodes() if interactive: gmsh_session.fltk.run() get_nodes_and_elements(gmsh_session, fem) if fem is None: gmsh_session.write(str(temp_dir / f"{name}.msh")) m = meshio.read(str(temp_dir / f"{name}.msh")) m.write(temp_dir / f"{name}.xdmf") gmsh.finalize() return None # TODO: Identify which part of cross section the entities belong to and add physical group to assign section props # Alternatively it might be more simple to just build the geometries from scratch. # p1, p2 = beam.n1.p, beam.n2.p if geom_repr == "solid": fem_sec = FemSection( f"{beam.name}_sec", "solid", fem.elsets["all_elements"], beam.material, ) fem.add_section(fem_sec) elif geom_repr == "shell": # Get element section properties ents = gmsh.model.occ.getEntities(2) for dim, ent in ents: r = model.occ.getCenterOfMass(2, ent) t, n, c = eval_thick_normal_from_cog_of_beam_plate(beam, r) # name = model.getEntityName(dim, ent) tags, coord, param = model.mesh.getNodes(2, ent, True) # get surface normal on all nodes, i.e. including on the geometrical # singularities (edges/points) # normals = gmsh.model.getNormal(ent, param) # curv = gmsh.model.getCurvature(2, ent, param) # print(ent, r) elemTypes, elemTags, elemNodeTags = model.mesh.getElements(2, ent) femset = FemSet( f"{beam.name}_ent{ent}", [fem.elements.from_id(x) for x in chain.from_iterable(elemTags)], "elset" ) fem.add_set(femset) fem_sec = FemSection( f"{beam.name}_{c}_{ent}", "shell", femset, beam.material, local_z=n, thickness=t, int_points=5, ) fem.add_section(fem_sec) else: # geom_repr == "beam": fem_sec = FemSection( f"d{beam.name}_sec", "beam", fem.elsets["all_elements"], beam.material, beam.section, beam.ori[2], ) fem.add_section(fem_sec) gmsh.finalize()