Migration Guide: ctwrap → STONE#

STONE (via Boulder) is the only supported YAML dialect. The ctwrap path (backend="ctwrap" in generate_calculation_note) is deprecated and will be removed. This guide maps every legacy artefact to its STONE replacement.


High-level mapping#

Legacy artefact

STONE replacement

tube_furnace.yaml + run_concept.py

tube_furnace_stone.yaml + run_yaml.py

tube_furnace_parametric.yaml + run_parametric_study.py

tube_furnace_stone.yaml (sweeps: block) + run_yaml_scenarios.py

SPRING_A3_BG_*.yaml + run_concept.py

SPRING_A3_BG_*_stone.yaml + run_yaml.py

run_scenarios.py (extra_yamls glob)

run_yaml_scenarios.py (inline scenarios: / sweeps:)

export.model_type: tube_furnace

export.reactor_kind: DesignTubeFurnace

export.model_type (any value)

Removed — model_type is no longer accepted


Key-by-key changes#

Mechanism declaration#

Before (ctwrap, top-level or nested under defaults.parameters):

defaults:
  parameters:
    mechanism_reac: Fincke_GRC.yaml
    mechanism_torch: Fincke_GRC.yaml

After (STONE):

phases:
  gas:
    mechanism: Fincke_GRC.yaml

When torch and reactor stages use different mechanisms, declare per-group:

groups:
  torch_stage:
    mechanism: Fincke_GRC.yaml
  pfr_stage:
    mechanism: CRECK_2003_TOT_HT_SOOT_kinetics.yaml

Reactor kind and KPI function#

Before (ctwrap export block):

export:
  model_type: "tube_furnace"

After (STONE):

export:
  reactor_kind: DesignTubeFurnace
  kpi_fn: "bloc.reactor_models:compute_tube_furnace_kpis"

For SPRING (Torch → PSR → PFR):

export:
  kpi_fn: "bloc.spring_kpi:compute_spring_kpis"

reactor_kind is optional when there is exactly one registered reactor kind in the YAML; it is only required for disambiguation.


Parametric variations#

Before (ctwrap, extra_yamls glob):

generate_calculation_note(
    "SPRING_A3_BG_20260326.yaml",
    module=simulation_module,
    extra_yamls="SPRING_A3_BG_*_gen*.yaml",
    backend="ctwrap",
)

After (STONE, inline sweeps:):

# SPRING_A3_BG_20260326_stone.yaml
sweeps:
  mass_flow_rate:
    path: "nodes[id=torch].DesignTorch.mass_flow_rate"
    values: [1.0e-3, 2.0e-3, 3.0e-3]
from bloc.calc_note import generate_calculation_note_stone
generate_calculation_note_stone("SPRING_A3_BG_20260326_stone.yaml")

For explicit named scenarios instead of a Cartesian sweep:

scenarios:
  - id: "case_A"
    set:
      nodes[id=pfr].DesignPFR.diameter: 0.08
  - id: "case_B"
    set:
      nodes[id=pfr].DesignPFR.diameter: 0.12

Sweep path syntax#

path is required in every sweep axis. A bare field name (short form) is auto-resolved to the node that declares it, as long as exactly one node matches:

sweeps:
  diameter:
    path: diameter          # short form — resolves to nodes[id=tube_furnace].properties.diameter
    values: [0.03, 0.05]

Use the explicit form when there is ambiguity:

sweeps:
  diameter:
    path: "nodes[id=tube_furnace].DesignTubeFurnace.diameter"
    values: [0.03, 0.05]

Python entry point#

Before:

from bloc.calc_note import generate_calculation_note
generate_calculation_note("my.yaml", module=sim_module, backend="ctwrap")

After:

from bloc.calc_note import generate_calculation_note_stone
generate_calculation_note_stone("my_stone.yaml")

Or equivalently, using the unified entry point with explicit backend:

from bloc.calc_note import generate_calculation_note
generate_calculation_note("my_stone.yaml", backend="stone")

What to do with _old.yaml files#

Do not keep *_old.yaml copies in the repository. Git already stores the history. If an old configuration is scientifically important, tag the commit that contains it (git tag -a v1.0-old-config -m "pre-migration baseline").