Source code for axisvm.com.axmodel

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

import numpy as np
from numpy import ndarray
import awkward as ak

from sigmaepsilon.mesh import PointCloud, CartesianFrame
from sigmaepsilon.mesh import TopologyArray
from sigmaepsilon.math.linalg.sparse.utils import count_cols

from .core.wrap import AxWrapper
from .core.utils import (
    RDisplacementValues2list,
    _LoadLevelOrModeShapeOrTimeStep,
    _DisplacementSystem,
)

from .axnode import IAxisVMNodes
from .axdomain import IAxisVMDomains, AxDomainCollection
from .axmember import IAxisVMMembers
from .axsurface import IAxisVMSurfaces
from .axline import IAxisVMLines
from .axwindow import IAxisVMWindows
from .axresult import IAxisVMResults
from .axmaterial import IAxisVMMaterials
from .axcalculation import IAxisVMCalculation
from .axloadcombinations import IAxisVMLoadCombinations
from .axnodalsupports import IAxisVMNodalSupports
from .axrcbeamdesign import IAxisVMRCBeamDesign

__all__ = ["IAxisVMModels", "IAxisVMModel"]


[docs]class IAxisVMModel(AxWrapper): """Wrapper for the `IAxisVMModel` COM interface.""" def __init__(self, *args, app=None, parent=None, **kwargs): super().__init__(*args, **kwargs) self.parent = parent self._app = app @property def app(self) -> AxWrapper: """Returns the application.""" if self._app is not None: return self._app elif self.parent is not None: if self.parent._app is not None: return self.parent._app return None @property def Nodes(self) -> IAxisVMNodes: """Returns a pointer object to the `IAxisVMNodes` COM interface.""" return IAxisVMNodes(model=self, wrap=self._wrapped.Nodes) @property def Members(self) -> IAxisVMMembers: """Returns a pointer object to the `IAxisVMMembers` COM interface.""" return IAxisVMMembers(model=self, wrap=self._wrapped.Members) @property def Domains(self) -> IAxisVMDomains: """Returns a pointer object to the `IAxisVMDomains` COM interface.""" return IAxisVMDomains(model=self, wrap=self._wrapped.Domains) @property def XLAMDomains(self) -> AxDomainCollection: return AxDomainCollection(self.Domains.XLAMItems) @property def Lines(self) -> IAxisVMLines: """Returns a pointer object to the `IAxisVMLines` COM interface.""" return IAxisVMLines(model=self, wrap=self._wrapped.Lines) @property def Surfaces(self) -> IAxisVMSurfaces: """Returns a pointer object to the `IAxisVMSurfaces` COM interface.""" return IAxisVMSurfaces(model=self, wrap=self._wrapped.Surfaces) @property def Windows(self) -> IAxisVMWindows: """Returns a pointer object to the `IAxisVMWindows` COM interface.""" return IAxisVMWindows(model=self, wrap=self._wrapped.Windows) @property def Results(self) -> IAxisVMResults: """Returns a pointer object to the `IAxisVMResults` COM interface.""" return IAxisVMResults(model=self, wrap=self._wrapped.Results) @property def Calculation(self) -> IAxisVMCalculation: """Returns a pointer object to the `IAxisVMCalculation` COM interface.""" return IAxisVMCalculation(model=self, wrap=self._wrapped.Calculation) @property def Materials(self) -> IAxisVMMaterials: """Returns a pointer object to the `IAxisVMMaterials` COM interface.""" return IAxisVMMaterials(model=self, wrap=self._wrapped.Materials) @property def LoadCombinations(self) -> IAxisVMLoadCombinations: """Returns a pointer object to the `IAxisVMLoadCombinations` COM interface.""" return IAxisVMLoadCombinations(model=self, wrap=self._wrapped.LoadCombinations) @property def NodalSupports(self) -> IAxisVMNodalSupports: """Returns a pointer object to the `IAxisVMNodalSupports` COM interface.""" return IAxisVMNodalSupports(model=self, wrap=self._wrapped.NodalSupports) @property def RCBeamDesign(self) -> IAxisVMRCBeamDesign: """Returns a pointer object to the `IAxisVMRCBeamDesign` COM interface.""" return IAxisVMRCBeamDesign(wrap=self._wrapped.RCBeamDesign) @property def MeshSurfaceIds(self) -> ndarray: """Returns the indices of the surfaces of all domains in the model as a NumPy array.""" d = self.Domains dc = d.Count def fnc(i): return d[i + 1].MeshSurfaceIds return np.vstack(list(map(fnc, range(dc)))).flatten().astype(np.int64)
[docs] def points(self, ids: Union[int, Iterable] = None) -> PointCloud: """ Returns the points of the model as an instance of :class:`sigmaepsilon.mesh.space.PointCloud`. Parameters ---------- ids: Union[int, Iterable], Optional The indices of the nodes for which the coordinates should be returned. If not spefified, coordinates for all the points in the model are returned. Default is None. """ frame = CartesianFrame(dim=3) if isinstance(ids, ndarray): ids = ids.astype(np.int32) elif isinstance(ids, int): ids = [ids] if ids is not None: coords = self.Nodes.BulkGetCoord(ids)[0] else: lines = self.Lines lc, mpc = lines.Count, self.Lines.MidPointCount ids = np.array(list(range(self.Nodes.Count))) + 1 coords = self.Nodes.BulkGetCoord(ids)[0] coords = np.array([[n.x, n.y, n.z] for n in coords]) if lc > 0 and mpc > 0: def fnc(i): return lines.GetMidpoint(i + 1)[0] def xyz(n): return [n.x, n.y, n.z] coords_mid = np.array(list(map(xyz, map(fnc, range(lc))))) def fnc(i): return lines.MidpointId[i + 1] mIDs = np.array(list(map(fnc, range(lc)))) i = np.where(mIDs > 0)[0] mIDs = mIDs[i] coords_mid = coords_mid[i] coords = np.vstack([coords, coords_mid]) ids = np.concatenate([ids, mIDs]) return PointCloud(coords, inds=ids, frame=frame)
[docs] def coordinates(self, ids: Iterable = None) -> ndarray: """ Returns the coordinates of the points in the model as a NumPy array. Parameters ---------- ids: Union[int, Iterable], Optional Indices of points, whose coordinates are to be returned. If there are no indices specified, coordinates for all points are returned. Default is None. Returns ------- numpy.ndarray """ return self.points(ids).show()
[docs] def topology(self) -> TopologyArray: """ Returns the topology of the model as an instance of :class:`sigmaepsilon.mesh.TopologyArray`. """ res = [] if self.Members.Count > 0: res.append(self.Members.topology()) if self.Surfaces.Count > 0: res.append(self.Surfaces.topology()) """s = self.Surfaces sIDs = self.MeshSurfaceIds def fnc_corner(i): return list(s[i].GetContourPoints()[0]) def fnc_mid(i): return list(s[i].GetMidPoints()[0]) def fnc(i): return fnc_corner(i) + fnc_mid(i) res.append(TopologyArray(ak.Array(list(map(fnc, sIDs)))))""" if len(res) >= 2: return np.vstack(res) return res[0] if len(res) == 1 else None
[docs] def dof_solution( self, *, displacement_system: Union[str, int] = 1, load_case_id: int = None, load_level: int = None, mode_shape: int = None, time_step: int = None, load_combination_id: int = None, case: str = None, combination: str = None, **__, ) -> ndarray: """ Returns degree of freedom solution for the whole model as a NumPy array. Parameters ---------- displacement_system: Union[str, int], Optional 0 for local, 1 for global. Default is 1. load_case_id: int, Optional Default is None. load_level: int, Optional Default is None. mode_shape: int, Optional Default is None. time_step: int, Optional Default is None. load_combination_id: int, Optional Default is None. case: str, Optional The name of a loadcase. Default is None. combination: str, Optional The name of a load combination. Default is None. Returns ------- numpy.ndarray """ if case is not None: load_combination_id = None if isinstance(case, str): LoadCases = self.LoadCases imap = {LoadCases.Name[i]: i for i in range(1, LoadCases.Count + 1)} if case in imap: load_case_id = imap[case] else: raise KeyError("Unknown case with name '{}'".format(case)) elif isinstance(case, int): load_case_id = case elif combination is not None: load_case_id = None if isinstance(combination, str): LoadCombinations = self.LoadCombinations imap = { LoadCombinations.Name[i]: i for i in range(1, LoadCombinations.Count + 1) } if combination in imap: load_combination_id = imap[combination] else: raise KeyError( "Unknown combination with name '{}'".format(combination) ) elif isinstance(combination, int): load_combination_id = combination disps = self.Results.Displacements disps.DisplacementSystem = _DisplacementSystem(displacement_system) if load_case_id is not None: disps.LoadCaseId = load_case_id if load_combination_id is not None: disps.load_combination_id = load_combination_id disps.LoadLevelOrModeShapeOrTimeStep = _LoadLevelOrModeShapeOrTimeStep( load_level=load_level, mode_shape=mode_shape, time_step=time_step, default=1 ) if load_case_id is not None: recs = disps.AllNodalDisplacementsByLoadCaseId()[0] elif load_combination_id is not None: recs = disps.AllNodalDisplacementsByLoadCombinationId()[0] return np.array(list(map(RDisplacementValues2list, recs)))
[docs] def generalized_surface_forces(self, *args, **kwargs) -> ndarray: """Returns internal forces and moments for all surfaces in the model.""" return self.Surfaces.generalized_surface_forces(*args, **kwargs)
[docs] def surface_stresses(self, *args, **kwargs) -> ndarray: """Returns stresses for all surfaces in the model.""" return self.Surfaces.surface_stresses(*args, **kwargs)
[docs] def critical_xlam_data( self, *, combination_type: int = None, analysis_type: int = 0, **__ ): """ Returns critical XLAM data. Parameters ---------- combination_type: int, Optional Default is None. analysis_type: int, Optional Default is 0. """ Domains = self.Domains Surfaces = self.Surfaces dparams = dict( MinMaxType=1, CombinationType=combination_type, AnalysisType=analysis_type, Component=4, # xse_Max ) def get_efficiencies(i): return Domains[i].critical_xlam_surface_efficiencies(**dparams) vmax = 0 did, sid, nid, f, lc = (None,) * 5 for d in Domains.XLAMItems: data = get_efficiencies(d.Index) cuts = count_cols(data) eff_max = ak.flatten(data[:, :, -1]).to_numpy() imax = np.argmax(eff_max) _vmax = eff_max[imax] if _vmax > vmax: vmax = _vmax did = d.Index csum = np.cumsum(cuts) iS = np.where(csum > imax)[0][0] iN = imax - csum[iS - 1] sid = d.MeshSurfaceIds[iS] nid = d.topology()[iS, iN] if cuts[iS] == 6: SurfaceVertexType = 0 if iN < 3 else 1 elif cuts[iS] == 8: SurfaceVertexType = 0 if iN < 4 else 1 else: raise NotImplementedError sparams = dict( SurfaceVertexType=SurfaceVertexType, SurfaceVertexId=nid, MinMaxType=1, CombinationType=combination_type, AnalysisType=analysis_type, Component=4, ) _, f, lc = Surfaces[sid].critical_xlam_efficiency(**sparams) return f, lc, (did, sid, nid)
def __enter__(self): if self._wrapped is not None: self._wrapped.BeginUpdate() return self def __exit__(self, exc_type, exc_value, exc_tb): if self._wrapped is not None: self._wrapped.EndUpdate() def _get_attrs(self): """Return the representation methods (internal helper).""" attrs = [] attrs.append(("N Nodes", self.Nodes.Count, "{}")) attrs.append(("N Lines", self.Lines.Count, "{}")) attrs.append(("N Members", self.Members.Count, "{}")) attrs.append(("N Surfaces", self.Surfaces.Count, "{}")) attrs.append(("N Domains", self.Domains.Count, "{}")) """bds = self.bounds fmt = f"{axisvm.FLOAT_FORMAT}, {axisvm.FLOAT_FORMAT}" attrs.append(("X Bounds", (bds[0], bds[1]), fmt)) attrs.append(("Y Bounds", (bds[2], bds[3]), fmt)) attrs.append(("Z Bounds", (bds[4], bds[5]), fmt))""" return attrs
class IAxisVMModels(AxWrapper): """Wrapper for the `IAxisVMModels` COM interface.""" __itemcls__ = IAxisVMModel def __init__(self, *args, app: AxWrapper = None, **kwargs): super().__init__(*args, **kwargs) self._app = app @property def app(self) -> AxWrapper: """Returns the application.""" return self._app