Physics export (rod_spec)
The rod_spec bridge exports a device's reduced constitutive properties — bending, torsion and axial stiffness, plus outer diameter and linear density, per section — as a small, versioned JSON file that any physics model can import. It is the supported way to drive an external simulator (a robotics gym, a navigation solver, a custom FEA or XPBD rod) with real device mechanics computed from construction, instead of stiffness values hand-tuned to a physical sample.
Introduced in VirtuCath™ 1.2.0.
Why it exists
Most rod and beam solvers model a catheter from a single material — one Young's modulus for the whole device, with torsion tied to bending through a fixed Poisson's ratio. That cannot represent a real catheter, which is a graded construction (a stiff braided shaft tapering to a soft atraumatic tip) and, in the case of a braid, one whose torsion is deliberately decoupled from bending.
VirtuCath already computes the true per-section stiffness profile from the actual construction — braid angle, wire, liner, durometers, extruded cores. The rod_spec bridge hands those numbers to your solver directly, section by section:
EI— bending stiffness (per axis; see anisotropy)GJ— torsional stiffness (independent ofEI)EA— axial stiffnessr_out,lin_density— geometry and mass for contact and inertia
The contract
Files declare a schema version (virtucath.rod_spec/1.0) and are SI throughout (N, m, kg, rad). The device is described as piecewise-constant sections, which is VirtuCath's native model, with an optional resampled convenience array for fixed-segment rods.
{
"schema": "virtucath.rod_spec/1.0",
"provenance": {
"virtucath_version": "1.2.0",
"config_hash": "sha256:…", // hash of the source configuration
"units": "SI"
},
"device": {
"name": "DefaultCatheter",
"total_length_m": 0.319888,
"proximal_is_s0": true, // s is measured from the proximal hub toward the tip
"transitions": "step" // sections are STEP changes, not tapers
},
"sections": [ // source of truth — piecewise constant
{
"s_start_m": 0.0,
"s_end_m": 0.20,
"label": "Proximal",
"EI_x_Nm2": 1.70e-3, // bending about local x
"EI_y_Nm2": 1.70e-3, // bending about local y (equal when isotropic)
"GJ_Nm2": 1.74e-3, // torsion (independent of EI)
"GJ_Nm2_weak": 1.74e-3, // free-warping torsion
"GJ_Nm2_strong": 1.74e-3, // warping-constrained torsion
"EA_N": 2831.1, // axial
"r_out_m": 0.001694, // OD / 2, for contact + rendering radii
"r_in_m": 0.0005,
"lin_density_kg_m": 8.996e-3
}
// … one entry per VirtuCath section
],
"resampled": { // OPTIONAL — present when requested
"ds_m": 0.001,
"s_m": [ … ],
"EI_x_Nm2": [ … ], "EI_y_Nm2": [ … ], "GJ_Nm2": [ … ],
"EA_N": [ … ], "r_out_m": [ … ], "lin_density_kg_m": [ … ]
}
}
Rules a consumer must respect
- SI units. Newtons, metres, kilograms, radians. No mm, no grams.
s = 0is the proximal hub, increasing toward the distal tip (proximal_is_s0: true).- Transitions are step changes. Do not smooth or interpolate stiffness across a section boundary unless you are deliberately modelling a physical taper — the steps are real (durometer and reinforcement changes).
- Use
lin_density_kg_mfor mass per unit length; do not derive mass fromr_outand an assumed density (the wall is a composite). EAandEIare independent of the geometry. Because the wall is a composite,EA/EIdoes not equal the section's area-over-second-moment, andGJ/EIvaries section to section. Feed the stiffnesses directly; do not back them out into a single modulus.
Anisotropic sections
For isotropic sections EI_x_Nm2 == EI_y_Nm2. They differ only when a section is genuinely anisotropic — most commonly a multi-lumen extruded core or an oval profile (VirtuCath 1.2.0). A solver that supports only a single bending stiffness can use EI_y_Nm2 (the primary axis); a Cosserat solver should take both. Off-axis material rotation, when present, is reported as principal_axis_angle_deg.
Steering (pullwires)
A steerable device carries an optional actuation block. It is geometry only — it describes where each pullwire sits and how a pull maps to a bending moment, so any engine can reproduce the steering from the exported EI profile. No construction is exposed.
"actuation": {
"type": "pullwire",
"convention": "moment_Nm = tension_N * radial_offset_m, applied over [proximal_s_m, distal_attachment_s_m], bending toward angle_deg",
"pullwires": [
{ "id": 0, "radial_offset_m": 0.00114, "angle_deg": 180.0,
"proximal_s_m": 0.0, "distal_attachment_s_m": 0.30 }
]
}
A wire at tension T applies a moment M = T · radial_offset_m over its span [proximal_s_m, distal_attachment_s_m], bending the device toward angle_deg in the material frame. Because the local EI is in the same file, an engine gets the resulting curvature directly (κ = M / EI). Adapters map this to each engine's native mechanism:
- MuJoCo — a spatial tendon through sites at the wire offset (VirtuCath's direct MJCF export already builds these tendons and their actuators; use it when you want a ready-to-run steerable MuJoCo model).
- NVIDIA Cosserat — an imposed tip rest-curvature (
set_tip_bend/RodTipConfig), since that solver steers by target curvature rather than a physical tendon.
The block is omitted entirely for a non-steerable device.
Producing an export
From the application
File → Export → Physics Simulation Spec (.json) writes the file for the currently loaded device.
From the CLI API
Load a device, then call export_rod_spec. It returns the rod_spec object and, if you pass path, also writes it to disk. Pass resample_ds_m to include the fixed-step array.
{"command": "load", "config": "Catheter Files/default_catheter.json"}
{"command": "export_rod_spec", "path": "device.rod_spec.json", "resample_ds_m": 0.001}
{
"status": "success",
"rod_spec": { "schema": "virtucath.rod_spec/1.0", … },
"warnings": [], // empty = passed the round-trip validator
"written_to": "device.rod_spec.json"
}
Reference adapters
Worked examples for loading a rod_spec into common solvers ship with the bridge:
- Generic Python loader — a dependency-free
load_rod_spec()that returns the localEI/GJ/EA/r_out/lin_densityat any arc-length, plus an evenly-sampled helper for fixed-segment rods. The starting point for any custom engine. - NVIDIA Isaac for Healthcare (Cosserat rod) — maps each section onto the per-edge bend/twist stiffness of the open XPBD Cosserat-rod solver in the Catheter Navigation workflow.
- MuJoCo (MJCF) — VirtuCath also exports a MuJoCo model directly; the adapter documents the same section-to-body mapping for an existing MJCF chain.
Solver support and current limitations
What a target engine can accept varies, and one common case needs a workaround today.
Per-segment properties (NVIDIA Cosserat solver)
The open NVIDIA Isaac for Healthcare Cosserat-rod solver takes a single scalar material for the whole rod — one Young's modulus, with the shear modulus tied to it through a fixed Poisson's ratio (ν = 0.3), and one bend-stiffness multiplier. There is no public API to set stiffness per segment, to make torsion independent of bending, or to set axial stiffness directly. As shipped, it cannot represent a graded catheter or a braided shaft.
The solver already stores stiffness per rod edge internally — the scalar config is only broadcast into those arrays at setup. The bundled adapter writes VirtuCath's real per-section EI/GJ straight into that per-edge array instead, neutralising the scalar modulus. Two details make it exact:
- Run the solver in mm-kg-s. Its bend/twist compliance is regularised with a fixed epsilon; catheter-scale rigidities in SI fall below it and get silently clamped. Working in millimetres scales
EIup by 1e9 and clears the floor. - Map to the discrete constraint. The solver's bend/twist constraint is
C ≈ κ·l/2, so the per-edge stiffness that reproduces a targetEIis4·EI/l²(l= segment length). Same factor forGJ.
This is validated against Euler-Bernoulli (δ = P·L³/3EI) to within a few percent. A feature request has been filed with NVIDIA to accept per-segment material natively; if accepted, the adapter simplifies to a direct assignment.
That solver's XPBD path treats stretch and shear as near-rigid regardless of configuration, so EA is not exercised there — the rod is effectively inextensible. This is usually fine for catheters (they are ~inextensible), but if your application depends on axial compliance, the NVIDIA Cosserat path is not the right target today. EA is present in the rod_spec and is honoured by MuJoCo and by custom solvers that model stretch.
MuJoCo and most custom beam/FEA solvers accept per-segment stiffness natively, so they consume the rod_spec directly with no workaround.
Pullwire steering
The actuation block is a v1 abstraction: it exports pullwire geometry (offset, angle, attachment span) and the moment convention, not a calibrated force→deflection curve. How faithfully it reproduces steering depends on the engine:
- MuJoCo models the pullwire directly as a spatial tendon, so steering is physical and multi-wire control is exact. For a steerable device, prefer VirtuCath's dedicated MJCF export, which builds the tendons and their actuators for you; the rod_spec
actuationblock is the engine-neutral fallback. - NVIDIA Cosserat has no tendon. It steers by imposing a rest curvature on the tip, so the adapter approximates a pullwire as a target tip bend. That approximation has limits: it applies a curvature at the distal tip rather than a moment distributed along the wire's full attachment span, and independent simultaneous control of multiple wires is not represented. It reproduces single-wire tip deflection well; complex multi-wire or proximal-shaft steering is out of scope on that solver.
The actuation block does not yet carry a calibrated actuation gain (pull force → tip deflection). Engines derive curvature from the exported EI and the wire offset (κ = T·offset / EI). A calibrated reference point may be added in a later schema revision.
What is not exported
The bridge emits only the reduced constitutive outputs. It never exports the composite internals that produced them — braid engagement model, flowdown stackup, ply moduli, layer-by-layer construction. That keeps the format engine-neutral and is the intellectual-property boundary of the export (EULA §2.8). Bulk automated exports are rate-limited.