Draft. This manual is new and still growing. If something here does not match what you see in the software, the software is right — tell us and we will fix the page.
Run a script and record a macro
Drive the application from a JavaScript file instead of by hand: change one thing, mesh, solve, read a number back, decide, and do it again.
Runs on the free tier, within whatever the tier allows the script to do.
Record what you already do
The quickest way to start a script is not to write one.
- Open the case.
- Model → SCRIPT → Record macro, and choose where to save the
.jsfile. - Do the work by hand. The command relabels itself Stop recording and its tooltip counts the lines written so far.
- Model → SCRIPT → Stop recording.
The recorder is driven by the undo history rather than by the controls, so
anything an undo can see it can see. It writes what changed, not how: a slider
dragged from 10 to 80 records as one line setting 80. Run state — the cell
count, whether a mesh exists, the last outcome, the run directory — is written
by the application about the case rather than by you into it, and is not
recorded; where one of those changed, the file gets a comment line reading
// changed but not recorded: and the names.
The file opens with a header of comment lines — a timestamp, the case, and how
to run the file — then sim.openCase("<name>"). Geometry import, meshing and
solving are not edits and are not recorded. Closing the window ends a recording
the way the button does, so the last edits are in the file rather than lost with
the buffer.
--record=<file.js> does the same from a terminal, and records until the
application exits.
Run one
Model → SCRIPT → Run script, and choose the .js file. The Log dock
opens; output, errors and the exit code go there. Only one script runs at a
time — the command is greyed with "A script is already running" while one is.
From a terminal, --script=<file.js> runs it and exits with its code. Put it
last on the command line: everything before it has already run, and anything
after it runs before the script's first yield resumes. If any earlier flag on
that command line was an edit the application refused, --script= does not run
at all, rather than automating a case that is not the one that was asked for.
What a script may do
A script runs in the application's own JavaScript engine with exactly one object
in scope: sim. CaseState and the other internals are deliberately not
reachable, so a script written against sim.set("reynolds", 200) survives a
rename of the pane that owns the value.
The long operations — an import, a mesh, a solve, a report — take minutes and
the engine has no await. Write yield in front of them instead; the file is
compiled as the body of a generator, so a top-level yield is legal.
sim.openCase("hull")
yield sim.importGeometry("D:/geometry/hull.obj")
sim.set("baseCellSize", 0.04)
const mesh = yield sim.mesh()
sim.log(mesh.cells + " cells, max non-orthogonality " + mesh.nonOrtho)
const run = yield sim.run()
sim.log("run " + run.outcome + ", " + run.warnings + " warning(s)")
yield sim.results()
const p = yield sim.probe("p", [0.25, 0.05, 0])
sim.log("p at the probe: " + p)
Broadly, sim covers:
- Cases —
catalogue(),newCase(),openCase(),saveCase(),cases(),importMesh(), andyield importGeometry().caseNameandversionare properties, not calls. - Setup —
properties()lists every property a script may change;get(),set(),boundaries(),boundary(),setBoundary(),problems(). Reading is wider than writing:get()also returns what the case derived —sim.get("solver"),sim.get("meshExists"),sim.get("lastOutcome")— which is most of what a script branches on, and none of which can be assigned. - Work, which you yield —
wait(),mesh(),run().stop()only asks a running solve to stop and write, and is not yielded. - Results —
results(),probe(),sampleLine(),monitors(),saveImage(),report(),dumpCase(). - Files and exit —
readFile(),writeFile(),log(),fail(),exit().
sim.importGeometry() must be waited for. Reading a surface is asynchronous, so
a script that carries straight on meshes the empty domain box, solves it, and
reports numbers for a case that names the model throughout. It throws if no body
arrives.
sim.run() refuses to start a case the Problems tab has errors on, and says
which. Both sim.mesh() and sim.run() throw if the job did not work, so a
script does not check a return value for failure — an uncaught error stops the
script, logs the message with the line number, and exits non-zero. A solve
counts as having worked if it converged, or if it was stopped deliberately, by
sim.stop() or by the wall-clock ceiling; both leave results worth reading.
Anything else throws, with the outcome and the run directory to look in. Both
take an options object with a timeout in seconds, and a job that exceeds it
throws rather than hanging the script for ever; sim.run({end: 200}) also sets
the end iteration or time.
What they return on success is worth reading: mesh() gives cells,
nonOrtho, ok and the problem rows; run() gives outcome, converged,
errors, warnings and directory.
yield sim.results() resolves to {ready, error, times, fields, cells, boundsMin, boundsMax}; ready is false when there is nothing loaded to read,
and error says why. sim.monitors() returns an array — one
{label, latest, tailMean} per trace — so it is looped over, not indexed by
name, and it is empty for a run that wrote no monitors.
sim.dumpCase(dir) writes the generated OpenFOAM case and creates the directory
if it is not there. The folder picker deliberately does not; a path a script
author wrote down is not a picked folder.
A syntax error is reported with the line number of the file, not of the wrapper.
Check it worked
- The Log dock ends with
finished with code 0. - For a recording, open the
.jsfile: every edit you made is asim.setline, and the comment lines name anything that changed but was not recorded. - Add
yield sim.mesh()andyield sim.run()to a recorded macro where the work should happen — the recorder writes the edits, not the jobs.