---
name: moose-simulation
description: >
  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.
allowed-tools: Read, Grep, Glob, Bash, Write, Edit
---

# MOOSE Simulation on Windows (Git Bash + Docker)

This skill governs the complete lifecycle of running MOOSE simulations on a
Windows machine using Docker. Follow every section as a checklist.

---

## 1. Prerequisites Checklist

Before running ANY simulation, verify all prerequisites. Do not skip any step.

### 1.1 Docker Desktop Must Be Running

```bash
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.

### 1.2 MOOSE Image Must Be Available

```bash
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.

### 1.3 Input File Must Exist

Every simulation requires a `.i` file (HIT format). Before running:

1. Verify the `.i` file exists in the case directory
2. Read the file to confirm it is syntactically valid HIT
3. Check that it has at minimum: `[Mesh]`, `[Variables]`, `[Kernels]` (or an
   Action that creates them), `[Executioner]`, and `[Outputs]`

---

## 2. Input File Authoring Standards

When creating a new MOOSE input file, follow these conventions learned from
21 successful quickstart cases.

### 2.1 File and Directory Naming

```
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)
```

- Directory name: `caseNN-kebab-case` (hyphens)
- Input file: `caseNN_snake_case.i` (underscores)
- Always include `exodus = true` and `csv = true` in `[Outputs]`

### 2.2 Header Comment Block

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
# ============================================================
```

### 2.3 Inline Comments

Add comments explaining:
- Why each kernel/BC/material is needed (not just what it does)
- Physical meaning of parameter values (units, typical ranges)
- Relationships between coupled variables
- Solver/preconditioner choices and why they suit this problem

### 2.4 Required Output Blocks

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]`:
- At least one domain-averaged quantity (conservation check)
- Extreme values (min/max of primary variable)
- Boundary fluxes or integrals where physically meaningful

### 2.5 Mesh Sizing for Quick Runs

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 |

### 2.6 Docker Portability Rules

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 |

---

## 3. Running Simulations in Docker

### 3.1 The Canonical Run Command

ALWAYS use this exact pattern. Never deviate.

```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 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) |

### 3.2 Verifying Success

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` |

### 3.3 Running Multiple Cases

```bash
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
  '
```

---

## 4. Output Artifacts and Validation

After a successful run, these files MUST exist in the case directory:

### 4.1 Required Artifacts

| 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. |

### 4.2 Validation Checks

After every run, verify:

1. **File existence**: Both `.e` and `.csv` files exist and have non-zero size
2. **CSV sanity**: Read the CSV and check that:
   - `time` column spans from `start_time` to `end_time`
   - Conserved quantities (e.g., average concentration, total energy) remain constant or change monotonically as expected
   - No `NaN` or `Inf` values
3. **Exodus sanity**: Open with netCDF4 and verify:
   - `time_whole` has the expected number of steps
   - Nodal or element variables have physically reasonable values (no overflow, no all-zeros)

### 4.3 Named Output Sub-Blocks

When 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`.

---

## 5. Visualization Requirements

Every case needs Python-generated PNG plots. The visualization script is at
`quickstart-runs/visualize_all.py`.

### 5.1 Plot Function Requirements

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

### 5.2 Reading Exodus Files

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.

### 5.3 Plot Naming Convention

```
caseNN_descriptive_name.png       # primary multi-panel plot
caseNN_variable_name.png          # single-variable plot
caseNN_time_history.png           # CSV-based time series
```

---

## 6. README Documentation Requirements

Every case directory MUST contain a `README.md` explaining the simulation.
Follow this structure:

```markdown
# 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'
```

## Expected Results

- What the solver output should look like (converged in N steps)
- Physical interpretation of the results
- What the plots show and how to read them

## Key Takeaways

Bullet list of what the learner should take away from this case.
```

---

## 7. Common Failure Patterns and Fixes

These are real failures encountered across 21 cases. Check for these FIRST
when debugging a failed run.

### 7.1 MINGW Path Mangling (Silent Failure)

**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`.

### 7.2 JIT Compilation Failure

**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
```

### 7.3 Missing Material Properties (PorousFlow)

**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
  []
[]
```

### 7.4 Renamed Parameters

**Symptom**: `unused parameter 'Outputs/exodus/interval'`
**Cause**: MOOSE renamed `interval` to `time_step_interval`.
**Fix**: Use `time_step_interval` in all `[Outputs]` sub-blocks.

### 7.5 FV Navier-Stokes Parameter Names

**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").

### 7.6 Solver Divergence

**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):
1. Reduce initial `dt` (e.g., from 0.5 to 0.1)
2. Switch preconditioner to LU: `-pc_type lu -pc_factor_mat_solver_type mumps`
3. Increase `nl_max_its` (e.g., from 20 to 30)
4. Add `nl_abs_tol` (e.g., 1e-11) alongside `nl_rel_tol`
5. Reduce `growth_factor` in `IterationAdaptiveDT` (e.g., from 1.5 to 1.2)

### 7.7 Porosity Material Type

**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
[]
```

---

## 8. Physics Module Quick Reference

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` |

---

## 9. Complete Run Workflow Checklist

When asked to create and run a new MOOSE simulation, follow ALL steps:

- [ ] **1. Verify prerequisites** (Section 1): Docker running, image available
- [ ] **2. Create case directory** with correct naming: `caseNN-kebab-name/`
- [ ] **3. Write input file** (Section 2): header, comments, outputs, portability rules
- [ ] **4. Run in Docker** (Section 3): use canonical command, check for convergence
- [ ] **5. Validate outputs** (Section 4): `.e` and `.csv` exist, values are sane
- [ ] **6. If run fails**: diagnose using Section 7, fix, and re-run
- [ ] **7. Generate plots** (Section 5): add function to `visualize_all.py`, handle nodal vs element vars
- [ ] **8. Verify plots visually**: read the PNG files and confirm physics looks correct
- [ ] **9. Write README.md** (Section 6): physics, walkthrough, Docker command, results
- [ ] **10. Report results** to user: summarize what converged, what the plots show, physical interpretation
