Skip to main content

CLI API reference

The VirtuCath™ CLI API provides a persistent REPL (Read-Eval-Print Loop) interface for interacting with the application programmatically over standard input/output (stdin/stdout). It supports fully headless operation — machine learning training, dataset generation, and direct interaction via AI agents or external scripts.

The API runs continuously, holding the loaded simulation model and Flowdown engine state in memory between commands. It communicates exclusively using single-line JSON strings.

About the examples on this page. Response samples use ... as a visual placeholder for truncated content (omitted object members, additional array entries, etc.). The samples are illustrative — copying one directly will not produce valid JSON. For the canonical schema, call export_schema at runtime; for actual live responses, call the relevant command and read what comes back.

For AI agents — start here

If you're an LLM-driven agent encountering VirtuCath for the first time:

  1. Start the process with ./VirtuCath.exe --cli-api (see Starting the API for the executable path on Windows).
  2. Send {"command": "export_schema"} over stdin. The response contains the full JSON Schema for every command — parameter names, types, required fields, enums. Treat that schema as the source of truth.
  3. Use {"command": "get_config"} after any load or wizard_step to inspect the active configuration as ground-truth state.
  4. Build catheters either by passing a .json file path / inline dict to load, or by walking the wizard_step state machine. The wizard validates each layer against the global OD constraint at submission time, so it's the easier path for trial-and-error optimization.
  5. Wrap each request in a try-step-observe loop: any command that errors returns {"status": "error", "error_code": "<CODE>", ...} for deterministic handling.

Most commands accept an optional keys array to trim the response payload — useful for keeping each round-trip small.

Command index

CategoryCommands
Introspectionexport_schema · get_config · get_license_info · get_materials
Configurationload · validate_config · wizard_step · add_temporary_material · create_blend
Static analysisget_static_kpis · calculate_flowdown · calculate_kink_safety
Dynamic simulationset_environment · reset_simulation · step_simulation · set_pullwires · get_dynamic_kpis
Outputrender_simulation · generate_graphics · generate_reports
DOE / response surfacerun_doe · get_doe_results
Lifecycleexit

JSON config glossary

The same catheter .json schema is used by load, validate_config, and the Setup Wizard GUI. Call export_schema for the full definition; the most-referenced fields are:

FieldWhereMeaning
catheter_definition.nametop levelHuman-readable design name (used in reports).
catheter_definition.dimension_modetop levelOne of FIXED_ID, FIXED_OD, or OD_ID_FIXED. Controls how the layer stackup is solved.
catheter_definition.mandrel_diameter_mmtop levelMandrel (innermost) diameter when dimension_mode = FIXED_ID.
catheter_definition.fixed_inner_diameter_mmtop levelInner diameter target when dimension_mode = OD_ID_FIXED. Takes precedence over mandrel_diameter_mm in that mode.
catheter_definition.overall_diameter_mmtop levelOuter diameter target when dimension_mode = FIXED_OD or OD_ID_FIXED.
catheter_definition.sections[]arrayOrdered list of catheter sections, distal → proximal.
sections[].length_mmper sectionSection length. Min 2 mm, cumulative max 1500 mm.
sections[].layers[]per sectionLayer stack, defined inside-out (liner first, jacket last).
sections[].is_manual_stiffnessper sectionWhen true, skips layer-based stiffness calculation and uses user-supplied EI/GJ overrides. Certain geometry-derived KPIs (like linear_density_kg_per_m) become null.
layers[].material_nameper layerMust match a name in the active material library. Use get_materials to list.
layers[].reinforcement_typeper layerNone, Polymer, Braid, or Coil. Polymer is a passive polymer layer; Braid and Coil additionally require reinforcement_settings.
layers[].reinforcement_settingsper layerNested object: ppi, num_carriers, wire_shape, wire_material_name, round_wire_diameter_mm or flat_wire_thickness_mm/flat_wire_width_mm, etc.
layers[].pullwire_settings.radial_offset_mmpullwire layerRadial position of the pullwire lumen centers. Bounded by radial_offset + lumen_radius + liner_wall <= section_outer_radius.
layers[].pullwire_settings.lumen_radius_mmpullwire layerRound-lumen radius (or use width/thickness fields for flat lumens).

Starting the API

Run the compiled executable with the --cli-api argument:

./VirtuCath.exe --cli-api

Installation Note: If you installed VirtuCath using the standard Windows setup wizard, the executable's location depends on your installation choice. If installed for "All Users", it is located at C:\Program Files\VirtuCath\VirtuCath.exe. If installed for "Current User Only", it is in %LocalAppData%\Programs\VirtuCath\VirtuCath.exe. You must navigate to this directory in your terminal or add it to your system PATH to run the commands below.

Once running, the API process waits silently for JSON commands on stdin. Logs are written to api_cli.log in the working directory to keep stdout clean.

Verbose mode: Append the --verbose flag (e.g., ./VirtuCath.exe --cli-api --verbose) to stream internal simulation engine logs to standard error (stderr). Useful when debugging physics divergence or command failures.

Usage protocol

  1. Send a single line of valid JSON to stdin. This can be a single command object {...} or an array of command objects [{...}, {...}] for batch execution. Note: Even when sending an array, the entire payload must be compacted onto a single string line without embedded newlines.
  2. Terminate the JSON string with a newline (\n).
  3. The program processes the command and responds with a single line of JSON on stdout, followed by a newline. If sending a batch array, it will respond with a single line of JSON per command.
  4. All commands are validated against an internal JSON Schema before execution.
  5. If a command causes an error (or fails schema validation), the response will be explicitly structured to include an "error_code" for deterministic programmatic handling.

Example Error Response (Schema Validation):

{
"status": "error",
"error_code": "SCHEMA_VALIDATION_ERROR",
"message": "Command failed validation: 'timeout_s' must be of type number",
"path": ["timeout_s"]
}

Security Note: All inputs are strictly parsed as JSON and type-casted internally. Do not use Python eval() or send arbitrary code.


API commands

export_schema

Returns the full JSON Schema defining every command, its expected parameters, required fields, and types. Use this as the runtime source of truth for what the API accepts — particularly useful for zero-prompt AI agents discovering the surface dynamically.

Request:

{
"command": "export_schema"
}

Response (Success):

{
"status": "success",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "VirtuCath CLI API Request",
...
}
}

load

Loads a catheter configuration into the simulation engine and initializes the mechanics.

Request:

{
"command": "load",
"config": "C:/path/to/catheter.json"
}

Note: config can be an absolute file path, a path relative to the working directory, or a complete nested JSON object representing the configuration. Absolute paths are highly recommended.

Dimension Mode Priority Note: When passing a raw configuration JSON directly to the CLI, if "dimension_mode": "OD_ID_FIXED" is specified within the catheter definition, the API will strictly enforce the fixed_inner_diameter_mm property over the mandrel_diameter_mm parameter when evaluating the internal layer flowdown mechanics.

Configuration Validation Note: When a configuration is loaded, its pullwire geometric constraints are strictly validated. Specifically, the radial extent of the pullwires (radial_offset_mm + lumen_radius_mm + liner_wall_thickness_mm) must not exceed the outer radius of the catheter section to which they are attached.

Response (Success):

{
"status": "success",
"message": "Catheter loaded successfully.",
"static_kpis": {... }
}

get_static_kpis

Retrieves the static mechanical properties (e.g., Sectional Stiffness, Elastic Instability Radius, Burst Pressure) of the currently loaded model. You can optionally request specific keys to minimize the payload size.

Note: If is_manual_stiffness is flagged for a section in the configuration, certain geometric KPIs derived from the cross-section (like linear_density_kg_per_m) are bypassed and will return null.

Request:

{
"command": "get_static_kpis",
"keys": ["sectional_stiffness"]
}

Note: The keys array is optional. If omitted, all static KPIs are returned.

Response (Success):

{
"status": "success",
"static_kpis": {... }
}

get_dynamic_kpis

Retrieves the current state of the simulation without advancing time. You can optionally request specific keys.

Request:

{
"command": "get_dynamic_kpis",
"keys": ["tip_position_mm", "physics_stable"]
}

Note: The keys array is optional. If omitted, all dynamic KPIs are returned.

Response (Success):

{
"status": "success",
"dynamic_kpis": {
"physics_stable": true,
"tip_position_mm": [4.9, 0.0, -120.5]
}
}

Note: The physics_stable flag allows agents to immediately recognize if the latest parameters caused the simulation to diverge (e.g., NaN velocities).

set_environment

Enables or disables gravity along a specific axis (x, -x, y, -y, z, -z).

Request:

{
"command": "set_environment",
"gravity_enabled": true,
"gravity_axis": "-z"
}

Response (Success):

{
"status": "success",
"message": "Gravity set to enabled along axis '-z'"
}

reset_simulation

Resets the simulation state to neutral/zero-deflection and flushes accumulated kinematics without reloading the model config from disk. Useful for rapidly starting a new sequence in bounded optimization loops.

Request:

{
"command": "reset_simulation"
}

Response (Success):

{
"status": "success",
"message": "Simulation reset successfully.",
"dynamic_kpis": {... }
}

step_simulation

Advances the physics simulation by a precise duration. Useful for algorithmic agents that need to observe continuous motion. Optionally accepts target X/Y deflections to update before stepping.

Real-time limiter: step_simulation is throttled to wall-clock speed — the simulation is not allowed to advance faster than real time. A request to step 10 seconds will take at least 10 seconds of wall time to return. Use small duration_s values (e.g., 0.01–0.1) for interactive loops. For bulk static-design exploration that does not require dynamic state, prefer run_doe or recompute static KPIs via repeated load calls.

Request:

{
"command": "step_simulation",
"duration_s": 0.01,
"x_mm": 5.0,
"y_mm": 0.0
}

Note: x_mm and y_mm are optional. If omitted, the simulation will step towards the last known target.

Response (Success):

{
"status": "success",
"message": "Stepped 0.01s.",
"dynamic_kpis": {... }
}

render_simulation

Captures a static frame of the current simulation state headlessly.

Request:

{
"command": "render_simulation",
"view": "custom",
"azimuth": 45.0,
"elevation": -30.0,
"distance": 0.5,
"lookat": [0.0, 0.0, -0.2],
"width": 800,
"height": 600,
"output_path": "C:/path/to/save/simulation_frame.png"
}

Note: view can be iso, front, side, top, or custom. If custom, you must specify azimuth, elevation, and distance. lookat is optional. Defaults to 800x600. Absolute paths are highly recommended for output_path.

Response (Success):

{
"status": "success",
"message": "Simulation rendered to /path/to/save/simulation_frame.png"
}

set_pullwires

Dynamically actuates the pullwires to achieve a specific spatial deflection at the catheter tip and steps the physics simulation until the tip settles (velocity drops below a threshold) or times out. Returns the dynamic KPIs of the settled state.

API Ambiguity Note: The x_mm and y_mm parameters refer to the target spatial position (deflection amplitude) of the distal tip in the simulation world, not the linear displacement (length) of the tendon pulled.

Note on Deflection Modeling: Catheters are modeled as cantilevers rigidly fixed at the base. Therefore, if you are designing and simulating a deflectable distal section, it is highly recommended to model the proximal shaft as a rigid, minimal-length stand-in (e.g., 50-100 mm) rather than its full anatomical length. This significantly improves simulation stability and focus.

Request:

{
"command": "set_pullwires",
"x_mm": 5.0,
"y_mm": 0.0,
"timeout_s": 15.0
}

Note: timeout_s is optional and defaults to 10.0 seconds of simulation time.

Response (Success):

{
"status": "success",
"message": "Pullwires set and simulation settled.",
"dynamic_kpis": {
"is_settled": true,
"tip_position_mm": [4.9, 0.0, -120.5],
"tendon_forces_N": { "0": 1.2, "1": 0.0,... },
...
}
}

Note: If the tip fails to settle within timeout_s, the response still returns status: "success" but with message: "Simulation reached timeout before settling." and dynamic_kpis.is_settled: false. Check is_settled rather than status to determine whether the tip actually reached steady state.

Error Codes:

CodeCondition
MODEL_NOT_LOADEDload or wizard_step has not been called yet.
SCHEMA_VALIDATION_ERRORx_mm or y_mm is missing or not a number.
SIMULATION_CRASHEDThe physics integrator diverged (NaN/Inf tip position or runaway velocity). The simulation is auto-reset before this error returns; the response includes "crashed": true.

calculate_flowdown

Interacts with the Flowdown Engine to iteratively calculate pre-reflow and post-reflow stackup dimensions.

Important Conceptual Note: The flowdown calculator is a secondary, manufacturing-focused tool. It is designed to be used after the catheter geometry is modeled and simulated to determine what raw, pre-reflow extrusions to procure in order to achieve the desired final design. It is not strictly required for the physics simulation itself, which runs off the final composite stackup.

This command allows AI agents to optimize designs by passing in manual layer overrides (e.g., fixed wall thicknesses or inner diameters).

Request:

{
"command": "calculate_flowdown",
"section_index": 0,
"layer_overrides": {
"0": { "is_manual": true, "fixed_wall_mm": 0.05 },
"1": { "is_manual": false, "gap_below_mm": 0.2 }
}
}

Note: section_index defaults to 0. layer_overrides uses the layer index as the key. Available override properties are is_manual, fixed_wall_mm, fixed_id_mm, gap_below_mm, and gap_above_mm. To change the base mandrel size, set mandrel_diameter_mm in the top-level catheter_definition of your loaded configuration. By default, polymer layers have a 0.15mm radial pre-reflow gap below them to simulate loose fitment prior to reflow which affects final OD if not actively accounted for. Override gap_below_mm to 0.0 to enforce a strict flush fit.

Response (Success):

{
"status": "success",
"stackup": [
{
"name": "Mandrel",
"pre_od_mm": 1.5,
...
},
...
]
}

generate_graphics

Headlessly generates 3D renderings of the catheter components (such as Braid/Coil technical illustrations and Peelaway diagrams) and saves them as images to the specified directory. This allows AI agents to retrieve visual feedback without a GUI.

Request:

{
"command": "generate_graphics",
"output_dir": "/path/to/save/images"
}

Note: The model must be loaded first. The directory will be created if it does not exist.

Response (Success):

{
"status": "success",
"message": "Graphics generated successfully.",
"saved_files": [
"/path/to/save/images/braid_render.png",
"/path/to/save/images/peelaway_render.png"
]
}

get_materials

Retrieves the full list of materials available in the local material library.

Request:

{
"command": "get_materials"
}

Response (Success):

{
"status": "success",
"materials": [
{
"name": "SS 304V",
"material_family": "Metal",
"thermoplastic": false,
"density_g_cm3": 8.0,
...
},
...
]
}

add_temporary_material

Adds a custom material to the library in-memory only for the duration of the API session. This material can then be referenced by name in subsequent calculate_flowdown or load commands without permanently altering the user's materials.json file.

Request:

{
"command": "add_temporary_material",
"material": {
"name": "Custom Agent Polymer",
"material_family": "PEBA",
"thermoplastic": true,
"density_g_cm3": 1.05,
"modulus_of_elasticity_mpa": 150.0,
"tensile_strength_mpa": 45.0,
"poissons_ratio": 0.45
}
}

Response (Success):

{
"status": "success",
"message": "Temporary material 'Custom Agent Polymer' added to memory.",
"material": {... }
}

create_blend

Creates a new blended material from two parents (or polymer + additive) using the same mechanics model as the GUI's Create Polymer Blend / Polymer + Additive dialog. The resulting material is added to the in-memory material library for the session (it is not persisted to materials.json) and can immediately be referenced by name in subsequent load, wizard_step, or calculate_flowdown commands.

Either parent can be referenced by library name (string) or supplied as an inline material object — mirroring the dialog's "Custom..." additive workflow.

Request — both parents from the library:

{
"command": "create_blend",
"base_material": "PEBAX® 2533 SA 01 MED",
"additive_material": "Barium Sulfate (BaSO4)",
"base_mass_fraction": 0.80,
"blend_mode": "additive"
}

Request — inline custom additive (equivalent to the dialog's "Custom..." entry):

{
"command": "create_blend",
"base_material": "PEBAX® 2533 SA 01 MED",
"additive_material": {
"name": "MyCustomFiller",
"density_g_cm3": 4.5,
"modulus_of_elasticity_mpa": 30000.0,
"tensile_strength_mpa": 20.0,
"poissons_ratio": 0.30
},
"base_mass_fraction": 0.80,
"blend_mode": "additive",
"name": "PEBAX 2533 + 20% MyCustomFiller"
}

Parameters:

FieldRequiredTypeDescription
base_materialYesstring | objectBase polymer. A library name, or an inline material object with at least name, density_g_cm3, modulus_of_elasticity_mpa, poissons_ratio.
additive_materialYesstring | objectAdditive (or second polymer for blend_mode = "blend"). Same accepted shapes as base_material.
base_mass_fractionYesnumberMass fraction of the base material in the resulting blend (0.05–0.95). The additive receives 1 - base_mass_fraction.
blend_modeNostring"additive" (default) treats additive_material as a rigid/lubricious filler — uses the mass-loading model where modulus follows the immiscible-blend law and tensile strength drops with filler fraction. "blend" treats both parents as miscible polymers (volume-rule-of-mixtures tensile strength).
nameNostringOverride the resulting material name. Must not collide with an existing library entry. If omitted, a name is auto-generated from the parents and ratio.

Inline material validation (same constraints as the GUI dialog): density_g_cm3 > 0, modulus_of_elasticity_mpa > 0, tensile_strength_mpa > 0 if provided, and −1 < poissons_ratio < 0.5.

Response (Success):

{
"status": "success",
"message": "Blend 'PEBAX 2533 + 20% MyCustomFiller' created and added to in-memory library.",
"material": {
"name": "PEBAX 2533 + 20% MyCustomFiller",
"material_family": "Blend",
"thermoplastic": true,
"density_g_cm3": 1.184,
"modulus_of_elasticity_mpa": 15.51,
"poissons_ratio": 0.442,
"tensile_strength_mpa": 27.79
}
}

Error Codes:

CodeCondition
MISSING_PARAMETERbase_material, additive_material, or base_mass_fraction not provided.
SCHEMA_VALIDATION_ERRORblend_mode is not "blend"/"additive", base_mass_fraction out of [0.05, 0.95], or name is an empty string.
NAME_CONFLICTA material with the resulting name already exists in the in-memory library.
INTERNAL_ERRORA library lookup failed, an inline material was invalid (missing fields, bad units, out-of-range Poisson's ratio, etc.), or the blend calculation itself raised. The message describes which input failed.

Persistence note: Like add_temporary_material, create_blend only mutates the in-memory library for the active session. The user's materials.json on disk is untouched. To persist a blend across sessions, use the GUI's Materials Library dialog — saved blends serialize as ordinary Material entries with material_family: "Blend" and reload through the standard library path with no schema additions.

get_license_info

Retrieves read-only information about the active application license, including Hardware ID, expiration status, and license type.

Request:

{
"command": "get_license_info"
}

Response (Success):

{
"status": "success",
"license_info": {
"type": "Team License (1 Year)",
"status": "Active",
"expires_at": "2027-10-31",
"days_remaining": "365 days",
"hwid": "UUID:12345678-ABCD-...",
"key_masked": "00000000-XX1234"
}
}

generate_reports

Generates the full analysis report bundle for the currently loaded configuration and saves it to the specified directory. The bundle always includes catheter_report.json (raw config + static KPIs) and, when generation succeeds, the PDF and Excel analysis reports. If dynamic simulation data has been logged, a simulation_log.csv is also written. PDF/Excel generation failures are non-fatal — the JSON dump still succeeds and saved_files reflects what was actually written.

Request:

{
"command": "generate_reports",
"output_dir": "/path/to/save/reports"
}

Note: The model must be loaded first. The directory is created if it does not exist.

Response (Success):

{
"status": "success",
"message": "Reports generated successfully.",
"saved_files": [
"/path/to/save/reports/catheter_report.json",
"/path/to/save/reports/catheter_report.pdf",
"/path/to/save/reports/catheter_data.xlsx"
]
}

validate_config

Performs pre-flight validation checks on a configuration without loading it into the physics engine. Useful for verifying geometric constraints like ensuring layer stackups do not exceed the specified overall outer diameter.

status vs valid: The two fields mean different things.

  • status is "success" whenever the command itself ran without an exception. A schema-malformed input or missing config parameter would return status: "error" instead.
  • valid is true only when the configuration passed every validation check. A configuration that loads cleanly but contains warnings will return status: "success" and valid: false, plus a warnings array describing what's wrong.

Agents looking for "did the config pass?" should branch on valid, not status.

Request:

{
"command": "validate_config",
"config": "C:/path/to/catheter.json"
}

Response — valid config:

{
"status": "success",
"valid": true,
"message": "Configuration is valid.",
"warnings": []
}

Response — loadable but with warnings:

{
"status": "success",
"valid": false,
"message": "Configuration loaded but has validation warnings.",
"warnings": [
"Section '1': Sum of layer thicknesses (5.200 mm) exceeds overall_diameter_mm (4.000 mm)."
]
}

calculate_kink_safety

For each flexible section in the currently loaded configuration, computes the safety factor between a target bend radius and that section's predicted Elastic Instability Radius — the tightest bend the linear-elastic model can be trusted for. A safety factor below 1.0 means the target bend is tighter than the section's elastic-instability limit. overall_safe is true only when every section's safety factor is ≥ 1.0. Rigid sections, or sections whose elastic instability radius is undefined (infinite/zero/null), return null for that section's safety factor and do not affect overall_safe.

Request:

{
"command": "calculate_kink_safety",
"radius_mm": 15.0
}

Response (Success):

{
"status": "success",
"message": "Calculated kink safety factors.",
"target_radius_mm": 15.0,
"overall_safe": true,
"safety_factors": {
"1": 3.25,
"2": null,
"3": 1.15
}
}

Error Codes:

CodeCondition
MODEL_NOT_LOADEDload or wizard_step has not been called yet.
SCHEMA_VALIDATION_ERRORradius_mm is missing or not a number.
INTERNAL_ERRORThe loaded configuration has no elastic-instability-radius data (e.g., a section with is_manual_stiffness and no derived radius).

get_config

Retrieves the full JSON configuration object currently loaded in the simulation engine. This allows an AI agent to inspect the current state (or a default load), tweak specific parameters (like a layer thickness or pullwire offset), and re-issue a load command without having to reconstruct the entire document from scratch.

Request:

{
"command": "get_config"
}

Response (Success):

{
"status": "success",
"config": {
"schema_version": "3.0.0",
"catheter_definition": {
"name": "MyCatheter",
...
}
}
}

wizard_step

Guides an AI agent through building a new catheter configuration step-by-step, mimicking the UI's Setup Wizard. It manages an internal state machine (Global Setup -> Section Setup -> Layer Setup -> Review). It performs real-time validation at each step (e.g., rejecting a layer if it causes the flowdown OD to exceed the global OD constraint).

Workflow:

  1. Send {"action": "start"} to initialize.
  2. Send {"action": "submit_global", "payload": {...}} with global parameters.
  3. Send {"action": "submit_section", "payload": {...}} to define the section parameters.
  4. Send {"action": "submit_layer", "payload": {...}} iteratively for each layer (from the inside out).
  5. Send {"action": "finish_section"} to close the current section and loop back to step 3 for the next section.
  6. Send {"action": "finish_wizard"}. This automatically hydrates the built configuration, calculates KPIs, loads it into the simulation engine, and returns the full "static_kpis" just like a standard load command.

Request (Example Layer Submission):

{
"command": "wizard_step",
"action": "submit_layer",
"payload": {
"name": "Braid Layer",
"material_name": "PEBAX 35D",
"reinforcement_type": "Braid",
"thickness_mm": 0.1,
"reinforcement_settings": {
"ppi": 80,
"num_carriers": 16,
"wire_shape": "Round",
"wire_material_name": "SS 304V",
"round_wire_diameter_mm": 0.05
}
}
}

Response (Example Validation Error):

{
"status": "error",
"message": "Layer rejected. Predicted Flowdown OD (4.150mm) exceeds global target (4.000mm)."
}

DOE / response surface commands

The following two commands expose the Response Surface Analysis Module programmatically. A catheter configuration must be loaded first (via load or wizard_step) before calling these commands.

run_doe

Runs a headless Design of Experiments (DOE) sweep over one or two continuous design parameters (with an optional A/B categorical split attribute). For each design point, the static KPIs are recalculated from scratch using the composite mechanics models and the results are aggregated into a response surface. A cubic polynomial is then fitted to the specified output metric so you can query predicted values at arbitrary input combinations.

Design Matrix:

  • 1 variable: 5-point linear sweep (min, 25%, mid, 75%, max).
  • 2 variables: 5×5 full factorial — 25 runs covering every combination of the 5 levels on each axis.
  • Attribute (A/B): The entire continuous DOE is duplicated for each attribute value, doubling the run count.

If too many of the requested simulations error out to support a cubic fit, the modeler fits a simpler quadratic surface instead so you still get a usable result. The surface_model.degree field in the response tells you which was used.

Path Specification: Variables and attributes reference a location inside the config using a JSON path array. Each element is either a string key or an integer array index. The path must resolve to a leaf value in the active catheter configuration. Use get_config first to inspect the structure if needed.

Note: run_doe currently supports static KPI sweeps only — no live dynamic simulation per run. If you need dynamic simulation data across design points, use the GUI's Response Surface Analysis Module.

Request:

{
"command": "run_doe",
"variables": [
{
"name": "Wall Thickness",
"path": ["catheter_definition", "sections", 0, "layers", 0, "thickness_mm"],
"min_val": 0.1,
"max_val": 0.5
},
{
"name": "Braid PPI",
"path": ["catheter_definition", "sections", 0, "layers", 1, "reinforcement_settings", "ppi"],
"min_val": 40,
"max_val": 120
}
],
"attribute": {
"path": ["catheter_definition", "sections", 0, "layers", 1, "reinforcement_settings", "wire_material_name"],
"val_a": "SS 304V",
"val_b": "MP35N"
},
"output_metric": "sec0_bending_stiffness_EI_Nm2",
"output_csv": "C:/path/to/results/doe_sweep.csv"
}

Parameters:

FieldRequiredTypeDescription
variablesYesarray (1-2 items)Continuous input variables to sweep. Each item must have name, path, min_val, and max_val.
attributeNoobjectCategorical A/B split. Must have path, val_a, and val_b.
output_metricNostringKPI column to fit the cubic surface to. Defaults to "sec0_bending_stiffness_EI_Nm2".
output_csvNostringAbsolute path to save the full raw results as a CSV file.

Available output metrics (prefix sec{N}_ for section index N):

  • bending_stiffness_EI_Nm2
  • torsional_stiffness_GJ_Nm2
  • axial_stiffness_EA_N
  • burst_pressure_mpa
  • display_linear_density_kg_per_m
  • elastic_instability_radius_mm — curvature radius at which the section first becomes elastically unstable (Brazier ovalization limit with helical-wire augmentation).
  • elastic_instability_moment_Nm — bending moment corresponding to the elastic instability radius.
  • tensile_failure_load_N
  • torque_failure_Nm
  • crush_pressure_atm

Response (Success):

{
"status": "success",
"message": "DOE complete: 50 runs, metric='sec0_bending_stiffness_EI_Nm2'.",
"total_runs": 50,
"output_metric": "sec0_bending_stiffness_EI_Nm2",
"runs_summary": [
{
"run": 1,
"x1": 0.1,
"x2": 40,
"attr": "SS 304V",
"sec0_bending_stiffness_EI_Nm2": 0.000412,
"error": null
}
],
"surface_model": {
"fitted": true,
"degree": 3,
"r2_score": 0.9987,
"adjusted_r2": 0.9978,
"residual_rms": 1.24e-5,
"predictions": {
"x1": [0.1, 0.144, "..."],
"x2": [40, 48.9, "..."],
"z": [[0.000412, "..."], "..."]
}
},
"output_csv": "C:/path/to/results/doe_sweep.csv"
}

surface_model fields:

FieldTypeMeaning
fittedbooltrue if the modeler produced a usable surface. false if too few simulations succeeded to fit one.
degreeintPolynomial degree used — 3 for the standard cubic fit, 2 when the modeler had to fall back to a quadratic.
r2_scorefloat | nullOverall goodness-of-fit (1.0 means the surface passes through every sample point).
adjusted_r2float | nullR² adjusted for the number of fitted coefficients — stays honest when the data is noisy or near-flat. Use this one when deciding whether to trust the surface.
residual_rmsfloat | nullAverage distance from the surface to the simulated points, in the metric's units. Treat predicted values as accurate to roughly ±residual_rms.
predictionsobject | nullFine-grid surface evaluation suitable for plotting (x1, x2, z).

Interpreting fit quality: adjusted_r2 ≥ 0.95 means the surface tracks the data closely and predictions are trustworthy. Between 0.70 and 0.95 the surface is usable but the underlying behavior likely has features the cubic doesn't fully capture — treat predictions directionally. Below 0.70 the surface is mostly fitting noise; rely on the raw simulated values instead. These are the same thresholds the GUI uses for its green/amber/red color tier.

Error Codes:

CodeCondition
MODEL_NOT_LOADEDload or wizard_step has not been called yet.
MISSING_PARAMETERvariables array is empty.
INTERNAL_ERRORUnhandled exception during the sweep.

get_doe_results

Returns the raw per-run data table from the most recent run_doe call. This is useful to retrieve the full result set (including all KPI columns, not just the surface-fitted metric) without repeating the sweep. Results are cached in memory until the next run_doe call.

Optionally, you can filter the returned columns to reduce payload size.

Request:

{
"command": "get_doe_results",
"columns": ["x1", "x2", "sec0_bending_stiffness_EI_Nm2", "sec0_elastic_instability_radius_mm"]
}

Note: columns is optional. If omitted, all columns are returned.

Response (Success):

{
"status": "success",
"last_metric": "sec0_bending_stiffness_EI_Nm2",
"total_runs": 50,
"columns": ["x1", "x2", "sec0_bending_stiffness_EI_Nm2", "sec0_elastic_instability_radius_mm"],
"rows": [
{
"x1": 0.1,
"x2": 40,
"sec0_bending_stiffness_EI_Nm2": 0.000412,
"sec0_elastic_instability_radius_mm": 8.3
}
]
}

Error Codes:

CodeCondition
NO_DOE_RESULTSrun_doe has not been called in this session.

exit or quit

Safely stops the simulation engine, deallocates memory, and closes the application.

Request:

{
"command": "exit"
}

Response (Success):

{
"status": "success",
"message": "Exiting CLI API."
}

(The program will then terminate)