def get_nodes_and_elements(gmsh_session, fem, fem_set_name="all_elements"): nodes = list(gmsh_session.model.mesh.getNodes(-1, -1)) # Get nodes fem._nodes = Nodes( [ Node( [roundoff(x) for x in gmsh_session.model.mesh.getNode(n)[0]], n, parent=fem, ) for n in nodes[0] ], parent=fem, ) # Get elements elemTypes, elemTags, elemNodeTags = gmsh_session.model.mesh.getElements( 2, -1) elements = [] for k, element_list in enumerate(elemTags): face, dim, morder, numv, parv, _ = gmsh_session.model.mesh.getElementProperties( elemTypes[k]) elem_type = gmsh_map[face] for j, eltag in enumerate(element_list): nodes = [] for i in range(numv): idtag = numv * j + i p1 = elemNodeTags[k][idtag] nodes.append(fem.nodes.from_id(p1)) el = Elem(eltag, nodes, elem_type, parent=fem) elements.append(el) fem._elements = FemElements(elements, fem_obj=fem) femset = FemSet(fem_set_name, elements, "elset") fem.sets.add(femset)
def meshio_read_fem(fem_file, fem_name=None): """Import a FEM file using the meshio package""" mesh = meshio.read(fem_file) name = fem_name if fem_name is not None else "Part-1" fem = FEM(name) def to_node(data): return Node(data[1], data[0]) point_ids = mesh.points_id if "points_id" in mesh.__dict__.keys() else [ i + 1 for i, x in enumerate(mesh.points) ] elem_counter = Counter(1) cell_ids = (mesh.cells_id if "cells_id" in mesh.__dict__.keys() else [[next(elem_counter) for cell in cellblock.data] for cellblock in mesh.cells]) fem.nodes = Nodes([to_node(p) for p in zip(point_ids, mesh.points)]) cell_block_counter = Counter(0) def to_elem(cellblock): block_id = next(cell_block_counter) return [ Elem( cell_ids[block_id][i], [fem.nodes.from_id(point_ids[c]) for c in cell], cellblock.type, ) for i, cell in enumerate(cellblock.data) ] fem.elements = FemElements(chain.from_iterable(map(to_elem, mesh.cells))) return Assembly("TempAssembly") / Part(name, fem=fem)
def get_elements(cls, bulk_str, parent): """ Import elements from Sesam Bulk str :param bulk_str: :param parent: :type parent: ada.fem.FEM :return: FemElementsCollections :rtype: ada.fem.containers.FemElements """ from ada.fem.containers import FemElements def grab_elements(match): d = match.groupdict() nodes = [ parent.nodes.from_id(x) for x in filter( lambda x: x != 0, map(str_to_int, d["nids"].replace("\n", "").split()), ) ] eltyp = d["eltyp"] el_type = cls.sesam_eltype_2_general(eltyp) metadata = dict(eltyad=str_to_int(d["eltyad"]), eltyp=eltyp) return Elem( str_to_int(d["elno"]), nodes, el_type, None, parent=parent, metadata=metadata, ) return FemElements(list(map(grab_elements, cls.re_gelmnt.finditer(bulk_str))), fem_obj=parent)
def get_fem(self, name="AdaFEM") -> FEM: from .utils import ( add_fem_sections, get_elements_from_entities, get_nodes_from_gmsh, ) fem = FEM(name) gmsh_nodes = get_nodes_from_gmsh(self.model, fem) fem.nodes = Nodes(gmsh_nodes, parent=fem) def add_obj_to_elem_ref(el: Elem, obj: Union[Shape, Beam, Plate, Pipe]): el.refs.append(obj) # Get Elements elements = [] for gmsh_data in self.model_map.values(): entity_elements = get_elements_from_entities( self.model, gmsh_data.entities, fem) gmsh_data.obj.elem_refs = entity_elements [add_obj_to_elem_ref(el, gmsh_data.obj) for el in entity_elements] elements += entity_elements fem.elements = FemElements(elements, fem_obj=fem) # Add FEM sections for model_obj, gmsh_data in self.model_map.items(): add_fem_sections(self.model, fem, model_obj, gmsh_data) fem.nodes.renumber() fem.elements.renumber() return fem
def test_from_iterables(self): el1, el2, el3, el4 = get_elems() def geniter(): yield el1 yield el2 yield el3 g = geniter() n = FemElements(g)
def get_fem_from_cache(cache_fem): node_groups = cache_fem["NODES"] fem = FEM(cache_fem.attrs["NAME"]) fem.nodes = get_nodes_from_cache(node_groups, fem) elements = [] for eltype, mesh in cache_fem["MESH"].items(): el_ids = mesh["ELEMENTS"][()] elements += [Elem(el_id[0], [fem.nodes.from_id(eli) for eli in el_id[1:]], eltype) for el_id in el_ids] fem.elements = FemElements(elements, fem) return fem
def get_elem_from_bulk_str(bulk_str, fem: "FEM") -> FemElements: """Read and import all *Element flags""" elements = FemElements( chain.from_iterable( filter(lambda x: x is not None, (grab_elements(m, fem) for m in cards.re_el.finditer(bulk_str)))), fem_obj=fem, ) return elements
def test_from_iterables(elems): el1, el2, el3, el4 = elems def geniter(): yield el1 yield el2 yield el3 g = geniter() n = FemElements(g) assert len(n) == 3
def get_nodes_and_elements(gmsh, fem=None, fem_set_name="all_elements"): """ :param gmsh: :type gmsh: gmsh :param fem: :type fem: ada.fem.FEM :param fem_set_name: :type fem_set_name: str """ from ada.fem import FEM fem = FEM("AdaFEM") if fem is None else fem nodes = list(gmsh.model.mesh.getNodes(-1, -1)) # Get nodes fem._nodes = Nodes( [ Node( [roundoff(x) for x in gmsh.model.mesh.getNode(n)[0]], n, parent=fem, ) for n in nodes[0] ], parent=fem, ) # Get elements elemTypes, elemTags, elemNodeTags = gmsh.model.mesh.getElements(2, -1) elements = [] for k, element_list in enumerate(elemTags): face, dim, morder, numv, parv, _ = gmsh.model.mesh.getElementProperties( elemTypes[k]) elem_type = gmsh_map[face] for j, eltag in enumerate(element_list): nodes = [] for i in range(numv): idtag = numv * j + i p1 = elemNodeTags[k][idtag] nodes.append(fem.nodes.from_id(p1)) el = Elem(eltag, nodes, elem_type, parent=fem) elements.append(el) fem._elements = FemElements(elements, fem_obj=fem) femset = FemSet(fem_set_name, elements, "elset") fem.sets.add(femset)
def meshio_read_fem(assembly, fem_file, fem_name=None): """ Import a FEM file using the meshio package. :param assembly: Assembly object :param fem_file: Path to fem file :param fem_name: Name of FEM model :type assembly: ada.Assembly """ from ada import Node, Part from . import meshio_to_ada_type mesh = meshio.read(fem_file) name = fem_name if fem_name is not None else "Part-1" fem = FEM(name) def to_node(data): return Node(data[1], data[0]) point_ids = mesh.points_id if "points_id" in mesh.__dict__.keys() else [ i + 1 for i, x in enumerate(mesh.points) ] elem_counter = Counter(0) cell_ids = (mesh.cells_id if "cells_id" in mesh.__dict__.keys() else [[next(elem_counter) for cell in cellblock.data] for cellblock in mesh.cells]) fem._nodes = Nodes([to_node(p) for p in zip(point_ids, mesh.points)]) cell_block_counter = Counter(-1) def to_elem(cellblock): block_id = next(cell_block_counter) return [ Elem( cell_ids[block_id][i], [fem.nodes.from_id(point_ids[c]) for c in cell], meshio_to_ada_type[cellblock.type], ) for i, cell in enumerate(cellblock.data) ] fem._elements = FemElements(chain.from_iterable(map(to_elem, mesh.cells))) assembly.add_part(Part(name, fem=fem))
def get_mass_from_bulk(bulk_str, parent: "FEM") -> FemElements: """ *MASS,ELSET=MASS3001 2.00000000E+03, :return: """ mass_ids = Counter(int(parent.elements.max_el_id + 1)) re_masses = re.compile( r"\*(?P<mass_type>Nonstructural Mass|Mass|Rotary Inertia),\s*elset=(?P<elset>.*?)" r"(?:,\s*type=(?P<ptype>.*?)\s*|\s*)(?:, units=(?P<units>.*?)|\s*)\n\s*(?P<mass>.*?)$", _re_in, ) return FemElements( (get_mass(m, parent, mass_ids) for m in re_masses.finditer(bulk_str)), fem_obj=parent)
def get_elements(bulk_str: str, fem: FEM) -> Tuple[FemElements, dict, dict, dict]: """Import elements from Sesam Bulk str""" mass_elem = dict() spring_elem = dict() internal_external_element_map = dict() def grab_elements(match): d = match.groupdict() el_no = str_to_int(d["elno"]) el_nox = str_to_int(d["elnox"]) internal_external_element_map[el_no] = el_nox nodes = [ fem.nodes.from_id(x) for x in filter( lambda x: x != 0, map(str_to_int, d["nids"].replace("\n", "").split()), ) ] eltyp = d["eltyp"] el_type = sesam_eltype_2_general(str_to_int(eltyp)) if el_type in ("SPRING1", "SPRING2"): spring_elem[el_no] = dict(gelmnt=d) return None metadata = dict(eltyad=str_to_int(d["eltyad"]), eltyp=eltyp) elem = Elem(el_no, nodes, el_type, None, parent=fem, metadata=metadata) if el_type == Elem.EL_TYPES.MASS_SHAPES.MASS: logging.warning( "Mass element interpretation in sesam is undergoing changes. Results should be checked" ) mass_elem[el_no] = dict(gelmnt=d) fem.sets.add( FemSet(f"m{el_no}", [elem], FemSet.TYPES.ELSET, parent=fem)) return elem elements = FemElements(filter( lambda x: x is not None, map(grab_elements, cards.re_gelmnt.finditer(bulk_str))), fem_obj=fem) return elements, mass_elem, spring_elem, internal_external_element_map
def test_empty(): n = FemElements([]) assert len(n) == 0
def get_elem_from_inp(bulk_str, fem): """ Extract elements from abaqus input file :param bulk_str: :param fem: :type fem: ada.fem.FEM :return: :rtype: ada.fem.containers.FemElements """ from ada import Node, Part re_el = re.compile( r"^\*Element,\s*type=(?P<eltype>.*?)(?:\n|,\s*elset=(?P<elset>.*?)\s*\n)(?<=)(?P<members>(?:.*?)(?=\*|\Z))", _re_in, ) def grab_elements(match): d = match.groupdict() eltype = d["eltype"] elset = d["elset"] members = d["members"] res = re.search("[a-zA-Z]", members) if eltype.upper( ) in ElemShapes.cube20 + ElemShapes.cube27 or res is None: if eltype.upper() in ElemShapes.cube20 + ElemShapes.cube27: temp = members.splitlines() ntext = "".join([ l1.strip() + " " + l2.strip() + "\n" for l1, l2 in zip(temp[:-1:2], temp[1::2]) ]) else: ntext = d["members"] res = np.fromstring(ntext.replace("\n", ","), sep=",", dtype=int) n = ElemShapes.num_nodes(eltype) + 1 res_ = res.reshape(int(res.size / n), n) return [ Elem(e[0], [fem.nodes.from_id(n) for n in e[1:]], eltype, elset, parent=fem) for e in res_ ] else: # TODO: This code needs to be re-worked! elems = [] for li in members.splitlines(): new_mem = [] temp = li.split(",") elid = str_to_int(temp[0]) for d in temp[1:]: temp2 = [x.strip() for x in d.split(".")] par_ = None if len(temp2) == 2: par, setr = temp2 pfems = [] parents = fem.parent.get_all_parts_in_assembly() for p in parents: assert isinstance(p, Part) pfems.append(p.fem.name) if p.fem.name == par: par_ = p break if par_ is None: raise ValueError( f'Unable to find parent for "{par}"') r = par_.fem.nodes.from_id(str_to_int(setr)) if type(r) != Node: raise ValueError("Node ID not found") new_mem.append(r) else: r = fem.nodes.from_id(str_to_int(d)) if type(r) != Node: raise ValueError("Node ID not found") new_mem.append(r) elems.append(Elem(elid, new_mem, eltype, elset, parent=fem)) return elems return FemElements( chain.from_iterable(map(grab_elements, re_el.finditer(bulk_str))), fem_obj=fem, )
def test_from_sequence(self): all_elemes = get_elems() n = FemElements(all_elemes[:3]) assert len(n) == 3
def test_with_duplicates(self): el1, el2, el3, el4 = get_elems() n = FemElements([el1, el2, el1]) assert len(n) == 3
def test_with_duplicates(elems): el1, el2, el3, el4 = elems with pytest.raises(ValueError): FemElements([el1, el2, el1])
def test_from_sequence(elems): n = FemElements(elems[:3]) assert len(n) == 3
def mesh( self, size=0.1, order=1, max_dim=2, interactive=False, mesh_algo=8, sh_int_points=5, ): """ :param size: :param order: :param max_dim: :param interactive: :param mesh_algo: :param sh_int_points: :return: """ part = self._part pl_in = [pl_ for p in part.get_all_subparts() for pl_ in p.plates] + [pl for pl in part.plates] bm_in = [bm_ for p in part.get_all_subparts() for bm_ in p.beams] + [bm for bm in part.beams] try: gmsh.finalize() except BaseException as e: logging.debug(e) gmsh.initialize() gmsh.option.setNumber("General.Terminal", 1) gmsh.option.setNumber("Mesh.SecondOrderIncomplete", 1) gmsh.option.setNumber("Mesh.Algorithm", mesh_algo) gmsh.option.setNumber("Mesh.ElementOrder", order) list( map( functools.partial( self._create_plate_geom, beams=bm_in, size=size, interactive=interactive, ), pl_in, )) gmsh.model.geo.synchronize() list( map( functools.partial(self._create_bm_geom, size=size), filter(lambda x: x not in [b for b in self._bm_map.values()], bm_in), )) gmsh.model.geo.synchronize() if len(pl_in) > 0: gmsh.model.mesh.setRecombine(2, 1) gmsh.model.mesh.generate(max_dim) gmsh.model.mesh.removeDuplicateNodes() if interactive: gmsh.fltk.run() nodes = list(gmsh.model.mesh.getNodes(-1, -1)) # Extract Gmsh model information and import the data into a FEM model self._part.fem._nodes = Nodes(list(map(self.get_mesh_nodes, nodes[0])), parent=self._part.fem) bm_elems = map(functools.partial(self.get_beam_elements, order=order), self._bm_map.keys()) pl_elems = map(functools.partial(self.get_shell_elements, order=order), self._pl_map.keys()) self._part.fem._elements = FemElements( chain.from_iterable(list(bm_elems) + list(pl_elems)), fem_obj=self._part.fem) self._part.fem.elements.renumber() gmsh.finalize()
def get_mass(bulk_str: str, fem: FEM, mass_elem: dict) -> FemElements: def checkEqual2(iterator): return len(set(iterator)) <= 1 def find_bnmass(match) -> Mass: d = match.groupdict() nodeno = str_to_int(d["nodeno"]) mass_in = [ roundoff(d["m1"]), roundoff(d["m2"]), roundoff(d["m3"]), roundoff(d["m4"]), roundoff(d["m5"]), roundoff(d["m6"]), ] masses = [m for m in mass_in if m != 0.0] if checkEqual2(masses): mass_type = Mass.PTYPES.ISOTROPIC masses = [masses[0]] if len(masses) > 0 else [0.0] else: mass_type = Mass.PTYPES.ANISOTROPIC no = fem.nodes.from_id(nodeno) fem_set = fem.sets.add( FemSet(f"m{nodeno}", [no], FemSet.TYPES.NSET, parent=fem)) el_id = fem.elements.max_el_id + 1 elem = fem.elements.add( Elem(el_id, [no], Elem.EL_TYPES.MASS_SHAPES.MASS, None, parent=fem)) mass = Mass(f"m{nodeno}", fem_set, masses, Mass.TYPES.MASS, ptype=mass_type, parent=fem, mass_id=el_id) elset = fem.sets.add( FemSet(f"m{nodeno}", [elem], FemSet.TYPES.ELSET, parent=fem)) elem.mass_props = mass elem.elset = elset return mass def find_mgmass(match) -> Mass: d = match.groupdict() matno = str_to_int(d["matno"]) mat_mass_map = { str_to_int(val["section_data"]["matno"]): val for key, val in mass_elem.items() } mass_el: dict = mat_mass_map.get(matno, None) if mass_el is None: raise ValueError() ndof = str_to_int(d["ndof"]) if ndof != 6: raise NotImplementedError( "Only mass matrices with 6 DOF are currently supported for reading" ) r = [float(x) for x in d["bulk"].split()] A = np.matrix([ [r[0], 0.0, 0.0, 0.0, 0.0, 0.0], [r[1], r[6], 0.0, 0.0, 0.0, 0.0], [r[2], r[7], r[11], 0.0, 0.0, 0.0], [r[3], r[8], r[12], r[15], 0.0, 0.0], [r[4], r[9], r[13], r[16], r[18], 0.0], [r[5], r[10], r[14], r[17], r[19], r[20]], ]) # use symmetry to complete the 6x6 matrix mass_matrix_6x6 = np.tril(A) + np.triu(A.T, 1) nodeno = str_to_int(mass_el["gelmnt"].get("nids")) elno = str_to_int(mass_el["gelmnt"].get("elno")) no = fem.nodes.from_id(nodeno) fem_set = fem.sets.add( FemSet(f"m{nodeno}", [no], FemSet.TYPES.NSET, parent=fem)) mass_type = Mass.PTYPES.ANISOTROPIC mass = Mass(f"m{nodeno}", fem_set, mass_matrix_6x6, Mass.TYPES.MASS, ptype=mass_type, parent=fem, mass_id=elno) mass_el["el"] = mass return mass bn_masses = map(find_bnmass, cards.re_bnmass.finditer(bulk_str)) mg_masses = map(find_mgmass, cards.re_mgmass.finditer(bulk_str)) return FemElements(chain(bn_masses, mg_masses), fem_obj=fem)
def read_fem(assembly, fem_file, fem_name=None): """ :param assembly: :param fem_file: :param fem_name: :return: """ from ada import Node, Part f = h5py.File(fem_file, "r") # Mesh ensemble mesh_ensemble = f["ENS_MAA"] meshes = mesh_ensemble.keys() if len(meshes) != 1: raise ValueError("Must only contain exactly 1 mesh, found {}.".format(len(meshes))) mesh_name = list(meshes)[0] mesh = mesh_ensemble[mesh_name] dim = mesh.attrs["ESP"] fem_name = fem_name if fem_name is not None else mesh_name # Initialize FEM object fem = FEM(mesh_name) # Possible time-stepping if "NOE" not in mesh: # One needs NOE (node) and MAI (French maillage, meshing) data. If they # are not available in the mesh, check for time-steppings. time_step = mesh.keys() if len(time_step) != 1: raise ValueError(f"Must only contain exactly 1 time-step, found {len(time_step)}.") mesh = mesh[list(time_step)[0]] # Points pts_dataset = mesh["NOE"]["COO"] n_points = pts_dataset.attrs["NBR"] points = pts_dataset[()].reshape((n_points, dim), order="F") if "NUM" in mesh["NOE"]: point_num = list(mesh["NOE"]["NUM"]) else: logging.warning("No node information is found on MED file") point_num = np.arange(1, len(points) + 1) fem._nodes = Nodes([Node(p, point_num[i]) for i, p in enumerate(points)], parent=fem) # Point tags tags = None if "FAM" in mesh["NOE"]: tags = mesh["NOE"]["FAM"][()] # Information for point tags point_tags = {} fas = mesh["FAS"] if "FAS" in mesh else f["FAS"][mesh_name] if "NOEUD" in fas: point_tags = _read_families(fas["NOEUD"]) point_sets = _point_tags_to_sets(tags, point_tags, fem) if tags is not None else [] # Information for cell tags cell_tags = {} if "ELEME" in fas: cell_tags = _read_families(fas["ELEME"]) # CellBlock cell_types = [] med_cells = mesh["MAI"] elements = [] element_sets = dict() for med_cell_type, med_cell_type_group in med_cells.items(): if med_cell_type == "PO1": logging.warning("Point elements are still not supported") continue cell_type = med_to_abaqus_type(med_cell_type) cell_types.append(cell_type) nod = med_cell_type_group["NOD"] n_cells = nod.attrs["NBR"] nodes_in = nod[()].reshape(n_cells, -1, order="F") if "NUM" in med_cell_type_group.keys(): num = list(med_cell_type_group["NUM"]) else: num = np.arange(0, len(nodes_in)) element_block = [ Elem(num[i], [fem.nodes.from_id(e) for e in c], cell_type, parent=fem) for i, c in enumerate(nodes_in) ] elements += element_block # Cell tags if "FAM" in med_cell_type_group: cell_data = med_cell_type_group["FAM"][()] cell_type_sets = _cell_tag_to_set(cell_data, cell_tags) for key, val in cell_type_sets.items(): if key not in element_sets.keys(): element_sets[key] = [] element_sets[key] += [element_block[i] for i in val] fem._elements = FemElements(elements, fem) elsets = [] for name, values in element_sets.items(): elsets.append(FemSet(name, values, "elset", parent=fem)) fem._sets = FemSets(elsets + point_sets, fem_obj=fem) assembly.add_part(Part(fem_name, fem=fem)) return
def test_empty(self): n = FemElements([])