Source code for axisvm.com.axline

# -*- coding: utf-8 -*-
from typing import Iterable

import awkward as ak
import numpy as np
from numpy import ndarray as Array
from sigmaepsilon.mesh import TopologyArray
from sigmaepsilon.mesh.plotting import plot_lines_plotly

import axisvm

from .core.abc import AxisVMModelItem, AxisVMModelItems
from .core.utils import RMatrix3x3toNumPy, RStiffness2dict
from .attr import AxisVMAttributes


linetype_to_str = {
    0: "Truss",
    1: "Beam",
    2: "Rib",
    3: "Spring",
    4: "Gap",
    5: "Edge",
    6: "Hole",
    7: "SimpleLine",
    8: "NNLink",
    9: "LLLink",
}

springdir_to_str = {
    0: "Global",
    1: "Geometry",
    2: "PointReference",
    3: "VectorReference",
    4: "ElementRelative",
    5: "NodeRelative",
}

trusstype_to_str = {
    0: "TensionAndCompression",  # linear behaviour
    1: "TensionOnly",  # tension only
    2: "CompressionOnly",  # compression only
}

gaptype_to_str = {
    0: "ActiveInTension",  # gap active in tension only
    1: "ActiveInCompression",  # gap active in compression only
}

geomtype_to_str = {
    0: "StraightLine",
    1: "CircleArc",
}

line_data_fields = ["NodeId1", "NodeId2", "GeomType", "CircleArc"]

line_attr_fields = [
    "LineType",
    "MaterialIndex",
    "StartCrossSectionIndex",
    "EndCrossSectionIndex",
    "AutoEccentricityType",
]


def get_line_attributes(
    obj, *args, i=None, fields=None, raw=False, rec=None, **kwargs
) -> AxisVMAttributes:
    """
    Turns a collection of RLineAttr records into dictionaries compatible
    with `awkward` and `pandas`.

    """
    if fields is None:
        fields = line_attr_fields
    elif isinstance(fields, str):
        fields = [fields]
    elif isinstance(fields, Iterable):
        fields = list(filter(lambda i: i in line_attr_fields, fields))
    if rec is None:
        i = i if len(args) == 0 else args[0]
        rec = obj._get_attributes_raw(i)
    if raw:
        return rec
    else:
        rec = rec[0]

    def xyz(p):
        return [p.x, p.y, p.z]

    def xyz2(p):
        return [p.xx, p.yy, p.zz]

    data = {}

    if "LineType" in fields:
        data["LineType"] = list(map(lambda r: linetype_to_str[r.LineType], rec))
    if "MaterialIndex" in fields:
        data["MaterialIndex"] = list(map(lambda r: r.MaterialIndex, rec))
    if "StartCrossSectionIndex" in fields:
        data["StartCrossSectionIndex"] = list(
            map(lambda r: r.StartCrossSectionIndex, rec)
        )
    if "EndCrossSectionIndex" in fields:
        data["EndCrossSectionIndex"] = list(map(lambda r: r.EndCrossSectionIndex, rec))
    if "AutoEccentricityType" in fields:
        data["AutoEccentricityType"] = list(map(lambda r: r.AutoEccentricityType, rec))
    if "StartEccentricity" in fields:
        data["StartEccentricity"] = list(
            map(lambda r: RMatrix3x3toNumPy(r.StartEccentricity), rec)
        )
    if "EndEccentricity" in fields:
        data["EndEccentricity"] = list(
            map(lambda r: RMatrix3x3toNumPy(r.EndEccentricity), rec)
        )
    if "TrussType" in fields:
        data["TrussType"] = list(map(lambda r: trusstype_to_str[r.TrussType], rec))
    if "Resistance" in fields:
        data["Resistance"] = list(map(lambda r: r.Resistance, rec))

    if "ServiceClass" in fields:
        data["ServiceClass"] = list(map(lambda r: r.ServiceClass, rec))
    if "kdef" in fields:
        data["kdef"] = list(map(lambda r: r.kdef, rec))
    if "kx" in fields:
        data["kx"] = list(map(lambda r: r.kx, rec))
    if "Domain1" in fields:
        data["Domain1"] = list(map(lambda r: r.Domain1, rec))
    if "Domain2" in fields:
        data["Domain2"] = list(map(lambda r: r.Domain2, rec))

    if "GapType" in fields:
        data["GapType"] = list(map(lambda r: gaptype_to_str[r.GapType], rec))
    if "ActiveStiffness" in fields:
        data["ActiveStiffness"] = list(map(lambda r: r.ActiveStiffness, rec))
    if "InactiveStiffness" in fields:
        data["InactiveStiffness"] = list(map(lambda r: r.InactiveStiffness, rec))
    if "InitialOpening" in fields:
        data["InitialOpening"] = list(map(lambda r: r.InitialOpening, rec))
    if "MinPenetration" in fields:
        data["MinPenetration"] = list(map(lambda r: r.MinPenetration, rec))
    if "MaxPenetration" in fields:
        data["MaxPenetration"] = list(map(lambda r: r.MaxPenetration, rec))
    if "AdjustmentRatio" in fields:
        data["AdjustmentRatio"] = list(map(lambda r: r.AdjustmentRatio, rec))
    if "SpringDirection" in fields:
        data["SpringDirection"] = list(
            map(lambda r: springdir_to_str[r.SpringDirection], rec)
        )
    if "Stiffnesses" in fields:
        data["Stiffnesses"] = list(map(lambda r: RStiffness2dict(r.Stiffnesses), rec))

    return AxisVMAttributes(data)


[docs]class IAxisVMLine(AxisVMModelItem): """Wrapper for the `IAxisVMLine` COM interface.""" @property def Index(self): return self.parent.IndexOf(self.StartNode, self.EndNode) @property def attributes(self): return self.parent.get_attributes(self.Index) @property def line_attributes(self): return self.parent.get_line_attributes(self.Index) @property def line_data(self): return self.parent.get_line_data(self.Index) @property def tr(self): return self.transformation_matrix() def record(self): return self.parent.records(self.Index) def _get_attrs(self): """Return the representation methods (internal helper).""" attrs = [] attrs.append(("Length", self.Length, axisvm.FLOAT_FORMAT)) attrs.append(("Volume", self.Volume, axisvm.FLOAT_FORMAT)) attrs.append(("Weight", self.Weight, axisvm.FLOAT_FORMAT)) return attrs def topology(self) -> TopologyArray: return TopologyArray(ak.Array([self.StartNode, self.EndNode])) def transformation_matrix(self) -> Array: return self.model.Members[self.MemberId].transformation_matrix()
[docs]class IAxisVMLines(AxisVMModelItems): """Wrapper for the `IAxisVMLines` COM interface.""" __itemcls__ = IAxisVMLine @property def frames(self) -> Array: return self.transformation_matrices() @property def attributes(self): return self.get_attributes() @property def line_attributes(self): return self.get_line_attributes() @property def line_data(self): return self.get_line_data() @property def tr(self): return self.transformation_matrices() def records(self, *args, **kwargs): return self.get_line_data(*args, raw=True, **kwargs) def topology(self, *args, i=None) -> TopologyArray: lines = self.wrapped i = i if len(args) == 0 else args[0] if isinstance(i, int): line = self[i].wrapped return TopologyArray(ak.Array([line.StartNode, line.EndNode])) if isinstance(i, np.ndarray): inds = i else: if isinstance(i, Iterable): inds = np.array(i, dtype=int) else: inds = np.array(list(range(lines.Count))) + 1 def fnc(i): return [lines.Item[i].StartNode, lines.Item[i].EndNode] return TopologyArray(ak.Array(list(map(fnc, inds)))) def transformation_matrices(self, *args, i=None) -> Array: i = i if len(args) == 0 else args[0] if isinstance(i, int): ids = [i] if isinstance(i, np.ndarray): ids = i else: if isinstance(i, Iterable): ids = np.array(i, dtype=int) else: ids = np.array(list(range(self.Count))) + 1 mids = np.array(self.BulkGetMemberIds(ids)[0]) if len(mids) == 1: return self.model.Members[mids[0]].transformation_matrix() uids, imap = np.unique(mids, return_inverse=True) mtr = self.model.Members.transformation_matrices(uids) imap -= 1 return np.array(list(map(lambda i: mtr[i], imap))) def _get_line_data_raw(self, *args, i=None) -> Iterable: i = i if len(args) == 0 else args[0] if isinstance(i, int): ids = np.array([i]) elif isinstance(i, np.ndarray): ids = i else: if isinstance(i, Iterable): ids = np.array(i, dtype=int) else: ids = np.array(list(range(self.Count))) + 1 return self.BulkGetLineData(ids) def get_line_data(self, *args, i=None, fields=None, raw=False) -> AxisVMAttributes: if fields is None: fields = line_data_fields elif isinstance(fields, str): fields = [fields] elif isinstance(fields, Iterable): fields = list(filter(lambda i: i in line_data_fields, fields)) i = i if len(args) == 0 else args[0] rec = self._get_line_data_raw(i) if raw: return rec else: rec = rec[0] data = {} if "NodeId1" in fields: data["NodeId1"] = list(map(lambda r: r.NodeId1, rec)) if "NodeId2" in fields: data["NodeId2"] = list(map(lambda r: r.NodeId2, rec)) if "GeomType" in fields: data["GeomType"] = list(map(lambda r: geomtype_to_str[r.GeomType], rec)) if "CircleArc" in fields: def xyz(p): return [p.x, p.y, p.z] def foo(ca): return dict( Center=xyz(ca.Center), NormalVector=xyz(ca.NormalVector), Alfa=ca.Alfa, ) def CircleArc(r): return foo(r.CircleArc) if r.GeomType == 1 else None data["CircleArc"] = list(map(CircleArc, rec)) return AxisVMAttributes(data) def _get_line_attributes_raw(self, *args, i=None, **kwargs) -> Iterable: i = i if len(args) == 0 else args[0] if isinstance(i, int): ids = np.array([i]) if isinstance(i, np.ndarray): ids = i else: if isinstance(i, Iterable): ids = np.array(i, dtype=int) else: ids = np.array(list(range(self.Count))) + 1 return self.BulkGetAttr(ids) def _get_attributes_raw(self, *args, **kwargs) -> AxisVMAttributes: return self._get_line_attributes_raw(*args, **kwargs) def get_line_attributes(self, *args, **kwargs) -> AxisVMAttributes: return get_line_attributes(self, *args, **kwargs) def get_attributes(self, *args, fields=None, **kwargs) -> AxisVMAttributes: dfields, afields = [], [] if fields is None: afields = line_attr_fields dfields = line_data_fields else: if isinstance(fields, str): fields = [fields] if isinstance(fields, Iterable): afields = list(filter(lambda i: i in line_attr_fields, fields)) dfields = list(filter(lambda i: i in line_data_fields, fields)) res = {} if len(afields) > 0: res.update(self.get_line_attributes(*args, fields=afields, **kwargs)) if len(dfields) > 0: res.update(self.get_line_data(*args, fields=dfields, **kwargs)) return AxisVMAttributes(res) def plot(self, *args, **kwargs): coords = self.model.coordinates() topo = self.topology().to_numpy() - 1 return plot_lines_plotly(coords, topo, *args, **kwargs)