If you want to bypass Kitware's animtovtkhdf translation layer entirely, you can read OpenRadioss ANIM files directly into Python memory using Vortex-Radioss, an open-source Python library developed by the OpenRadioss community specifically for post-processing.
Vortex-Radioss unpacks the compressed binary/ASCII arrays inside A00x files into standard NumPy arrays. Once the data is in NumPy, it is straightforward to construct a native pyvista.UnstructuredGrid.
Vortex-Radioss relies on lasso-python for CAE array handling.
pip install lasso-python
Next, download or clone the Vortex-Radioss library from their GitHub repository: Vortex-CAE/Vortex-Radioss. Ensure the module is in your Python path.
Here is a template on how to bridge the RadiossReader output natively into PyVista. Because Vortex-Radioss returns raw arrays, we must manually format the element connectivity into VTK's expected format (where each cell is prefixed by its number of points).
import numpy as np
import pyvista as pv
# Import the native Radioss reader from Vortex-CAE
from vortex_radioss.animtod3plot.RadiossReader import RadiossReader
def read_anim_to_pyvista(filepath):
# 1. Parse the OpenRadioss ANIM file
anim = RadiossReader(filepath)
# You can inspect the available arrays using:
# print(anim.raw_header.keys())
# 2. Extract Geometry (Adjust dictionary keys based on your specific ANIM output)
# Assuming 'nodes' is an (N, 3) array of XYZ coordinates
nodes = anim.raw_header['node_coordinates']
# Assuming 'shells' is an (M, 4) array of 0-indexed node IDs for Quad elements
shell_connectivity = anim.raw_header['shell_connectivity']
# 3. Format Connectivity for PyVista / VTK
# VTK requires connectivity arrays to be padded with the number of points per cell.
# For example, a quad is: [4, node0, node1, node2, node3]
num_cells = shell_connectivity.shape[0]
points_per_cell = shell_connectivity.shape[1]
# Create the padding column [4, 4, 4, ...]
padding = np.full((num_cells, 1), points_per_cell, dtype=np.int64)
# Horizontally stack the padding and the connectivity, then flatten it
vtk_connectivity = np.hstack((padding, shell_connectivity)).flatten()
# Specify the VTK cell type (VTK_QUAD = 9, VTK_HEXAHEDRON = 12, etc.)
# PyVista stores these in pv.CellType
cell_types = np.full(num_cells, pv.CellType.QUAD, dtype=np.uint8)
# 4. Construct the PyVista UnstructuredGrid
grid = pv.UnstructuredGrid(vtk_connectivity, cell_types, nodes)
# 5. Attach Results Data
# For example, if you requested velocities (/ANIM/VECT/VEL)
if 'nodal_velocities' in anim.raw_header:
grid.point_data['Velocity'] = anim.raw_header['nodal_velocities']
# If you requested Von Mises stress (/ANIM/ELEM/VONM)
if 'element_von_mises' in anim.raw_header:
grid.cell_data['Von Mises Stress'] = anim.raw_header['element_von_mises']
return grid
# --- Usage ---
mesh = read_anim_to_pyvista("data/cube_TYPE7A001")
mesh.plot(scalars="Von Mises Stress", cmap="turbo", show_edges=True)- Array Keys: Depending on what you requested in your Engine file (e.g.,
/ANIM/VECT/VEL,/ANIM/ELEM/VONM), the exact string keys insideanim.raw_headerwill vary. You will need to printanim.raw_header.keys()on your specific file to map the names correctly. - Mixed Element Types: If your model contains multiple element types (e.g., hexas, shells, and beams), you will need to concatenate their connectivity arrays and
cell_typesarrays together before passing them intopv.UnstructuredGrid. - Zero-Indexing: Ensure your connectivity arrays are 0-indexed. If Radioss outputs 1-indexed node IDs, subtract
1from the connectivity array before stacking it with the VTK padding.