Пример #1
0
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)
Пример #2
0
    def __init__(self, beam: Beam):
        """

        :param beam:
        """
        self._beam = beam
        self._w = []
        self._p = []
        self._pnames = Counter(prefix="p-load-")
        self._wnames = Counter(prefix="w-load-")
Пример #3
0
def create_usfos_set_str(fem: FEM, nonstrus):
    """USFOS documentation `GroupDef <https://usfos.no/manuals/usfos/users/documents/Usfos_UM_06.pdf#page=119>`_"""

    gr_ids = Counter(1)

    def create_groupdef_str(elset: FemSet):
        if "include" not in elset.metadata.keys():
            return None
        if "unique_id" in elset.metadata.keys():
            gid = elset.metadata["unique_id"]
        else:
            gid = next(gr_ids)

        if "nonstru" in elset.metadata.keys():
            nonstrus.append(gid)

        nline = NewLine(10)
        mem_str = " ".join([f"{x.id}{next(nline)}" for x in elset.members])
        if elset.type == "elset":
            return f" Name  Group         {gid}  {elset.name}\n GroupDef            {gid}  Elem\n {mem_str}\n\n"
        else:
            return f" Name  Group         {gid}  {elset.name}\n GroupNod  {gid}  {mem_str}\n\n"

    gelset = "\n".join(
        filter(
            lambda x: x is not None,
            map(create_groupdef_str, fem.elsets.values()),
        )
    )
    gnset = "\n".join(filter(lambda x: x is not None, map(create_groupdef_str, fem.nsets.values())))
    return gelset + gnset
Пример #4
0
def get_sh_sections_for_shape_obj(model: gmsh.model, model_obj: Shape,
                                  gmsh_data: GmshData, fem: FEM):
    from ada.core.utils import Counter

    sides = Counter(1, "S")

    for dim, ent in gmsh_data.entities:
        _, tag, _ = model.mesh.getElements(2, ent)
        _, _, param = model.mesh.getNodes(2, ent, True)

        elements = [fem.elements.from_id(x) for x in chain.from_iterable(tag)]

        thickness = 0.0
        normal = np.array([
            0.0 if abs(x) == 0.0 else x
            for x in model.getNormal(ent, param)[:3]
        ])
        s = next(sides)
        set_name = make_name_fem_ready(f"el{model_obj.name}{s}_sh")
        fem_sec_name = make_name_fem_ready(f"d{model_obj.name}{s}_sh")

        add_shell_section(set_name,
                          fem_sec_name,
                          normal,
                          thickness,
                          elements,
                          model_obj,
                          fem,
                          is_rigid=True)
Пример #5
0
def univec_str(fem: FEM) -> str:
    out_str = ""
    uvec_id = Counter(1)

    unit_vecs = dict()

    def write_local_z(vec):
        tvec = tuple(vec)
        if tvec in unit_vecs.keys():
            return unit_vecs[tvec], None
        trans_no = next(uvec_id)
        data = [tuple([trans_no, *vec])]
        unit_vecs[tvec] = trans_no
        return trans_no, write_ff("GUNIVEC", data)

    for el in fem.elements.stru_elements:
        local_z = el.fem_sec.local_z
        transno, res_str = write_local_z(local_z)
        if res_str is None:
            el.metadata["transno"] = transno
            continue
        out_str += res_str
        el.metadata["transno"] = transno

    return out_str
Пример #6
0
    def _hinges_str(self):
        from ada.core.utils import Counter

        out_str = ""
        h = Counter(1)

        def write_hinge(hinge):
            dofs = [0 if i in hinge else 1 for i in range(1, 7)]
            fix_id = next(h)
            data = [tuple([fix_id, 3, 0, 0]), tuple(dofs[:4]), tuple(dofs[4:])]
            return fix_id, self.write_ff("BELFIX", data)

        for el in self._gelements:
            h1, h2 = el.metadata.get("h1", None), el.metadata.get("h2", None)
            if h2 is None and h1 is None:
                continue
            h1_fix, h2_fix = 0, 0
            if h1 is not None:
                h1_fix, res_str = write_hinge(h1)
                out_str += res_str
            if h2 is not None:
                h2_fix, res_str = write_hinge(h2)
                out_str += res_str
            el.metadata["fixno"] = h1_fix, h2_fix

        return out_str
Пример #7
0
def get_shell_sections_from_inp(bulk_str, fem: FEM) -> Iterable[FemSection]:
    if bulk_str.lower().find("*shell section") == -1:
        return []

    a = fem.parent.get_assembly()
    sh_name = Counter(1, "sh")
    return (get_shell_section(m, sh_name, fem, a) for m in cards.re_shell.finditer(bulk_str))
Пример #8
0
def convert_hinges_2_couplings(fem: "FEM"):
    """Convert beam hinges to coupling constraints"""
    from ada import Node
    from ada.core.utils import Counter
    from ada.fem.elements import Hinge

    constrain_ids = []

    max_node_id = fem.nodes.max_nid
    new_node_id = Counter(int(max_node_id + 10000))

    def convert_hinge(elem: Elem, hinge: Hinge):
        if hinge.constraint_ref is not None:
            return
        n = hinge.fem_node
        csys = hinge.csys
        d = hinge.retained_dofs

        n2 = Node(n.p, next(new_node_id), parent=elem.parent)
        elem.parent.nodes.add(n2, allow_coincident=True)
        i = elem.nodes.index(n)
        elem.nodes[i] = n2

        if elem.eccentricity is not None:
            if elem.eccentricity.end1 is not None:
                if n == elem.eccentricity.end1.node:
                    elem.eccentricity.end1.node = n2

            if elem.eccentricity.end2 is not None:
                if n == elem.eccentricity.end2.node:
                    elem.eccentricity.end2.node = n2

        if n2.id not in constrain_ids:
            constrain_ids.append(n2.id)
        else:
            logging.error(f"Hinged node {n2} cannot be added twice to different couplings")
            return None

        m_set = FemSet(f"el{elem.id}_hinge{i + 1}_m", [n], "nset")
        s_set = FemSet(f"el{elem.id}_hinge{i + 1}_s", [n2], "nset")

        elem.parent.add_set(m_set)
        elem.parent.add_set(s_set)
        c = Constraint(
            f"el{elem.id}_hinge{i + 1}_co",
            Constraint.TYPES.COUPLING,
            m_set,
            s_set,
            d,
            csys=csys,
        )
        elem.parent.add_constraint(c)
        hinge.constraint_ref = c
        logging.info(f"added constraint {c}")

    for el in fem.elements.lines_hinged:
        if el.hinge_prop.end1 is not None:
            convert_hinge(el, el.hinge_prop.end1)
        if el.hinge_prop.end2 is not None:
            convert_hinge(el, el.hinge_prop.end2)
Пример #9
0
def get_solid_sections_from_inp(bulk_str, fem):
    """

    ** Section: Section-80-MAT2TH1
    *Shell Section, elset=MAT2TH1, material=S3_BS__S355_16_T__40_M2
    0.02, 5

    :param bulk_str:
    :param fem:
    :type fem: ada.fem.FEM

    """
    secnames = Counter(1, "solidsec")

    if bulk_str.lower().find("*solid section") == -1:
        return []
    re_solid = re.compile(
        r"(?:\*\s*Section:\s*(.*?)\n|)\*\Solid Section,\s*elset=(.*?)\s*,\s*material=(.*?)\s*$",
        _re_in,
    )
    solid_iter = re_solid.finditer(bulk_str)

    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,
        )

    return map(grab_solid, solid_iter)
Пример #10
0
def get_interactions_from_bulk_str(bulk_str, assembly):
    """

    :param bulk_str:
    :param assembly:
    :type assembly: ada.Assembly
    :return:
    """
    gen_name = Counter(1, "general")

    if bulk_str.find("** Interaction") == -1 and bulk_str.find(
            "*Contact") == -1:
        return

    def resolve_surface_ref(surf_ref):
        surf_name = surf_ref.split(".")[-1] if "." in surf_ref else surf_ref
        surf = None
        if surf_name in assembly.fem.surfaces.keys():
            surf = assembly.fem.surfaces[surf_name]

        for p in assembly.get_all_parts_in_assembly():
            if surf_name in p.fem.surfaces.keys():
                surf = p.fem.surfaces[surf_name]
        if surf is None:
            raise ValueError("Unable to find surfaces in assembly parts")

        return surf

    for m in AbaCards.contact_pairs.regex.finditer(bulk_str):
        d = m.groupdict()
        intprop = assembly.fem.intprops[d["interaction"]]
        surf1 = resolve_surface_ref(d["surf1"])
        surf2 = resolve_surface_ref(d["surf2"])

        assembly.fem.add_interaction(
            Interaction(d["name"],
                        "surface",
                        surf1,
                        surf2,
                        intprop,
                        metadata=d))

    for m in AbaCards.contact_general.regex.finditer(bulk_str):
        s = m.start()
        e = m.endpos
        interact_str = bulk_str[s:e]
        d = m.groupdict()
        intprop = assembly.fem.intprops[d["interaction"]]
        # surf1 = resolve_surface_ref(d["surf1"])
        # surf2 = resolve_surface_ref(d["surf2"])

        assembly.fem.add_interaction(
            Interaction(next(gen_name),
                        "general",
                        None,
                        None,
                        intprop,
                        metadata=dict(aba_bulk=interact_str)))
Пример #11
0
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))
Пример #12
0
    def add_obj(
        self,
        obj: Union[BackendGeom, Shape, Beam, Plate, Pipe],
        geom_repr=ElemType.SOLID,
        el_order=1,
        silent=True,
        mesh_size=None,
        build_native_lines=False,
        point_tol=Settings.point_tol,
        use_native_pointer=True,
    ):
        from ada.core.utils import Counter

        from .utils import build_bm_lines

        geom_repr = geom_repr.upper()

        self.apply_settings()
        temp_dir = Settings.temp_dir
        os.makedirs(temp_dir, exist_ok=True)

        if build_native_lines is True and geom_repr == ElemType.LINE and type(
                obj) is Beam:
            entities = build_bm_lines(self.model, obj, point_tol)
        else:
            if use_native_pointer and hasattr(self.model.occ,
                                              "importShapesNativePointer"):
                # Use hasattr to ensure that it works for gmsh < 4.9.*
                if type(obj) is Pipe:
                    entities = []
                    for seg in obj.segments:
                        entities += import_into_gmsh_use_nativepointer(
                            seg, geom_repr, self.model)
                else:
                    entities = import_into_gmsh_use_nativepointer(
                        obj, geom_repr, self.model)
            else:
                entities = import_into_gmsh_using_step(obj, geom_repr,
                                                       self.model, temp_dir,
                                                       silent)

        obj_name = Counter(1, f"{obj.name}_")
        for dim, ent in entities:
            ent_name = next(obj_name)
            self.model.set_physical_name(dim, ent, ent_name)
            self.model.set_entity_name(dim, ent, ent_name)

        self.model.occ.synchronize()
        self.model.geo.synchronize()

        gmsh_data = GmshData(entities,
                             geom_repr,
                             el_order,
                             obj,
                             mesh_size=mesh_size)
        self.model_map[obj] = gmsh_data
        return gmsh_data
Пример #13
0
def get_shell_sections_from_inp(bulk_str, fem):
    """

    ** Section: Section-80-MAT2TH1
    *Shell Section, elset=MAT2TH1, material=S3_BS__S355_16_T__40_M2
    0.02, 5
    :param bulk_str:
    :param fem:
    :type fem: ada.fem.FEM
    :return: map object containing list of FemSection objects

    """

    shname = Counter(1, "sh")

    if bulk_str.lower().find("*shell section") == -1:
        return []
    re_offset = r"(?:, offset=(?P<offset>.*?)|)"
    re_controls = r"(?:, controls=(?P<controls>.*?)|)"

    re_shell = re.compile(
        rf"(?:\*\s*Section:\s*(?P<name>.*?)\n|)\*\Shell Section, elset"
        rf"=(?P<elset>.*?)\s*, material=(?P<material>.*?){re_offset}{re_controls}\s*\n(?P<t>.*?),"
        rf"(?P<int_points>.*?)$",
        _re_in,
    )

    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,
        )

    return map(grab_shell, re_shell.finditer(bulk_str))
Пример #14
0
def shorten_material_names(assembly):
    """:type assembly: ada.Assembly"""
    from ada.core.utils import Counter

    short_suffix = Counter(1)
    for p in assembly.get_all_parts_in_assembly(True):
        for mat in p.materials:
            name_len = 5
            if len(mat.name) > name_len:
                short_mat_name = mat.name[:name_len]
                if short_mat_name in p.materials.name_map.keys():
                    short_mat_name = short_mat_name[:-3] + str(
                        next(short_suffix))
                mat.name = short_mat_name
                p.materials.recreate_name_and_id_maps(p.materials._materials)
Пример #15
0
def multisession_gmsh_tasker(fem: FEM, gmsh_tasks: List[GmshTask]):
    """Run multiple meshing operations within a single GmshSession."""

    model_names = Counter(1, "gmsh")
    with GmshSession(silent=True) as gs:
        for gtask in gmsh_tasks:
            gs.model.add(next(model_names))
            gs.options = gtask.options
            for obj in gtask.ada_obj:
                gs.add_obj(obj, gtask.geom_repr)
            gs.mesh(gtask.mesh_size)

            # TODO: Add operand type += for FEM
            tmp_fem = gs.get_fem()
            tmp_fem.parent = fem.parent
            fem += tmp_fem
            gs.model_map = dict()
    return fem
Пример #16
0
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)
Пример #17
0
    def _univec_str(self):
        from ada.core.utils import Counter

        out_str = ""
        unit_vector = Counter(1)

        def write_local_z(vec):
            transno = next(unit_vector)
            data = [tuple([transno, *vec])]
            return transno, self.write_ff("GUNIVEC", data)

        for el in self._gelements:
            local_z = el.fem_sec.local_z
            transno, res_str = write_local_z(local_z)
            out_str += res_str
            el.metadata["transno"] = transno

        return out_str
Пример #18
0
    def create_usfos_set_str(self):
        """
        From USFOS documentation `GroupDef <http://usfos.no/manuals/usfos/users/documents/Usfos_UM_06.pdf#page=119>`_

        """
        from ada.core.utils import Counter, NewLine

        gr_ids = Counter(1)

        def create_groupdef_str(elset):
            """

            :param elset:
            :type elset: ada.fem.FemSet
            """

            if "include" not in elset.metadata.keys():
                return None
            if "unique_id" in elset.metadata.keys():
                gid = elset.metadata["unique_id"]
            else:
                gid = next(gr_ids)

            if "nonstru" in elset.metadata.keys():
                self._gnonstru.append(gid)

            nline = NewLine(10)
            mem_str = " ".join([f"{x.id}{next(nline)}" for x in elset.members])
            if elset.type == "elset":
                return f" Name  Group         {gid}  {elset.name}\n GroupDef            {gid}  Elem\n {mem_str}\n\n"
            else:
                return f" Name  Group         {gid}  {elset.name}\n GroupNod  {gid}  {mem_str}\n\n"

        gelset = "\n".join(
            filter(
                lambda x: x is not None,
                map(create_groupdef_str, self._gelsets.values()),
            ))
        gnset = "\n".join(
            filter(lambda x: x is not None,
                   map(create_groupdef_str, self._gnsets.values())))
        return gelset + gnset
Пример #19
0
    def renumber(self):
        from ada.core.utils import Counter

        elid = Counter(1)

        def mapid2(el):
            """

            :param el:
            :type el: ada.fem.Elem
            :return:
            """
            el.id = next(elid)

        list(map(mapid2, self._elements))
        self._idmap = {e.id: e
                       for e in self._elements
                       } if len(self._elements) > 0 else dict()

        self._group_by_types()
Пример #20
0
class Penetration(BackendGeom):
    _name_gen = Counter(1, "Pen")
    """A penetration object. Wraps around a primitive"""
    # TODO: Maybe this class should be evaluated for removal?
    def __init__(self, primitive, metadata=None, parent=None, units="m", guid=None):
        if issubclass(type(primitive), Shape) is False:
            raise ValueError(f'Unsupported primitive type "{type(primitive)}"')

        super(Penetration, self).__init__(primitive.name, guid=guid, metadata=metadata, units=units)
        self._primitive = primitive
        self._parent = parent
        self._ifc_opening = None

    @property
    def primitive(self):
        return self._primitive

    @property
    def geom(self):
        return self.primitive.geom

    @property
    def units(self):
        return self._units

    @units.setter
    def units(self, value):
        if value != self._units:
            self.primitive.units = value
            self._units = value

    @property
    def ifc_opening(self):
        if self._ifc_opening is None:
            from ada.ifc.write.write_openings import generate_ifc_opening

            self._ifc_opening = generate_ifc_opening(self)
        return self._ifc_opening

    def __repr__(self):
        return f"Pen(type={self.primitive})"
Пример #21
0
    def renumber(self):
        from ada.core.utils import Counter

        elid = Counter(0)

        def mapid2(el):
            """

            :param el:
            :type el: ada.fem.Elem
            :return:
            """
            el.id = next(elid)

        list(map(mapid2, self._elements))
        self._idmap = {e.id: e for e in self._elements} if len(self._elements) > 0 else dict()

        if len(self._elements) > 0:
            self._by_types = groupby(self._elements, key=attrgetter("type", "elset"))
        else:
            self._by_types = dict()
Пример #22
0
def update_connector_data(bulk_str: str, fem: FEM):
    """Extract connector elements from bulk string"""

    nsuffix = Counter(1, "_")
    for m in cards.connector_section.regex.finditer(bulk_str):
        d = m.groupdict()
        csys_ref = d["csys"].replace('"', "")
        name = d["behavior"] + next(nsuffix)
        elset = fem.elsets[d["elset"]]
        connector: Connector = elset.members[0]
        con_sec = fem.connector_sections[d["behavior"]]
        csys_ref = csys_ref[:-1] if csys_ref[-1] == "," else csys_ref
        csys = fem.lcsys[csys_ref]
        con_type = d["contype"]
        if con_type[-1] == ",":
            con_type = con_type[:-1]

        connector.elset = elset
        connector.name = name
        connector.con_sec = con_sec
        connector.con_type = con_type
        connector.csys = csys
Пример #23
0
def test_edges_intersect(test_meshing_dir):
    bm_name = Counter(1, "bm")
    pl = ada.Plate("pl1", [(0, 0), (1, 0), (1, 1), (0, 1)], 10e-3)
    points = pl.poly.points3d
    objects = [pl]

    # Beams along 3 of 4 along circumference
    for p1, p2 in zip(points[:-1], points[1:]):
        objects.append(ada.Beam(next(bm_name), p1, p2, "IPE100"))

    # Beam along middle in x-dir
    objects.append(
        ada.Beam(next(bm_name), (0, 0.5, 0.0), (1, 0.5, 0), "IPE100"))

    # Beam along diagonal
    objects.append(ada.Beam(next(bm_name), (0, 0, 0.0), (1, 1, 0), "IPE100"))

    a = ada.Assembly() / (ada.Part("MyPart") / objects)
    p = a.get_part("MyPart")
    # p.connections.find()

    p.fem = p.to_fem_obj(0.1, interactive=False)
Пример #24
0
def get_solid_sections_from_inp(bulk_str, fem: FEM):
    secnames = Counter(1, "solidsec")
    a = fem.parent.get_assembly()
    if bulk_str.lower().find("*solid section") == -1:
        return []

    solid_iter = cards.re_solid.finditer(bulk_str)

    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,
        )

    return map(grab_solid, solid_iter)
Пример #25
0
    def __init__(self,
                 sections: Iterable[Section] = None,
                 parent: Union[Part, Assembly] = None,
                 units="m"):
        sec_id = Counter(1)
        super(Sections, self).__init__(parent=parent)
        sections = [] if sections is None else sections
        self._units = units
        self._sections = sorted(sections, key=attrgetter("name"))

        def section_id_maker(section: Section) -> Section:
            if section.id is None:
                section.id = next(sec_id)
            return section

        [section_id_maker(sec) for sec in self._sections]

        self.recreate_name_and_id_maps(self._sections)

        if len(self._name_map.keys()) != len(self._id_map.keys()):
            logging.warning(
                f"Non-unique ids or name for section container belonging to part '{parent}'"
            )
Пример #26
0
def get_connectors_from_inp(bulk_str, fem):
    """

    :param bulk_str:
    :param fem:
    :type fem: ada.fem.FEM
    :return:
    """

    nsuffix = Counter(1, "_")
    cons = dict()
    for m in AbaCards.connector_section.regex.finditer(bulk_str):
        d = m.groupdict()
        name = d["behavior"] + next(nsuffix)
        elset = fem.elsets[d["elset"]]
        elem = elset.members[0]

        csys_ref = d["csys"].replace('"', "")
        csys_ref = csys_ref[:-1] if csys_ref[-1] == "," else csys_ref

        con_type = d["contype"]
        if con_type[-1] == ",":
            con_type = con_type[:-1]

        n1 = elem.nodes[0]
        n2 = elem.nodes[1]

        cons[name] = Connector(
            name,
            elem.id,
            n1,
            n2,
            con_type,
            fem.connector_sections[d["behavior"]],
            csys=fem.lcsys[csys_ref],
        )
    return cons
Пример #27
0
from OCC.Core.STEPConstruct import stepconstruct_FindEntity
from OCC.Core.STEPControl import (
    STEPControl_AsIs,
    STEPControl_ShellBasedSurfaceModel,
    STEPControl_Writer,
)
from OCC.Core.TCollection import TCollection_HAsciiString

from ada import Assembly, Beam, Part, Pipe, Plate, Shape, Wall
from ada.base.physical_objects import BackendGeom
from ada.core.utils import Counter
from ada.fem.shapes import ElemType

# Reference: https://www.opencascade.com/doc/occt-7.4.0/overview/html/occt_user_guides__step.html#occt_step_3

shp_names = Counter(1, "shp")
valid_types = Union[BackendGeom, Beam, Plate, Wall, Part, Assembly, Shape,
                    Pipe]


class StepExporter:
    def __init__(self, schema="AP242", assembly_mode=1):
        self.writer = STEPControl_Writer()
        fp = self.writer.WS().TransferWriter().FinderProcess()
        self.fp = fp

        Interface_Static_SetCVal("write.step.schema", schema)
        # Interface_Static_SetCVal('write.precision.val', '1e-5')
        Interface_Static_SetCVal("write.precision.mode", "1")
        Interface_Static_SetCVal("write.step.assembly", str(assembly_mode))
Пример #28
0
class FemSection(FemBase):
    id_count = Counter()
    SEC_TYPES = ElemType

    def __init__(
        self,
        name,
        sec_type: str,
        elset: FemSet,
        material: Material,
        section=None,
        local_z=None,
        local_y=None,
        thickness=None,
        int_points=5,
        metadata=None,
        parent=None,
        refs=None,
        sec_id=None,
        is_rigid=False,
    ):
        super().__init__(name, metadata, parent)
        if sec_type is None:
            raise ValueError("Section type cannot be None")
        sec_type = sec_type.upper()
        if sec_type not in ElemType.all:
            raise ValueError(f'Element section type "{sec_type}" is not supported. Must be in {ElemType.all}')
        self._id = sec_id if sec_id is not None else next(FemSection.id_count)
        self._sec_type = sec_type
        self._elset = elset
        self._material = material
        material.refs.append(self)
        self._section = section
        if section is not None:
            section.refs.append(self)
        if self._sec_type == ElemType.LINE:
            if local_y is None and local_z is None:
                raise ValueError("You need to specify either local_y or local_z")
        self._local_z = local_z
        self._local_y = local_y
        self._local_x = None
        if self._sec_type == ElemType.SHELL and thickness is None:
            raise ValueError("Thickness of shell cannot be None")
        self._thickness = thickness
        self._int_points = int_points
        self._refs = refs
        self._is_rigid = is_rigid

    def __hash__(self):
        return hash(f"{self.name}{self.id}")

    def link_elements(self):
        from .elements import Elem

        def link_elem(el: Elem):
            el.fem_sec = self

        list(map(link_elem, self.elset.members))

    @property
    def type(self):
        return self._sec_type

    @property
    def id(self):
        return self._id

    @property
    def elset(self):
        return self._elset

    @elset.setter
    def elset(self, value):
        self._elset = value

    @property
    def local_z(self) -> np.ndarray:
        """Local Z describes the up vector of the cross section"""
        if self._local_z is not None:
            return self._local_z

        if self.type == ElemType.LINE:
            n1, n2 = self.elset.members[0].nodes[0], self.elset.members[0].nodes[-1]
            v = n2.p - n1.p
            if vector_length(v) == 0.0:
                logging.error(f"Element {self.elset.members[0].id} has zero length")
                xvec = [1, 0, 0]
            else:
                xvec = unit_vector(v)
            self._local_z = calc_zvec(xvec, self.local_y)
        elif self.type == ElemType.SHELL:
            self._local_z = normal_to_points_in_plane([n.p for n in self.elset.members[0].nodes])
        else:
            from ada.core.constants import Z

            self._local_z = np.array(Z, dtype=float)

        return self._local_z

    @property
    def local_y(self) -> np.ndarray:
        """Local y describes the cross vector of the beams X and Z axis"""
        if self._local_y is not None:
            return self._local_y

        if self.type == ElemType.LINE:
            el = self.elset.members[0]
            n1, n2 = el.nodes[0], el.nodes[-1]
            v = n2.p - n1.p
            if vector_length(v) == 0.0:
                raise ValueError(f'Element "{el}" has no length. UNable to calculate y-vector')

            xvec = unit_vector(v)

            # See https://en.wikipedia.org/wiki/Cross_product#Coordinate_notation for order of cross product
            vec = calc_yvec(xvec, self.local_z)
        elif self.type == ElemType.SHELL:
            vec = calc_yvec(self.local_x, self.local_z)
        else:
            vec = calc_yvec(self.local_x, self.local_z)

        self._local_y = np.where(abs(vec) == 0, 0, vec)

        return self._local_y

    @property
    def local_x(self) -> np.ndarray:
        if self._local_x is not None:
            return self._local_x

        el = self.elset.members[0]

        if self.type == ElemType.LINE:
            vec = unit_vector(el.nodes[-1].p - el.nodes[0].p)
        elif self.type == ElemType.SHELL:
            vec = unit_vector(el.nodes[1].p - el.nodes[0].p)
        else:
            from ada.core.constants import X

            vec = np.array(X, dtype=float)

        self._local_x = np.round(np.where(abs(vec) == 0, 0, vec), 8)

        return self._local_x

    @property
    def csys(self):
        return [self.local_x, self.local_y, self.local_z]

    @property
    def section(self) -> Section:
        return self._section

    @property
    def material(self) -> Material:
        return self._material

    @material.setter
    def material(self, value):
        self._material = value

    @property
    def thickness(self):
        return self._thickness

    @thickness.setter
    def thickness(self, value):
        self._thickness = value

    @property
    def int_points(self):
        return self._int_points

    @property
    def refs(self) -> List[Union[Beam, Plate]]:
        return self._refs

    def unique_fem_section_permutation(self) -> Tuple[int, Material, Section, tuple, tuple, float]:
        if self.type == self.SEC_TYPES.LINE:
            return self.id, self.material, self.section, tuple(self.local_x), tuple(self.local_z), self.thickness
        elif self.type == self.SEC_TYPES.SHELL:
            return self.id, self.material, self.section, (None,), tuple(self.local_z), self.thickness
        else:
            return self.id, self.material, self.section, (None,), tuple(self.local_z), 0.0

    def has_equal_props(self, other: FemSection):
        equal_mat = self.material == other.material
        if self.type == self.SEC_TYPES.SHELL:
            equal_sec = self.thickness == other.thickness
        elif self.type == self.SEC_TYPES.LINE:
            equal_sec = self.section.equal_props(other.section)
        else:
            equal_sec = True
        if equal_mat is True and equal_sec is True:
            return True
        return False

    # def __eq__(self, other: FemSection):
    #     self_perm = self.unique_fem_section_permutation()
    #     other_perm = other.unique_fem_section_permutation()
    #     return self_perm == other_perm

    def __repr__(self):
        return (
            f'FemSection({self.type} - name: "{self.name}", sec: "{self.section.name}", '
            f'mat: "{self.material.name}",  elset: "{self.elset.name}")'
        )
Пример #29
0
    def to_stp(self, destination_file, geom_repr="solid", schema="AP242"):
        """
        Write current assembly to STEP file

        OpenCascade reference:

            https://www.opencascade.com/doc/occt-7.4.0/overview/html/occt_user_guides__step.html#occt_step_3


        :param destination_file:
        :param geom_repr:
        :param schema: STEP Schemas.
        """

        from OCC.Core.IFSelect import IFSelect_RetError
        from OCC.Core.Interface import Interface_Static_SetCVal
        from OCC.Core.STEPConstruct import stepconstruct_FindEntity
        from OCC.Core.STEPControl import STEPControl_AsIs, STEPControl_Writer
        from OCC.Core.TCollection import TCollection_HAsciiString

        from ada.core.utils import Counter

        if geom_repr not in ["shell", "solid"]:
            raise ValueError(
                'Geometry representation can only accept either "solid" or "shell" as input'
            )

        destination_file = pathlib.Path(destination_file).with_suffix(".stp")

        assembly_mode = 1
        shp_names = Counter(1, "shp")
        writer = STEPControl_Writer()
        fp = writer.WS().TransferWriter().FinderProcess()
        Interface_Static_SetCVal("write.step.schema", schema)
        # Interface_Static_SetCVal('write.precision.val', '1e-5')
        Interface_Static_SetCVal("write.precision.mode", "1")
        Interface_Static_SetCVal("write.step.assembly", str(assembly_mode))

        from ada import Assembly, Beam, Part, Pipe, Plate, Shape, Wall

        def add_geom(geo, o):
            name = o.name if o.name is not None else next(shp_names)
            Interface_Static_SetCVal("write.step.product.name", name)
            stat = writer.Transfer(geo, STEPControl_AsIs)
            if int(stat) > int(IFSelect_RetError):
                raise Exception("Some Error occurred")

            item = stepconstruct_FindEntity(fp, geo)
            if not item:
                logging.debug("STEP item not found for FindEntity")
            else:
                item.SetName(TCollection_HAsciiString(name))

        if type(self) is Shape:
            assert isinstance(self, Shape)
            add_geom(self.geom, self)
        elif type(self) in (Beam, Plate, Wall):
            assert isinstance(self, (Beam, Plate, Wall))
            if geom_repr == "shell":
                add_geom(self.shell, self)
            else:
                add_geom(self.solid, self)
        elif type(self) is Pipe:
            assert isinstance(self, Pipe)
            for geom in self.geometries:
                add_geom(geom, self)
        elif type(self) in (Part, Assembly):
            assert isinstance(self, Part)

            for p in self.get_all_subparts() + [self]:
                for obj in list(p.plates) + list(p.beams) + list(
                        p.shapes) + list(p.pipes) + list(p.walls):
                    if type(obj) in (Plate, Beam, Wall):
                        try:
                            if geom_repr == "shell":
                                add_geom(obj.shell, self)
                            else:
                                add_geom(obj.solid, self)
                        except BaseException as e:
                            logging.info(f'passing pl "{obj.name}" due to {e}')
                            continue
                    elif type(obj) in (Pipe, ):
                        assert isinstance(obj, Pipe)
                        for geom in obj.geometries:
                            add_geom(geom, self)
                    elif type(obj) is Shape:
                        add_geom(obj.geom, self)
                    else:
                        raise ValueError("Unkown Geometry type")

        os.makedirs(destination_file.parent, exist_ok=True)

        status = writer.Write(str(destination_file))
        if int(status) > int(IFSelect_RetError):
            raise Exception("Error during write operation")

        print(f'step file created at "{destination_file}"')
Пример #30
0
    def beam_str(self):
        """

        # USFOS Strings

        # Beam String
        '            Elem ID     np1      np2   material   geom    lcoor    ecc1    ecc2
        BEAM            1127     1343     1344        1        1       1

        # Unit Vector String
        '            Loc-Coo           dx             dy             dz
        UNITVEC    60000001        0.00000        0.00000        1.00000

        """
        from ada.core.utils import Counter

        locvecs = []
        eccen_counter = Counter(1)
        loc_str = "'\n'            Loc-Coo           dx             dy             dz\n"
        bm_str = "'\n'            Elem ID     np1      np2   material   geom    lcoor    ecc1    ecc2\n"

        def write_elem(el):
            """

            :param el:
            :type el: ada.fem.Elem
            """
            nonlocal locvecs
            n1 = el.nodes[0]
            n2 = el.nodes[1]
            fem_sec = el.fem_sec
            mat = fem_sec.material
            sec = fem_sec.section
            xvec = fem_sec.local_z
            xvec_str = f"{xvec[0]:>13.5f}{xvec[1]:>15.5f}{xvec[2]:>15.5f}"

            mat_id = mat.id

            if xvec_str in locvecs:
                locid = locvecs.index(xvec_str)
            else:
                locvecs.append(xvec_str)
                locid = locvecs.index(xvec_str)

            if fem_sec.offset is not None:
                ecc1_str = " 0"
                ecc2_str = " 0"
                for n, e in fem_sec.offset:
                    if n == n1:
                        ecc1 = next(eccen_counter)
                        self._geccen.append((ecc1, e))
                        ecc1_str = f" {ecc1}"
                    if n == n2:
                        ecc2 = next(eccen_counter)
                        self._geccen.append((ecc2, e))
                        ecc2_str = f" {ecc2}"
            else:
                ecc1_str = ""
                ecc2_str = ""
            return f" BEAM{el.id:>15}{n1.id:>8}{n2.id:>9}{mat_id:>11}{sec.id:>7}{locid + 1:>9}{ecc1_str}{ecc2_str}"

        bm_str += "\n".join(list(map(write_elem, self._gelements.beams)))

        for i, loc in enumerate(locvecs):
            loc_str += " UNITVEC{:>13}{:<10}\n".format(i + 1, loc)

        return bm_str + "\n" + loc_str