Extending ops-post¶
Adding a new element type¶
Adding an element to ELEMENT_REGISTRY in ops_elements.py is the
only change needed. The registry drives TCL parsing, mesh building,
and result processing automatically.
Step 1: If the element fits an existing topology¶
Just add it to ELEMENT_REGISTRY:
"MyNewShellQ4": _Q4,
This gives it Q4 shape functions, 2x2 Gauss points, 4-node surface parsing, and Q4 extrapolation.
Step 2: If it needs a new topology¶
Define the GP coordinates, shape functions, and extrapolation matrix,
then create a new ElemInfo:
GP_TRI_6 = np.array([...]) # natural coordinates
def shape_t6(xi, eta):
"""6-node triangle shape functions."""
...
return N # (6,) array
_T6 = ElemInfo(
family=ElemFamily.SHELL_TRI,
num_nodes=6, num_gp=3,
gp_coords=GP_TRI_3,
shape_fn=shape_t6,
extrap_fn=None,
face_nodes=[0, 1, 2, 3, 4, 5],
)
ELEMENT_REGISTRY["MyTriElement"] = _T6
What happens automatically¶
Once the element is in the registry:
| System | Behavior |
|---|---|
| TCL parser | Uses ElemFamily to pick the right parser (surface, beam, truss, zero-length) and reads the correct number of nodes |
| Postdata generator | Computes local axes from -local, geomTransf, or -orient flags |
| Mesh builder | Builds surface faces, extrusion, fiber edges, and GP cloud using the registry's shape functions and GP coordinates |
| Result processor | Uses the registry's extrapolation matrix for GP-to-node mapping |
Adding beam inline property extraction¶
If a new beam type has inline section properties in a different argument
layout, add it to _BEAM_INLINE_PROPS in tcl_parser.py:
_BEAM_INLINE_PROPS = {
"Timoshenko": (7, 9, 10), # A at token[7], Iy at [9], Iz at [10]
"elasticBeamColumn": (5, 9, 10),
"myNewBeam": (6, 8, 9), # new
}
Adding a new result type¶
Nodal results are auto-discovered from RESULTS/ON_NODES/ in the HDF5 file.
Element results are auto-discovered from RESULTS/ON_ELEMENTS/.
To customize component labels for a new nodal result, add it to
NODAL_COMPONENTS in result_processor.py:
NODAL_COMPONENTS = {
"DISPLACEMENT": ["Ux", "Uy", "Uz", "|U|"],
"REACTION_FORCE": ["Fx", "Fy", "Fz", "|F|"],
"VELOCITY": ["Vx", "Vy", "Vz", "|V|"], # new
}
Element result component names are read from the HDF5 META/COMPONENTS
field automatically.
Adding a new derived quantity¶
To add a derived scalar (like von Mises), modify result_processor.py:
-
Add the name to the component list in
get_available_results():if sg0.num_components >= 6: comps.append("Tresca") -
Handle it in
_extract_gp_fiber_component()andextract_element_result_for_gp_cloud(), using the component index to detect when the derived quantity is selected (index >=n_comp).
Adding a new visualization layer¶
-
Build the mesh in
MeshBuilder(e.g.build_my_layer()). -
In
MainWindow.__init__, call the builder and store the base mesh. -
In
_full_rebuild, add it withadd_mesh(...)and store inself._meshes["my_layer"]/self._actors["my_layer"]. -
In
_fast_update, update its.points[:]from the base + displacement. -
Add a visibility checkbox in the Results tab display options if needed.
Customizing the View tab¶
The View tab in gui.py contains camera presets and figure controls.
Key points for extension:
- GP zero mode: controlled by a dropdown in the Figure section of
the View tab. To add a new zero mode, update the dropdown items and
the sphere radius calculation in
result_processor.py. - Scale range clamping: min/max spinboxes in the Figure section.
To add more clamping options, extend the spinbox layout and the
scalar array clamping logic in
_apply_scale_range(). - All settings apply immediately: there is no Apply button. Connect
new controls to their update methods directly (e.g.
spinbox.valueChanged.connect(self._full_rebuild)).
Customizing interaction¶
The arcball interactor is in utils.py (ArcballInteractorStyle).
It uses the Shoemake arcball algorithm:
- Mouse positions are projected onto a virtual unit sphere.
- A single rotation is computed from drag-start to current position.
- The rotation is applied to the saved initial camera state (no drift).
To change the rotation pivot from world origin to another point, modify
_arcball_rotate() to rotate around a different center.
To add left-click pick/inspect, implement _on_left_press and use
VTK's cell picker to identify the clicked element.