From d26de790061eb008d4657bc62eceeb0e3156a935 Mon Sep 17 00:00:00 2001 From: Christoph Goniva Date: Fri, 4 Sep 2026 12:39:02 +0200 Subject: [PATCH 1/2] improvements wrt simulation control --- references/RULES.md | 6 ++++++ references/RUNNING.md | 14 ++++++++++++++ references/strategies/STRATEGIES.md | 6 ++++++ 3 files changed, 26 insertions(+) diff --git a/references/RULES.md b/references/RULES.md index d067472..80aeba2 100644 --- a/references/RULES.md +++ b/references/RULES.md @@ -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 ` * `, 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. diff --git a/references/RUNNING.md b/references/RUNNING.md index 9a9298d..b6cb849 100644 --- a/references/RUNNING.md +++ b/references/RUNNING.md @@ -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 max min `, 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. diff --git a/references/strategies/STRATEGIES.md b/references/strategies/STRATEGIES.md index 0f93661..afadc02 100644 --- a/references/strategies/STRATEGIES.md +++ b/references/strategies/STRATEGIES.md @@ -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 From f2685aacb5273f434a740a958213f08f8a8cfbea Mon Sep 17 00:00:00 2001 From: Christoph Goniva Date: Sun, 6 Sep 2026 20:17:22 +0200 Subject: [PATCH 2/2] addition info on time variable settings like ramping velocity of a mesh --- references/commands/status.md | 4 ++++ references/commands/variable.md | 4 ++++ references/strategies/STRATEGIES.md | 16 ++++++++-------- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/references/commands/status.md b/references/commands/status.md index 35ee775..6ba694a 100644 --- a/references/commands/status.md +++ b/references/commands/status.md @@ -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 ``` diff --git a/references/commands/variable.md b/references/commands/variable.md index fa9a794..2af1370 100644 --- a/references/commands/variable.md +++ b/references/commands/variable.md @@ -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. diff --git a/references/strategies/STRATEGIES.md b/references/strategies/STRATEGIES.md index afadc02..03e54f9 100644 --- a/references/strategies/STRATEGIES.md +++ b/references/strategies/STRATEGIES.md @@ -40,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 -`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 `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). -## `packing_generator style simple` can fall well short of a high target +## Verify a `pack` insertion actually reached its target -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 `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"). + +## Ramp prescribed mesh motion from rest, don't start it at full speed + +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