Troubleshooting¶
Common problems and their solutions.
Installation Issues¶
ModuleNotFoundError: No module named 'mp3du'¶
Cause: The mp3du package is not installed in the active Python environment.
Solution:
Install the wheel directly from the GitHub Releases page:
pip install https://github.com/sspa-inc/mp3du-rs/releases/download/vX.Y.Z/mp3du_py-X.Y.Z-cp38-abi3-win_amd64.whl
Replace the URL with the actual link to the latest .whl asset. See the Installation guide for full instructions.
Tip
Verify you are in the correct virtual environment:
Configuration Errors¶
Invalid solver name¶
Error pattern: unknown variant 'dormandprince', expected one of 'Euler', 'Rk4StepDoubling', ...
Cause: Solver names are case-sensitive enums. Lowercase or underscore-separated names are not accepted.
Solution: Use the exact enum value:
Valid values: Euler, Rk4StepDoubling, DormandPrince, CashKarp, VernerRobust, VernerEfficient.
See Solver Methods for all solver options.
Schema validation failures¶
Error pattern: jsonschema.ValidationError: 'xyz' is not valid under any of the given schemas
Cause: The configuration JSON does not conform to the schema. Common sub-causes:
- Missing required fields
- Extra fields (the schema sets
additionalProperties: false) - Wrong types (e.g., integer
1instead of float1.0fordirection)
Solution: Validate against the schema to get a specific error message:
import json
import urllib.request
import jsonschema
schema_url = "https://sspa-inc.github.io/mp3du-rs-docs/assets/raw/mp3du_schema.json"
with urllib.request.urlopen(schema_url) as response:
schema = json.load(response)
with open("my_config.json") as f:
config = json.load(f)
try:
jsonschema.validate(instance=config, schema=schema)
except jsonschema.ValidationError as e:
print(f"Path: {'.'.join(str(p) for p in e.absolute_path)}")
print(f"Error: {e.message}")
See Schema Reference for field specifications and Building Configs for common mistakes.
direction must be exactly 1.0 or -1.0¶
Error pattern: 1 is not one of [1.0, -1.0]
Cause: The direction field uses an enum constraint. Integer values like 1 or -1 are rejected because JSON distinguishes integers from floats.
Solution:
Runtime Errors¶
Particle outside grid¶
Error pattern: particle exited domain at step N or final_status = "Exited"
Cause: The particle's starting coordinates are outside the specified cell, or the particle naturally exits the model domain during tracking.
Solution:
- Verify starting coordinates: ensure \((x, y, z)\) is inside the polygon of
cell_idand between the cell's top and bottom elevations - If particles are exiting unexpectedly, check that the flow field is correctly loaded and the grid boundary conditions are as expected
Simulation hangs or is very slow¶
Cause: Several possibilities:
- Tolerance too tight: Very small
tolerancevalues cause many rejected steps and tiny step sizes - Pathological velocity field: Near-zero or oscillating velocities in some cells
min_dttoo small: Allows the solver to take extremely small steps instead of failing
Solution:
- Start with the default tolerance (
1e-6) and DormandPrince solver - Check for cells with near-zero velocity — these may indicate dry cells or data issues
- Set
min_dtto a reasonable floor (e.g.,1e-10) to prevent the solver from stalling - Enable stagnation detection with
stagnation_velocityandstagnation_limit
Tip
Start with default settings and gradually adjust. If a simulation takes longer than expected, reduce max_steps temporarily to diagnose the issue quickly.
max_rejects exceeded¶
Error pattern: final_status = "Error" with step size rejection
Cause: The solver cannot find a step size that satisfies the tolerance. This usually happens in regions with discontinuous or extremely steep velocity gradients.
Solution:
- Increase
max_rejects(e.g., from 10 to 50) - Loosen
tolerance(e.g., from1e-8to1e-6) - Lower
min_scaleto allow more aggressive step reduction - Check the velocity field for discontinuities near the particle location
Data Issues¶
Array dimension mismatch¶
Error pattern: array length N does not match expected M during hydration
Cause: One or more NumPy arrays passed to hydrate_cell_properties() or hydrate_cell_flows() has the wrong length.
Solution:
n = grid.n_cells()
assert top.shape == (n,), f"top: expected ({n},), got {top.shape}"
assert bot.shape == (n,), f"bot: expected ({n},), got {bot.shape}"
# ... check all arrays
All per-cell arrays must have shape (n_cells,). Face arrays (face_flow, face_neighbor) must have shape (n_faces,), and face_offset must have shape (n_cells + 1,).
Non-contiguous array error¶
Error pattern: array must be C-contiguous
Cause: NumPy arrays passed to hydration functions must be C-contiguous. Transposed or sliced arrays may not be.
Solution:
NaN or Inf in results¶
Cause: Numerical issues in the velocity field, typically from:
- Division by zero in cells with zero porosity or zero area
- Extremely large velocity gradients
- Incorrect input data (e.g., top elevation below bottom elevation)
Solution:
- Check input arrays for NaN/Inf:
assert np.all(np.isfinite(array)) - Verify
top > botfor all cells - Verify
porosity > 0for all cells - Check for cells with zero area or zero perimeter
Getting Help¶
When reporting an issue, include:
- mod-PATH3DU version:
python -c "import mp3du; print(mp3du.version())" - Python version:
python --version - Platform: Windows, macOS, or Linux
- Exact error text (full traceback if available)
- Configuration JSON (or minimal reproducing config)
- Grid dimensions: number of cells, number of faces
Boundary Capture Issues¶
Particles pass through CHD cells without being captured¶
Cause: No boundary data was provided to hydrate_cell_flows(), or the IFACE value is wrong.
Solution: Pass the bc_* arrays to hydrate_cell_flows() with the correct IFACE mapping for each BC package:
| BC Package | Typical IFACE |
|---|---|
| WEL | 0 (well at cell centre) |
| CHD | 2 (side face) |
| RCH | 6 (top face) |
| EVT | 6 (top face) |
| DRN | 6 (top face) |
| GHB | 2 (side face) |
See IFACE & Boundary Capture for the full IFACE reference.
Particles captured as CapturedByWell when they should be CapturedByBoundary¶
Cause: The legacy has_well=True workaround is still set for non-well BC cells (e.g., CHD cells marked as wells to force capture).
Solution: Remove the has_well workaround. Instead, pass the proper bc_* arrays with the correct IFACE values. When boundary entries exist for a cell, has_well is ignored.
Particles terminated as CapturedAtModelEdge instead of well capture¶
Cause: is_domain_boundary=True is set for a cell that contains an IFACE 0 (well) entry. Domain-boundary capture has the highest priority and overrides well capture.
Solution: Do not set is_domain_boundary=True for cells with IFACE 0 wells. The C++ implementation excludes IFACE 0 cells from domain-boundary capture.
Unexpected termination_reason for IFACE 7 cells¶
Cause: IFACE 7 routes flow to q_top (with negation) for the velocity field, but uses the INTERNAL capture classification — not TopFace.
Solution: This is the intended behaviour. IFACE 7 represents an internal BC without a specific well, so capture triggers immediately on cell entry (like IFACE 2), but the flow contribution goes to q_top for velocity reconstruction. The termination_reason will show the BC type name.
See Also¶
- Error Diagnostics — Full error catalog with all known error patterns
- Building Configs — Configuration guide and common mistakes
- Units & Conventions — Ensure consistent units across all inputs