def add_section(self, section: FemSection) -> FemSection: section.parent = self if section.elset.parent is None: if section.elset.name in self.elsets.keys(): fs = self.elsets[section.elset.name] else: fs = self.sets.add(section.elset) if fs != section.elset: logging.info( f'Element set "{section.elset}" is replaced by {fs}') section.elset = fs if section.material.parent is None and self.parent is not None: self.parent.add_material(section.material) self.sections.add(section) return section
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 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_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 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 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 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_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 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_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 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 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 create_sconcept_str(fem_sec: FemSection) -> Tuple[str, str, str]: sconcept_str = "" # Give concept relationship based on inputted values beams = [x for x in fem_sec.refs if type(x) is Beam] if len(beams) != 1: raise ValueError("A FemSection cannot be sourced from multiple beams") beam = beams[0] fem_sec.metadata["ircon"] = next(concept_ircon) bm_name = make_name_fem_ready(beam.name, no_dot=True) tdsconc_str = write_ff( "TDSCONC", [(4, fem_sec.metadata["ircon"], 100 + len(bm_name), 0), (bm_name, )], ) sconcept_str += write_ff("SCONCEPT", [(8, next(concept), 7, 0), (0, 1, 0, 2)]) sconc_ref = next(concept) sconcept_str += write_ff("SCONCEPT", [(5, sconc_ref, 2, 4), (1, )]) elids: List[tuple] = [] i = 0 numel = len(beam.elem_refs) elid_bulk = [numel] for el in fem_sec.elset.members: if i == 3: elids.append(tuple(elid_bulk)) elid_bulk = [] i = -1 elid_bulk.append(el.id) i += 1 if len(elid_bulk) != 0: elids.append(tuple(elid_bulk)) mesh_args = [(5 + numel, sconc_ref, 1, 2)] + elids scon_mesh = write_ff("SCONMESH", mesh_args) return tdsconc_str, sconcept_str, scon_mesh