From 4f6b0704dccecaab4862fea65f1099851409bf8c Mon Sep 17 00:00:00 2001 From: Christoph Goniva Date: Mon, 21 Sep 2026 10:29:42 +0200 Subject: [PATCH 1/3] Add multi-phase restart/output hygiene notes, servo center_of_mass caveat RULES.md: two new entries under Command Ordering/Simulation Output -- only declare a physics setting (e.g. heating) in the script phase that actually needs it, since a packing/prep phase split off via write_restart/read_restart can silently inherit one left over from an earlier script version; and give each named script its own output_settings folder, clearing it (not just the restart file) before rerunning outside a full clean, since Aspherix renumbers rather than overwrites colliding step files with no error. STRATEGIES.md: two new entries -- mesh_module servo's center_of_mass must track the pushed body's actual current position when the same piston geometry is reused across scripts/restarts, since the mesh's imported STL coordinates don't update on their own; and only regenerate a restart when the phase that produced it actually needs to change, since re-running an earlier phase unnecessarily wastes wall-clock time on an expensive DEM/CFD case. SKILL.md: link primitive_wall.md from the Guidelines list (it existed but wasn't linked). Co-Authored-By: Claude Sonnet 5 --- references/RULES.md | 8 ++++++++ references/strategies/INSERTION.md | 4 ++++ references/strategies/STRATEGIES.md | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/references/RULES.md b/references/RULES.md index 9a9bcae..7da9c73 100644 --- a/references/RULES.md +++ b/references/RULES.md @@ -55,6 +55,10 @@ Several commands only work once others have already been declared, and the error - `simulation_timestep` must be declared before `insertion` and `check_timestep` - declare it right after mesh imports, not grouped with output-settings near the bottom of a script. - Any `simulate` call beyond `simulate time 0` needs a `particle_template` *and* a `particle_distribution` referencing it, even for a minimal mesh-import test with no real particles inserted - a template alone isn't enough. +## Known Silent-Failure Traps + +Only declare a physics setting (e.g. heating) in the script phase that actually needs it, not earlier — a packing/prep phase split off via `write_restart`/`read_restart` can silently inherit one left over from an earlier script version. + ## Default Values Always prefer to use default values for commands when they are available. @@ -87,6 +91,10 @@ As a rule of thumb, set `write_to_terminal_timestep` to a smaller value than `wr Every one-shot event a script triggers (a mark, a final compress, any other state change meant to be captured) must run before the last `write_output_timestep` write it's meant to appear in. Verifying the event actually took effect (see `strategies/STRATEGIES.md`'s "Verify a per-particle-state command actually worked" entry) is a separate concern from this ordering — a verified change that ran after the last capturing write still won't show up in the output. +### Output folders in a multi-phase case + +Give each named script (`init`/`main`/`fill`/...) its own `output_settings folder`, and clear it (not just the restart file) before rerunning outside a full clean — see `commands/output_settings.md`. + ## Timestep Criteria Large timesteps may cause numerical instability. diff --git a/references/strategies/INSERTION.md b/references/strategies/INSERTION.md index d5d5344..80b91a3 100644 --- a/references/strategies/INSERTION.md +++ b/references/strategies/INSERTION.md @@ -34,3 +34,7 @@ Restore the real direction in the script that reads the restart. Once a bed is placed, `mesh_module servo` can compact it further by driving a wall against the bed toward a target force or torque. `kp`'s default (1e-2) is often orders of magnitude too small to reach `maximum_velocity` in a reasonable time — verify actual displacement rather than trusting the default. `simulate mode until_settled` won't detect servo progress either, since it converges on kinetic energy, not on the servo's own target — use `fixed_time` instead (see the `until_filled`/`until_settled` entry above for the same convergence-check caveat in the insertion case). + +## `mesh_module servo`'s `center_of_mass` must track the pushed body, not the mesh's own STL position + +When reusing the same piston geometry across scripts/restarts, point `center_of_mass` at the pushed body's actual current position, not the mesh's imported STL coordinates, which don't update when an earlier phase moves the body. diff --git a/references/strategies/STRATEGIES.md b/references/strategies/STRATEGIES.md index dd0f63b..aa2d50b 100644 --- a/references/strategies/STRATEGIES.md +++ b/references/strategies/STRATEGIES.md @@ -65,6 +65,11 @@ Keep this separate from a final one-shot `write_restart` at a `simulate` block's If a later phase's `read_restart` path should be swappable between the two, make it an `index`-style variable overridable via `-var` rather than a literal filename. This mechanism is for a standalone Aspherix run only - a CFD-coupled case (`enable_cfd_coupling`) syncs restarts from the CFD side, not through this `restart` mechanism, so don't assume it applies there too (see `commands/enable_cfd_coupling.md`). +## Only regenerate a restart when the phase that produced it actually needs to change + +Before re-running an earlier phase's script over a later phase's parameter change, check whether the earlier phase's own physics actually depends on it. +E.g. packing is independent of particle heat capacity, so `read_restart` can just pick up the new value instead of re-running the packing phase. + ## 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. From 6a287254594b0ef7e8a9c2aa7f6d95089ada00fc Mon Sep 17 00:00:00 2001 From: Daniel Louw Date: Wed, 23 Sep 2026 10:30:08 +0200 Subject: [PATCH 2/3] Fold Known Silent-Failure Traps into Cross-script Parameter Consistency It was a new top-level heading holding a single entry, on the same theme as the existing Cross-script Parameter Consistency section (state leaking across a restart split) -- move it there instead. While there, fix that section's now-stale claim that ${name} always crashes at evaluation; per the quoting fix landed in variable.md via #12, only a *quoted* ${name} fails. Co-Authored-By: Claude Sonnet 5 --- references/RULES.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/references/RULES.md b/references/RULES.md index 7da9c73..b0e82fb 100644 --- a/references/RULES.md +++ b/references/RULES.md @@ -55,10 +55,6 @@ Several commands only work once others have already been declared, and the error - `simulation_timestep` must be declared before `insertion` and `check_timestep` - declare it right after mesh imports, not grouped with output-settings near the bottom of a script. - Any `simulate` call beyond `simulate time 0` needs a `particle_template` *and* a `particle_distribution` referencing it, even for a minimal mesh-import test with no real particles inserted - a template alone isn't enough. -## Known Silent-Failure Traps - -Only declare a physics setting (e.g. heating) in the script phase that actually needs it, not earlier — a packing/prep phase split off via `write_restart`/`read_restart` can silently inherit one left over from an earlier script version. - ## Default Values Always prefer to use default values for commands when they are available. @@ -104,7 +100,7 @@ Refer to the `check_timestep` command. Shared parameters (e.g. `simulation_timestep`) across split scripts (`init.asx`, `main.asx`, ...) aren't enforced automatically — confirm they still match before running. -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 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 *quoted* formula fails at evaluation via `${name}`, and `v_name` re-evaluates live every time — 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. @@ -112,3 +108,4 @@ A threshold on an *extensive* quantity — total `ke(...)`, total mass, a partic 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. +This includes physics settings, not just data: only declare one (e.g. heating) in the script phase that actually needs it, not earlier — a packing/prep phase split off via `write_restart`/`read_restart` can silently inherit one left over from an earlier script version. From caf2112ef3f5b979d8d4a6a6cba2dd862a461cc6 Mon Sep 17 00:00:00 2001 From: Daniel Louw Date: Wed, 23 Sep 2026 10:34:06 +0200 Subject: [PATCH 3/3] Group the two mesh_module servo entries under a compaction header kp tuning and center_of_mass tracking are both about the same mesh_module servo bed-compaction workflow, so nest them as subheaders under one 'Compacting a bed with mesh_module servo' header instead of two flat, redundantly-titled entries. Co-Authored-By: Claude Sonnet 5 --- references/strategies/INSERTION.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/references/strategies/INSERTION.md b/references/strategies/INSERTION.md index 80b91a3..412a4f3 100644 --- a/references/strategies/INSERTION.md +++ b/references/strategies/INSERTION.md @@ -29,12 +29,15 @@ Use `mode rate_in_region` with `insert_every_time` instead (self-limits correctl In a non-physical prep phase (checkpointed via `write_restart`), point `enable_gravity`'s `direction` toward wherever the bed should end up — settling does the work for free instead of a slow pusher mesh. Restore the real direction in the script that reads the restart. -## `mesh_module servo`'s `kp` often needs to be much larger than its default +## Compacting a bed with `mesh_module servo` Once a bed is placed, `mesh_module servo` can compact it further by driving a wall against the bed toward a target force or torque. + +### `kp` often needs to be much larger than its default + `kp`'s default (1e-2) is often orders of magnitude too small to reach `maximum_velocity` in a reasonable time — verify actual displacement rather than trusting the default. `simulate mode until_settled` won't detect servo progress either, since it converges on kinetic energy, not on the servo's own target — use `fixed_time` instead (see the `until_filled`/`until_settled` entry above for the same convergence-check caveat in the insertion case). -## `mesh_module servo`'s `center_of_mass` must track the pushed body, not the mesh's own STL position +### `center_of_mass` must track the pushed body, not the mesh's own STL position When reusing the same piston geometry across scripts/restarts, point `center_of_mass` at the pushed body's actual current position, not the mesh's imported STL coordinates, which don't update when an earlier phase moves the body.