Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions references/RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,9 @@ Shared parameters (e.g. `simulation_timestep`) across split scripts (`init.asx`,
This includes a stop condition expressed as "N% of an earlier state" (e.g. a settled particle/mass count from a prior `fill`-style script) — Aspherix's variable system cannot snapshot a value from earlier in the *same* script for later comparison either, let alone across scripts (referencing one variable from inside another's formula either crashes at evaluation via `${name}`, or silently re-evaluates live every time via `v_name` — neither freezes a value; see `commands/variable.md`).
This kind of threshold has to be computed externally, from the prior script's *actual* achieved output, and hardcoded - never derived from the originally intended target.
Confirmed directly: a threshold sized for an intended count that insertion didn't fully reach (see `strategies/STRATEGIES.md`'s packing-generator entry) made `simulate mode until_condition_reached` satisfy on its very first check - no error, just a silent early exit that looks like the run did nothing.

A threshold on an *extensive* quantity — total `ke(...)`, total mass, a particle count — must likewise be rescaled whenever the particle count is, since it states a total over the system rather than a per-particle condition.
Derive it as `<per-particle value> * <this script's actual count>`, or avoid the problem with an intensive criterion — `simulate mode until_settled` breaks on a velocity threshold, which holds at any scale.

State handed between scripts needs the same care: `read_restart` reads whatever file is at the path, with no record of what wrote it (`read_restart.html`), so record provenance beside it — script, achieved count, timestamp — and check that before the phase that consumes it.
Write intermediate restarts during long runs, since one reached only at the end is lost if the run is aborted.
14 changes: 14 additions & 0 deletions references/RUNNING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ Reading the whole thing into context will pollute it.
- When checking output, prefer `tail`, `grep`, or piping through a filter over reading the whole log file — e.g. check the last N lines for the final status, or grep for `ERROR`/`WARN`.
- Set `-log filename` (rather than leaving it on screen/stdout) so the log can be searched/filtered on disk instead of scrolling through captured terminal output.

## Parallel execution

Parallelism is a launcher, not a solver flag: `mpirun -np N aspherix -in input.asx`.
Skip the wrapper at N=1 rather than `mpirun -np 1`.

Check the load balance rather than assuming every rank is busy: each `simulate` block's summary reports `Nlocal: ave <a> max <b> min <c>`, and a `min` of 0 means a rank holds no particles at all.
Expect this wherever `simulation_domain` is much larger than the region the particles actually occupy, which it must be whenever geometry extends beyond them.
See `balance` (one-off) and `fix balance` (continuous).

## Estimating how long a run will take

Use the built-in `cu` status column (Cundall number) rather than extrapolating a wall-clock rate by hand — `status_style.html` gives its definition and the wall-time formula.
It is in the default column set (`commands/status.md`), and predicted total wall time to within ~15% when checked against a completed run.

## Concurrent runs

Never start a second `aspherix` process against a case directory that already has a run in progress.
Expand Down
4 changes: 4 additions & 0 deletions references/commands/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ write_to_terminal_timestep 0.001

Set `write_to_terminal_timestep` to a finer cadence than `output_settings`'s `write_output_timestep` — status output is a handful of scalars, cheap enough to sample often and genuinely useful for monitoring a running simulation, unlike the full per-particle/per-mesh snapshots `write_output_timestep` writes. See `../RULES.md`'s Simulation Output section.

## Exception to the above: `simulate mode until_condition_reached`/`until_settled`/`until_filled`

See `simulate.html` for the `write_output_timestep`/`write_to_terminal_timestep`/`check_convergence_every_time` constraint these modes document - both should equal `check_convergence_every_time` for that `simulate` call, overriding the finer-cadence default above.

## `status_style` — content and destination

```
Expand Down
4 changes: 4 additions & 0 deletions references/commands/variable.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ Examples: (Avoid -> Prefer)
- `count_particles(assembly_group, target_region)` -> `count_particles(assembly_group,target_region)`
- `mass( assembly_group )` -> `mass(assembly_group)`

## Status keywords as formula terms

Any `status_style` column keyword (`time`, `step`, `elapsed`, `dt`, ...) is also usable directly inside an `equal`/`atom`/`boolean` formula, not just group functions and `calculate`/`variable` references (below) - see `variable.html`'s Syntax section and `status_style.html` for what each keyword means.

## Referencing other commands' output

`equal`, `atom`, and `boolean` formulas aren't limited to group functions (`count_particles(...)`, `mass(...)`, etc.) — they can also pull in results already produced by other commands in the script.
Expand Down
22 changes: 14 additions & 8 deletions references/strategies/STRATEGIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ If a case needs a smooth curved surface without shrinking every triangle to part

A mesh (walls, moving geometry) imported into a case may need preprocessing before Aspherix will accept it or before it'll behave correctly — unit mismatches, topological defects caught at import, mesh-quality hard limits that only trigger on first real use, distinguishing intentional geometry from defects, and deriving/verifying regions from a mesh's actual enclosed interior.
See `strategies/MESH_PREPROCESSING.md` for the full walkthrough.
=======
## What a reduced-scale ("smoke") run establishes

Running a script at a much lower particle count validates plumbing — it parses, meshes import, motion and measurement commands bind, output appears — but not physics or termination.
Packing geometry changes with count, so anything driven by bed depth (conveying, shearing, burden weight) becomes a different problem rather than a smaller one; check where the particles actually settle before treating a reduced run as representative.
Cost does not scale with count either, since wall meshes are re-binned every timestep however few particles there are — compare wall-triangle count against particle count first, and note that moving meshes cost substantially more per step than static ones (measured ~4x).

## Artificially soft Young's modulus for numerical stability

Expand All @@ -34,17 +40,17 @@ If the preferred choice turns out to be GPU-unsupported, look for a GPU-supporte
A sphere is the default shape for a reason (cheapest to simulate) — but for markedly non-spherical particles (elongated, angular, flat), represent that with either a genuinely non-spherical shape (multi-sphere, convex/concave, superquadric) or a rolling-friction contact model on ordinary spheres.
Prefer rolling friction by default: it approximates bulk flow behavior (angle of repose, mixing) well at much lower cost, and is sufficient unless the particle geometry itself is what the case needs to get right.

## `simulate mode until_filled` is for continuous insertion, not one-shot `pack`
## `simulate mode until_filled`/`until_settled` - pick the mode that matches the insertion style

See `simulate.html` for what each mode actually checks - don't guess from the name. In short: `until_filled` assumes a `pack`-then-`stream` pattern and is not a fit for a one-shot `pack` (use `until_settled` instead) or for a `rate_in_region` insertion with its own `target_particle_count`/`target_mass` (use a separate `until_condition_reached` on that target, then `until_settled` - `until_settled`'s own convergence check is not reliable while insertion is still running, per its documented note).

## Verify a `pack` insertion actually reached its target

`insertion mode pack` inserts its full target in one shot at the next `simulate` call, not as an ongoing stream.
Pairing it with `simulate mode until_filled` is still a mistake, but for a more specific reason than "the two don't compose well": confirmed directly, in isolation, with nothing after `until_filled` in the script - once its own convergence criterion is met, `until_filled` itself issues a literal internal `delete_atoms region deletion_region_ remove_multispheres_completely yes`, wiping every particle in the case, no error or warning.
For a one-shot `pack` insertion, use `simulate mode until_settled` (optionally with its own `velocity_threshold`) instead - it settles the already-inserted bed without this cleanup step.
Reserve `until_filled` for `stream`/`rate_in_region`-style continuous insertion, where deleting a trial fill before the real one starts is presumably the intended behavior.
See `insertion.html` for `packing_generator` styles, the `dense_experimental` ceiling, and when to prefer `rate_in_region` over any one-shot packing style. Whichever style is used, check the actual inserted count against the target afterward rather than assuming it was met - a silent shortfall can also make a downstream stop condition sized for the *intended* count wrong (see `RULES.md`'s "Cross-script Parameter Consistency").

## `packing_generator style simple` can fall well short of a high target
## Ramp prescribed mesh motion from rest, don't start it at full speed

The default `insertion mode pack` packing generator (`style simple`) can insert noticeably fewer particles than requested once the target volume fraction in the insertion region gets high - Aspherix prints its own warning (`Less insertions than requested (NN%)`) and suggests `packing_generator style dense_experimental` (previously `dense`) as the fix.
Check the actual inserted count against the target after any `pack` insertion rather than assuming it was met - a silent shortfall here doesn't just under-fill the case, it can also make a downstream stop condition sized for the *intended* count wrong (see `RULES.md`'s "Cross-script Parameter Consistency").
See `mesh_module_motion.html`'s note on starting at full speed, and `variable.html`'s note on building a temporal ramp for a `simulate`-based script (not the `ramp(x,y)` math function, which isn't a fit there) - apply that general pattern to the motion command's velocity/period/omega argument.

## Cohesion

Expand Down