Repository navigation
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.
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 versionA 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 setmakePlotsorsaveFiguresin the config. -
--outwrites a JSON summary, or a.npzof 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, andschemado not import the numerical stack, so they answer immediately.
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.
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.
Install the optional extra and register the server:
pip install "laserttm[mcp]"
claude mcp add laserttm -- laserttm-mcpBecause 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.
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.
Ultrafast Laser TTM Toolbox (Python) · MIT License · Paper: 10.1007/s11665-026-14738-6 · Software: 10.5281/zenodo.22210435
Using the package
Understanding the model
Help
Links