Run MOOSE finite-element simulations on Windows via Docker. Use when creating, running, debugging, or visualizing MOOSE input files (.i). Covers the full lifecycle: prerequisites check, input file authoring, Docker execution, output validation, plot generation, and README documentation. Applies to heat transfer, solid mechanics, fluid dynamics, phase field, porous flow, electromagnetics, and any MOOSE module.
This skill governs the complete lifecycle of running MOOSE simulations on a Windows machine using Docker. Follow every section as a checklist.
Before running ANY simulation, verify all prerequisites. Do not skip any step.
docker info > /dev/null 2>&1 && echo "DOCKER OK" || echo "FAIL: Start Docker Desktop"
If Docker is not running, inform the user: "Docker Desktop must be running. Please start it and confirm." Do NOT proceed until Docker responds.
MSYS_NO_PATHCONV=1 docker image inspect idaholab/moose:latest > /dev/null 2>&1 \
&& echo "IMAGE OK" || echo "PULLING IMAGE..." && MSYS_NO_PATHCONV=1 docker pull idaholab/moose:latest
The MOOSE executable is at /opt/moose/bin/combined-opt inside the container.
This is the combined application that includes ALL 25+ physics modules.
Every simulation requires a .i file (HIT format). Before running:
.i file exists in the case directory[Mesh], [Variables], [Kernels] (or an
Action that creates them), [Executioner], and [Outputs]When creating a new MOOSE input file, follow these conventions learned from 21 successful quickstart cases.
quickstart-runs/caseNN-descriptive-name/
caseNN_descriptive_name.i # input file (underscores in filename)
README.md # physics + usage documentation
caseNN_descriptive_name_out.e # Exodus output (auto-generated)
caseNN_descriptive_name_out.csv # CSV postprocessor output (auto-generated)
caseNN_*.png # visualization plots (generated by script)
caseNN-kebab-case (hyphens)caseNN_snake_case.i (underscores)exodus = true and csv = true in [Outputs]Every .i file must start with a descriptive header:
# ============================================================
# Case NN: Title — Subtitle
# Brief description of the physics being solved.
#
# Governing equations (in readable math notation)
# Boundary conditions summary
# Domain dimensions and mesh size
# ============================================================
Add comments explaining:
Every simulation must produce both spatial and scalar outputs:
[Outputs]
exodus = true # spatial fields for visualization
csv = true # postprocessor time histories
[]
For transient problems, also include relevant [Postprocessors]:
Keep meshes small enough to converge in under 2 minutes on a laptop:
| Problem Type | Recommended Mesh |
|---|---|
| 2D steady state | 20x20 to 40x40 |
| 2D transient | 20x20 to 40x40 |
| 2D FV (Navier-Stokes) | 30x30 |
| Quasi-1D (thin strip) | 100x5 |
| Phase field | 40x40 |
These rules prevent failures inside the idaholab/moose:latest container:
| Rule | Reason |
|---|---|
Add disable_fpoptimizer = true and enable_jit = false to ALL DerivativeParsedMaterial blocks | The container lacks mpicxx, so JIT compilation fails. The fpoptimizer can also cause issues. |
Use time_step_interval not interval in [Outputs] sub-blocks | MOOSE renamed this parameter; interval triggers an unused-parameter error |
Use NEWTON or PJFNK solve types with lu or hypre/boomeramg preconditioner | These are the most robust choices for small educational meshes |
Avoid type = FileMesh unless the mesh file is in the same directory | Docker volume mounts map a single host directory |
ALWAYS use this exact pattern. Never deviate.
MSYS_NO_PATHCONV=1 docker run --rm \
-v "C:/Users/simon/Downloads/moose-next/quickstart-runs:/work" \
-w /work/caseNN-directory-name \
--entrypoint /bin/bash \
idaholab/moose:latest \
-c '/opt/moose/bin/combined-opt -i INPUT_FILE.i 2>&1 | tail -40'
Every element is mandatory:
| Element | Purpose |
|---|---|
MSYS_NO_PATHCONV=1 | Prevents MINGW from mangling Unix paths like /work, /opt/moose |
--rm | Auto-removes the container after exit |
-v "C:/...:/work" | Mounts the host directory into the container. Use forward slashes for the Windows path. |
-w /work/subdir | Sets the working directory inside the container |
--entrypoint /bin/bash | Overrides the default entrypoint to use bash |
-c '...' | Single-quoted command string prevents host shell expansion |
2>&1 | tail -40 | Captures stderr+stdout and shows only the last 40 lines (MOOSE is verbose) |
A successful run ends with output containing:
Solve Converged!
...
Finished Executing [XX.XX s] [XXX MB]
Check for these failure indicators:
| Indicator | Meaning |
|---|---|
*** ERROR *** | Fatal error — read the message for the cause |
MPI_ABORT | Crash — usually a missing material property or invalid parameter |
Solve failed and timestep already at dtmin | Solver divergence — reduce dt, switch preconditioner, or relax tolerances |
unused parameter | A parameter name is wrong or was renamed in this MOOSE version |
not defined on block | A material property is missing — add the required [Materials] block |
JIT compile failed | Missing mpicxx — add disable_fpoptimizer = true and enable_jit = false |
MSYS_NO_PATHCONV=1 docker run --rm \
-v "C:/Users/simon/Downloads/moose-next/quickstart-runs:/work" \
--entrypoint /bin/bash \
idaholab/moose:latest \
-c '
for dir in case14-thermoelasticity case15-lid-driven-cavity; do
echo "=== $dir ==="
cd /work/$dir
ifile=$(ls *.i | head -1)
/opt/moose/bin/combined-opt -i $ifile 2>&1 | tail -5
echo "STATUS: $?"
echo
done
'
After a successful run, these files MUST exist in the case directory:
| Artifact | Source | Purpose |
|---|---|---|
caseNN_name_out.e | exodus = true | Exodus II file — spatial field data for all variables at all time steps. Read with netCDF4 in Python or ParaView. |
caseNN_name_out.csv | csv = true | CSV of postprocessor values vs. time. Each row is a time step. Columns are time plus each postprocessor name. |
After every run, verify:
.e and .csv files exist and have non-zero sizetime column spans from start_time to end_timeNaN or Inf valuestime_whole has the expected number of stepsWhen the input file uses a named [Outputs] sub-block like:
[Outputs]
csv = true
[exodus]
type = Exodus
time_step_interval = 5
[]
[]
The exodus file will be named caseNN_name_exodus.e (NOT caseNN_name_out.e).
The CSV always gets the _out.csv suffix from the top-level csv = true.
Every case needs Python-generated PNG plots. The visualization script is at
quickstart-runs/visualize_all.py.
Each case needs a plot_caseNN() function that produces at least one PNG.
For steady-state problems: 2D contour of the primary variable(s) For transient problems: Snapshots at multiple times + time-history from CSV For multi-physics: Side-by-side panels showing each coupled field
MOOSE outputs two types of variables:
| Type | Where to Find | How to Read | Typical Variables |
|---|---|---|---|
Nodal (name_nod_var) | vals_nod_var{N} | get_nod_var(ds, idx, timestep) with node coordinates coordx, coordy | T, u, disp_x, disp_y, c, w, V, porepressure, temperature |
Element (name_elem_var) | vals_elem_var{N}eb{block} | get_elem_var(ds, idx, block, timestep) with element centroids | vonmises_stress, stress_xx, stress_yy |
FV (Finite Volume) variables (Navier-Stokes, etc.) are ALL element variables with NO nodal variables. Use element centroids for plotting.
Multi-block meshes (e.g., bimetallic strip with two materials) have separate
element variable arrays per block: vals_elem_var1eb1, vals_elem_var1eb2, etc.
Concatenate them for full-domain plots.
caseNN_descriptive_name.png # primary multi-panel plot
caseNN_variable_name.png # single-variable plot
caseNN_time_history.png # CSV-based time series
Every case directory MUST contain a README.md explaining the simulation.
Follow this structure:
# Case NN: Title — Subtitle
## Overview
2-3 paragraphs explaining:
- What physics is being modeled and why it matters
- What MOOSE modules/objects are used (with object names)
- What new concepts this case introduces vs. previous cases
---
## The Physics
- Governing equation(s) in readable form
- Boundary conditions and their physical meaning
- Material properties and their values (with units)
- Domain geometry and mesh
## Input File Walkthrough
Block-by-block explanation of the `.i` file:
- [Mesh]: domain and discretization
- [Variables]: what is being solved for
- [Kernels] or [Modules/...]: weak form terms
- [BCs]: boundary conditions
- [Materials]: constitutive relations
- [Executioner]: solver strategy and time stepping
- [Postprocessors]: quantities of interest
- [Outputs]: what files are produced
## Running the Simulation
Docker command (copy-paste ready):
```bash
MSYS_NO_PATHCONV=1 docker run --rm \
-v "C:/Users/simon/Downloads/moose-next/quickstart-runs:/work" \
-w /work/caseNN-directory-name \
--entrypoint /bin/bash \
idaholab/moose:latest \
-c '/opt/moose/bin/combined-opt -i caseNN_name.i 2>&1 | tail -30'
Bullet list of what the learner should take away from this case.
---
## 7. README Image Display Grid (Root README.md)
After generating plots for new cases, update the root `README.md` image grid
so that simulation thumbnails appear on GitHub. The grid uses a 4-column HTML
table with linked thumbnail images.
### 7.1 Grid Structure
Each batch of cases gets its own `<table>` section. Cases are arranged in rows
of 4, with each cell following this exact pattern:
```html
<table>
<tr>
<td align="center" width="25%">
<a href="quickstart-runs/caseNN-slug"><img src="quickstart-runs/caseNN-slug/caseNN_slug.png" width="100%"/></a><br/>
<b>Case NN</b>: Short Title<br/>
<sub>One-line physics description</sub>
</td>
<!-- repeat for up to 4 columns per row -->
</tr>
</table>
| Rule | Why |
|---|---|
Use <img src="..." width="100%"/> (not markdown ) | Markdown images don't respect column widths on GitHub |
Set width="25%" on every <td> | Ensures equal 4-column layout |
Wrap <img> in <a href="..."> pointing to the case directory | Clicking the thumbnail navigates to the case README |
Use <b>Case NN</b>: Title + <sub>description</sub> | Matches the established visual style |
Start a new <tr> every 4 cases | Keeps the grid compact and readable |
| If the final row has fewer than 4 cases, leave remaining cells empty | GitHub renders the partial row correctly |
New batch sections go after the last existing batch in README.md. Look for
the pattern:
### Batch X: Title (Cases NN-MM)
<table>
...
</table>
Add the new batch heading and table immediately after the previous batch's
closing </table>.
When adding a new batch, search the entire README.md for the previous total
case count (e.g., "93") and update all occurrences to the new total. Also check
these files for stale counts:
docs/quick-start.mddocs/zero-to-hero.mddocs/moose-simulation-skill-guide.mdCLAUDE.mdquickstart-runs/README.mdAfter completing a new batch of cases:
<table> grid to root README.md<img src="..."> path matches the actual PNG filenameThese are real failures encountered across 21 cases. Check for these FIRST when debugging a failed run.
Symptom: Docker starts but produces no output files, or output is empty.
Cause: Missing MSYS_NO_PATHCONV=1.
Fix: Always prefix Docker commands with MSYS_NO_PATHCONV=1.
Symptom: sh: mpicxx: command not found / JIT compile failed
Cause: DerivativeParsedMaterial tries to JIT-compile expressions using
mpicxx, which is not on PATH in the Docker container.
Fix: Add to every DerivativeParsedMaterial:
disable_fpoptimizer = true
enable_jit = false
Symptom: Material property 'PorousFlow_constant_biot_modulus_qp' not defined on block 0
Cause: PorousFlowBasicTHM action does NOT auto-create these materials.
Fix: Add explicit material blocks:
[Materials]
[biot_modulus]
type = PorousFlowConstantBiotModulus
biot_coefficient = 1.0
solid_bulk_compliance = 1e-10
fluid_bulk_modulus = 2e9
[]
[thermal_expansion]
type = PorousFlowConstantThermalExpansionCoefficient
biot_coefficient = 1.0
drained_coefficient = 0.0
fluid_coefficient = 0.0
[]
[]
Symptom: unused parameter 'Outputs/exodus/interval'
Cause: MOOSE renamed interval to time_step_interval.
Fix: Use time_step_interval in all [Outputs] sub-blocks.
Symptom: Vector parameter size mismatch errors in NavierStokesFV.
Cause: momentum_inlet_function was renamed to momentum_inlet_functors.
Fix: Use momentum_inlet_functors (plural, with "functors").
Symptom: Solve failed and timestep already at dtmin, cannot continue!
Cause: Newton iterations not converging — usually dt too large, bad
preconditioner, or ill-conditioned system.
Fix (try in order):
dt (e.g., from 0.5 to 0.1)-pc_type lu -pc_factor_mat_solver_type mumpsnl_max_its (e.g., from 20 to 30)nl_abs_tol (e.g., 1e-11) alongside nl_rel_tolgrowth_factor in IterationAdaptiveDT (e.g., from 1.5 to 1.2)Symptom: Errors about missing porosity derivatives or qp materials.
Cause: PorousFlowPorosityConst may not provide all derivatives that
PorousFlowBasicTHM expects.
Fix: Use PorousFlowPorosity with porosity_zero instead:
[porosity]
type = PorousFlowPorosity
porosity_zero = 0.3
mechanical = false
thermal = false
fluid = false
[]
Modules used in quickstart cases 01-21 and their key objects:
| Module | Cases | Key Objects |
|---|---|---|
| Framework only | 01-13 | Diffusion, ADDiffusion, BodyForce, TimeDerivative, MatDiffusion, ConservativeAdvection |
heat_transfer | 14, 17, 21 | ADHeatConduction, ADHeatConductionTimeDerivative, ADJouleHeatingSource |
solid_mechanics | 14, 20, 21 | Physics/SolidMechanics/QuasiStatic, Physics/SolidMechanics/Dynamic, ComputeIsotropicElasticityTensor, ComputeLinearElasticStress, ADComputeThermalExpansionEigenstrain |
navier_stokes | 15, 16 | [Modules/NavierStokesFV] action — INSFVMomentumDiffusion, INSFVMomentumAdvection, INSFVMassAdvection, INSFVMomentumBoussinesq, INSFVEnergyAdvection |
phase_field | 18 | SplitCHParsed, SplitCHWRes, CoupledTimeDerivative, DerivativeParsedMaterial |
porous_flow | 19 | [PorousFlowBasicTHM] action, PorousFlowPorosity, PorousFlowPermeabilityConst, PorousFlowMatrixInternalEnergy, PorousFlowThermalConductivityIdeal, PorousFlowConstantBiotModulus, PorousFlowConstantThermalExpansionCoefficient |
fluid_properties | 19 | SimpleFluidProperties |
When asked to create and run a new MOOSE simulation, follow ALL steps:
caseNN-kebab-name/.e and .csv exist, values are sanevisualize_all.py, handle nodal vs element vars