Skip to content

Command Line and MCP

dfieser edited this page Sep 4, 2026 · 2 revisions

Command Line and MCP

The package installs two console scripts. laserttm drives the solvers from a shell, and laserttm-mcp serves them to an AI assistant over the Model Context Protocol.

The command line

laserttm list                      # solvers, and which one answers which question
laserttm describe radial_profile   # every config key with unit, default and valid range
laserttm materials                 # material presets and their properties
laserttm validate study.json       # check a config without running it
laserttm run study.json --dry-run  # validate and report the cost, then stop
laserttm run study.json --out results.json
laserttm schema radial_profile     # JSON Schema, for typed consumers
laserttm version

A config file is the solver's config dict plus a solver key, using the same names as the Python and MATLAB interfaces:

{
  "solver": "radial_profile",
  "material": "W",
  "Pavg": 70,
  "f_rep": 40e6,
  "spotRadius": 150e-6,
  "simDuration": 2.5e-5,
  "storeHistory": false
}

Notes:

  • Plots are off by default in command-line runs. Pass --plots, or set makePlots or saveFigures in the config.
  • --out writes a JSON summary, or a .npz of the arrays if the path ends in .npz.
  • Configs are validated before a run starts, so a mistyped key stops immediately with the correction named rather than quietly running on defaults.
  • Exit codes are 0 for success, 2 for a config problem, and 4 for an unknown solver.
  • laserttm list, describe, materials, and schema do not import the numerical stack, so they answer immediately.

Checking a config before spending time on it

validate reports every problem at once, each with a suggested fix:

$ laserttm validate study.json
2 problem(s) with the config for 'depth_profile':
  [error] Unknown key 'pavg' for solver 'depth_profile'.
          Did you mean 'Pavg'? Config keys are case-sensitive.
  [error] spotRadius = 150 is outside the plausible range 1e-09 to 0.01 m.
          That value looks like micrometres. Pass SI units: spotRadius = 0.00015.

The two failures it is built to catch are the ones that used to pass silently. An unknown key was ignored, so a typo produced a plausible run on default parameters. A unit slip is a positive number that passes any simple check while producing nonsense.

A valid config prints what it implies, so a mistaken Pavg and f_rep pair shows up as an implausible fluence before any run is spent on it:

$ laserttm validate study.json
Config is valid for depth_profile.
  Pulse energy 5e-05 J, peak fluence 0.4974 J/cm^2, absorbed 0.2735 J/cm^2.
  100 pulses, roughly 16.5 s plus about 3 s of kernel loading on the first call.
  [warning] Peak fluence 0.497 J/cm^2 exceeds the single-shot ablation threshold of W (0.44 J/cm^2). ...

The warnings carry codes: above_ablation, truncated_period when simDuration is not a whole number of periods, coarse_coast when the solver will raise Ndiff, unusual_value and expensive_run. The estimate accounts for the pulse width, which sets the depth solver's step count, and for the history table when it is written.

Batch runs and sweeps

There is no separate batch runner. A sweep is an ordinary Python loop, and caseTag keeps each run's output files apart:

from laserttm import radial_profile_solver

for absorbance in (0.40, 0.45, 0.50, 0.55):
    cfg = {
        "material": "W",
        "Pavg": 70,
        "f_rep": 40e6,
        "spotRadius": 150e-6,
        "tau_FWHM": 500e-15,
        "simDuration": 5000 / 40e6,
        "absorbance": absorbance,
        "makePlots": False,
        "storeHistory": False,
        "caseTag": f"A{absorbance:.2f}",
    }
    results = radial_profile_solver(cfg)
    print(absorbance, results["finalResid_C"])

For long sweeps, set makePlots to False and storeHistory to False where the solver supports it. Validate one config first with validate_config so a typo does not cost the whole sweep.

The MCP server

Install the optional extra and register the server:

pip install "laserttm[mcp]"
claude mcp add laserttm -- laserttm-mcp

Because multi-pulse runs can take minutes, the server uses a job pattern rather than blocking tool calls.

Tool What it does
list_solvers which solver answers which question, with a minimal working config for each
describe_solver every accepted key with type, unit, default, valid range, and meaning
validate_config check a config in milliseconds, with a suggested fix for each problem, the derived pulse energy and fluence, and the runtime estimate
list_materials material presets, their properties, and which solvers accept each
start_run launch a solver in a background worker and return a run id
check_run poll status with a log tail
get_results the results summary once the run finishes
get_log the captured solver output
cancel_run terminate a running job
run_quick run and wait, for short cases only

Full arrays land in ~/.laserttm/runs/<run_id>/results.npz, and the LASERTTM_RUNS_DIR environment variable overrides that location.

The discovery tools exist so an assistant gets the config right the first time instead of learning by failed runs. start_run validates before spawning and returns the pulse count and estimated runtime alongside the run id, and run_quick refuses a run that cannot fit its timeout rather than returning a partial answer.

Working on the repository with an AI agent

AGENTS.md at the repository root holds the constraints an agent needs before changing anything, chiefly that solver numerics are pinned to the MATLAB golden fixtures and that the published interface is additive only. Most agent tools read that file automatically.

Clone this wiki locally