Source code for febio_python.container.febio_container

from pathlib import Path
from typing import Union, List, Optional

from febio_python.core import (
    Nodes,
    Elements,
    NodeSet,
    SurfaceSet,
    ElementSet,
    Material,
    NodalLoad,
    SurfaceLoad,
    LoadCurve,
    BoundaryCondition,
    FixCondition,
    RigidBodyCondition,
    NodalData,
    SurfaceData,
    ElementData,
    # XpltMeshPart,
    # GenericDomain
)

from febio_python.feb import Feb25, Feb30, Feb40, Feb
from febio_python.xplt import Xplt


[docs] class FEBioContainer(): """Container class for FEBio files (FEB and XPLT files). """ def __init__(self, feb: Union[Feb30, Feb25, str, Path] = None, xplt: Union[Xplt, str, Path] = None, auto_find: bool = True) -> None: self.feb: Optional[Union[Feb30, Feb25]] = self._load_feb(feb) if feb else None self.xplt: Optional[Xplt] = self._load_xplt(xplt) if xplt else None if auto_find: self._auto_find_files(feb, xplt) # Make sure that we have the correct input if self.feb is None and self.xplt is None: raise ValueError("No FEB or XPLT file is provided") if self.feb is not None and not isinstance(self.feb, (Feb30, Feb25, Feb40)): raise ValueError("FEB is not valid. Check input file or input parameters.") if self.xplt is not None and not isinstance(self.xplt, Xplt): raise ValueError("XPLT is not valid. Check input file or input parameters.") # Now, if both files are provided, we must ensure that they are compatible. # We will compare the number of nodes and elements in the FEB and XPLT files. if self.feb is not None and self.xplt is not None: feb_node_count = sum([node.ids.size for node in self.feb.get_nodes()]) feb_elem_count = sum([elem.ids.size for elem in self.feb.get_elements()]) # feb_surf_count = sum([surf.ids.size for surf in self.feb.get_surface_elements()]) xplt_node_count = sum([node.ids.size for node in self.xplt.nodes]) xplt_elem_count = sum([elem.ids.size for elem in self.xplt.elements]) # xplt_surf_count = sum([surf.ids.size for surf in self.xplt.surfaces]) if feb_node_count != xplt_node_count: raise ValueError("Number of nodes in FEB and XPLT files do not match." "Please, make sure that the FEB and XPLT files are compatible.") if feb_elem_count != xplt_elem_count: raise ValueError("Number of elements in FEB and XPLT files do not match." "Please, make sure that the FEB and XPLT files are compatible.") def _load_feb(self, feb: Union[Feb30, Feb25, str, Path]) -> Optional[Union[Feb30, Feb25]]: if isinstance(feb, (str, Path)): print("feb: ", feb) feb_path = Path(feb) return Feb(filepath=feb_path) return feb def _load_xplt(self, xplt: Union[Xplt, str, Path]) -> Optional[Xplt]: if isinstance(xplt, (str, Path)): return Xplt(filepath=Path(xplt)) return xplt def _auto_find_files(self, feb: Union[Feb30, Feb25, str, Path], xplt: Union[Xplt, str, Path]): if not self.xplt and feb and isinstance(feb, (str, Path)): xplt_path = Path(feb).with_suffix('.xplt') if xplt_path.is_file(): self.xplt = Xplt(filepath=xplt_path) if not self.feb and xplt and isinstance(xplt, (str, Path)): feb_path = Path(xplt).with_suffix('.feb') if feb_path.is_file(): self.feb = self._load_feb(feb_path) # ======================================================================== # Properties # ======================================================================== # Main geometry (mesh) properties # ------------------------------- @property def nodes(self) -> List[Nodes]: if self.feb is not None: return self.feb.get_nodes() elif self.xplt is not None: return self.xplt.nodes else: raise ValueError("No FEB or XPLT file is provided") @property def elements(self) -> List[Elements]: if self.feb is not None: return self.feb.get_elements() elif self.xplt is not None: return self.xplt.elements else: raise ValueError("No FEB or XPLT file is provided") @property def surfaces(self) -> List[Elements]: if self.feb is not None: return self.feb.get_surfaces() elif self.xplt is not None: return self.xplt.surfaces else: raise ValueError("No FEB or XPLT file is provided") # Other geometry (mesh) properties # -------------------------------- @property def nodesets(self) -> List[NodeSet]: if self.feb is not None: return self.feb.get_node_sets() elif self.xplt is not None: return self.xplt.nodesets else: raise ValueError("No FEB or XPLT file is provided") @property def surfacesets(self) -> List[SurfaceSet]: if self.feb is not None: return self.feb.get_surface_sets() elif self.xplt is not None: raise RuntimeError("XPLT file does not save surface sets. Please provide a FEB file.") else: raise ValueError("No FEB or XPLT file is provided") @property def elementsets(self) -> List[ElementSet]: if self.feb is not None: return self.feb.get_element_sets() elif self.xplt is not None: raise RuntimeError("XPLT file does not save element sets. Please provide a FEB file.") else: raise ValueError("No FEB or XPLT file is provided") # Material properties # ------------------- @property def materials(self) -> List[Material]: if self.feb is not None: return self.feb.get_materials() else: raise RuntimeError( "Trying to access material data without a FEB file. " "Currently only FEB files save material data." "To access material data, provide a FEB file.") # Loads # ------------------- @property def nodal_loads(self) -> List[NodalLoad]: if self.feb is not None: return self.feb.get_nodal_loads() else: raise RuntimeError( "Trying to access nodal load data without a FEB file. " "Currently only FEB files save nodal load data." "To access nodal load data, provide a FEB file.") @property def pressure_loads(self) -> List[SurfaceLoad]: if self.feb is not None: # return self.feb.get_surface_loads() surface_loads = self.feb.get_surface_loads() # filter by type = "pressure" return [surface_load for surface_load in surface_loads if surface_load.type == "pressure"] else: raise RuntimeError( "Trying to access pressure load data without a FEB file. " "Currently only FEB files save pressure load data." "To access pressure load data, provide a FEB file.") @property def load_curves(self) -> List[LoadCurve]: if self.feb is not None: return self.feb.get_load_curves() else: raise RuntimeError( "Trying to access load curve data without a FEB file. " "Currently only FEB files save load curve data." "To access load curve data, provide a FEB file.") # Boundary conditions # ------------------- @property def boundary_conditions(self) -> List[Union[BoundaryCondition, FixCondition, RigidBodyCondition]]: if self.feb is not None: return self.feb.get_boundary_conditions() else: raise RuntimeError( "Trying to access boundary condition data without a FEB file. " "Currently only FEB files save boundary condition data." "To access boundary condition data, provide a FEB file.") # Mesh data # ------------------- @property def nodal_data(self) -> List[NodalData]: if self.feb is not None: return self.feb.get_nodal_data() elif self.xplt is not None: raise RuntimeError("XPLT file does not save nodal data. Please provide a FEB file." "If you are looking for nodal state data, please, use the 'states' property.") else: raise ValueError("No FEB or XPLT file is provided") @property def surface_data(self) -> List[SurfaceData]: if self.feb is not None: return self.feb.get_surface_data() elif self.xplt is not None: raise RuntimeError("XPLT file does not save surface data. Please provide a FEB file." "If you are looking for surface state data, please, use the 'states' property.") else: raise ValueError("No FEB or XPLT file is provided") @property def element_data(self) -> List[ElementData]: if self.feb is not None: return self.feb.get_element_data() elif self.xplt is not None: raise RuntimeError("XPLT file does not save element data. Please provide a FEB file." "If you are looking for element state data, please, use the 'states' property.") else: raise ValueError("No FEB or XPLT file is provided") # States (results) # ------------------- @property def states(self) -> None: if self.xplt is not None: return self.xplt.states else: raise RuntimeError( "Trying to access state data without a XPLT file. " "Currently XPLT files save state data." "To access state data, provide a XPLT file.") @property def node_states(self) -> List[Nodes]: if self.xplt is not None: return self.xplt.node_states else: raise RuntimeError( "Trying to access node state data without a XPLT file. " "Currently XPLT files save state data." "To access state data, provide a XPLT file.") @property def element_states(self) -> List[Elements]: if self.xplt is not None: return self.xplt.element_states else: raise RuntimeError( "Trying to access element state data without a XPLT file. " "Currently XPLT files save state data." "To access state data, provide a XPLT file.") @property def surface_states(self) -> List[Elements]: if self.xplt is not None: return self.xplt.surface_states else: raise RuntimeError( "Trying to access surface state data without a XPLT file. " "Currently XPLT files save state data." "To access state data, provide a XPLT file.")