pyvista_utils

febio_python.utils.pyvista_utils.add_boundary_conditions(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]

Adds boundary conditions from the FEBioContainer to the PyVista UnstructuredGrid. This function manages two main types of boundary conditions: fixed conditions (FixCondition) and rigid body conditions (RigidBodyCondition).

Parameters:
  • container (FEBioContainer) – The container containing boundary conditions.

  • grid (pv.UnstructuredGrid) – The PyVista UnstructuredGrid where boundary conditions will be added.

Returns:

The updated UnstructuredGrid with processed and added boundary conditions.

Return type:

pv.UnstructuredGrid

Example

After processing, to access the constraints:

  • Displacement constraints for a specific mesh block: grid.point_data[‘fix’] # Outputs a binary array where 1 indicates a fixed displacement.

  • Shell rotation constraints for the same block: grid.point_data[‘fix_shell’] # Outputs a binary array where 1 indicates a fixed shell rotation.

  • For rigid body constraints related to a specific material ID: grid.point_data[‘rigid_body’] # Fixed position constraints. grid.point_data[‘rigid_body_rot’] # Fixed rotational constraints.

Fixed Conditions:

Applies constraints on node displacements (‘x’, ‘y’, ‘z’) or shell rotations (‘sx’, ‘sy’, ‘sz’) for specific node sets. Recorded as binary arrays in point_data, each element represents whether a node is fixed along a certain axis:

  • ‘fix’: Binary array of shape [n_points, 3], indicating fixed displacements in X, Y, and Z directions.

  • ‘fix_shell’: Binary array of shape [n_points, 3], indicating fixed rotations in X, Y, and Z directions.

Both arrays consolidate all applicable constraints per node, summing constraints where multiple conditions affect the same node.

Rigid Body Conditions:

Restrict the movement or rotation of all nodes associated with a specific material, denoted by:

  • ‘rigid_body’: Binary array of shape [n_points, 3], indicating fixed positions in X, Y, and Z directions for nodes associated with a material.

  • ‘rigid_body_rot’: Binary array of shape [n_points, 3], indicating fixed rotations in X, Y, and Z directions for nodes associated with a material.

These conditions are labeled with specific material IDs, enhancing traceability and management in complex models.

febio_python.utils.pyvista_utils.add_element_sets(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]

Adds element sets from the FEBioContainer to the PyVista UnstructuredGrid. Element sets define specific groups of elements. This function maps these groups to the corresponding elements in the PyVista grids. Element sets are converted to binary arrays (masks) where each element represents whether an element is part of the set, and these masks are stored in the ‘cell_data’ of the grid. The key for each element set is the name of the set. The reason we use binary arrays is to allow for easy visualization and analysis of element sets in PyVista; it also allows us to keep data consistent even after we “extract” parts of the mesh or apply filters.

Parameters:
  • container (FEBioContainer) – The container containing element sets.

  • UnstructuredGrid (pv.UnstructuredGrid) – The UnstructuredGrid to which the element sets will be added.

Returns:

The updated UnstructuredGrid with element sets added.

Return type:

pv.UnstructuredGrid

febio_python.utils.pyvista_utils.add_elementdata(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]

Adds element data from the FEBioContainer to the PyVista UnstructuredGrid. Element data is stored in the ‘cell_data’ of the appropriate grid. NaNs are used to fill the gaps in the data arrays to ensure consistent dimensions across the grid.

Parameters:
  • container (FEBioContainer) – The container containing element data.

  • UnstructuredGrid (pv.UnstructuredGrid) – The UnstructuredGrid where element data will be added.

Returns:

The updated UnstructuredGrid with element data added.

Return type:

pv.UnstructuredGrid

Notes

This function assumes that the element data provided in the FEBioContainer is appropriately formatted and that element sets match the indices used in the data. If element sets are not properly aligned or if data is missing, NaNs are used to fill the gaps in the data arrays ensuring consistent dimensions across the grid.

febio_python.utils.pyvista_utils.add_material(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]

Adds material properties from the FEBioContainer to the PyVista UnstructuredGrid. Material properties such as Young’s modulus, Poisson’s ratio, or any other parameters defined in FEBio are associated with specific elements based on their material IDs.

Material Parameters:

These are transferred to PyVista as arrays in cell_data under “mat_parameters:{mat_id}”, where each row corresponds to an element and each column to a material parameter. The order of parameters is consistent across cell_data and field_data.

Material Type and Name:

These are stored in field_data under “mat_type:{mat_id}” and “mat_name:{mat_id}”, respectively, providing a reference to the type and name of the material used.

Parameters Order:

The names of the parameters (e.g., ‘Young’s modulus’, ‘Poisson’s ratio’) are stored in field_data under “mat_parameters:{mat_id}” to maintain an understanding of the data structure in cell_data.

Parameters:
  • container (FEBioContainer) – The container containing material data.

  • grid (pv.UnstructuredGrid) – The UnstructuredGrid where material properties will be added.

Returns:

The updated UnstructuredGrid with material properties added.

Return type:

pv.UnstructuredGrid

Example

If a material in FEBio with mat_id=1 has a Young’s modulus of 210 GPa and a Poisson’s ratio of 0.3, after running this function, the parameters can be accessed in PyVista as follows:

  • Access material parameters: grid.cell_data[‘mat_parameters:1’] # Array of shape [n_elements, 2] where the first column is Young’s modulus and the second is Poisson’s ratio.

  • Access material type and name: grid.field_data[‘mat_type:1’] # Returns [‘Elastic’] grid.field_data[‘mat_name:1’] # Returns [‘GenericElasticMaterial’]

  • Access the order of parameters: grid.field_data[‘mat_parameters:1’] # Returns [‘Young’s modulus’, ‘Poisson’s ratio’]

febio_python.utils.pyvista_utils.add_nodaldata(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]

Adds nodal data from the FEBioContainer to the PyVista UnstructuredGrid. Nodal data is stored in the ‘point_data’ of the grid, where each data field is associated with the corresponding nodes. NaNs are used to fill the gaps in the data arrays to ensure consistent dimensions across the grid.

Parameters:
  • container (FEBioContainer) – The container containing nodal data.

  • UnstructuredGrid (pv.UnstructuredGrid) – The UnstructuredGrid where nodal data will be added.

Returns:

The updated UnstructuredGrid with nodal data added.

Return type:

pv.UnstructuredGrid

febio_python.utils.pyvista_utils.add_nodalload(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]

Adds nodal force loads from the FEBioContainer to the PyVista UnstructuredGrid. This function interprets force loads applied to specific nodes as described in the FEBio model. It processes these loads, assigning them to the correct nodes based on the node sets specified in the loads, and stores a resultant vector for each node in point_data under the key “nodal_load”. The resultant load vector for each node is calculated by summing all applicable force vectors along the x, y, and z axes.

Parameters:
  • container (FEBioContainer) – The container containing nodal force load data.

  • UnstructuredGrid (pv.UnstructuredGrid) – The UnstructuredGrid where nodal loads will be added.

Returns:

The updated UnstructuredGrid with nodal force loads aggregated and added.

Return type:

pv.UnstructuredGrid

Example

Consider nodal loads specified in FEBio for certain nodes in various directions: - 100 N in the X direction for nodes in ‘NodeSet1’ - 150 N in the Y direction for nodes in ‘NodeSet2’ After processing by this function, these loads are combined where they overlap and result in a summed force vector for each node. The resultant force vectors can be accessed in PyVista as: multiblock[‘MeshBlockName’].point_data[‘nodal_load’] # Array of shape [n_points, 3] Each row in the array represents the total force vector for each node, with columns corresponding to forces in the X, Y, and Z directions.

febio_python.utils.pyvista_utils.add_nodalsets(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]

Adds nodal sets from the FEBioContainer to the PyVista UnstructuredGrid. Nodal sets define specific groups of nodes. This function maps these groups to the corresponding nodes in the PyVista grids. Node sets are converted to binary arrays (masks) where each element represents whether a node is part of the set, and these masks are stored in the ‘point_data’ of the grid. The key for each nodal set is the name of the set. The reason we use binary arrays is to allow for easy visualization and analysis of nodal sets in PyVista; it also allows us to keep data consistent even after we “extract” parts of the mesh or apply filters.

Parameters:
  • container (FEBioContainer) – The container containing nodal sets.

  • grid (pv.UnstructuredGrid) – The UnstructuredGrid to which the nodal sets will be added.

Returns:

The updated UnstructuredGrid with nodal sets added.

Return type:

pv.UnstructuredGrid

febio_python.utils.pyvista_utils.add_pressure_load(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]
febio_python.utils.pyvista_utils.add_states_to_grid(container: FEBioContainer, grid: UnstructuredGrid, apply_load_curves=True) List[UnstructuredGrid][source]
febio_python.utils.pyvista_utils.add_surface_data(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]
febio_python.utils.pyvista_utils.add_surface_sets(container: FEBioContainer, grid: UnstructuredGrid) UnstructuredGrid[source]
febio_python.utils.pyvista_utils.carefully_pass_cell_data_to_point_data(mesh: UnstructuredGrid) UnstructuredGrid[source]

This function corrects the ‘cell_data_to_point_data’ behavior from pyvista when there are NaN values in the cell data. In the original implementation, if there are NaN values in the cell data, all the point data is set to NaN. This function corrects this behavior by only setting the point data to NaN when there are no valid data to interpolate from the cell data. This is done by finding the cells that have valid data first, then converting only those cells to point data, while the remaining cells are ignored in the conversion (not affecting the point data and leaving it as NaN for those cells). This is useful when converting data that is defined only for a portion of the cells in the mesh, such as surface loads. e.g. surface loads are usually defined for only one side of the mesh, so the other side will have NaN values in the cell data. If the original implementation is used, the entire point data will be set to NaN, which is not desired. If we try to fill the NaN values with zeros, it will affect the interpolation and the results will be incorrect (border values will be interpolated incorrectly). Thus, this function is a workaround to handle this issue.

Parameters:

mesh (pv.UnstructuredGrid) – The mesh to convert cell data to point data.

Returns:

The mesh with cell data converted to point data, handling NaN values correctly.

Return type:

pv.UnstructuredGrid

febio_python.utils.pyvista_utils.create_unstructured_grid_from_febio_container(container: FEBioContainer) UnstructuredGrid[source]

Converts an FEBioContainer object containing mesh data into a PyVista UnstructuredGrid object. This function handles the conversion of node coordinates and element connectivity from the FEBio format (1-based indexing) to the PyVista format (0-based indexing). For each node set in the container, it creates a corresponding unstructured grid in the UnstructuredGrid.

Parameters:

container (FEBioContainer) – The FEBio container with mesh data.

Returns:

A UnstructuredGrid object containing the mesh data.

Return type:

pv.UnstructuredGrid

febio_python.utils.pyvista_utils.ensure_febio_container(data: FEBioContainer | Feb25 | Feb30 | Feb40) FEBioContainer[source]

Ensure the input data is a FEBioContainer object.

febio_python.utils.pyvista_utils.febio_to_pyvista(data: str | Path | FEBioContainer | Tuple | Feb25 | Feb30 | Feb40 | Xplt, apply_load_curves=True) List[UnstructuredGrid][source]

Converts FEBio simulation data into a PyVista MultiBlock structure for advanced visualization and analysis. This function orchestrates a series of operations to transfer all pertinent data from FEBio into a structured MultiBlock format that PyVista can utilize effectively.

Steps involved in the conversion include: 1. Validation of Input: Converts the input data into a FEBioContainer object if not already one. 2. Creation of MultiBlock: Initializes a MultiBlock from the FEBio container’s mesh data including nodes and elements. 3. Addition of Sets: Integrates nodal, element, and surface sets, mapping these to the corresponding elements and nodes within the PyVista grids. 4. Integration of Data: Nodal, element, and surface data are added, ensuring all mesh-related information is transferred. 5. Inclusion of Material Properties: Material properties defined in the FEBio model are mapped to the respective elements in PyVista. 6. Application of Loads: Both nodal and pressure loads specified in the FEBio model are applied to the respective nodes and elements. 7. Implementation of Boundary Conditions: Boundary conditions, both fixed and rigid body, are applied to the nodes as specified.

Please check the individual helper functions for more details on each step.

Parameters:

data (Union[FEBioContainer, Feb]) – Data container from an FEBio simulation.

Returns:

A fully populated PyVista MultiBlock object representing the entire FEBio model.

Return type:

pv.MultiBlock

febio_python.utils.pyvista_utils.split_mesh_into_surface_and_volume(mesh: UnstructuredGrid, surface_cell_types=None) Tuple[UnstructuredGrid, UnstructuredGrid][source]

Splits a mesh into a surface mesh and a volume mesh. The surface mesh contains only the outer surface of the original mesh, while the volume mesh contains the original mesh without the outer surface.

Parameters:

mesh (pv.UnstructuredGrid) – The mesh to split.

Returns:

A tuple containing the surface mesh and the volume mesh, respectively.

Return type:

Tuple[pv.UnstructuredGrid, pv.UnstructuredGrid]