Compare commits

..
Author SHA1 Message Date
ClaudeandClaude Opus 5.5 aceea293a3 docs: drop 'rigorous' wording for the window tolerance (no threshold change)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 13:19:44 +00:00
ClaudeandClaude Opus 5.5 a233c90324 test: measurement-only A-versus-window timing for shifted-MRT refined DFG
A (per-base read-and-sum per 80-step interval), W (window + step(80) +
one read) and W1 (window + 80 x step(1)) over equal simulated duration
from the same fresh state and warm-up, 3 interleaved repeats. Bitwise
populations and per-interval total impulses (documented engineering
tolerance) are compared outside timing; health checks untimed. Records
candidate source identity (revision, dirty flag, file hashes) and does not
use or modify frozen refined-DFG manifests/results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 13:09:31 +00:00
ClaudeandClaude Opus 5.5 f851aecf73 test: shifted-MRT no-Jet window gate with step(0), reset and split-step checks
Separate GPU class for a shifted MRT, all-blocked, stationary-body case
without Jets: window totals vs summed per-base reads (substep-scaled
tolerance), bitwise populations vs a raw-only stepper, a single step(N)
stepper with bitwise-equal window rows and populations, step(0)
non-change, and reset after a window. SRT/Jet test stays separately
scoped. Test-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 13:03:18 +00:00
ClaudeandClaude Opus 5.5 51202fc1c3 test: substep-scaled tolerance and bitwise populations in window GPU gate
Scale the window-vs-summed-reads tolerance by the actual absolute fine
substep contributions (last_raw after every fine hop), labelled a
conservative engineering tolerance rather than a proof. Compare
populations by finite FP32 bits plus NaN masks and reject infinities.
Test-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:59:09 +00:00
ClaudeandClaude Opus 5.5 d930323479 feat: optional observation-window raw exchange ledger
FixedPatchStepper(observe_window_exchange=True), which requires
observe_raw_exchange, allocates a second per-link FP64 ledger per body
level. While a window is open, the unchanged BlockAccumulateExchange
kernel also accumulates into it after each fine hop. Small API:
start_exchange_window() zeroes and opens at the current completed step;
read_exchange_window(body_id, level=) is non-destructive and reports
impulse with rates over the integer window duration. initialize/
_initialize_raw and step failure invalidate; remap builds a new instance
with no open window; Jet amplitude updates may stay in-window. Default
disabled: no allocation and no extra launch; last_substep/last_base_step
unchanged. summarize_exchange gains window='window' with duration.
Host contract tests (mocked driver) and a GPU gate against summed
per-base reads with a reordering-bound FP64 tolerance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:54:44 +00:00
ClaudeandClaude Opus 5.5 6c53d2e74a test: fix flat uniform DDF masking and clarify harness labels
Simulation.get_ddf() is flat (9*ny*nx); view it as (Q, cells) before
applying the fluid mask, with a flat-DDF regression. Label A/E as
runner-like force-read workloads (values discarded, no aggregation or
validation; no macro/probe/CSV cost; not benchmark throughput) and split
status lines into CONSTRUCTED and WARM_READY. Test/doc only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:33:07 +00:00
ClaudeandClaude Opus 5.5 724afb607c test: physical health and stricter parity in timing harness
Untimed physical-leaf/fluid health after warm-up and after each timed
window using the existing runner limits (finite macros, rho in [0.5,1.5],
max Mach <= 0.2); refined masks as in run_refined_dfg. Parity comparator
rejects unequal level counts and any infinity; matching NaN stays allowed
only as a storage mask. Regression tests for both. No numerical gate or
production change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:29:21 +00:00
ClaudeandClaude Opus 5.5 77bab1c4ea test: apply timing harness review caveats
Explicit stream synchronization before/after each timed loop (refined
FixedPatchStepper stream, uniform Simulation stream, in their contexts);
required --max-wall-seconds outer timeout checked between variants and in
per-step loops; untimed finite leaf/fluid health checks; force notes for
B/C/E' (no host reads; final base interval only; whole-window average with
different summation order). Parity stays A/B/C vs A and E/E' vs E only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:27:16 +00:00
ClaudeandClaude Opus 5.5 15fb58e36f test: measurement-only refined DFG MRT timing harness
Wall-time A/B/C/E/E' variants over equal simulated duration, reusing
run_refined_dfg setup functions. Fresh state and identical warm-up per
repeat, 3 interleaved repeats, construction/JIT, warm-up and bitwise
population/NaN-mask parity checks outside timed regions. B, C and E' are
labelled timing-only (no valid force history). No numerical or
production change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 12:25:43 +00:00
TRON 4d4b9ba00a test: compare all-dense MRT fine stepping with blocked layouts 2026-10-18 03:51:53 -07:00
TRON 2abc48f0d8 test: select matched MRT DFG pilot with separate provenance 2026-10-18 03:49:21 -07:00
ClaudeandClaude Opus 5.5 3ea131e92c test: MRT refinement coverage and obsolete rejection fix
Remove MRT from the FixedPatch2D rejection matrix (TRT and other
rejections retained); convert host MRT tests to stdlib unittest; add GPU
gates for unshifted dense-vs-blocked MRT two-level roots (exact bits) and
a shifted all-blocked three-level MRT smoke checking per-level omega.
No numerical source change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 10:31:25 +00:00
ClaudeandClaude Opus 5.5 00d7a54829 feat: opt-in MRT collision for blocked/refined stepping
Additive compile-time COLLISION_MODEL == 2 branches in BlockStep,
BlockChannelStep and patch_collide repeat the uniform collide_dispatch
MRT sequence (zero forcing, omega clamp, collide_mrt_no_force). SRT
statements, including the shifted retained-delta/direct-momentum path,
are unchanged under the alternate branch. Guards accept SRT or MRT only;
TRT, LES, non-FP32, non-double-buffer and shifted dense/mixed refinement
stay rejected. Transfers, subcycling, BFL, raw ledgers, channel closures,
shifted-Jet SRT guard and PeriodicBlockStepper are untouched. Existing
MRT operator, shifted representation and fixed kinetic rates are reused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 10:26:55 +00:00
77 changed files with 1484 additions and 1488 deletions
+34
View File
@@ -0,0 +1,34 @@
# MRT reuse in blocked/refined stepping (candidate)
Base `9805383`. Opt-in by `LBMConfig(collision="MRT")`; SRT remains the default and its
kernel statements, including the shifted retained-delta/direct-momentum path, are unchanged
under the alternate compile branch.
## What changes
- `blocks.cu` (`BlockStep`), `step/block_channel.cu` (`BlockChannelStep`) and `refinement.cu`
(`patch_collide`) gain a compile-time `COLLISION_MODEL == 2` branch that repeats the uniform
`collide_dispatch` sequence with zero forcing: `compute_rho_u`, omega clamp to
`[OMEGA_COLLISION_MIN, OMEGA_COLLISION_MAX]`, `collide_mrt_no_force`.
- Kernel and host guards accept SRT or MRT only. TRT, LES, non-FP32 storage, non-double-buffer
streaming, and shifted dense/mixed refinement remain rejected.
- Transfers, subcycling, BFL, raw exchange ledgers and channel closures are untouched. The
existing pressure-NEQ outlet selects its MRT branch (unknowns-only NEQ extrapolation) from
`COLLISION_MODEL`, so MRT channel parity must use uniform MRT as reference.
## Contracts (existing operator, not redefined here)
- Shifted storage uses the existing MRT representation (equilibrium moments from `rho - 1`),
not the SRT retained-delta/direct-momentum precision. Mass and momentum are conserved
moments (relaxation rate 0).
- Kinetic rates are the operator's fixed `s_e = s_eps = s_q = 1.2` on every level; the shear
rate is the existing per-level omega. Under acoustic 2:1 scaling the physical bulk viscosity
therefore halves on each finer level. No rate rescaling is applied.
- No LES, no external forcing (`d_params` force fields stay zero).
- Shifted Jets stay SRT-only: `body/jets.py` keeps its existing guard. This extension does not
provide shifted MRT Jets.
- `PeriodicBlockStepper` (uniform blocked stepper) remains SRT-only.
## Evidence status
CPU: `tests/unit/test_refinement_mrt.py` (host guards, source contract). GPU:
`tests/validation/multigrid/test_refinement_mrt_gpu.py` (uniform-MRT channel parity, AMR MRT
smoke) and unchanged SRT GPU tests. Strict parity may be subject to cross-kernel FMA
contraction differences already documented for SRT. Not a DFG/benchmark validation.
+71
View File
@@ -0,0 +1,71 @@
# Matched MRT DFG pilot preparation
Preparation only: this test-only extension reuses the existing runner and existing MRT
operator. GPU admission awaits reviewed MRT capability results; no pilot/full execution
is implied by CPU preflight. No production, historical SRT manifest, reference data,
periodic gate, geometry, initialization or observation algorithm is changed here.
## Selection and provenance
Use `--collision MRT` for **both** uniform D80 and refined root D40/fine D80. There are
no independently selectable collision models per case. Default remains SRT.
MRT verifies `data/refined_dfg/source_manifest_mrt.json`, pinned to reviewed numerical
source snapshot `3ea131e92c057843034f11a1c574301a2430dfce`, including the shared geometry,
pressure/cycle helpers and official reference. Test-only commits may change HEAD without
changing this numerical source pin. Plan, READY, case summaries and comparison separately
record `checkout_revision` and `checkout_dirty` using existing source-provenance helper;
the runner hash remains separate. Collision is recorded in every receipt, and full-mode
validation rejects missing or different collision labels in plan, either summary or either
READY receipt, in addition to existing source/runner/health/time checks.
The historical SRT manifest remains byte-for-byte unchanged. SRT on the MRT candidate
checkout deliberately fails that source pin; use a matching historical checkout via
`--source` for SRT. No fallback or automatic repinning is permitted. Historical SRT
failure/diagnostic evidence remains attached to its original source and runner hashes;
it cannot authorize an MRT full run. The existing failed-observation step-reporting
undercount is not changed in this narrowly scoped selection patch.
## Frozen physical comparison
All settings remain those documented in `refined_dfg.md`: U_lattice=.01, physical mean
U=1 m/s, D=.1 m, shear ν=.001 m²/s, fixed physical domain/body/wall planes, patch
(40,24,320,140), shifted FP32 double buffers, no LES/forcing/Jets, finest dx=.00125 m,
finest dt=.0000125 s, unchanged half-cell frame conversion and axis-specific phase.
Force interval accumulation, physical leaf mass, pressure interpolation, flux sampling,
safety thresholds, t*=5 pilot and t*=300 cap are unchanged. Existing accuracy/periodicity
criteria are imported unchanged. Both MRT cases are fresh runs; old MRT or SRT results
are not substituted as controls.
Both cases use the **existing MRT pressure-NEQ branch**: only unknown directions q2/6/8
are extrapolated. This differs from SRT's all-nine .5-damped branch; the retained
`srt_neq_damp=.5` configuration value is inactive under MRT. Backflow clamp remains off.
The outlet is still noncanonical relative to exact DFG do-nothing conditions.
The reused MRT operator keeps fixed kinetic rates `s_e=s_eps=s_q=1.2` on all levels;
only the shear rate follows existing per-level viscosity. Physical bulk relaxation
therefore differs between coarse and fine levels. Transfer operators and subcycling
are unchanged. This is the candidate's declared behavior, not a new fully mode-scaled
MRT transfer scheme. Do not tune rates, the patch or gates after seeing outcomes.
Capability smoke/parity gates do not establish DFG accuracy or speedup.
## CPU and admission commands
From this checkout:
```sh
python tests/unit/test_refined_dfg.py
python tests/validation/run_refined_dfg.py --collision MRT --mode plan --output /tmp/new-mrt-dfg-plan
```
After root verifies the candidate MRT root/parity/refinement capability results and admits
an idle device, the paired pilot may use the existing bounds and external watchdog:
```sh
CUDA_VISIBLE_DEVICES=<admitted-device> timeout --signal=TERM --kill-after=30s <hard-budget>s python tests/validation/run_refined_dfg.py --collision MRT --mode pilot --gpu-gates-approved --max-wall-seconds <soft-budget> --output <new-mrt-pilot-directory>
```
The flag is caller attestation, not evidence. An unhealthy first case prevents the second.
Existing strict pilot receipt validation and calibrated wall-time controls remain; full
mode is not being admitted as part of this preparation. Root must review both healthy
pilot outcomes and separately decide any full-run admission.
+58
View File
@@ -0,0 +1,58 @@
# Refined DFG MRT timing harness (measurement only)
`tests/validation/time_refined_dfg.py` times the matched MRT refined/uniform DFG Re100 setup of
`run_refined_dfg.py` (same configuration, geometry and initial state functions). No numerical,
physics-gate or production change; no force or accuracy result is produced.
| Variant | Loop | Force reads |
|---|---|---|
| A | refined `step(1)` + `read_raw_exchange` per base step | runner-like force-read workload (values discarded) |
| B | refined `step(1)` only, no host reads (`observe_raw_exchange` stays on) | timing-only |
| C | refined single `step(N)` | timing-only; ledger keeps the final base interval only |
| E | uniform `sim.run(<=100)` + `read_force` | runner-like force-read workload (values discarded) |
| E' | uniform single `sim.run(2N)` | timing-only; at most a whole-window average, different summation order |
- No variant retains a valid force history; A/E omit the runner's interval aggregation and
validation, and no variant includes macro/probe/CSV costs. Results are not full benchmark
throughput.
- Status lines: `CONSTRUCTED` (construction/JIT complete) and `WARM_READY` (first warm-up and
health check passed) per case.
- Equal simulated duration: N refined base steps vs 2N uniform D80 steps.
- Every repeat starts from the same fresh state (refined `initialize`, uniform `snapshot/restore`)
and the same warm-up; construction/JIT, warm-up, downloads and parity checks are untimed.
- The actual stepping stream is synchronized explicitly before and after each timed loop; the
wall timer (`time.perf_counter`) is the only source. No CUDA-event span is called kernel time.
- `--max-wall-seconds` is required for GPU runs (outer timeout, checked between variants and
every 100 steps in per-step loops).
- Final populations and NaN masks must be bitwise identical to the first A repeat (A/B/C) or the
first E repeat (E/E'); refined and uniform grids are never compared. Leaf/fluid populations
must be finite. Physical health (finite leaf/fluid macros, rho in [0.5, 1.5], max Mach <= 0.2,
the existing runner limits) is checked after warm-up and after each timed window. Matching NaN
is accepted only as a storage mask; any infinity or level-count mismatch fails parity. All
parity/health checks are untimed.
- Cases run sequentially (uniform, then refined) in one process with startup serialized;
variants are interleaved within each repeat. A-B and B-C are measured comparative
differences under GPU variability, not exact causal decompositions.
Usage (root selects one verified idle GPU):
PYTHONPATH=src python -m unittest tests/unit/test_time_refined_dfg.py
python tests/validation/time_refined_dfg.py --output <new> --plan
CUDA_VISIBLE_DEVICES=<gpu> python tests/validation/time_refined_dfg.py --output <new> --max-wall-seconds <s>
Defaults: 2000 base steps, 200 warm-up base steps, 3 repeats. Profiler capture and the
`observe_raw_exchange=False` variant are deferred until these measurements exist.
## A versus observation-window ledger (`tests/validation/time_window_dfg.py`)
Measurement-only comparison on the same shifted-MRT refined setup: A (per-base `step(1)` +
`read_raw_exchange`, summed per 80-base-step interval), W (`start_exchange_window`, `step(80)`,
one window read) and W1 (window with 80 x `step(1)`, isolating the read pattern from call
batching). Same fresh state, warm-up and simulated duration; populations must be bitwise equal
to the first A repeat and per-interval total impulses within the documented engineering
tolerance, all outside timing. The candidate source is recorded (checkout revision, dirty flag,
file hashes); frozen refined-DFG manifests/results are not used or changed.
PYTHONPATH=src python -m unittest tests/unit/test_time_window_dfg.py
python tests/validation/time_window_dfg.py --output <new> --plan
CUDA_VISIBLE_DEVICES=<gpu> python tests/validation/time_window_dfg.py --output <new> --max-wall-seconds <s>
-52
View File
@@ -1,52 +0,0 @@
# First-failure uniform SRT diagnostic (prepared, not executed)
Purpose: locate the first physical failure in the unchanged uniform D80 SRT control that was healthy at executed step 160 and nonfinite at the next observation, executed step 320. The original failure's summary `steps=160` is the last accepted observation, not the last executed step. This diagnostic does not select different numerical parameters, run an AMR case or perform a new benchmark campaign.
## Exact source and configuration
The default source is the containing repository (override with `--source`); the exact pinned production/runtime source is commit `9805383f9c50d867e8555471baf5dbda8333a652`. The manifest pins production files and the helper/runner dependencies directly against the original failure's `source_before.json`. All pinned contents match. Import guards require CelerisLab and the runner from the selected pinned checkout.
The script calls the original `run_refined_dfg.config(helper,80)` factory and unchanged `Simulation(...).initialize()`. Thus it retains D80, U=.01, ν=.008, τ=.524, ω≈1.9084, shifted FP32, SRT, double buffer, parabolic local Zou–He inlet, all-nine pressure-NEQ damping .5, backflow clamp disabled, identical cylinder geometry and initialization. No clipping, equilibrium rewrite or solver patch is added.
The inlet overload in this source may differ by FP32 rounding from older d79 code even where the algebra matches; that is not changed here and is not established as the cause of failure. MRT's outlet branch also differs. Neither prior MRT success nor this diagnostic establishes an SRT/outlet/body attribution.
## Observation and stop contract
- At most 320 actual solver steps, starting from the original fresh initialization. Stop at the first physical health failure (or wall deadline).
- Read the production macroscopic path, its decoded populations, and force after every completed step. Preserve the actual executed count separately from the last observed count.
- Independently report nonfinite physical populations, nonfinite physical macros and nonfinite reaction. Apply the original density [.5,1.5] and Mach≤.2 checks to physical FLUID nodes. A new population-only check may stop earlier than the original macro-only health check; the report explicitly distinguishes it.
- Per-step `Simulation.run(1)` resets/reads the observation buffer for a one-step force window. This changes observation cadence and force accumulation windows, not configuration or fluid updates. A cumulative-force-only overflow from the original 100/60-step batching would not be reproduced identically; that limitation is explicit. Original macro warnings already show nonfinite populations/macros, so this instrument prioritizes locating the physical failure.
- Ghost/inactive/body-solid populations are reported in separate categories; their NaNs do not independently trigger physical failure. Category masks are disjoint and complete. Boundary subtypes are decoded as the nibble, not mistaken for independent bit flags.
- Physical region labels are body-near (within radius+3 cells), outlet/inlet-near (three fluid columns), wall-near (three fluid rows), and remaining bulk. These locate symptoms, not causal mechanisms.
- Initial, preceding and firstbad/final compact reports retain category counts, finite global extrema and positions, the first 16 offending nodes in row-major order, their bad q indices/all populations, and up to four 5×5 population/flag neighborhoods. “First” identifies earliest sampled step; within that step the list is row-major, not an asserted temporal order among GPU threads.
## Bounded evidence
Only the immediately preceding and firstbad/final active-buffer states are retained. `states.npz` contains their exact raw shifted FP32 values, production-decoded FP32 populations and step numbers, plus flags. This is ~81 MiB at the exact D80 shape, with a 128 MiB artifact limit enforced. There are no saved field trajectories. Initial conditions are reproducible from the source/config; only their diagnostic summary is retained.
These are diagnostic snapshots, not full restart checkpoints (spare buffers and observation/control state are not a restart bundle). `diagnostics.json` stores nonfinite numbers as explicit `NaN`, `+Inf`, `-Inf` strings and is strict finite JSON; NPZ preserves actual IEEE values. A force-only failure can have no offending fluid node. A clean cap means no sampled failure through 320, not benchmark acceptance.
## CPU validation
```sh
python tests/validation/uniform_srt_diagnostic/test_diagnostic.py
python tests/validation/uniform_srt_diagnostic/diagnose_uniform_srt.py --output /tmp/new-srt-preflight
```
Seven CPU-only tests pass: source/config, complete category partition, inactive nonfinite exclusion, independent population/macro/force reasons, health thresholds, bounded two-state artifact writing, and deadline/source guards. `py_compile` and the real-source default preflight pass. No CUDA import is required by preflight/tests and no GPU was executed here.
## Root-only admitted execution
After independent review and root GPU admission:
```sh
CUDA_VISIBLE_DEVICES=<admitted-device> timeout --signal=TERM --kill-after=30s <hard-budget>s python tests/validation/uniform_srt_diagnostic/diagnose_uniform_srt.py --source <exact-9805383-checkout> --execute --gpu-admitted --wall-seconds <soft-budget> --output <new-output-directory>
```
The external watchdog is required for a blocked CUDA call; cooperative wall checks cannot interrupt one. Budget should allow per-step downloads and ~81 MiB evidence writing; this diagnostic is not a performance measurement. The step ceiling cannot be increased by a CLI flag. `READY` is emitted after the first completed step and all observation paths. First physical failure is expected diagnostic evidence and returns exit 2; step cap returns 0. `preflight.json` records the pre-execution configuration, not a completion receipt.
Original failure files, production source, original pilot runner and gates are untouched. This test-only handoff is based on exact commit 9805383; added diagnostic files are not part of the historical failure source manifest.
## Historical reporting undercount (not changed here)
The failed pilot executed to step 320 before its second observation failed. Its summary `steps=160` reflects `begin`, which advances only after an accepted observation. This is a reporting undercount, not evidence that the second batch did not execute. The original failure package and runner/gates are preserved unchanged. This diagnostic records both `executed_steps` and `observation_step`, and labels previous-state steps explicitly. Fixing the historical runner's reporting is a separate change.
+2 -2
View File
@@ -1,4 +1,4 @@
"""Host contract for the blocked root's uniform-SRT channel boundary.
"""Host contract for the blocked root's uniform SRT/MRT channel boundary.
Boundary ghosts are evolved state, but are not physical fluid leaves. Halo
ownership remains periodic to reproduce the uniform kernel's wrapped pulls.
@@ -29,7 +29,7 @@ def validate_channel_config(cfg, blocks):
def validate_channel_transfers(pair, layout, targets):
"""Reject actual exchange/closure overlap, not a padded geometric envelope.
Explosion donors and restriction receivers must use ordinary bulk SRT
Explosion donors and restriction receivers must use ordinary bulk collision
semantics. Restriction writes receiver-local source slots; these may not
overwrite the channel's extra immutable-input reads (pressure donor and
same-node halfway-wall corrections). The slot check deliberately respects
+13 -2
View File
@@ -14,12 +14,15 @@
#include "core/obs.cuh"
#include "operators/macro.cuh"
#include "operators/collision_srt.cuh"
#if COLLISION_MODEL == 2
#include "operators/collision_mrt.cuh"
#endif
#include "streaming/pull_double_buffer.cuh"
#include "boundary/curved_boundary.cuh"
#include "boundary/planar_velocity.cuh"
#if DIM != 2 || NQ != 9 || COLLISION_MODEL != 0 || STORE_PRECISION != 0 || USE_LES || STREAMING_MODEL != 0
#error "Blocks require FP32 D2Q9 SRT double buffers without LES"
#if DIM != 2 || NQ != 9 || (COLLISION_MODEL != 0 && COLLISION_MODEL != 2) || STORE_PRECISION != 0 || USE_LES || STREAMING_MODEL != 0
#error "Blocks require FP32 D2Q9 SRT or MRT double buffers without LES"
#endif
// Fixed-patch cell kinds, matching refinement.py ACTIVE/INNER_GHOST/OUTER_GHOST.
@@ -141,6 +144,13 @@ extern "C" __global__ void BlockStep(const fpxx* in, fpxx* out, unsigned int hal
gx, d_block_wall.nx, d_block_wall.slot_width, d_block_wall.amplitude));
else if (gy == d_block_wall.ny - 2) reconstruct_top_reservoir(f, RHO);
}
#if COLLISION_MODEL == 2
// Uniform MRT sequence (collide_dispatch, zero forcing); SRT path below unchanged.
float rho, ux, uy;
compute_rho_u(f, rho, ux, uy);
collide_mrt_no_force(f, rho, ux, uy,
fminf(OMEGA_COLLISION_MAX, fmaxf(OMEGA_COLLISION_MIN, d_params.omega)));
#else
float rho, ux, uy, feq[NQ];
compute_rho_u(f, rho, ux, uy);
#if USE_DDF_SHIFTING
@@ -153,6 +163,7 @@ extern "C" __global__ void BlockStep(const fpxx* in, fpxx* out, unsigned int hal
compute_feq(rho, ux, uy, feq);
#endif
collide_srt_no_force(f, feq, d_params.omega);
#endif
}
}
stream_pull_store(k, f, out + base);
+12 -2
View File
@@ -11,6 +11,9 @@
#include "core/obs.cuh"
#include "operators/macro.cuh"
#include "operators/collision_srt.cuh"
#if COLLISION_MODEL == 2
#include "operators/collision_mrt.cuh"
#endif
#include "streaming/pull_double_buffer.cuh"
#include "boundary/planar_velocity.cuh"
#include "boundary/curved_boundary.cuh"
@@ -19,8 +22,8 @@ extern "C" {
#include "step/curved_double.cu"
}
#if DIM != 2 || NQ != 9 || COLLISION_MODEL != 0 || STORE_PRECISION != 0 || USE_DDF_SHIFTING || USE_LES || STREAMING_MODEL != 0
#error "Refinement requires unshifted FP32 D2Q9 SRT double buffers without LES"
#if DIM != 2 || NQ != 9 || (COLLISION_MODEL != 0 && COLLISION_MODEL != 2) || STORE_PRECISION != 0 || USE_DDF_SHIFTING || USE_LES || STREAMING_MODEL != 0
#error "Refinement requires unshifted FP32 D2Q9 SRT or MRT double buffers without LES"
#endif
// Enabled only in the validation build; no diagnostic arrays in normal builds.
@@ -33,10 +36,17 @@ __device__ unsigned int incoming_counts[NQ * TOTAL_CELLS];
#endif
__device__ __forceinline__ void patch_collide(float* f, unsigned long k) {
#if COLLISION_MODEL == 2
float rho, ux, uy;
compute_rho_u(f, rho, ux, uy);
collide_mrt_no_force(f, rho, ux, uy,
fminf(OMEGA_COLLISION_MAX, fmaxf(OMEGA_COLLISION_MIN, d_params.omega)));
#else
float rho, ux, uy, feq[NQ];
compute_rho_u(f, rho, ux, uy);
compute_feq(rho, ux, uy, feq);
collide_srt_no_force(f, feq, d_params.omega);
#endif
#ifdef CELERIS_REFINEMENT_AUDIT
++collision_counts[k];
#endif
@@ -54,12 +54,20 @@ extern "C" __global__ void BlockChannelStep(
f[7] = load_ddf(in + base, index_f(k, 8));
}
if (!wall && !outlet) {
#if COLLISION_MODEL == 2
// Match uniform MRT arithmetic (collide_dispatch, zero forcing).
float rho, ux, uy;
compute_rho_u(f, rho, ux, uy);
collide_mrt_no_force(f, rho, ux, uy,
fminf(OMEGA_COLLISION_MAX, fmaxf(OMEGA_COLLISION_MIN, d_params.omega)));
#else
// Match uniform SRT arithmetic, including its shifted equilibrium path.
float rho, ux, uy, feq[NQ], forcing[NQ] = {};
compute_rho_u(f, rho, ux, uy);
compute_feq(rho, ux, uy, feq);
const float omega = fminf(OMEGA_COLLISION_MAX, fmaxf(OMEGA_COLLISION_MIN, d_params.omega));
collide_srt(f, feq, forcing, omega);
#endif
}
}
stream_pull_store(k, f, out + base);
+15 -4
View File
@@ -7,16 +7,26 @@ import numpy as np
def summarize_exchange(rows, body_ids, aperture, *, body_id, level, h,
time_end, window, reference_center):
time_end, window, reference_center, duration=None):
"""Reduce FP64 interval integrals or convert FP32 last-substep raw rows.
dt_l=h_l under acoustic 2:1 refinement. Local momentum j -> base force
h*j -> impulse h*dt*j; torque adds one h; mass is h**2*dm.
window="window" reduces an FP64 observation-window ledger spanning
``duration`` (integer >= 1) base intervals; rates divide by that duration.
"""
if window not in ("last_base_step", "last_substep"):
if window not in ("last_base_step", "last_substep", "window"):
raise ValueError("unknown exchange window")
if window == "window":
if isinstance(duration, bool) or not isinstance(duration, (int, np.integer)) or duration < 1:
raise ValueError("window duration must be an integer number of base intervals >= 1")
elif duration is not None:
raise ValueError("duration applies only to window='window'")
values = np.array(rows, dtype=np.float64, copy=True)
duration = 1.0 if window == "last_base_step" else h
if window == "window":
duration = float(duration)
else:
duration = 1.0 if window == "last_base_step" else h
if window == "last_substep":
values *= np.array([h*h, h*h, h*h*h, h*h])
selected = np.asarray(body_ids) == body_id
@@ -31,6 +41,7 @@ def summarize_exchange(rows, body_ids, aperture, *, body_id, level, h,
return dict(wall=reduce(selected & ~aperture), aperture=reduce(selected & aperture),
total=reduce(selected), body_id=int(body_id), level=int(level),
time_start=time_end-duration, time_end=time_end, dt=h,
sample_count=round(1/h) if window == "last_base_step" else 1,
sample_count=(round(duration/h) if window == "window"
else round(1/h) if window == "last_base_step" else 1),
window=window, units="base_lattice_per_unit_depth",
definition="raw_boundary_exchange", reference_center=tuple(reference_center), valid=True)
+4 -4
View File
@@ -52,17 +52,17 @@ class FixedPatch2D:
def from_config(cls, cfg: LBMConfig, bounds) -> "FixedPatch2D":
"""Prepare maps without changing cfg or allocating coarse-sized tables.
The initial backend contract is D2Q9/SRT/FP32/double_buffer,
The backend contract is D2Q9/SRT or MRT/FP32/double_buffer,
without LES. Two coarse cells of margin keep all halo donors in bounds;
this does NOT certify that those donors are fluid or periodic.
"""
checked = replace(cfg)
checked.validate()
if (not checked.is_d2q9 or checked.collision != "SRT"
if (not checked.is_d2q9 or checked.collision not in ("SRT", "MRT")
or checked.streaming != "double_buffer"
or checked.store_precision != "FP32"
or checked.les_enabled):
raise ValueError("FixedPatch2D requires D2Q9/SRT/FP32/double_buffer without LES")
raise ValueError("FixedPatch2D requires D2Q9/SRT or MRT/FP32/double_buffer without LES")
bounds = tuple(bounds)
if len(bounds) != 4 or any(isinstance(v, (bool, np.bool_))
or not isinstance(v, Integral) for v in bounds):
@@ -451,7 +451,7 @@ def prepare_fine_boundary(cfg, patch, objects, *, wall_aware=False, jets=(),
checked = replace(cfg)
checked.validate()
if (patch.coarse_shape != (cfg.ny, cfg.nx) or not checked.is_d2q9
or checked.collision != "SRT" or checked.streaming != "double_buffer"
or checked.collision not in ("SRT", "MRT") or checked.streaming != "double_buffer"
or checked.store_precision != "FP32" or checked.les_enabled
or patch.tau_coarse != 3*checked.viscosity+.5):
raise ValueError("Fine boundary requires the matching fixed-patch configuration")
+69 -2
View File
@@ -172,6 +172,9 @@ class FixedPatchStepper:
base interval or last substep in base-lattice units per unit depth. This
is boundary momentum reaction, not a validated nozzle/stress load. Dense
body layouts are not supported by this new diagnostic in this candidate.
``observe_window_exchange=True`` (requires observe_raw_exchange) adds a second
per-link FP64 ledger accumulated by the same kernel between
start_exchange_window() and read_exchange_window(); disabled by default.
``jets`` (body.jets.Jet) use the same edge frame as ``fine_objects`` and
drive fine cut links selected at their true hits; ``set_jet_amplitude``
re-uploads the per-link velocity column only.
@@ -216,7 +219,7 @@ class FixedPatchStepper:
fine_block=None, base_block=None, jets=(), child=None, child_block=None,
child_objects=(), child_jets=(), child_rectangles_in_parent=None,
refinements=None, level_blocks=None, level_objects=None, level_jets=None,
observe_raw_exchange=False):
observe_raw_exchange=False, observe_window_exchange=False):
if HALO != 4:
raise RuntimeError("refinement.cu requires a four-cell fine halo")
if coarse_boundary not in ("periodic", "slot_reservoir", "channel"):
@@ -315,6 +318,13 @@ class FixedPatchStepper:
for b, layout in zip(self._boundary_hosts, self._layouts)):
raise ValueError("raw exchange currently requires blocked body levels")
self._observe_raw_exchange = observe_raw_exchange
if not isinstance(observe_window_exchange, bool):
raise ValueError("observe_window_exchange must be bool")
if observe_window_exchange and not observe_raw_exchange:
raise ValueError("observe_window_exchange requires observe_raw_exchange")
self._observe_window = observe_window_exchange
self._window_valid = False
self._window_start = None
self._exchange_valid = False
self._exchange_spacing = tuple(spacings)
self._exchange_centers = tuple(tuple(tuple(o.geometry.center) for o in objects)
@@ -365,6 +375,8 @@ class FixedPatchStepper:
count = len(b.tables["cell"])
b.last_raw = self._allocate(count * 4 * 4)
b.interval_integral = self._allocate(count * 4 * 8)
if self._observe_window:
b.window_integral = self._allocate(count * 4 * 8)
b.accumulate = level.module.get_function("BlockAccumulateExchange")
b.kernel = level.module.get_function("BlockCurvedBoundary")
if self._level_boundaries[1] is not None:
@@ -559,6 +571,7 @@ class FixedPatchStepper:
cuda.memset_d8(self._fine_curved.link_exchange_gpu, 0, self._fine_curved.count * 12)
self._step_count = 0
self._exchange_valid = False
self._window_valid = False
self._status = "ready"
except BaseException:
self._status = "failed"
@@ -639,7 +652,8 @@ class FixedPatchStepper:
fine_block=fine_block, child_block=child_block,
child_rectangles_in_parent=new.child.bounds,
child_objects=child_objects, child_jets=jets,
observe_raw_exchange=self._observe_raw_exchange)
observe_raw_exchange=self._observe_raw_exchange,
observe_window_exchange=self._observe_window)
try:
if self._ddf_shifting:
candidate._initialize_raw(_StoredPopulations(transferred.g, transferred.shifted))
@@ -771,6 +785,10 @@ class FixedPatchStepper:
b.accumulate(b.last_raw, b.interval_integral, np.uint32(count),
np.float64(h), np.float64(h),
grid=((count + self._block[0] - 1) // self._block[0], 1), **kw)
if self._window_valid and b.window_integral is not None:
b.accumulate(b.last_raw, b.window_integral, np.uint32(count),
np.float64(h), np.float64(h),
grid=((count + self._block[0] - 1) // self._block[0], 1), **kw)
flags = np.uintp(0) if level.boundary is None else level.boundary.flags
level.kernel(src, dst, np.uint32(level.layout.halo), flags, level.kind, grid=level.grid, **kw)
@@ -804,9 +822,57 @@ class FixedPatchStepper:
self._exchange_valid = self._observe_raw_exchange
self._status = "ready"
except BaseException:
self._window_valid = False
self._status = "failed"
raise
def start_exchange_window(self):
"""Zero the window ledgers and open a window at the current completed step count."""
with self._lock, self.ctx.activate():
self._require("ready")
if not self._observe_window:
raise RuntimeError("window exchange observation is disabled")
self._window_valid = False
try:
for b in self._level_boundaries:
if b is not None and b.window_integral is not None:
cuda.memset_d8(b.window_integral, 0, len(b.tables["cell"]) * 32)
except BaseException:
self._status = "failed"
raise
self._window_start = self._step_count
self._window_valid = True
def read_exchange_window(self, body_id, *, level=1):
"""Non-destructive read of [window start, current step count] in base-lattice units."""
with self._lock, self.ctx.activate():
self._require("ready")
if not self._observe_window:
raise RuntimeError("window exchange observation is disabled")
if not self._window_valid:
raise RuntimeError("no valid exchange window; call start_exchange_window()")
duration = self._step_count - self._window_start
if duration < 1:
raise RuntimeError("exchange window requires at least one completed base interval")
if (isinstance(level, bool) or not isinstance(level, Integral)
or not 0 <= level < len(self._levels)):
raise ValueError("level must name an existing level")
b = self._level_boundaries[level]
if (b is None or isinstance(body_id, bool) or not isinstance(body_id, Integral)
or not 0 <= body_id < len(b.host.objects)):
raise ValueError("body_id must name a body on this level")
rows = np.empty((len(b.tables["cell"]), 4), np.float64)
try:
cuda.memcpy_dtoh(rows, b.window_integral)
except BaseException:
self._status = "failed"
raise
return summarize_exchange(rows, b.tables["body_id"], b.tables["aperture"],
body_id=body_id, level=level, h=self._exchange_spacing[level],
time_end=self._step_count, window="window",
reference_center=self._exchange_centers[level][body_id],
duration=duration)
def read_raw_exchange(self, body_id, *, level=1, window="last_base_step"):
"""Read raw boundary reaction about its geometric center in the root edge frame.
@@ -885,6 +951,7 @@ class FixedPatchStepper:
if b is not None:
b.flags = b.device = b.kernel = None
b.last_raw = b.interval_integral = b.accumulate = None
b.window_integral = None
self._levels.clear()
self._pairs = []
if getattr(self, "_fine_curved", None) is not None:
+1
View File
@@ -85,6 +85,7 @@ class _BlockedBoundary:
last_raw: object = None
interval_integral: object = None
accumulate: object = None
window_integral: object = None # optional observation-window FP64 ledger
def _prepare_blocked_boundary(boundary, layout, cfg, jets, *, _shifted_blocked=False):
+45
View File
@@ -0,0 +1,45 @@
"""Host reduction contract for the optional observation-window exchange ledger."""
import unittest
import numpy as np
from CelerisLab.lbm.raw_exchange import summarize_exchange
def reduce(rows, window, duration=None, h=.5, time_end=10):
return summarize_exchange(rows, np.array([0, 0, 1]), np.array([False, True, False]),
body_id=0, level=1, h=h, time_end=time_end, window=window,
reference_center=(0., 0.), duration=duration)
class ExchangeWindowReduction(unittest.TestCase):
def test_window_duration_scaling(self):
rows = np.array([[1., 2., 3., 4.], [.5, -1., 0., 1.], [9., 9., 9., 9.]])
out = reduce(rows, "window", duration=4)
np.testing.assert_array_equal(out["total"]["impulse"], [1.5, 1.])
np.testing.assert_array_equal(out["total"]["force"], [1.5 / 4, 1. / 4])
self.assertEqual(out["total"]["torque"], 3. / 4)
self.assertEqual(out["total"]["mass_rate"], 5. / 4)
np.testing.assert_array_equal(out["aperture"]["impulse"], [.5, -1.])
self.assertEqual((out["time_start"], out["time_end"]), (6., 10))
self.assertEqual(out["sample_count"], 8) # duration / h fine substeps
self.assertEqual(out["window"], "window")
def test_existing_windows_unchanged(self):
rows = np.array([[1., 2., 3., 4.], [0., 0., 0., 0.], [0., 0., 0., 0.]])
base = reduce(rows, "last_base_step")
self.assertEqual((base["time_start"], base["sample_count"]), (9., 2))
np.testing.assert_array_equal(base["total"]["force"], [1., 2.])
sub = reduce(rows, "last_substep")
self.assertEqual(sub["sample_count"], 1)
def test_duration_validation(self):
rows = np.zeros((3, 4))
for bad in (None, 0, -1, 1.5, True):
with self.subTest(duration=bad), self.assertRaises(ValueError):
reduce(rows, "window", duration=bad)
with self.assertRaises(ValueError):
reduce(rows, "last_base_step", duration=2)
if __name__ == "__main__": unittest.main()
+59 -7
View File
@@ -13,7 +13,11 @@ h, periodic = r.helpers(r.DEFAULT_SOURCE)
def test_source_pin():
assert r.verify_source(r.DEFAULT_SOURCE)["commit"].startswith("cd3a657")
historical = json.loads((r.HERE / "data/refined_dfg/source_manifest.json").read_text())
assert historical["commit"].startswith("cd3a657")
assert r.verify_source(r.DEFAULT_SOURCE, "MRT")["commit"].startswith("3ea131e")
with unittest.TestCase().assertRaisesRegex(RuntimeError, "Source mismatch"):
r.verify_source(r.DEFAULT_SOURCE, "SRT")
def test_matched_units_and_planes():
@@ -135,16 +139,17 @@ def test_axis_specific_sampling_phase():
def test_full_requires_completed_pilot():
with unittest.TestCase().assertRaisesRegex(ValueError, "pilot-results"):
r.verify_pilot(None, r.verify_source(r.DEFAULT_SOURCE))
r.verify_pilot(None, r.verify_source(r.DEFAULT_SOURCE, "MRT"))
def pilot_fixture(path):
"""Synthetic contract fixture only; never a physical result or run receipt."""
manifest = r.verify_source(r.DEFAULT_SOURCE)
manifest = r.verify_source(r.DEFAULT_SOURCE, "MRT")
(path / "plan.json").write_text(
json.dumps(
dict(
source_manifest=manifest,
collision="MRT",
bounds_root_edge=list(r.BOUNDS),
runner_sha256=r.runner_hash(),
)
@@ -177,6 +182,7 @@ def pilot_fixture(path):
json.dumps(
dict(
case=case,
collision="MRT",
mode="pilot",
status="pilot_complete",
healthy=True,
@@ -192,6 +198,7 @@ def pilot_fixture(path):
json.dumps(
dict(
case=case,
collision="MRT",
mode="pilot",
step=interval,
runner_sha256=r.runner_hash(),
@@ -208,7 +215,7 @@ def test_pilot_validation_and_calibration():
with TemporaryDirectory() as tmp:
path = Path(tmp)
manifest = pilot_fixture(path)
assert r.verify_pilot(path, manifest) == 3606.0
assert r.verify_pilot(path, manifest, "MRT") == 3606.0
def test_reject_malformed_pilot_receipts():
@@ -238,7 +245,7 @@ def test_reject_malformed_pilot_receipts():
mutate(bad)
receipt.write_text(json.dumps(bad))
with unittest.TestCase().assertRaises(ValueError):
r.verify_pilot(path, manifest)
r.verify_pilot(path, manifest, "MRT")
# Exact reviewer regression: previously accepted NaN endpoint.
receipt.write_text(
json.dumps(
@@ -250,11 +257,11 @@ def test_reject_malformed_pilot_receipts():
)
)
with unittest.TestCase().assertRaises(ValueError):
r.verify_pilot(path, manifest)
r.verify_pilot(path, manifest, "MRT")
receipt.write_text(json.dumps(valid))
(path / "uniform/ready.json").write_text("{}")
with unittest.TestCase().assertRaises(ValueError):
r.verify_pilot(path, manifest)
r.verify_pilot(path, manifest, "MRT")
def test_strict_finite_json_and_deadline():
@@ -283,6 +290,51 @@ def test_pressure_probes_actual_body_mask():
assert h.pressure_probes(np.ones(pair.fine_shape), fluid, p)["dp"] == 0.0
def test_matched_mrt_selection():
for diameter in (40, 80):
srt, sbody, sp = r.config(h, diameter)
mrt, mbody, mp = r.config(h, diameter, "MRT")
assert mrt["method"]["collision"] == "MRT"
mrt["method"]["collision"] = "SRT"
assert mrt == srt and mbody == sbody and mp == sp
srt_plan, mrt_plan = r.plan(h), r.plan(h, "MRT")
for key in ("root", "uniform", "bounds_root_edge", "finest_dx_m", "finest_dt_s"):
assert srt_plan[key] == mrt_plan[key]
assert "q2/6/8" in mrt_plan["outlet"] and "all nine" in srt_plan["outlet"]
cfg, pair, _, host = r.host_geometry(r.DEFAULT_SOURCE, h, "MRT")
assert cfg.collision == "MRT" and pair.fine_shape == (240, 568)
assert len(host.boundary_cells) > 0
def test_reject_collision_receipts():
from tempfile import TemporaryDirectory
for rel in ("plan.json", "uniform/summary.json", "refined/summary.json",
"uniform/ready.json", "refined/ready.json"):
for invalid in ("SRT", None):
with TemporaryDirectory() as tmp:
path = Path(tmp)
manifest = pilot_fixture(path)
receipt = path / rel
record = json.loads(receipt.read_text())
if invalid is None:
record.pop("collision")
else:
record["collision"] = invalid
receipt.write_text(json.dumps(record))
with unittest.TestCase().assertRaises(ValueError):
r.verify_pilot(path, manifest, "MRT")
def test_record_actual_checkout_separately():
from source_provenance import checkout_provenance
actual = checkout_provenance(r.DEFAULT_SOURCE)
assert len(actual["checkout_revision"]) == 40
assert isinstance(actual["checkout_dirty"], bool)
assert r.verify_source(r.DEFAULT_SOURCE, "MRT")["production_origin_commit"].startswith("3ea131e")
if __name__ == "__main__":
suite = unittest.TestSuite(
unittest.FunctionTestCase(fn)
+1 -1
View File
@@ -142,7 +142,7 @@ class FixedPatchTests(unittest.TestCase):
FixedPatch2D.from_config(LBMConfig(nx=nx, ny=ny, viscosity=.1), bounds)
def test_unsupported_backend_and_fine_relaxation_rejected(self):
for kwargs in ({"collision": "TRT"}, {"collision": "MRT"}, {"streaming": "esopull"},
for kwargs in ({"collision": "TRT"}, {"streaming": "esopull"},
{"les_enabled": True},
{"store_precision": "FP16S"}, {"lattice_model": "D3Q19"},
{"data_type": "FP64"}, {"omega_min": 1.0}):
+44
View File
@@ -0,0 +1,44 @@
"""Host guards and source contract for MRT reuse in refined/blocked stepping (no CUDA)."""
from pathlib import Path
import unittest
from CelerisLab.config import LBMConfig
from CelerisLab.lbm.refinement import FixedPatch2D
KERNELS = Path(__file__).resolve().parents[2] / "src/CelerisLab/lbm/kernels"
BOUNDS = (8, 6, 16, 14)
class RefinementMRTHost(unittest.TestCase):
def test_patch_accepts_implemented_models(self):
for collision in ("SRT", "MRT"):
with self.subTest(collision=collision):
FixedPatch2D.from_config(LBMConfig(nx=24, ny=20, viscosity=.1, collision=collision), BOUNDS)
def test_patch_rejects_unimplemented(self):
for options in (dict(collision="TRT"), dict(collision="MRT", les_enabled=True)):
with self.subTest(options=options), self.assertRaises(ValueError):
FixedPatch2D.from_config(LBMConfig(nx=24, ny=20, viscosity=.1, **options), BOUNDS)
def test_srt_statements_and_guards_preserved(self):
"""MRT is an additive compile-time branch; SRT statements and other guards remain."""
blocks = (KERNELS / "blocks.cu").read_text()
channel = (KERNELS / "step/block_channel.cu").read_text()
refinement = (KERNELS / "refinement.cu").read_text()
for text in ("compute_feq_from_momentum(drho, jx, jy, ux, uy, feq);",
"compute_feq(rho, ux, uy, feq);",
"collide_srt_no_force(f, feq, d_params.omega);"):
self.assertIn(text, blocks)
self.assertIn("collide_srt(f, feq, forcing, omega);", channel)
self.assertIn("collide_srt_no_force(f, feq, d_params.omega);", refinement)
for source in (blocks, refinement):
self.assertIn("(COLLISION_MODEL != 0 && COLLISION_MODEL != 2)", source)
self.assertIn("USE_LES", source)
self.assertIn("STORE_PRECISION != 0", source)
self.assertIn('#if COLLISION_MODEL == 2\n#include "operators/collision_mrt.cuh"\n#endif', source)
self.assertIn("USE_DDF_SHIFTING ||", refinement) # dense/mixed shifted stays rejected
for source in (blocks, channel, refinement):
self.assertEqual(source.count("collide_mrt_no_force("), 1)
if __name__ == "__main__": unittest.main()
+86
View File
@@ -0,0 +1,86 @@
"""CPU contract of the measurement-only refined DFG timing harness (no CUDA)."""
from pathlib import Path
import sys
import unittest
import numpy as np
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "validation"))
import time_refined_dfg as t # noqa: E402
class TimingHarnessContract(unittest.TestCase):
def test_equal_simulated_duration(self):
s = t.schedule(2000, 200)
self.assertEqual(s["refined"], (200, 2000))
self.assertEqual(s["uniform"], (400, 4000)) # one refined base step = two D80 steps
self.assertAlmostEqual(s["tstar_window"], 2000 * .01 / 40)
for bad in ((0, 1), (1, -1)):
with self.assertRaises(ValueError):
t.schedule(*bad)
def test_timing_only_labels(self):
for name in ("B", "C", "E'"):
self.assertFalse(t.VARIANTS[name]["force_history_valid"])
self.assertTrue(t.VARIANTS[name]["timing_only"])
for name in ("A", "E"):
self.assertFalse(t.VARIANTS[name]["force_history_valid"]) # reads discarded
self.assertTrue(t.VARIANTS[name]["force_reads"])
self.assertIn("runner-like", t.VARIANTS[name]["force_note"])
self.assertEqual({v["case"] for v in t.VARIANTS.values()}, {"refined", "uniform"})
self.assertIn("final base interval", t.VARIANTS["C"]["force_note"])
self.assertIn("whole-window", t.VARIANTS["E'"]["force_note"])
def test_deadline(self):
import time
with self.assertRaises(TimeoutError):
t.check_deadline(time.monotonic() - 1)
t.check_deadline(time.monotonic() + 60)
def test_parity_detects_bits_and_nan_masks(self):
a = np.array([[1., np.nan], [2., 3.]], np.float32)
self.assertIsNone(t.same_state([a], [a.copy()]))
b = a.copy(); b[1, 1] = np.nextafter(np.float32(3), np.float32(4))
self.assertIn("bits", t.same_state([a], [b]))
c = a.copy(); c[0, 0] = np.nan
self.assertIn("NaN", t.same_state([a], [c]))
self.assertIn("level count", t.same_state([a], [a, a]))
inf = a.copy(); inf[1, 0] = np.inf
self.assertIn("infinite", t.same_state([inf], [inf.copy()])) # matching inf still fails
self.assertIn("infinite", t.same_state([a], [inf]))
def test_flat_uniform_ddf(self):
fluid = np.array([[True, False, True], [True, True, False]])
flat = np.ones(9 * fluid.size, np.float32) # Simulation.get_ddf() layout
self.assertTrue(t.uniform_populations_finite(flat, fluid))
flat[1 * fluid.size + 1] = np.nan # q=1, solid cell 1: ignored
self.assertTrue(t.uniform_populations_finite(flat, fluid))
flat[4 * fluid.size + 0] = np.nan # q=4, fluid cell 0: detected
self.assertFalse(t.uniform_populations_finite(flat, fluid))
self.assertTrue(t.uniform_populations_finite(np.ones((9,) + fluid.shape), fluid))
with self.assertRaises(RuntimeError):
t.uniform_populations_finite(np.ones(9 * fluid.size + 1), fluid)
def test_physical_health_limits(self):
ok = (np.array([1., 1.01]), np.array([.01, .02]), np.array([0., .01]))
health = t.physical_health([ok])
self.assertAlmostEqual(health["rho_max"], 1.01)
for bad in ((np.array([1., np.nan]),) + ok[1:],
(np.array([.4, 1.]),) + ok[1:],
(ok[0], np.array([.2, 0.]), ok[2]),
(np.array([]), np.array([]), np.array([]))):
with self.assertRaises(RuntimeError):
t.physical_health([bad])
def test_summary_reports_differences_without_claims(self):
rows = [dict(variant=v, seconds=s) for v, s in
(("A", 3.), ("A", 5.), ("B", 2.), ("C", 1.), ("E", 2.), ("E'", 1.5))]
s = t.summarize(rows, .5)
self.assertEqual(s["A"]["median_seconds"], 4.)
self.assertEqual(s["A_minus_B_seconds"], 2.)
self.assertEqual(s["B_minus_C_seconds"], 1.)
self.assertEqual(s["A_over_E"], 2.)
self.assertIn("not exact causal", s["interpretation"])
if __name__ == "__main__": unittest.main()
+38
View File
@@ -0,0 +1,38 @@
"""CPU contract of the A-versus-window timing harness (no CUDA)."""
from pathlib import Path
import sys
import unittest
import numpy as np
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "validation"))
import time_window_dfg as w # noqa: E402
class WindowTimingContract(unittest.TestCase):
def test_interval_and_variants(self):
self.assertEqual(w.INTERVAL, 80)
self.assertEqual(w.VARIANTS, ("A", "W", "W1"))
def test_components(self):
obs = dict(total=dict(impulse=np.array([1., 2.]), angular_impulse=3., mass_into_fluid=4.))
np.testing.assert_array_equal(w.components(obs), [1., 2., 3., 4.])
def test_interval_comparison(self):
ref = np.array([[1., -1., 0., 0.]])
scale = np.array([[10., 10., 1., 1.]])
self.assertEqual(w.compare_intervals(ref, scale, ref.copy()), 0.)
near = ref + np.array([[5e-9, 0., 0., 0.]])
self.assertLessEqual(w.compare_intervals(ref, scale, near), 1.)
far = ref + np.array([[1e-7, 0., 0., 0.]])
self.assertGreater(w.compare_intervals(ref, scale, far), 1.)
zero = np.zeros((1, 4))
self.assertGreater(w.compare_intervals(zero, zero, zero + 1e-12), 1.) # floor, no div-by-0
def test_candidate_identity_records_files(self):
identity = w.candidate_identity(Path(__file__).resolve().parents[2])
self.assertIn("checkout_revision", identity)
self.assertEqual(set(identity["sha256"]), set(w.CANDIDATE_FILES))
if __name__ == "__main__": unittest.main()
@@ -1,6 +1,7 @@
{
"commit": "9805383f9c50d867e8555471baf5dbda8333a652",
"failure_source_receipt_sha256": "a77f71550c52d4b8b6e946a3cb98fc5de5db3da1bcbbb3457c6d60167677ce4e",
"commit": "3ea131e92c057843034f11a1c574301a2430dfce",
"production_origin_commit": "3ea131e92c057843034f11a1c574301a2430dfce",
"collision": "MRT",
"sha256": {
"src/CelerisLab/__init__.py": "21cc469bd6e970a1f9ff5970c8eea4602065e41fc881854759ee565ee55c10c6",
"src/CelerisLab/body/__init__.py": "e4e0e8f0769a94428d5b02fac790443997556cfc5515a5f1ed1595d2c694d69d",
@@ -43,14 +44,14 @@
"src/CelerisLab/lbm/__init__.py": "7f60fb3aaae81501b510d08c2fedff44fcb05657260eb10b6f5cc91e7204306b",
"src/CelerisLab/lbm/block_stepper.py": "00b313daddc6e63d8ab8423c9190ca7e92ad291de20a2f6b80eb53e3f2d85ec7",
"src/CelerisLab/lbm/blocks.py": "1e644c5719993f418185ad4a10b6950a30636fc912befd9eab41ff48b4cf85cd",
"src/CelerisLab/lbm/channel.py": "2d5b5ff43414cb35633ac4ce90ce2c3a3353950b25c168e1c2ab58d498dd8b0f",
"src/CelerisLab/lbm/channel.py": "40d0354e5dc97bcdb7e7b5c1e7f9303a109b7134d8a3af88b8ff4cd75ab5a095",
"src/CelerisLab/lbm/curved_links.py": "b6957fa13d13f864dba4f7364e93a39905d062dbb3ee9b3f5191add81fff0732",
"src/CelerisLab/lbm/descriptors.py": "c9f025dfc14da43b989047b84cc22bd05d5cc92c9ec695c1da68fdfb788e3f2b",
"src/CelerisLab/lbm/equilibrium.py": "2fb2f2bb7ff326d23abce80fc2a4c0907b17740ea3e29fe6ae079c5044783826",
"src/CelerisLab/lbm/field.py": "0e727eacc3706add4d8d15c418e9b631050871f831698d3ac689dd5f2c701b9b",
"src/CelerisLab/lbm/hierarchy.py": "f234975074f6b6d289d573ff6ea6832feae0e27cb04f80b37fe81792b13a12e7",
"src/CelerisLab/lbm/initializers.py": "dacf9586963e862d6d0a98ef1a066036be6f91e9d423720661d8ef2c1fb2df6a",
"src/CelerisLab/lbm/kernels/blocks.cu": "e3b9606f861bfea8c4b0f34e8356bb230081f899c584f67be89178d889099b17",
"src/CelerisLab/lbm/kernels/blocks.cu": "2fa894b20a29f006911ac3e3aad0793cc4aaf9ccd7a67d01c6320a0836b1d8ef",
"src/CelerisLab/lbm/kernels/boundary/bounce_back.cuh": "aba3748c564ed91b161d268ef8b737b7c7be96a823063d201f3da684dd845233",
"src/CelerisLab/lbm/kernels/boundary/curved_boundary.cuh": "aeb16bfd483514fb03e15a2fed437d673c3b8b2fe68ab83edf4244ef593878ea",
"src/CelerisLab/lbm/kernels/boundary/esopull_curved_helpers.cuh": "b9b474bc4edaff05681c5443235472d04072d0d775fc0eb9c5967faef52b0258",
@@ -63,12 +64,12 @@
"src/CelerisLab/lbm/kernels/boundary/inlet_outlet.cuh": "de8b213a6da42c2e5e9f8966199fc66ea4541b85144a90f3f5dbad3c6ab63b97",
"src/CelerisLab/lbm/kernels/boundary/outlet/pressure_neq.cuh": "c8b2adc66d12fe602076ddc9693c5c208711fcaddb58aa9a31401a269f51c4c4",
"src/CelerisLab/lbm/kernels/boundary/planar_velocity.cuh": "501b2759d0e2e4280cb6fdd127d66a50fa89f6de48fc2cae9a7eafb11ae90bed",
"src/CelerisLab/lbm/kernels/config.h": "7d1124125e0b354558297934460e64c760fb68cdd7bf6d01a1238bb2eaab8c37",
"src/CelerisLab/lbm/kernels/config/config_grid.h": "1db3e030ebdc116cd7f02362d1fd077daac55e8f0b4329f6285948c224d3ca5d",
"src/CelerisLab/lbm/kernels/config/config_method.h": "4374e04a130f90f97d17cc20c40d2f9ea0ed0dd8603817d07f215d02266e247c",
"src/CelerisLab/lbm/kernels/config/config_objects.h": "db793af052c756561a190a3ff2cb93ee5fe28462ee4f97c6af80882b4dc8b072",
"src/CelerisLab/lbm/kernels/config/config_obs.h": "c11e2249359145b5c4cbaaf0487506fa77c1f4b82c7c169ddc574aa0babcd727",
"src/CelerisLab/lbm/kernels/config/config_physics.h": "8ac0990b168e1058588676cc05c80df8634cfd671dbc92a89246c3c372d83a4e",
"src/CelerisLab/lbm/kernels/config.h": "7d1124125e0b354558297934460e64c760fb68cdd7bf6d01a1238bb2eaab8c37",
"src/CelerisLab/lbm/kernels/core/descriptors.cuh": "8440bc14857da9007982650f828a23608eec9f7cc4bf772e8c8dc1239cb45356",
"src/CelerisLab/lbm/kernels/core/flags.cuh": "0025705f24710330d9d9195f713879bfb650a85a3449baef0e196b831af104ab",
"src/CelerisLab/lbm/kernels/core/layout.cuh": "1fbd820021c89ac3efcde24145996cb0147769e607e498e61f308ed3e0b13706",
@@ -83,9 +84,9 @@
"src/CelerisLab/lbm/kernels/operators/helpers.cuh": "0b3a4d95d7d19f5fec09e5423b8f4cc99f8a226b541967425967330da5a051ec",
"src/CelerisLab/lbm/kernels/operators/macro.cuh": "2be20eb2b7d7f5522daaad7f4b57b1ff8cdf883efe4a67846a96783b2fe846a3",
"src/CelerisLab/lbm/kernels/operators/turbulence_smag.cuh": "ff7f000297ee0817e255ad9fcb6a13b647e3ddd5b206518d35f38d2895a9f501",
"src/CelerisLab/lbm/kernels/refinement.cu": "129f3d91da93b4324f88a0da73a4da1e5390f72c14cce574ee63306712da9895",
"src/CelerisLab/lbm/kernels/refinement.cu": "b45aad9c022cecb64f7e968ec3cae2d8385a3cc430ee409700c404a3f4dd8cf8",
"src/CelerisLab/lbm/kernels/step/aux_kernels.cu": "578a5b20a157241ee678547059abb1372dd5a589ad06bb2c15b987eb01ca1013",
"src/CelerisLab/lbm/kernels/step/block_channel.cu": "befbf6d757e532a59c166d41f920d16d71557cd3a574478e7aa83da737c48cbd",
"src/CelerisLab/lbm/kernels/step/block_channel.cu": "ee8a31398b8e5233d977c816e6b8e060c1eb2ec71320e594226dbca55593c0d0",
"src/CelerisLab/lbm/kernels/step/curved_double.cu": "bfa7a1df1e939020314d49755045f7a85fe4a19cc1c68dbe62653c66c5e7c2b3",
"src/CelerisLab/lbm/kernels/step/esopull_macro.cu": "c73116020ca217ede1e4de27c8269c31f9d91e33433ac8252a21e9b14187c50f",
"src/CelerisLab/lbm/kernels/step/esopull_sync.cu": "c0ff3e72900c3ab89a05dd03684e96d3b740cf1672d565727fc2af165933d087",
@@ -97,16 +98,15 @@
"src/CelerisLab/lbm/kernels/streaming/pull_double_buffer.cuh": "b65d741ed78b7b62f99531ba0c0ce1936663d8dc9640e7d7d16c707f1baf6549",
"src/CelerisLab/lbm/population_storage.py": "a6a86c29c52c892edfe4802fb773c387212e3f4cc86708d80e154986ddf88044",
"src/CelerisLab/lbm/raw_exchange.py": "8694202466eba848563e298656353b0f5db94e21a01fa05f51aad6dc2b9fd311",
"src/CelerisLab/lbm/refinement.py": "08c2a0557276a98cbcaa459d9bb7a9735d8bbbf64a6114c57af2fda61481a687",
"src/CelerisLab/lbm/refinement.py": "100d5e46ac894f6008b61364cdad5d37c2ca7ed949d8d71405572d6366526417",
"src/CelerisLab/lbm/refinement_stepper.py": "f2bb34fa90805ad21c3e7cf9f9a67d88d3ae3e249b4517d3898567b4bf9e364d",
"src/CelerisLab/lbm/refinement_tables.py": "fdd344024b89df3a83174dc810ca5e32db5e19eb8b1609f8f73b0821f56546b6",
"src/CelerisLab/lbm/stepper.py": "0dcb7cd7ae87e33e3dc67a38b6aa43042fbe673e37d9ad165342ee1d695933ce",
"src/CelerisLab/lbm/synchronized_remap.py": "7400fc4beaffd4649d6a9c524d38ce5fd6fa7eeb32eb5332e4030a4b6648f197",
"src/CelerisLab/simulation.py": "0a03904dc6de88667d7af699005a289adf8b09f0976cb0d099b041f4830a8f4c",
"tests/validation/data/refined_dfg/source_manifest.json": "e495948b10f8112c77ca67255122b5e8bc9e32570e8c899802afcb85e608fef4",
"tests/validation/periodic.py": "a2212c0e2705126327a5019e9cafe64eeca398da1b75061ff23630c9843697a6",
"tests/validation/re100_helpers.py": "289c6e01075ff361573f862b90cfd61e5980c9a8efcbc78aef69979b4004fd60",
"tests/validation/run_refined_dfg.py": "256aacd84b3f8412a31ffaba9c4b5635db895c3177686dd34ef8e31f08119414",
"tests/validation/periodic.py": "a2212c0e2705126327a5019e9cafe64eeca398da1b75061ff23630c9843697a6",
"tests/validation/data/dfg_re100/reference_cycle.json": "073d1bda1629697efebad95667bfe80598e217d708dbffd7d5f6c6999379c55f",
"tests/validation/source_provenance.py": "6dfe8f2d819dba0e240ba761d31162a5033685d492d09db75eb2b8aaab3a5a4c"
}
}
}
@@ -0,0 +1,260 @@
"""Optional observation-window exchange ledger: host contract (mocked driver) and GPU gate.
Run CPU and GPU classes in separate processes; GPU callers select the device.
ExchangeWindowGPU uses the SRT/unshifted Jet fixture; ExchangeWindowShiftedMRTGPU covers a
shifted MRT, all-blocked, stationary-body case without Jets (no shifted-MRT Jet claim).
GPU tolerance (conservative engineering tolerance, not a universal proof): the window ledger
sums h*dt*raw per link over fine substeps, while the reference sums per-base interval ledgers
over links and then over base steps. Both are FP64 reorderings of the same FP32-exact substep
contributions, so the scale is the sum of the ACTUAL absolute substep contributions (read from
last_raw after every fine hop), not of per-base totals that could hide substep cancellation:
|window - reference| <= 4 * m * eps * sum|substep terms| + 1e-300, m = links * substeps.
"""
from contextlib import ExitStack
import unittest
from unittest.mock import patch
import numpy as np
import pycuda.driver as cuda
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
from test_refinement_blocked_base import mocked_backend
from test_refinement_blocked_fine import BOUNDS, circle, config
EPS = np.finfo(np.float64).eps
def build(m, window=True, raw=True):
return FixedPatchStepper(config("periodic"), BOUNDS, context=m["context"], base_block=(3, 4),
fine_block=(16, 20), fine_objects=[circle()],
observe_raw_exchange=raw, observe_window_exchange=window)
def same_bits(test, a, b):
"""Identical NaN masks, no infinities, identical finite FP32 bits (incl. signed zero)."""
a, b = np.asarray(a), np.asarray(b)
test.assertEqual(a.dtype, b.dtype)
test.assertFalse(np.isinf(a).any() or np.isinf(b).any())
np.testing.assert_array_equal(np.isnan(a), np.isnan(b))
finite = np.isfinite(a)
np.testing.assert_array_equal(a[finite].view(np.uint32), b[finite].view(np.uint32))
def accumulations(m):
return [c for c in m["calls"] if c[0] == "BlockAccumulateExchange"]
class ExchangeWindowCPU(unittest.TestCase):
def test_constructor_validation(self):
with mocked_backend() as m:
with self.assertRaisesRegex(ValueError, "requires observe_raw_exchange"):
build(m, window=True, raw=False)
with self.assertRaisesRegex(ValueError, "must be bool"):
build(m, window=1)
def test_state_machine_and_launches(self):
with mocked_backend() as m, ExitStack() as stack:
stack.enter_context(patch.object(cuda, "memset_d8"))
stack.enter_context(patch.object(cuda, "memset_d8_async"))
stack.enter_context(patch.object(cuda, "memcpy_dtoh",
side_effect=lambda out, src: out.fill(0)))
backend = build(m)
b = backend._level_boundaries[1]
self.assertIsNotNone(b.window_integral)
with self.assertRaises(RuntimeError):
backend.start_exchange_window() # not initialized
arrays = [np.full(level.shape, 1 / 9, np.float32) for level in backend._levels]
backend.initialize(*arrays)
with self.assertRaisesRegex(RuntimeError, "no valid exchange window"):
backend.read_exchange_window(0)
backend.step(1)
self.assertEqual(len(accumulations(m)), 2) # closed window: interval ledger only
backend.start_exchange_window()
with self.assertRaisesRegex(RuntimeError, "at least one completed"):
backend.read_exchange_window(0)
m["calls"].clear()
backend.step(2)
calls = accumulations(m)
self.assertEqual(len(calls), 8) # two fine hops x two ledgers x two base steps
self.assertEqual({id(c[1][1]) for c in calls},
{id(b.interval_integral), id(b.window_integral)})
out = backend.read_exchange_window(0)
self.assertEqual((out["time_start"], out["time_end"], out["sample_count"]), (1., 3, 4))
self.assertEqual(backend.read_exchange_window(0)["time_end"], 3) # non-destructive
backend.initialize(*arrays) # invalidates
with self.assertRaisesRegex(RuntimeError, "no valid exchange window"):
backend.read_exchange_window(0)
backend.start_exchange_window()
with patch.object(backend, "_hop", side_effect=RuntimeError("injected")):
with self.assertRaises(RuntimeError):
backend.step(1)
self.assertFalse(backend._window_valid)
with self.assertRaises(RuntimeError):
backend.read_exchange_window(0) # failed status
def test_disabled_default_has_no_window_cost(self):
with mocked_backend() as m, ExitStack() as stack:
stack.enter_context(patch.object(cuda, "memset_d8_async"))
backend = build(m, window=False)
self.assertIsNone(backend._level_boundaries[1].window_integral)
backend.initialize(*[np.full(l.shape, 1 / 9, np.float32) for l in backend._levels])
backend.step(1)
self.assertEqual(len(accumulations(m)), 2)
with self.assertRaisesRegex(RuntimeError, "disabled"):
backend.start_exchange_window()
class ExchangeWindowGPU(unittest.TestCase):
def test_window_matches_summed_base_reads_and_populations_unchanged(self):
from test_raw_exchange_gpu import BOUNDS as RB, CFG, circle as rc, jet, state
from CelerisLab.cuda.context import CudaContext
with CudaContext(0) as ctx:
kw = dict(context=ctx, fine_block=(16, 20), fine_objects=[rc()], jets=[jet()],
observe_raw_exchange=True)
with FixedPatchStepper(CFG, RB, observe_window_exchange=True, **kw) as windowed, \
FixedPatchStepper(CFG, RB, **kw) as plain:
arrays = [state(level.shape) for level in windowed._levels]
windowed.initialize(*arrays)
plain.initialize(*arrays)
windowed.step(2)
plain.step(2)
windowed.start_exchange_window()
b = windowed._level_boundaries[1]
count = len(b.tables["cell"])
factors = np.array([.25, .25, .125, .25]) # h*dt, h*h*dt, h*h for level-1 h=.5
scale = np.zeros(4)
substeps = 0
kernel = windowed._levels[1].kernel
def audited(src, dst, *args, **kw):
nonlocal scale, substeps
windowed._stream.synchronize() # BFL and both accumulations are complete
raw = np.empty((count, 4), np.float32)
cuda.memcpy_dtoh(raw, b.last_raw)
scale = scale + (np.abs(raw.astype(np.float64)) * factors).sum(axis=0)
substeps += 1
kernel(src, dst, *args, **kw)
windowed._levels[1].kernel = audited
keys = ("impulse", "angular_impulse", "mass_into_fluid")
summed = {part: [0., 0., 0., 0.] for part in ("total", "wall", "aperture")}
steps = 0
for speed in (0., .002, .002, -.001, 0., 0.): # amplitude updates stay in-window
windowed.set_jet_amplitude(0, speed)
plain.set_jet_amplitude(0, speed)
windowed.step(1)
plain.step(1)
steps += 1
obs = windowed.read_raw_exchange(0)
for part in summed:
o = obs[part]
summed[part] = [summed[part][0] + o["impulse"][0], summed[part][1] + o["impulse"][1],
summed[part][2] + o["angular_impulse"],
summed[part][3] + o["mass_into_fluid"]]
for a, e in zip(windowed._download_raw().values, plain._download_raw().values):
same_bits(self, a, e)
out = windowed.read_exchange_window(0)
self.assertEqual((out["time_end"] - out["time_start"], out["sample_count"]),
(steps, 2 * steps))
self.assertEqual(substeps, 2 * steps)
bound = 4 * (count * substeps) * EPS * scale + 1e-300
for part in summed:
o = out[part]
got = np.array([o["impulse"][0], o["impulse"][1], o["angular_impulse"],
o["mass_into_fluid"]])
diff = np.abs(got - np.array(summed[part]))
self.assertTrue((diff <= bound).all(), f"{part}: {diff} > {bound}")
np.testing.assert_array_equal(o["force"], o["impulse"] / steps)
again = windowed.read_exchange_window(0)
np.testing.assert_array_equal(again["total"]["impulse"], out["total"]["impulse"])
windowed.initialize(*arrays)
with self.assertRaises(RuntimeError):
windowed.read_exchange_window(0)
def audit_substeps(stepper, b, count, record):
"""Wrap the level-1 step kernel: after BFL and accumulation, add |substep terms| to record."""
factors = np.array([.25, .25, .125, .25])
kernel = stepper._levels[1].kernel
def audited(src, dst, *args, **kw):
stepper._stream.synchronize()
raw = np.empty((count, 4), np.float32)
cuda.memcpy_dtoh(raw, b.last_raw)
record["scale"] = record["scale"] + (np.abs(raw.astype(np.float64)) * factors).sum(axis=0)
record["substeps"] += 1
kernel(src, dst, *args, **kw)
stepper._levels[1].kernel = audited
def components(obs):
o = obs["total"]
return np.array([o["impulse"][0], o["impulse"][1], o["angular_impulse"], o["mass_into_fluid"]])
class ExchangeWindowShiftedMRTGPU(unittest.TestCase):
"""Shifted MRT, all-blocked, stationary body, NO Jet (scoped separately from SRT/Jet)."""
def test_window_step0_reset_and_split_step(self):
from test_raw_exchange_gpu import BOUNDS as RB, circle as rc, state
from CelerisLab.config import LBMConfig
from CelerisLab.cuda.context import CudaContext
cfg = LBMConfig(nx=32, ny=24, viscosity=.1, collision="MRT", ddf_shifting=True)
with CudaContext(0) as ctx:
kw = dict(context=ctx, base_block=(12, 8), fine_block=(16, 20), fine_objects=[rc()],
observe_raw_exchange=True)
with FixedPatchStepper(cfg, RB, observe_window_exchange=True, **kw) as windowed, \
FixedPatchStepper(cfg, RB, observe_window_exchange=True, **kw) as split, \
FixedPatchStepper(cfg, RB, **kw) as plain:
arrays = [state(level.shape) for level in windowed._levels]
for run in (windowed, split, plain):
run.initialize(*arrays)
run.step(2)
if run is not plain:
run.start_exchange_window()
b = windowed._level_boundaries[1]
count = len(b.tables["cell"])
record = dict(scale=np.zeros(4), substeps=0)
audit_substeps(windowed, b, count, record)
steps, summed = 5, np.zeros(4)
for _ in range(steps):
windowed.step(1)
plain.step(1)
summed += components(windowed.read_raw_exchange(0))
for a, e in zip(windowed._download_raw().values, plain._download_raw().values):
same_bits(self, a, e)
split.step(steps) # one call: same ledger arithmetic as five step(1) calls
for a, e in zip(windowed._download_raw().values, split._download_raw().values):
same_bits(self, a, e)
rows = [np.empty((count, 4), np.float64) for _ in range(2)]
cuda.memcpy_dtoh(rows[0], b.window_integral)
cuda.memcpy_dtoh(rows[1], split._level_boundaries[1].window_integral)
np.testing.assert_array_equal(rows[0].view(np.uint64), rows[1].view(np.uint64))
out = windowed.read_exchange_window(0)
self.assertEqual(record["substeps"], 2 * steps)
self.assertEqual((out["time_end"] - out["time_start"], out["sample_count"]),
(steps, 2 * steps))
bound = 4 * (count * record["substeps"]) * EPS * record["scale"] + 1e-300
diff = np.abs(components(out) - summed)
self.assertTrue((diff <= bound).all(), f"{diff} > {bound}")
np.testing.assert_array_equal(split.read_exchange_window(0)["total"]["impulse"],
out["total"]["impulse"])
windowed.step(0) # no interval: window and its duration unchanged
again = windowed.read_exchange_window(0)
self.assertEqual(again["time_end"], out["time_end"])
np.testing.assert_array_equal(again["total"]["impulse"], out["total"]["impulse"])
windowed.start_exchange_window() # reset after a window
with self.assertRaisesRegex(RuntimeError, "at least one completed"):
windowed.read_exchange_window(0)
record.update(scale=np.zeros(4), substeps=0)
windowed.step(1)
single = components(windowed.read_raw_exchange(0))
reset = windowed.read_exchange_window(0)
self.assertEqual(reset["time_end"] - reset["time_start"], 1)
bound = 4 * (count * record["substeps"]) * EPS * record["scale"] + 1e-300
self.assertTrue((np.abs(components(reset) - single) <= bound).all())
if __name__ == "__main__": unittest.main()
@@ -0,0 +1,95 @@
"""MRT reuse GPU gates. Caller owns GPU admission (CUDA_VISIBLE_DEVICES).
Run: python -m unittest discover -s tests/validation/multigrid -p test_refinement_mrt_gpu.py
Parity compares the blocked MRT channel root with uniform MRT OneStep: the existing
pressure-NEQ outlet branch differs by collision model, so SRT is never the reference.
AMR checks are finite-evolution/split-invariance smoke tests, not benchmark validation.
"""
from dataclasses import replace
import unittest
import numpy as np
from CelerisLab.config import LBMConfig
from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.population_storage import _encode_physical
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
from test_channel_root_gpu import run_root, state
from test_refinement_blocked_base import raw, exact
class RefinementMRTGPU(unittest.TestCase):
def test_uniform_matched_mrt_root(self):
with CudaContext(0) as context:
for shifted in (False, True):
for profile in ("uniform", "parabolic"):
cfg = LBMConfig(nx=24, ny=20, viscosity=.1, velocity=.025, collision="MRT",
ddf_shifting=shifted, inlet_profile=profile)
initial = _encode_physical(state(cfg.ny, cfg.nx), shifted)
expected = run_root(cfg, context, initial)
self.assertTrue(np.isfinite(expected).all())
for block in ((20, 24), (5, 6), (4, 1)):
np.testing.assert_array_equal(run_root(cfg, context, initial, block), expected)
def test_amr_mrt_smoke(self):
from CelerisLab.body.geometry.circle import CircleGeometry
from CelerisLab.body.objects import SimObject
center = (24., 16.)
body = SimObject(0, geometry=CircleGeometry(*center, 2.15), center=center, radius=2.15)
with CudaContext(0) as context:
for boundary in ("periodic", "channel"):
for shifted in (False, True):
cfg = LBMConfig(nx=48, ny=32, viscosity=.1, velocity=.015 if boundary == "channel" else 0.,
collision="MRT", ddf_shifting=shifted)
reference = None
for block in ((32, 48), (8, 8), (4, 1)):
with FixedPatchStepper(cfg, (8, 6, 40, 26), context=context, coarse_boundary=boundary,
base_block=block, fine_block=(8, 8), fine_objects=(body,)) as backend:
backend.initialize(*[state(*level.shape[1:]) for level in backend._levels])
backend.step(8)
raw = backend._download_raw()
for a, mask in zip(raw.values, backend._state):
self.assertTrue(np.isfinite(a[:, mask]).all())
if reference is None: reference = raw.values
else:
for a, b in zip(reference, raw.values): np.testing.assert_array_equal(a, b)
def test_dense_versus_blocked_mrt_two_level(self):
"""Unshifted MRT: all-dense PatchCoarseStep/PatchFineStep vs mixed/all-blocked storage."""
from test_refinement_blocked_base import BASE_BLOCKS, FINE_BLOCK
from test_refinement_blocked_fine import NX, NY, BOUNDS
import test_refinement_blocked_fine as fixture
cfg = LBMConfig(nx=NX, ny=NY, viscosity=.1, collision="MRT")
with CudaContext(0) as context:
results = {}
layouts = ((None, None), *((base, FINE_BLOCK) for base in (None, *BASE_BLOCKS)))
for base_block, fine_block in layouts:
with FixedPatchStepper(cfg, BOUNDS, context=context, fine_block=fine_block,
base_block=base_block) as backend:
backend.initialize(*[fixture.state(*level.shape[1:], seed) for seed, level in enumerate(backend._levels)])
backend.step(4)
results[base_block, fine_block] = raw(backend)
for layout in layouts[1:]:
for level, (a, b) in enumerate(zip(results[layout], results[None, None])):
exact(self, a, b, f"layout={layout} level={level}")
def test_shifted_all_blocked_three_level_mrt_smoke(self):
"""Per-level shear rate omega_l = 1/(3*2**l*nu + 1/2); finite ACTIVE leaves."""
cfg = LBMConfig(nx=16, ny=16, viscosity=.1, collision="MRT", ddf_shifting=True)
kw = dict(fine_block=(4, 4), base_block=(4, 4), child=(8, 8, 16, 16), child_block=(4, 4))
with CudaContext(0) as context:
with FixedPatchStepper(cfg, (4, 4, 12, 12), context=context, **kw) as backend:
self.assertEqual(len(backend._level_cfgs), 3)
for level, level_cfg in enumerate(backend._level_cfgs):
checked = replace(level_cfg)
checked.validate() # omega is derived only by validate()
self.assertEqual(checked.collision, "MRT")
self.assertTrue(checked.ddf_shifting)
self.assertTrue(np.isclose(checked.omega, 1 / (3 * 2**level * .1 + .5), rtol=1e-14))
backend.initialize(*[state(*level.shape[1:]) for level in backend._levels])
backend.step(4)
values = backend._download_raw().values
for a, mask in zip(values, backend._state):
self.assertTrue(np.isfinite(a[:, mask]).all())
if __name__ == "__main__": unittest.main()
+48 -20
View File
@@ -1,4 +1,4 @@
"""Frozen matched SRT DFG comparison. GPU execution requires explicit root admission."""
"""Frozen matched SRT/MRT DFG comparison. GPU execution requires explicit root admission."""
import argparse
import csv
@@ -39,20 +39,21 @@ def helpers(source):
return h, periodic
def config(h, diameter):
cfg, body, p = h.make_config(diameter, SPEED, "SRT", "neq_extrap", "zou_he_local")
def config(h, diameter, collision="SRT"):
cfg, body, p = h.make_config(diameter, SPEED, collision, "neq_extrap", "zou_he_local")
cfg["method"]["outlet"]["srt_neq_damp"] = 0.5
return cfg, body, p
def plan(h):
_, _, c = config(h, 40)
_, _, f = config(h, 80)
def plan(h, collision="SRT"):
_, _, c = config(h, 40, collision)
_, _, f = config(h, 80, collision)
x0, y0, x1, y1 = BOUNDS
fine_active = 4 * (x1 - x0) * (y1 - y0)
coarse_uncovered = c["nx"] * c["ny"] - fine_active // 4
return dict(
status="prepared_not_run",
collision=collision,
root_gpu_gates_required=True,
root=c,
uniform=f,
@@ -82,7 +83,11 @@ def plan(h):
/ (2 * f["nx"] * f["ny"]),
cost_caveat="Geometry-only estimates include ghosts/solids; exclude block halos, transfers, observation and launch overhead. Not measured speedup.",
sampling_offset="For origin (38,22), fine physical x=(j+75.5)*dx80 versus uniform i*dx80: half-fine-cell x offset. Fine physical y=(k+42.5)*dx80 equals uniform (l-.5)*dx80 at l=k+43: y samples align. Body, wall and source planes coincide.",
outlet="SRT pressure NEQ, all nine fneq damped by .5, no backflow clamp; noncanonical DFG outlet",
outlet=(
"SRT pressure NEQ, all nine fneq damped by .5, no backflow clamp; noncanonical DFG outlet"
if collision == "SRT" else
"MRT pressure NEQ, unknowns q2/6/8 extrapolated; no backflow clamp; noncanonical DFG outlet"
),
modes={"pilot_tstar": 5.0, "full_tstar": 300.0},
observation_dense_tstar=0.02,
)
@@ -120,7 +125,7 @@ def initial_state(shape, origin, spacing, height=164.0, speed=SPEED, root=False)
return w * (1 + 3 * cu + 4.5 * cu * cu - 1.5 * velocity * velocity)
def host_geometry(source, h):
def host_geometry(source, h, collision="SRT"):
"""Production donor/transfer and complete cut-link checks, without CUDA."""
from CelerisLab.config import load_lbm_config
from CelerisLab.lbm.refinement import FixedPatch2D, prepare_fine_boundary
@@ -133,7 +138,7 @@ def host_geometry(source, h):
from CelerisLab.body.geometry.circle import CircleGeometry
from CelerisLab.body.objects import SimObject
cfgdict, _, _ = config(h, 40)
cfgdict, _, _ = config(h, 40, collision)
with TemporaryDirectory() as tmp:
p = Path(tmp) / "cfg.json"
p.write_text(json.dumps(cfgdict))
@@ -151,8 +156,11 @@ def host_geometry(source, h):
return cfg, pair, body, host
def verify_source(source):
expected = json.loads((HERE / "data/refined_dfg/source_manifest.json").read_text())
def verify_source(source, collision="SRT"):
if collision not in ("SRT", "MRT"):
raise ValueError("Matched collision must be SRT or MRT")
name = "source_manifest.json" if collision == "SRT" else "source_manifest_mrt.json"
expected = json.loads((HERE / "data/refined_dfg" / name).read_text())
for name, digest in expected["sha256"].items():
if hashlib.sha256((source / name).read_bytes()).hexdigest() != digest:
raise RuntimeError("Source mismatch: " + name)
@@ -167,7 +175,7 @@ def run_case(a, h, periodic, case):
from contextlib import ExitStack
refined = case == "refined"
cfgdict, bodydict, p = config(h, 40 if refined else 80)
cfgdict, bodydict, p = config(h, 40 if refined else 80, a.collision)
cap = 5.0 if a.mode == "pilot" else 300.0
max_steps = math.ceil(cap * p["diameter"] / SPEED)
rows = []
@@ -179,7 +187,7 @@ def run_case(a, h, periodic, case):
dest.mkdir()
with ExitStack() as stack:
if refined:
cfg, pair, body, host = host_geometry(a.source, h)
cfg, pair, body, host = host_geometry(a.source, h, a.collision)
context = stack.enter_context(CudaContext(0))
backend = stack.enter_context(
FixedPatchStepper(
@@ -336,6 +344,8 @@ def run_case(a, h, periodic, case):
if len(rows) == 1:
ready = dict(
case=case,
collision=a.collision,
**a.provenance,
mode=a.mode,
step=begin,
tstar=row["tstar"],
@@ -348,6 +358,8 @@ def run_case(a, h, periodic, case):
print("READY " + json.dumps(ready, allow_nan=False), flush=True)
result = dict(
case=case,
collision=a.collision,
**a.provenance,
mode=a.mode,
history=rows,
healthy=bool(healthy),
@@ -416,12 +428,14 @@ def check_deadline(deadline):
)
def verify_pilot(path, manifest):
def verify_pilot(path, manifest, collision="SRT"):
if path is None:
raise ValueError(
"Full comparison requires --pilot-results from a completed matched pilot"
)
previous = read_finite_json(path / "plan.json")
if previous.get("collision") != collision:
raise ValueError("Pilot collision differs")
if previous["source_manifest"] != manifest or previous["bounds_root_edge"] != list(
BOUNDS
):
@@ -432,7 +446,8 @@ def verify_pilot(path, manifest):
for case, diameter in (("uniform", 80), ("refined", 40)):
summary = read_finite_json(path / case / "summary.json")
if (
summary.get("case") != case
summary.get("collision") != collision
or summary.get("case") != case
or summary.get("mode") != "pilot"
or summary.get("status") != "pilot_complete"
or summary.get("healthy") is not True
@@ -483,7 +498,8 @@ def verify_pilot(path, manifest):
raise ValueError("Unhealthy pilot observations")
ready = read_finite_json(path / case / "ready.json")
if (
ready.get("case") != case
ready.get("collision") != collision
or ready.get("case") != case
or ready.get("mode") != "pilot"
or ready.get("step") != interval
or ready.get("runner_sha256") != runner_hash()
@@ -507,6 +523,7 @@ def verify_pilot(path, manifest):
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--collision", choices=["SRT", "MRT"], default="SRT")
parser.add_argument("--source", type=Path, default=DEFAULT_SOURCE)
parser.add_argument("--output", type=Path, required=True)
parser.add_argument("--mode", choices=["plan", "pilot", "full"], default="plan")
@@ -519,9 +536,15 @@ def main():
)
a = parser.parse_args()
a.source = a.source.resolve()
manifest = verify_source(a.source)
manifest = verify_source(a.source, a.collision)
h, periodic = helpers(a.source)
calibration = verify_pilot(a.pilot_results, manifest) if a.mode == "full" else None
from source_provenance import checkout_provenance
a.provenance = checkout_provenance(a.source)
calibration = (
verify_pilot(a.pilot_results, manifest, a.collision)
if a.mode == "full" else None
)
if a.mode != "plan" and (
a.max_wall_seconds is None
or not math.isfinite(a.max_wall_seconds)
@@ -536,16 +559,17 @@ def main():
if a.output.exists() and any(a.output.iterdir()):
raise ValueError("Output must be empty/new")
a.output.mkdir(parents=True, exist_ok=True)
specification = plan(h)
specification = plan(h, a.collision)
specification.update(
source_manifest=manifest,
**a.provenance,
gates=periodic.GATES,
reference_gates=periodic.REFERENCE_GATES,
runner_sha256=runner_hash(),
wall_time_budget_seconds=budget,
full_pilot_calibration_seconds=calibration,
)
host_geometry(a.source, h)
host_geometry(a.source, h, a.collision)
(a.output / "plan.json").write_text(json.dumps(specification, indent=2))
if a.mode == "plan":
return 0
@@ -561,6 +585,8 @@ def main():
except TimeoutError as exc:
failure = dict(
status="wall_time_limit",
collision=a.collision,
**a.provenance,
case=case,
matched_case_pass=False,
error=str(exc),
@@ -574,6 +600,8 @@ def main():
if not result["healthy"]:
break
comparison = dict(
collision=a.collision,
**a.provenance,
status="pilot_only" if a.mode == "pilot" else "incomplete",
matched_case_pass=False,
)
+326
View File
@@ -0,0 +1,326 @@
"""Measurement-only wall timing for the matched MRT refined DFG case. No numerical edits.
Variants over EQUAL simulated duration (one refined base step = two uniform D80 steps):
A refined: step(1) + read_raw_exchange per base step -- runner-like force-read workload
B refined: step(1) only, no host reads -- timing-only, no force history
C refined: one step(N) call -- timing-only; ledger keeps final base interval only
E uniform: sim.run(<=100) + read_force -- runner-like force-read workload
E' uniform: one sim.run(2N) call -- timing-only; at most a whole-window force
average (different summation order), no history
A/E read forces but discard them: no retained force history, no interval aggregation/validation,
and no macro/probe/CSV cost, so they are not full benchmark throughput.
observe_raw_exchange stays True for A/B/C: B/C omit host reads only.
Status lines: CONSTRUCTED = backend/simulation built (JIT done); WARM_READY = first warm-up and
health check passed for that case.
Parity compares A/B/C with each other and E/E' with each other, never uniform with refined.
A-B and B-C are measured comparative differences, not exact causal decompositions.
Each repeat starts from the same fresh initial state with the same warm-up; construction,
compilation, parity and health checks are outside timed regions. The actual stepping stream is
synchronized explicitly immediately before the timer starts and after the timed loop. Wall time
(perf_counter) is the only timing source; no CUDA-event span is reported as kernel time. An outer
--max-wall-seconds deadline is checked between variants and inside per-step loops.
"""
import argparse
import json
import math
import os
from pathlib import Path
import statistics
import sys
import time
from tempfile import TemporaryDirectory
import numpy as np
HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
import run_refined_dfg as r # noqa: E402 (published runner: same setup functions)
VARIANTS = {
"A": dict(case="refined", force_history_valid=False, force_reads=True,
force_note="runner-like force-read workload; values discarded, no aggregation"),
"B": dict(case="refined", force_history_valid=False, timing_only=True,
force_note="no host reads"),
"C": dict(case="refined", force_history_valid=False, timing_only=True,
force_note="raw ledger retains only the final base interval"),
"E": dict(case="uniform", force_history_valid=False, force_reads=True,
force_note="runner-like force-read workload; values discarded, no aggregation"),
"E'": dict(case="uniform", force_history_valid=False, timing_only=True,
force_note="at most a whole-window accumulated average; different summation order"),
}
def schedule(n_base, warmup_base):
"""Steps per case for equal simulated duration (refined dt_root = 2 dt_uniform)."""
if n_base <= 0 or warmup_base < 0:
raise ValueError("n_base must be positive and warmup_base nonnegative")
return dict(refined=(warmup_base, n_base), uniform=(2 * warmup_base, 2 * n_base),
tstar_window=n_base * r.SPEED / 40.0)
# Existing run_refined_dfg safety limits (rho in [.5, 1.5], sampled max Mach <= .2).
RHO_LIMITS, MAX_MACH = (0.5, 1.5), 0.2
def same_state(reference, values):
"""Bitwise populations and identical NaN masks; returns a short description or None.
Matching NaN is accepted only as a storage mask (inactive/ghost/solid slots); physical
leaf health is checked separately. Any infinity in either state is a mismatch.
"""
reference, values = list(reference), list(values)
if len(reference) != len(values):
return f"level count {len(reference)} != {len(values)}"
for level, (a, b) in enumerate(zip(reference, values)):
a, b = np.asarray(a), np.asarray(b)
if a.shape != b.shape:
return f"level {level}: shape {a.shape} != {b.shape}"
if np.isinf(a).any() or np.isinf(b).any():
return f"level {level}: infinite population"
if not np.array_equal(np.isnan(a), np.isnan(b)):
return f"level {level}: NaN mask differs"
finite = np.isfinite(a)
if a.dtype != b.dtype or not np.array_equal(a[finite].view(np.uint8), b[finite].view(np.uint8)):
return f"level {level}: finite bits differ"
return None
def uniform_populations_finite(ddf, fluid):
"""Simulation.get_ddf() may be flat (9*ny*nx); view it as (Q, cells) before masking."""
ddf, fluid = np.asarray(ddf), np.asarray(fluid, bool).ravel()
if fluid.size == 0 or ddf.size % fluid.size:
raise RuntimeError(f"DDF size {ddf.size} incompatible with {fluid.size} cells")
return bool(np.isfinite(ddf.reshape(ddf.size // fluid.size, fluid.size)[:, fluid]).all())
def physical_health(fields):
"""fields: (rho, ux, uy) arrays already restricted to physical leaves/fluid."""
if not fields or any(not np.isfinite(v).all() or v.size == 0 for f in fields for v in f):
raise RuntimeError("nonfinite or empty physical macroscopic field")
rho_min = float(min(f[0].min() for f in fields))
rho_max = float(max(f[0].max() for f in fields))
max_mach = float(max(np.sqrt(3 * (f[1] ** 2 + f[2] ** 2)).max() for f in fields))
if not (RHO_LIMITS[0] <= rho_min <= rho_max <= RHO_LIMITS[1] and max_mach <= MAX_MACH):
raise RuntimeError(f"health limits violated: rho [{rho_min}, {rho_max}], Mach {max_mach}")
return dict(rho_min=rho_min, rho_max=rho_max, max_mach=max_mach)
def refined_health(backend, masks):
arrays = backend.download() # physical FP64 populations; non-leaves NaN by contract
if any(not np.isfinite(g[:, m]).all() for g, m in zip(arrays, masks)):
raise RuntimeError("nonfinite physical leaf population")
return physical_health([tuple(v[m] for v in r.macros(g)) for g, m in zip(arrays, masks)])
def uniform_health(sim, fluid):
m = sim.get_macroscopic()
return physical_health([tuple(np.asarray(m[k], np.float64).reshape(fluid.shape)[fluid]
for k in ("rho", "ux", "uy"))])
def check_deadline(deadline):
if time.monotonic() >= deadline:
raise TimeoutError("timing harness exceeded --max-wall-seconds")
def sync_refined(backend):
with backend.ctx.activate():
backend._stream.synchronize()
def sync_uniform(sim):
with sim.ctx.activate():
sim.stream.synchronize()
def refined_loop(backend, variant, n, deadline):
if variant == "C":
backend.step(n)
return
for i in range(n):
backend.step(1)
if variant == "A":
backend.read_raw_exchange(0, level=1, window="last_base_step")
if i % 100 == 99:
check_deadline(deadline)
def uniform_loop(sim, variant, n, deadline):
if variant == "E'":
sim.run(n)
return
done = 0
while done < n:
batch = min(100, n - done)
sim.run(batch)
sim.read_force(0)
done += batch
check_deadline(deadline)
def time_refined(a, h, sched):
from contextlib import ExitStack
from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
from CelerisLab.lbm.channel import channel_masks
from CelerisLab.lbm.refinement import ACTIVE
from CelerisLab.lbm.descriptors import SOLID
warm, n = sched["refined"]
rows, reference = [], {}
with ExitStack() as stack:
cfg, pair, body, host = r.host_geometry(a.source, h, "MRT")
context = stack.enter_context(CudaContext(0))
backend = stack.enter_context(FixedPatchStepper(
cfg, r.BOUNDS, context=context, coarse_boundary="channel", base_block=r.BASE_BLOCK,
fine_block=r.FINE_BLOCK, fine_objects=(body,), observe_raw_exchange=True))
masks = [channel_masks(pair.coarse_shape)[0] & ~pair.covered, # as run_refined_dfg
(pair.fine_kind == ACTIVE) & ((host.flags.reshape(pair.fine_shape) & SOLID) == 0)]
fresh = (r.initial_state(pair.coarse_shape, (0.0, 0.0), 1.0, root=True),
r.initial_state(pair.fine_shape, pair.fine_origin, 0.5))
print(json.dumps(dict(status="CONSTRUCTED", case="refined")), flush=True)
for repeat in range(a.repeats):
for variant in ("A", "B", "C"):
check_deadline(a.deadline)
backend.initialize(*fresh) # resets step count; same fresh state every time
refined_loop(backend, variant, warm, a.deadline)
warm_health = refined_health(backend, masks) # untimed
if repeat == 0 and variant == "A":
print(json.dumps(dict(status="WARM_READY", case="refined")), flush=True)
sync_refined(backend)
start = time.perf_counter()
refined_loop(backend, variant, n, a.deadline)
sync_refined(backend)
seconds = time.perf_counter() - start
end_health = refined_health(backend, masks) # untimed
values = [np.array(v, copy=True) for v in backend._download_raw().values]
if not all(np.isfinite(v[:, m]).all() for v, m in zip(values, backend._state)):
raise RuntimeError(f"refined {variant} repeat {repeat}: nonfinite leaf populations")
mismatch = None
if repeat == 0 and variant == "A":
reference["A"] = values
else:
mismatch = same_state(reference["A"], values)
rows.append(dict(variant=variant, repeat=repeat, seconds=seconds,
base_steps=n, step_count=backend.step_count,
health_after_warmup=warm_health, health_after_window=end_health,
parity_vs_A=mismatch or "identical", **VARIANTS[variant]))
if mismatch:
raise RuntimeError(f"refined {variant} repeat {repeat}: {mismatch}")
return rows
def time_uniform(a, h, sched):
from CelerisLab.simulation import Simulation
from CelerisLab.lbm.descriptors import FLUID
warm, n = sched["uniform"]
rows, reference = [], {}
cfgdict, bodydict, params = r.config(h, 80, "MRT")
with TemporaryDirectory() as tmp:
tmp = Path(tmp)
(tmp / "lbm.json").write_text(json.dumps(cfgdict))
(tmp / "body.json").write_text(json.dumps(bodydict))
with Simulation(str(tmp / "lbm.json"), str(tmp / "body.json"), device_id=0) as sim:
sim.initialize()
sim.snapshot() # fresh state; restore keeps clock and streaming parity
fluid = (sim.get_flags() & FLUID) != 0
ny, nx = params["ny"], params["nx"]
fluid = fluid.reshape(ny, nx)
print(json.dumps(dict(status="CONSTRUCTED", case="uniform")), flush=True)
for repeat in range(a.repeats):
for variant in ("E", "E'"):
check_deadline(a.deadline)
sim.restore()
if sim.stepper.step_count % 2:
raise RuntimeError("uniform restore parity changed between variants")
uniform_loop(sim, variant, warm, a.deadline)
warm_health = uniform_health(sim, fluid) # untimed
if repeat == 0 and variant == "E":
print(json.dumps(dict(status="WARM_READY", case="uniform")), flush=True)
sync_uniform(sim)
start = time.perf_counter()
uniform_loop(sim, variant, n, a.deadline)
sync_uniform(sim)
seconds = time.perf_counter() - start
end_health = uniform_health(sim, fluid) # untimed
values = [sim.get_ddf()]
if not uniform_populations_finite(values[0], fluid):
raise RuntimeError(f"uniform {variant} repeat {repeat}: nonfinite fluid populations")
mismatch = None
if repeat == 0 and variant == "E":
reference["E"] = values
else:
mismatch = same_state(reference["E"], values)
rows.append(dict(variant=variant, repeat=repeat, seconds=seconds,
uniform_steps=n, parity_vs_E=mismatch or "identical",
health_after_warmup=warm_health, health_after_window=end_health,
**VARIANTS[variant]))
if mismatch:
raise RuntimeError(f"uniform {variant} repeat {repeat}: {mismatch}")
return rows
def summarize(rows, tstar_window):
summary = {}
for variant in VARIANTS:
seconds = [row["seconds"] for row in rows if row["variant"] == variant]
if seconds:
median = statistics.median(seconds)
summary[variant] = dict(median_seconds=median, seconds=seconds,
seconds_per_tstar=median / tstar_window,
**VARIANTS[variant])
if {"A", "B", "C"} <= summary.keys():
summary["A_minus_B_seconds"] = summary["A"]["median_seconds"] - summary["B"]["median_seconds"]
summary["B_minus_C_seconds"] = summary["B"]["median_seconds"] - summary["C"]["median_seconds"]
if {"A", "E"} <= summary.keys():
summary["A_over_E"] = summary["A"]["median_seconds"] / summary["E"]["median_seconds"]
if {"C", "E'"} <= summary.keys():
summary["C_over_Eprime"] = summary["C"]["median_seconds"] / summary["E'"]["median_seconds"]
summary["interpretation"] = ("Measured comparative differences under GPU variability; "
"not exact causal decompositions or performance claims.")
return summary
def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("--source", type=Path, default=r.DEFAULT_SOURCE)
p.add_argument("--output", type=Path, required=True)
p.add_argument("--base-steps", type=int, default=2000)
p.add_argument("--warmup-base-steps", type=int, default=200)
p.add_argument("--repeats", type=int, default=3)
p.add_argument("--max-wall-seconds", type=float, help="Required outer timeout for GPU runs")
p.add_argument("--plan", action="store_true")
a = p.parse_args()
if a.repeats < 1 or a.base_steps > 20000:
p.error("repeats must be >= 1 and base-steps <= 20000")
a.source = a.source.resolve()
manifest = r.verify_source(a.source, "MRT")
sched = schedule(a.base_steps, a.warmup_base_steps)
plan = dict(collision="MRT", manifest_commit=manifest["commit"], schedule=sched,
repeats=a.repeats, variants=VARIANTS, timer="time.perf_counter wall",
excluded="construction/JIT, warm-up, state download and parity checks")
if a.plan:
print(json.dumps(plan, indent=2))
return 0
if a.max_wall_seconds is None or not math.isfinite(a.max_wall_seconds) or a.max_wall_seconds <= 0:
p.error("GPU timing requires a finite positive --max-wall-seconds")
a.deadline = time.monotonic() + a.max_wall_seconds
if not os.environ.get("CUDA_VISIBLE_DEVICES") or "," in os.environ["CUDA_VISIBLE_DEVICES"]:
p.error("Root must select exactly one verified idle GPU via CUDA_VISIBLE_DEVICES")
if a.output.exists() and any(a.output.iterdir()):
p.error("Output must be empty/new")
a.output.mkdir(parents=True, exist_ok=True)
h, _ = r.helpers(a.source)
rows = time_uniform(a, h, sched) + time_refined(a, h, sched)
result = dict(plan=plan, rows=rows, summary=summarize(rows, sched["tstar_window"]))
if not all(math.isfinite(row["seconds"]) for row in rows):
raise RuntimeError("Nonfinite timing")
(a.output / "timing.json").write_text(json.dumps(result, indent=2))
print(json.dumps(result["summary"], indent=2), flush=True)
return 0
if __name__ == "__main__":
sys.exit(main())
+183
View File
@@ -0,0 +1,183 @@
"""Measurement-only A-versus-window timing for the matched shifted-MRT refined DFG setup.
Candidate source (window ledger) is recorded by checkout revision, dirty flag and file hashes;
the frozen refined-DFG manifests/results are NOT used or modified (they pin pre-window source).
Equal simulated duration, same fresh state and warm-up per variant, one observation interval =
80 root base steps (the runner's dense-phase interval):
A per base step: step(1) + read_raw_exchange, summed per interval (current runner workload)
W per interval: start_exchange_window(); step(80); read_exchange_window()
W1 per interval: start_exchange_window(); 80 x step(1); read_exchange_window()
All variants keep observe_raw_exchange=True; the backend is built once with
observe_window_exchange=True (a closed window adds no launch). Populations (bitwise) and
per-interval total impulses are compared OUTSIDE timing; the impulse tolerance is a
conservative engineering tolerance (see INTERVAL_RTOL); the tighter substep-scaled engineering
tolerance is exercised by the capability test tests/validation/multigrid/test_exchange_window.py.
Wall time (perf_counter) with explicit stream synchronization is the only timing source.
"""
import argparse
import hashlib
import json
import math
import os
from pathlib import Path
import statistics
import sys
import time
import numpy as np
HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
import time_refined_dfg as t # noqa: E402 (reuses run_refined_dfg setup via t.r)
r = t.r
INTERVAL = 80
VARIANTS = ("A", "W", "W1")
# Interval impulses differ only by FP64 summation order (per link over time vs per step over
# links). Engineering tolerance: 1e-9 of the interval's summed absolute per-step totals.
INTERVAL_RTOL = 1e-9
CANDIDATE_FILES = ("src/CelerisLab/lbm/refinement_stepper.py", "src/CelerisLab/lbm/raw_exchange.py",
"src/CelerisLab/lbm/refinement_tables.py", "src/CelerisLab/lbm/kernels/blocks.cu")
def components(obs):
o = obs["total"]
return np.array([o["impulse"][0], o["impulse"][1], o["angular_impulse"], o["mass_into_fluid"]])
def candidate_identity(source):
from source_provenance import checkout_provenance
return dict(checkout_provenance(source),
sha256={f: hashlib.sha256((source / f).read_bytes()).hexdigest()
for f in CANDIDATE_FILES})
def run_variant(backend, variant, n_intervals, deadline):
"""Returns per-interval totals and, for A, per-interval summed |per-step totals|."""
totals, scales = [], []
for _ in range(n_intervals):
if variant == "A":
impulse, scale = np.zeros(4), np.zeros(4)
for _ in range(INTERVAL):
backend.step(1)
c = components(backend.read_raw_exchange(0, level=1, window="last_base_step"))
impulse += c
scale += np.abs(c)
totals.append(impulse)
scales.append(scale)
else:
backend.start_exchange_window()
if variant == "W":
backend.step(INTERVAL)
else:
for _ in range(INTERVAL):
backend.step(1)
totals.append(components(backend.read_exchange_window(0)))
t.check_deadline(deadline)
return np.array(totals), (np.array(scales) if scales else None)
def compare_intervals(reference, scales, totals):
"""Max violation ratio; <= 1 passes. Scale includes a floor so zero cancels cannot divide."""
bound = INTERVAL_RTOL * scales + 1e-300
return float(np.max(np.abs(totals - reference) / bound))
def main():
p = argparse.ArgumentParser(description=__doc__)
p.add_argument("--source", type=Path, default=r.DEFAULT_SOURCE)
p.add_argument("--output", type=Path, required=True)
p.add_argument("--base-steps", type=int, default=2000)
p.add_argument("--warmup-base-steps", type=int, default=200)
p.add_argument("--repeats", type=int, default=3)
p.add_argument("--max-wall-seconds", type=float)
p.add_argument("--plan", action="store_true")
a = p.parse_args()
if a.base_steps <= 0 or a.base_steps % INTERVAL or a.base_steps > 20000 or a.repeats < 1:
p.error(f"base-steps must be a positive multiple of {INTERVAL} (<= 20000); repeats >= 1")
a.source = a.source.resolve()
identity = candidate_identity(a.source)
plan = dict(collision="MRT", shifted_storage="as run_refined_dfg MRT config",
candidate_source=identity, frozen_manifests_used=False, interval_base_steps=INTERVAL,
base_steps=a.base_steps, warmup_base_steps=a.warmup_base_steps, repeats=a.repeats,
variants=VARIANTS, tstar_window=a.base_steps * r.SPEED / 40.0,
timer="time.perf_counter wall with explicit stream sync",
excluded="construction/JIT, warm-up, health, downloads, parity/impulse comparison")
if a.plan:
print(json.dumps(plan, indent=2))
return 0
if a.max_wall_seconds is None or not math.isfinite(a.max_wall_seconds) or a.max_wall_seconds <= 0:
p.error("GPU timing requires a finite positive --max-wall-seconds")
if not os.environ.get("CUDA_VISIBLE_DEVICES") or "," in os.environ["CUDA_VISIBLE_DEVICES"]:
p.error("Root must select exactly one verified idle GPU via CUDA_VISIBLE_DEVICES")
if a.output.exists() and any(a.output.iterdir()):
p.error("Output must be empty/new")
a.output.mkdir(parents=True, exist_ok=True)
deadline = time.monotonic() + a.max_wall_seconds
h, _ = r.helpers(a.source)
from contextlib import ExitStack
from CelerisLab.cuda.context import CudaContext
from CelerisLab.lbm.refinement_stepper import FixedPatchStepper
from CelerisLab.lbm.channel import channel_masks
from CelerisLab.lbm.refinement import ACTIVE
from CelerisLab.lbm.descriptors import SOLID
rows, ref = [], {}
n_intervals = a.base_steps // INTERVAL
with ExitStack() as stack:
cfg, pair, body, host = r.host_geometry(a.source, h, "MRT")
context = stack.enter_context(CudaContext(0))
backend = stack.enter_context(FixedPatchStepper(
cfg, r.BOUNDS, context=context, coarse_boundary="channel", base_block=r.BASE_BLOCK,
fine_block=r.FINE_BLOCK, fine_objects=(body,), observe_raw_exchange=True,
observe_window_exchange=True))
masks = [channel_masks(pair.coarse_shape)[0] & ~pair.covered,
(pair.fine_kind == ACTIVE) & ((host.flags.reshape(pair.fine_shape) & SOLID) == 0)]
fresh = (r.initial_state(pair.coarse_shape, (0.0, 0.0), 1.0, root=True),
r.initial_state(pair.fine_shape, pair.fine_origin, 0.5))
print(json.dumps(dict(status="CONSTRUCTED", case="refined")), flush=True)
for repeat in range(a.repeats):
for variant in VARIANTS:
t.check_deadline(deadline)
backend.initialize(*fresh)
for _ in range(a.warmup_base_steps):
backend.step(1)
warm = t.refined_health(backend, masks)
if repeat == 0 and variant == "A":
print(json.dumps(dict(status="WARM_READY", case="refined")), flush=True)
t.sync_refined(backend)
start = time.perf_counter()
totals, scales = run_variant(backend, variant, n_intervals, deadline)
t.sync_refined(backend)
seconds = time.perf_counter() - start
end = t.refined_health(backend, masks)
values = [np.array(v, copy=True) for v in backend._download_raw().values]
if variant == "A" and repeat == 0:
ref.update(values=values, totals=totals, scales=scales)
parity, ratio = "identical", 0.0
else:
parity = t.same_state(ref["values"], values) or "identical"
ratio = compare_intervals(ref["totals"], ref["scales"], totals)
rows.append(dict(variant=variant, repeat=repeat, seconds=seconds,
intervals=n_intervals, population_parity_vs_A=parity,
interval_impulse_violation_ratio=ratio,
health_after_warmup=warm, health_after_window=end))
if parity != "identical" or not ratio <= 1:
raise RuntimeError(f"{variant} repeat {repeat}: parity {parity}, impulse ratio {ratio}")
summary = {v: dict(median_seconds=statistics.median(x["seconds"] for x in rows if x["variant"] == v),
seconds=[x["seconds"] for x in rows if x["variant"] == v]) for v in VARIANTS}
summary.update(W_over_A=summary["W"]["median_seconds"] / summary["A"]["median_seconds"],
W1_over_A=summary["W1"]["median_seconds"] / summary["A"]["median_seconds"],
interpretation="Measured comparative timings under GPU variability; W also "
"batches step calls, W1 isolates the read pattern. Not a "
"benchmark-throughput or causal claim.")
(a.output / "window_timing.json").write_text(json.dumps(dict(plan=plan, rows=rows, summary=summary),
indent=2))
print(json.dumps(summary, indent=2), flush=True)
return 0
if __name__ == "__main__":
sys.exit(main())
@@ -1,12 +0,0 @@
unittest.case.FunctionTestCase (test_bounded_state_evidence) ... ok
unittest.case.FunctionTestCase (test_disjoint_complete_categories) ... ok
unittest.case.FunctionTestCase (test_exact_config_and_source) ... ok
unittest.case.FunctionTestCase (test_inactive_nonfinite_does_not_fail) ... ok
unittest.case.FunctionTestCase (test_original_safety_limits) ... ok
unittest.case.FunctionTestCase (test_population_macro_force_separate) ... ok
unittest.case.FunctionTestCase (test_source_guard_and_deadline) ... ok
----------------------------------------------------------------------
Ran 7 tests in 0.039s
OK
@@ -1,219 +0,0 @@
"""Read-only observations of the exact failed SRT control, at most 320 steps.
Default is CPU preflight. Execution requires root admission and an external watchdog.
No solver, initialization, geometry or numerical parameter modifications.
"""
import argparse
import hashlib
import importlib
import json
import math
import os
from pathlib import Path
import sys
import time
from tempfile import TemporaryDirectory
import numpy as np
HERE=Path(__file__).resolve().parent
DEFAULT_SOURCE=HERE.parents[2]
LIMIT_BYTES=128*1024**2
def dump(path,value):
path.write_text(json.dumps(value,indent=2,allow_nan=False))
def number(value):
value=float(value)
return value if math.isfinite(value) else ('NaN' if math.isnan(value) else ('+Inf' if value>0 else '-Inf'))
def source_config(source):
manifest=json.loads((HERE/'source_manifest.json').read_text())
for name,digest in manifest['sha256'].items():
if hashlib.sha256((source/name).read_bytes()).hexdigest()!=digest:
raise ValueError('Pinned source mismatch: '+name)
sys.path.insert(0,str(source/'src')); sys.path.insert(0,str(source/'tests/validation'))
import CelerisLab
if Path(CelerisLab.__file__).resolve()!=source/'src/CelerisLab/__init__.py':
raise ValueError('Wrong CelerisLab import')
runner=importlib.import_module('run_refined_dfg')
if Path(runner.__file__).resolve()!=source/'tests/validation/run_refined_dfg.py':
raise ValueError('Wrong runner import')
h,_=runner.helpers(source)
cfg,body,p=runner.config(h,80) # Exact original config factory, not a reimplementation.
return cfg,body,p,manifest
def categories(flags,p):
"""Disjoint physical categories; subtype nibble is not a bitfield."""
from CelerisLab.lbm.descriptors import FLUID,SOLID,OBSTACLE
y,x=np.indices(flags.shape); fluid=(flags&FLUID)!=0
masks={}; left=fluid.copy()
for name,test in (
('body_near',(x-p['center'][0])**2+(y-p['center'][1])**2 <= (p['radius']+3)**2),
('outlet_near',x>=flags.shape[1]-4),('inlet_near',x<=3),
('wall_near',(y<=3)|(y>=flags.shape[0]-4))):
masks[name]=left&test; left &= ~test
masks['bulk']=left
subtype=flags&0xf0
masks['inlet_ghost']=(~fluid)&(subtype==0x20)
masks['outlet_ghost']=(~fluid)&(subtype==0x30)
masks['wall_ghost']=(~fluid)&(subtype==0x10)
assigned=np.logical_or.reduce(list(masks.values()))
masks['body_solid']=(~assigned)&(((flags&OBSTACLE)!=0)|((flags&SOLID)!=0))
assigned|=masks['body_solid']; masks['other_inactive']=~assigned
return fluid,masks
def finite_extrema(a,mask):
good=mask&np.isfinite(a)
if not good.any(): return dict(min=None,max=None)
idx=np.flatnonzero(good); values=a.ravel()[idx]
lo=int(idx[np.argmin(values)]); hi=int(idx[np.argmax(values)])
return dict(min=float(a.ravel()[lo]),max=float(a.ravel()[hi]),
min_yx=list(map(int,np.unravel_index(lo,a.shape))),
max_yx=list(map(int,np.unravel_index(hi,a.shape))))
def diagnose(g,macro,force,flags,p,step):
fluid,masks=categories(flags,p)
badpop=~np.isfinite(g); badnode=badpop.any(axis=0)
badmacro=np.logical_or.reduce([~np.isfinite(macro[k]) for k in ('rho','ux','uy')])
with np.errstate(over='ignore',invalid='ignore'):
mach=np.sqrt(3*(np.asarray(macro['ux'],np.float64)**2+np.asarray(macro['uy'],np.float64)**2))
rho=macro['rho']
# Exactly the original physical macro/reaction conditions, now sampled each step.
nonfinite_macro=bool(np.any(badmacro&fluid))
force_bad=force is not None and not np.isfinite(force).all()
density_bad=bool(np.any(fluid&((rho<.5)|(rho>1.5))))
mach_bad=bool(np.any(fluid&(mach>.2)))
population_bad=bool(np.any(badnode&fluid))
original_failure=nonfinite_macro or force_bad or density_bad or mach_bad
offending=fluid&(badnode|badmacro|(rho<.5)|(rho>1.5)|(mach>.2))
examples=[]
for y,x in np.argwhere(offending)[:16]:
examples.append(dict(y=int(y),x=int(x),physical_xy_m=[float(x*p['dx']),float((y-.5)*p['dx'])],
category=next(name for name,mask in masks.items() if mask[y,x]),flag=int(flags[y,x]),
nonfinite_q=np.flatnonzero(badpop[:,y,x]).tolist(),
populations=[number(v) for v in g[:,y,x]],
rho=number(rho[y,x]),ux=number(macro['ux'][y,x]),uy=number(macro['uy'][y,x])))
neighborhoods=[]
for node in examples[:4]:
y,x=node['y'],node['x']; y0,y1=max(0,y-2),min(flags.shape[0],y+3); x0,x1=max(0,x-2),min(flags.shape[1],x+3)
neighborhoods.append(dict(bounds_xy=[x0,y0,x1,y1],flags=flags[y0:y1,x0:x1].tolist(),
physical_populations=[[[number(v) for v in row] for row in plane] for plane in g[:,y0:y1,x0:x1]]))
return dict(step=step,tstar=step*p['mean_speed']/p['diameter'],
physical_failure=bool(original_failure or population_bad),
original_health_failure=bool(original_failure),
physical_population_nonfinite=population_bad,physical_macro_nonfinite=nonfinite_macro,
force_nonfinite=bool(force_bad),density_limit=density_bad,mach_limit=mach_bad,
force=None if force is None else [number(v) for v in force],
categories={name:dict(nodes=int(mask.sum()),nonfinite_population_nodes=int((mask&badnode).sum()),
nonfinite_populations=int(badpop[:,mask].sum()),nonfinite_macro_nodes=int((mask&badmacro).sum()))
for name,mask in masks.items()},
rho=finite_extrema(rho,fluid),mach=finite_extrema(mach,fluid),
first_physical_examples=examples,local_neighborhoods=neighborhoods)
def snapshot(sim,p):
# Public physical decode and original production macro path. No host reconstruction
# substitutes for the original health check. get_ddf shares its completed-step cache.
with np.errstate(all='ignore'):
macro={k:np.asarray(v).copy() for k,v in sim.get_macroscopic().items()}
g=sim.get_ddf().reshape(9,p['ny'],p['nx'])
import pycuda.driver as cuda
raw=np.empty_like(g,dtype=np.float32)
with sim.ctx.activate():
cuda.memcpy_dtoh(raw,sim.field.ddf_gpu)
return dict(raw=raw,g=g,macro=macro,step=int(sim.stepper.step_count))
def save_states(dest,previous,current,flags,diagnostic):
"""Two states only; raw shifted bits and decoded observations, no trajectory."""
arrays={'flags':flags}
for name,state in (('previous',previous),('current',current)):
if state is None: continue
arrays[name+'_raw_shifted']=state['raw']
arrays[name+'_physical']=state['g']
arrays[name+'_step']=np.array(state['step'],np.int64)
# At D80, raw+physical for two states ~84 MiB; reserve >4 MiB for JSON/NPZ overhead.
if sum(v.nbytes for v in arrays.values())>LIMIT_BYTES-4*1024**2:
raise ValueError('Evidence arrays exceed bounded artifact budget')
np.savez(dest/'states.npz',**arrays)
dump(dest/'diagnostics.json',diagnostic)
size=sum(p.stat().st_size for p in dest.iterdir() if p.is_file())
if size>LIMIT_BYTES: raise RuntimeError('Evidence directory exceeds 128 MiB')
return size
def deadline_check(deadline):
if time.monotonic()>=deadline: raise TimeoutError('Diagnostic wall ceiling reached')
def execute(a,cfg,body,p):
from CelerisLab.simulation import Simulation
started=time.monotonic(); deadline=started+a.wall_seconds
previous=None; prior_report=None; initial_report=None
with TemporaryDirectory() as temp:
temp=Path(temp); dump(temp/'lbm.json',cfg); dump(temp/'body.json',body)
with Simulation(str(temp/'lbm.json'),str(temp/'body.json'),device_id=0) as sim:
sim.initialize() # Exact original production initialization, unchanged.
flags=sim.get_flags().reshape(p['ny'],p['nx'])
current=snapshot(sim,p)
initial_report=diagnose(current['g'],current['macro'],None,flags,p,0)
report=initial_report; status='initial_physical_failure' if report['physical_failure'] else 'step_cap_reached'
try:
deadline_check(deadline)
if not report['physical_failure']:
for _ in range(320):
deadline_check(deadline)
previous=current; prior_report=report
sim.run(1) # Same solver; observation buffers reset/read once per step.
force=sim.read_force(0).astype(np.float64)
current=snapshot(sim,p)
report=diagnose(current['g'],current['macro'],force,flags,p,current['step'])
if current['step']==1:
print('READY '+json.dumps(dict(step=1,all_observation_paths_exercised=True,
physical_healthy=not report['physical_failure']),allow_nan=False),flush=True)
if report['physical_failure']:
status='first_physical_failure'; break
deadline_check(deadline)
except TimeoutError:
status='wall_time_limit'
details=dict(status=status,executed_steps=int(sim.stepper.step_count),
observation_step=current['step'],previous_observation_step=None if previous is None else previous['step'],
initial=initial_report,preceding=prior_report,current=report,
wall_seconds=time.monotonic()-started,
storage='raw_shifted FP32 is exact active-buffer data; physical is production FP32 decoded G. Both are diagnostic snapshots, not complete restart checkpoints.',
health_scope='Physical FLUID nodes and force only; ghost/body categories cannot independently trigger physical failure.',
interpretation='Near-region labels locate symptoms, not the root cause. Per-step inspection changes observation cadence only. No physical acceptance.')
size=save_states(a.output,previous,current,flags,details)
print(json.dumps(dict(status=status,executed_steps=int(sim.stepper.step_count),evidence_bytes=size),allow_nan=False),flush=True)
return 0 if status=='step_cap_reached' else 2
def main():
parser=argparse.ArgumentParser(description=__doc__)
parser.add_argument('--source',type=Path,default=DEFAULT_SOURCE)
parser.add_argument('--output',type=Path,required=True)
parser.add_argument('--execute',action='store_true')
parser.add_argument('--gpu-admitted',action='store_true')
parser.add_argument('--wall-seconds',type=float)
a=parser.parse_args(); a.source=a.source.resolve()
cfg,body,p,manifest=source_config(a.source)
if a.output.exists() and any(a.output.iterdir()): raise ValueError('Use a new/empty output directory')
if a.execute and (not a.gpu_admitted or not os.environ.get('CUDA_VISIBLE_DEVICES') or
a.wall_seconds is None or not math.isfinite(a.wall_seconds) or a.wall_seconds<=0):
raise ValueError('Explicit root admission, device selection and finite wall ceiling required')
a.output.mkdir(parents=True,exist_ok=True)
dump(a.output/'preflight.json',dict(source=manifest,config=cfg,body=body,parameters=p,
diagnostic_sha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),max_steps=320,
max_evidence_bytes=LIMIT_BYTES,executed=False))
if not a.execute: return 0
return execute(a,cfg,body,p)
if __name__=='__main__': raise SystemExit(main())
@@ -1,100 +0,0 @@
"""CPU-only synthetic diagnostic and source-contract tests; no simulation results."""
import json
from pathlib import Path
import sys
from tempfile import TemporaryDirectory
import unittest
import numpy as np
sys.path.insert(0,str(Path(__file__).resolve().parent))
import diagnose_uniform_srt as d
cfg,body,p,manifest=d.source_config(d.DEFAULT_SOURCE)
def fixture():
flags=np.ones((12,20),np.uint16)
flags[:,0]=2|0x20; flags[:,-1]=2|0x30
flags[[0,-1]]=2|0x10; flags[5,6]=2|0x40|0x200
g=np.full((9,12,20),1/9,np.float32)
macro=dict(rho=np.ones((12,20)),ux=np.zeros((12,20)),uy=np.zeros((12,20)))
params=dict(center=[6,5],radius=1,dx=.1,mean_speed=.01,diameter=80)
return g,macro,flags,params
def test_exact_config_and_source():
assert manifest['commit']=='9805383f9c50d867e8555471baf5dbda8333a652'
assert p['diameter']==80 and p['mean_speed']==.01 and p['nx']==1761 and p['ny']==330
assert cfg['method']['collision']=='SRT' and cfg['method']['ddf_shifting']
assert cfg['method']['outlet']['srt_neq_damp']==.5
assert np.isclose(3*p['viscosity']+.5,.524)
assert body['objects'][0]['center']==[160,160.5]
def test_inactive_nonfinite_does_not_fail():
g,m,f,p=fixture(); fluid,_=d.categories(f,p)
g[:,~fluid]=np.nan
for a in m.values(): a[~fluid]=np.nan
r=d.diagnose(g,m,np.zeros(2),f,p,1)
assert not r['physical_failure']
assert r['categories']['body_solid']['nonfinite_population_nodes']==1
assert r['categories']['outlet_ghost']['nodes']==10
assert r['categories']['inlet_ghost']['nodes']==10
json.dumps(r,allow_nan=False)
def test_population_macro_force_separate():
g,m,f,p=fixture(); g[4,6,17]=np.inf
r=d.diagnose(g,m,np.zeros(2),f,p,27)
assert r['physical_failure'] and r['physical_population_nonfinite']
assert not r['original_health_failure'] and not r['force_nonfinite']
assert r['first_physical_examples'][0]['category']=='outlet_near'
assert r['first_physical_examples'][0]['nonfinite_q']==[4]
assert r['first_physical_examples'][0]['populations'][4]=='+Inf'
json.dumps(r,allow_nan=False)
g,m,f,p=fixture(); m['ux'][6,10]=np.nan
r=d.diagnose(g,m,np.zeros(2),f,p,28)
assert r['physical_macro_nonfinite'] and not r['physical_population_nonfinite']
assert not r['force_nonfinite'] and r['original_health_failure']
g,m,f,p=fixture(); r=d.diagnose(g,m,np.array([np.nan,0]),f,p,29)
assert r['force_nonfinite'] and not r['physical_macro_nonfinite']
assert not r['first_physical_examples']
def test_original_safety_limits():
g,m,f,p=fixture(); m['rho'][5,7]=.49
r=d.diagnose(g,m,[0,0],f,p,1)
assert r['density_limit'] and r['first_physical_examples'][0]['category']=='body_near'
g,m,f,p=fixture(); m['ux'][6,10]=.2
assert d.diagnose(g,m,[0,0],f,p,1)['mach_limit']
def test_disjoint_complete_categories():
_,_,f,p=fixture(); fluid,masks=d.categories(f,p)
np.testing.assert_array_equal(sum(mask.astype(int) for mask in masks.values()),np.ones(f.shape))
physical=sum(masks[k].astype(int) for k in ('body_near','inlet_near','outlet_near','wall_near','bulk'))
np.testing.assert_array_equal(physical,fluid.astype(int))
def test_bounded_state_evidence():
g,m,f,p=fixture(); state=dict(raw=g.copy(),g=g,macro=m,step=1)
with TemporaryDirectory() as tmp:
dest=Path(tmp); size=d.save_states(dest,state,state,f,{'status':'synthetic_test'})
assert size<d.LIMIT_BYTES
with np.load(dest/'states.npz') as saved:
np.testing.assert_array_equal(saved['previous_raw_shifted'],g)
np.testing.assert_array_equal(saved['current_physical'],g)
assert sorted(x.name for x in dest.iterdir())==['diagnostics.json','states.npz']
actual_bytes=4*(9*330*1761*4)+(330*1761*2)+16
assert actual_bytes<d.LIMIT_BYTES-4*1024**2
def test_source_guard_and_deadline():
with TemporaryDirectory() as tmp:
with unittest.TestCase().assertRaises((ValueError,FileNotFoundError)):
d.source_config(Path(tmp))
with unittest.TestCase().assertRaises(TimeoutError): d.deadline_check(0)
if __name__=='__main__':
result=unittest.TextTestRunner(verbosity=2).run(unittest.TestSuite(
unittest.FunctionTestCase(fn) for name,fn in sorted(globals().items()) if name.startswith('test_')))
raise SystemExit(not result.wasSuccessful())
-12
View File
@@ -1,12 +0,0 @@
CelerisLab reviewed scalar evidence,2026-10-18.
The two archives are intact originals. SHA256 and exact sizes are in transport_manifest.json.
Equilibrium comparator92da2e8:exit0,2400000steps healthy;ascending-zero v2 qualification passes. Frozen result.json remains periodic=false/accuracy_qualified=false;qualification_v2.json is separate and binds both original receipts.
Shifted/unshifted tiny e8b8c58:exit0,23methods pass,one N64 interval each mode only;no shifted full-N64 trajectory.
No production/default/dev/main change.
Both archives retain all their original member bytes,including gzip protection inventories. Metadata were scanned for credentials/private keys/access tokens and unrelated private paths. Only the authorized CelerisLab project/interpreter/system metadata and a reviewed literal official-reference fixture path were found. No credentials or unrelated private paths.
Original larger archives,all scientific receipts and any successful Drive transfers are retained. This single existing-validation-branch commit is evidence transport only.
CPU covered-predictor pair5468695:44tests pass;one FP64 raw/stress pair exit0;raw4samples exact to07879bc;both unchanged campaign/comparative/conservation screens pass,historical uniform pressure budget fails separately for both.No GPU pin or production/default/main/dev merge.
@@ -1,505 +0,0 @@
{
"utc": "2026-10-18T23:44:13.848348+00:00",
"status": "REMOTE_DEV_INTEGRATED_AND_BOUNDED_CLEANUP_COMPLETE",
"integration": {
"utc": "2026-10-18T23:41:22.351573+00:00",
"status": "remote_dev_fast_forward_confirmed",
"candidate": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"local_dev_preserved": "f75d543586315b6272cfdf23046aa7d4550f5fbe",
"local_dev_not_ancestor_of_remote_baseline": true,
"remote_before": {
"refs/heads/claude/dense-jet-validation": "17f3f11007de0df8f5b03e05f5ef0477cb2edb4d",
"refs/heads/claude/jet-condition": "fbf6f1d1224f19a42dae4630a74c6aad845134a3",
"refs/heads/claude/les-normalization": "5465832fe5617e1685b0f48926b14065fdf84491",
"refs/heads/claude/projected-explosion": "519473a61c7b319183aa54e55b9f097499dde0bf",
"refs/heads/claude/refinement-mrt": "aceea293a3ad3ba4b6b8de0c21c1ed4413efece1",
"refs/heads/claude/smoke-test": "5ad4995f89f7db30db9f6c10321194aa9abbc68c",
"refs/heads/claude/window-dfg-runner": "185a919cc5b1e00d2ea98f3a9ae53916e5056120",
"refs/heads/dev": "ed9d8c937d446b854d6963bd92d718bb4fb98b96",
"refs/heads/main": "eeda651626dbbc4d9fb2695ad069898b0bbcd5ab",
"refs/heads/tron/full9-inlet": "2359605b7aae694851671f3229aaa83b783f5856",
"refs/heads/tron/multigrid-usage": "f75d543586315b6272cfdf23046aa7d4550f5fbe",
"refs/heads/tron/spacetime-coupling": "f287b460fd06125cf83294e4bd8cd8f7bf3230e3",
"refs/heads/tron/validation-2d": "e81a103f3007e9bc86a0c29dcf73c35af0ed4f39"
},
"remote_after": {
"refs/heads/claude/dense-jet-validation": "17f3f11007de0df8f5b03e05f5ef0477cb2edb4d",
"refs/heads/claude/jet-condition": "fbf6f1d1224f19a42dae4630a74c6aad845134a3",
"refs/heads/claude/les-normalization": "5465832fe5617e1685b0f48926b14065fdf84491",
"refs/heads/claude/projected-explosion": "519473a61c7b319183aa54e55b9f097499dde0bf",
"refs/heads/claude/refinement-mrt": "aceea293a3ad3ba4b6b8de0c21c1ed4413efece1",
"refs/heads/claude/smoke-test": "5ad4995f89f7db30db9f6c10321194aa9abbc68c",
"refs/heads/claude/window-dfg-runner": "185a919cc5b1e00d2ea98f3a9ae53916e5056120",
"refs/heads/dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"refs/heads/main": "eeda651626dbbc4d9fb2695ad069898b0bbcd5ab",
"refs/heads/tron/full9-inlet": "2359605b7aae694851671f3229aaa83b783f5856",
"refs/heads/tron/multigrid-usage": "f75d543586315b6272cfdf23046aa7d4550f5fbe",
"refs/heads/tron/spacetime-coupling": "f287b460fd06125cf83294e4bd8cd8f7bf3230e3",
"refs/heads/tron/validation-2d": "e81a103f3007e9bc86a0c29dcf73c35af0ed4f39"
},
"push_exit": 0,
"checks": {
"remote_exact": true,
"remote_dev_exact": true,
"main_unchanged": true,
"all_local_worktrees_unchanged": true,
"local_dev_checkout_and_branch_preserved": true,
"root_index_unchanged": true,
"all_local_branches_tags_preserved": true,
"candidate_clean_exact": true
},
"source_scope": {
"chain": [
"ed9d8c937d446b854d6963bd92d718bb4fb98b96",
"a135252ae78b47b57d7e77d19001700b3bedac8b",
"1aa8110ec8caf04350638d2e07361ce72ba5d22e",
"2cf9853952e52f59bea63cf5c1d3a1cd76e53eed",
"eec4677db1308e2a9ce4e5f195c994356c11de13"
],
"production_src_tree": "f262316529a99eb922813212d0fbb0c6fb385590",
"constant_default": "constant",
"files": [
"docs/development/projected_pair_explosion.md",
"src/CelerisLab/lbm/kernels/blocks.cu",
"src/CelerisLab/lbm/refinement_stepper.py",
"src/CelerisLab/lbm/refinement_tables.py",
"tests/unit/test_les_flow_runner.py",
"tests/unit/test_projected_explosion.py",
"tests/unit/test_projected_pair_gate.py",
"tests/unit/test_projected_pair_stepper.py",
"tests/validation/data/les_flow/source_pins_a135252.json",
"tests/validation/multigrid/check_projected_pairs.py",
"tests/validation/run_uniform_les_flow.py",
"tests/validation/taylor_green/assess_projected_pairs.py",
"tests/validation/taylor_green/run_case.py",
"tests/validation/taylor_green/test_projected_pairs.py"
],
"diff_stat": " docs/development/projected_pair_explosion.md | 57 +++\n src/CelerisLab/lbm/kernels/blocks.cu | 33 ++\n src/CelerisLab/lbm/refinement_stepper.py | 29 +-\n src/CelerisLab/lbm/refinement_tables.py | 44 +++\n tests/unit/test_les_flow_runner.py | 57 ++-\n tests/unit/test_projected_explosion.py | 394 +++++++++++++++++++\n tests/unit/test_projected_pair_gate.py | 162 ++++++++\n tests/unit/test_projected_pair_stepper.py | 198 ++++++++++\n .../data/les_flow/source_pins_a135252.json | 110 ++++++\n .../validation/multigrid/check_projected_pairs.py | 425 ++++++++++++++++++++\n tests/validation/run_uniform_les_flow.py | 10 +-\n .../taylor_green/assess_projected_pairs.py | 208 ++++++++++\n tests/validation/taylor_green/run_case.py | 155 +++++++-\n .../taylor_green/test_projected_pairs.py | 434 +++++++++++++++++++++\n 14 files changed, 2269 insertions(+), 47 deletions(-)\n"
},
"remote_commit_tree": "7952cba5b8383712bbafdcc98cbdcd2b4111123d",
"remote_src_tree": "f262316529a99eb922813212d0fbb0c6fb385590"
},
"cleanup": {
"utc": "2026-10-18T23:42:13.216523+00:00",
"removed": [
{
"path": "/home/frank14f/CelerisLab/output/review-jet-063508d-20261015",
"commit": "063508d1a3440c1311c3a7e6eb1a2b83e12a2092",
"tree": "746f07e1aae0de9744e9dcb2dae185577bbacacc",
"tracked_files": 440,
"source_bytes": 9233268,
"allocated_bytes": 10534912,
"management_bytes": 81920,
"reflog_commits": [
"063508d1a3440c1311c3a7e6eb1a2b83e12a2092"
],
"recoverable_via_remote_dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"clean": true,
"untracked_or_ignored_files": 0,
"command": [
"git",
"-c",
"gc.auto=0",
"-c",
"maintenance.auto=false",
"-C",
"/home/frank14f/CelerisLab",
"worktree",
"remove",
"/home/frank14f/CelerisLab/output/review-jet-063508d-20261015"
],
"exit": 0,
"stdout": "",
"stderr": "",
"recovery_map": "review-jet-063508d-20261015_recovery.json.gz",
"recovery_map_sha256": "8805598e9274f7f2e1cd1dbb75aca1cecae2412a44e18e221e5e0a75606dbccc"
},
{
"path": "/home/frank14f/CelerisLab/output/review-jet-19bd308-20261015",
"commit": "19bd3088ef30e3193402e921c387b50c81ddbd45",
"tree": "c1d6203d02404798c597ad2c3755b112d3db6226",
"tracked_files": 440,
"source_bytes": 9234697,
"allocated_bytes": 10534912,
"management_bytes": 81920,
"reflog_commits": [
"19bd3088ef30e3193402e921c387b50c81ddbd45"
],
"recoverable_via_remote_dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"clean": true,
"untracked_or_ignored_files": 0,
"command": [
"git",
"-c",
"gc.auto=0",
"-c",
"maintenance.auto=false",
"-C",
"/home/frank14f/CelerisLab",
"worktree",
"remove",
"/home/frank14f/CelerisLab/output/review-jet-19bd308-20261015"
],
"exit": 0,
"stdout": "",
"stderr": "",
"recovery_map": "review-jet-19bd308-20261015_recovery.json.gz",
"recovery_map_sha256": "a83afe1b0900963d9ad7b94f4260a6e55b45e1fd6410b5c09976f0ead96bd5c6"
},
{
"path": "/home/frank14f/CelerisLab/output/review-jet-508d412-20261015",
"commit": "508d412e43aff7a27cba2a60255ebf2500fdfb18",
"tree": "4b0189adf5480e3f757193e0d660df3a318fadad",
"tracked_files": 440,
"source_bytes": 9230649,
"allocated_bytes": 10530816,
"management_bytes": 81920,
"reflog_commits": [
"508d412e43aff7a27cba2a60255ebf2500fdfb18"
],
"recoverable_via_remote_dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"clean": true,
"untracked_or_ignored_files": 0,
"command": [
"git",
"-c",
"gc.auto=0",
"-c",
"maintenance.auto=false",
"-C",
"/home/frank14f/CelerisLab",
"worktree",
"remove",
"/home/frank14f/CelerisLab/output/review-jet-508d412-20261015"
],
"exit": 0,
"stdout": "",
"stderr": "",
"recovery_map": "review-jet-508d412-20261015_recovery.json.gz",
"recovery_map_sha256": "41bd6140c7058cb492f801671ddd3e293127dad0c66d4d1ee0df1c50788d4f3e"
},
{
"path": "/home/frank14f/CelerisLab/output/review-jet-62c525e-20261015",
"commit": "62c525e73532a974663be2e112af671fa868b972",
"tree": "0152729f4898295c508def8360b415fe147ee57b",
"tracked_files": 437,
"source_bytes": 9194520,
"allocated_bytes": 10489856,
"management_bytes": 81920,
"reflog_commits": [
"62c525e73532a974663be2e112af671fa868b972"
],
"recoverable_via_remote_dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"clean": true,
"untracked_or_ignored_files": 0,
"command": [
"git",
"-c",
"gc.auto=0",
"-c",
"maintenance.auto=false",
"-C",
"/home/frank14f/CelerisLab",
"worktree",
"remove",
"/home/frank14f/CelerisLab/output/review-jet-62c525e-20261015"
],
"exit": 0,
"stdout": "",
"stderr": "",
"recovery_map": "review-jet-62c525e-20261015_recovery.json.gz",
"recovery_map_sha256": "a06d4f65f1ed3002bbef0bf21786741276cf0a4a09888238354bf2aab8ae4722"
},
{
"path": "/home/frank14f/CelerisLab/output/review-jet-f1e0342-20261015",
"commit": "f1e03423f336bfdf120e5f2ee5c949fded17130c",
"tree": "3b6106280809096d1dfb73037894d0846f2572ce",
"tracked_files": 440,
"source_bytes": 9237148,
"allocated_bytes": 10534912,
"management_bytes": 81920,
"reflog_commits": [
"f1e03423f336bfdf120e5f2ee5c949fded17130c"
],
"recoverable_via_remote_dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"clean": true,
"untracked_or_ignored_files": 0,
"command": [
"git",
"-c",
"gc.auto=0",
"-c",
"maintenance.auto=false",
"-C",
"/home/frank14f/CelerisLab",
"worktree",
"remove",
"/home/frank14f/CelerisLab/output/review-jet-f1e0342-20261015"
],
"exit": 0,
"stdout": "",
"stderr": "",
"recovery_map": "review-jet-f1e0342-20261015_recovery.json.gz",
"recovery_map_sha256": "1444f7ca5825ce490660f38be89be0331f57a87a26828f9f25eaa123f3a93683"
},
{
"path": "/home/frank14f/CelerisLab/output/review-jet-99ddb5f-20261016",
"commit": "99ddb5fc27e5a2c52bd27312981e34e6be98883b",
"tree": "d616e328a0afee4e2832fc7999852306205f761e",
"tracked_files": 440,
"source_bytes": 9242940,
"allocated_bytes": 10539008,
"management_bytes": 81920,
"reflog_commits": [
"99ddb5fc27e5a2c52bd27312981e34e6be98883b"
],
"recoverable_via_remote_dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"clean": true,
"untracked_or_ignored_files": 0,
"command": [
"git",
"-c",
"gc.auto=0",
"-c",
"maintenance.auto=false",
"-C",
"/home/frank14f/CelerisLab",
"worktree",
"remove",
"/home/frank14f/CelerisLab/output/review-jet-99ddb5f-20261016"
],
"exit": 0,
"stdout": "",
"stderr": "",
"recovery_map": "review-jet-99ddb5f-20261016_recovery.json.gz",
"recovery_map_sha256": "47bef4af7d27850a277603c5247ed9532534c90727e9870b8174ec38e45994ab"
}
],
"skipped": [],
"before_bytes": {
"output_bytes": 1867370496,
"git_management_bytes": 64847872,
"receipt_bytes": 5877760,
"total_bytes": 1932218368
},
"after_bytes": {
"output_bytes": 1805164544,
"git_management_bytes": 64356352,
"receipt_bytes": 6836224,
"total_bytes": 1869520896
},
"worktrees_before": 38,
"worktrees_after": 32,
"checks": {
"only_selected_worktrees_removed": true,
"remaining_worktrees_unchanged": true,
"all_refs_unchanged": true,
"branches_tags_root_index_remote_unchanged": true,
"all_source_object_files_preserved": true,
"all_scientific_evidence_files_preserved": true,
"untracked_and_ignored_user_files_preserved": true,
"dev_checkout_retained": true
},
"evidence_files": 10001,
"evidence_aggregate_sha256": "503dcd4dbd4514e577b09b761c66502d3f8c8e57ef1c7e12f46c0a24a6af0ea4",
"original_source_object_files": 2154,
"no_scientific_evidence_deleted": true,
"no_refs_or_source_history_pruned": true,
"no_environment_changes": true
},
"current_remote_heads": {
"refs/heads/claude/dense-jet-validation": "17f3f11007de0df8f5b03e05f5ef0477cb2edb4d",
"refs/heads/claude/jet-condition": "fbf6f1d1224f19a42dae4630a74c6aad845134a3",
"refs/heads/claude/les-normalization": "5465832fe5617e1685b0f48926b14065fdf84491",
"refs/heads/claude/projected-explosion": "519473a61c7b319183aa54e55b9f097499dde0bf",
"refs/heads/claude/refinement-mrt": "aceea293a3ad3ba4b6b8de0c21c1ed4413efece1",
"refs/heads/claude/smoke-test": "5ad4995f89f7db30db9f6c10321194aa9abbc68c",
"refs/heads/claude/window-dfg-runner": "185a919cc5b1e00d2ea98f3a9ae53916e5056120",
"refs/heads/dev": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"refs/heads/main": "eeda651626dbbc4d9fb2695ad069898b0bbcd5ab",
"refs/heads/tron/full9-inlet": "2359605b7aae694851671f3229aaa83b783f5856",
"refs/heads/tron/multigrid-usage": "f75d543586315b6272cfdf23046aa7d4550f5fbe",
"refs/heads/tron/spacetime-coupling": "f287b460fd06125cf83294e4bd8cd8f7bf3230e3",
"refs/heads/tron/validation-2d": "e81a103f3007e9bc86a0c29dcf73c35af0ed4f39"
},
"current_local_dev": {
"path": "/home/frank14f/CelerisLab/output/dev-worktree",
"commit": "f75d543586315b6272cfdf23046aa7d4550f5fbe",
"clean": true,
"preserved_reason": "f75d543 is not ancestor of remote ed9d8c9;no reset/unrelated local merge"
},
"constant_default": "constant",
"projected_eligibility": "explicit opt-in experimental scope unchanged",
"science_scope": {
"TG": "narrow four-case Re100 smooth-decay diagnostic only;projected PASS,constant relative velocity FAIL,aggregate false preserved",
"LES": "new named current profile resolves only introduced pin mismatches;uniform corrected regression only;Cs1 amplified diagnostic",
"unresolved_historical_issues": [
"channel.py Jet-CV mismatch",
"pre-existing optional dependency errors"
],
"no_new_GPU_or_tests": true
},
"preserved_original_archives": {
"projected-grid-11901a7-20261018/CelerisLab_projected_grid_11901a7_complete_20261018.zip": "c20e364e72b96858bf7bc317cba3d02a40e03be74ab1816048e78f7e89678f47",
"projected-pairs-gate-1aa8110-20261018/CelerisLab_projected_pair_gate_1aa8110_20261018.zip": "589a5537069cb7f10c6e349648aae2900b0af996b0dc1ac147a138581cb913e3",
"projected-pairs-tg-2cf9853-20261018/CelerisLab_projected_pairs_TG_2cf9853_20261018.zip": "d312bfd0175e5a79d1a28a595ba229a6d8435ba13e3b9058c409fcc9737cafc1",
"uniform-les-eec4677-20261018/CelerisLab_uniform_LES_eec4677_20261018.zip": "7b8e6951b24a8c2852387bc0a026e133c491931d97340056195a981fb51db879"
},
"proof_files": {
"cleanup.py": {
"bytes": 6513,
"sha256": "5b3db9f9d59b58be1ea9c4427ab06d1e2f41671d3a17245a97cb7979da6b6826"
},
"cleanup_activity_preflight.json": {
"bytes": 588,
"sha256": "51d0b5403b66980cb4d272bae498c4c71197634cd5c892877ca4ab351cf02a11"
},
"cleanup_after.json.gz": {
"bytes": 710267,
"sha256": "c897f2d61c04c1c2bcc955108d41538b277663ed1059e560bfe7ebf3d993fc00"
},
"cleanup_before.json.gz": {
"bytes": 834537,
"sha256": "12213622ee7b4ad2e48b32f3c0d1f8b676b362243430329781dc76a76908cc88"
},
"cleanup_result.json": {
"bytes": 7540,
"sha256": "d042619320d9c26ff92cd531cf4d4620dfc673aaacb3a10f892819beb790beb0"
},
"dev_push_result.json": {
"bytes": 333,
"sha256": "e6cb70eea47d92840ab2253cc3afc1fa842e3b08a4fc4b8c4fa8c62941f7fa3b"
},
"dev_push_started.json": {
"bytes": 1532,
"sha256": "0ff359e7153eaa44f53c9e6a4c61e336ce34a416d27db4fbb59e88d4db36502a"
},
"evidence_before.json.gz": {
"bytes": 470636,
"sha256": "f255aec46b524325c006427f809d83f2792f46aac35fe5e089a61e36ba38910b"
},
"gate_common.py": {
"bytes": 3086,
"sha256": "106688da96d6946cc7d86bcff9fba16ebebb1cb8ac6d84f083afdac51f44ae30"
},
"integrate.py": {
"bytes": 3831,
"sha256": "d25de325d395ef8f315f16bf5471c30776986239980037015ec761c375ed3687"
},
"integration_before.json.gz": {
"bytes": 834540,
"sha256": "38a1d639a3dd0be479ddb2959b4cdc9bcd1f28aff9153471e06aa96f44b9f020"
},
"integration_first_attempt_error.txt": {
"bytes": 747,
"sha256": "8af828b2e3f1deb96457fd52298f1cfec9b18351e714f6b35ffabcda89d1bb47"
},
"integration_result.json": {
"bytes": 5178,
"sha256": "3d8bb9f2ef761e0e94a1695d1b7a7aec02f724f837269922d4faf1c1d239b0ca"
},
"inventory.json": {
"bytes": 997138,
"sha256": "2865b1162bfd704c43bb8c108a7b0b75fc9df4709a0d75cb2195d9f71ada601b"
},
"inventory.py": {
"bytes": 2750,
"sha256": "78bed3f832fb245cf80e88e80864293242544726b2141a66f4ace6ee08f19547"
},
"management.py": {
"bytes": 4710,
"sha256": "3dbfadb0a13532d21282f2830269eb40398485be9063460fc87ff3414516b451"
},
"protected_extra_files.json.gz": {
"bytes": 19413,
"sha256": "4efcc18c5d028f38c761ba0ffcf949c793ef8e42aa80f4ba60bb2486944cf9e8"
},
"protection_before.json.gz": {
"bytes": 834539,
"sha256": "60a786d506e7dd3b94836541a601821fb26e4a5e68393fb23cc87a73d8c5669d"
},
"publish_receipt.py": {
"bytes": 2736,
"sha256": "5ed94713bdf9de11c8a0ce6b772c8ef3f025a7b4cc41f986d442ae3f80e7fa1b"
},
"publish_reviewed_dev.py": {
"bytes": 2817,
"sha256": "efb08358295f94a843047804866110d3de132ff2ea372c5c6f3641b3952a54e2"
},
"remote_only_integration_after.json.gz": {
"bytes": 834552,
"sha256": "2d2b125fcd1826be790ddecabdb27dec8851c84c0f46e23aa0e749407f6b4045"
},
"remote_only_integration_before.json.gz": {
"bytes": 834552,
"sha256": "0368c5f0c393a78474fa872950512c2b3db10b30277d2477056b1696782d8c4c"
},
"review-jet-063508d-20261015_recovery.json.gz": {
"bytes": 35325,
"sha256": "8805598e9274f7f2e1cd1dbb75aca1cecae2412a44e18e221e5e0a75606dbccc"
},
"review-jet-063508d-20261015_removal.json": {
"bytes": 942,
"sha256": "50381cd4a36e616fdcada15fe2508a3aa4cadfcca22d65ada15b66c8c9b01373"
},
"review-jet-19bd308-20261015_recovery.json.gz": {
"bytes": 35320,
"sha256": "a83afe1b0900963d9ad7b94f4260a6e55b45e1fd6410b5c09976f0ead96bd5c6"
},
"review-jet-19bd308-20261015_removal.json": {
"bytes": 942,
"sha256": "8fc1b317a8a16ae6325ada98201771834583891a8a81f5f440993441b1675bc0"
},
"review-jet-508d412-20261015_recovery.json.gz": {
"bytes": 35321,
"sha256": "41bd6140c7058cb492f801671ddd3e293127dad0c66d4d1ee0df1c50788d4f3e"
},
"review-jet-508d412-20261015_removal.json": {
"bytes": 942,
"sha256": "51610ededb9123dfb492e2802ff28f823ba1589a1bb56c675a1adf6e0dfe07af"
},
"review-jet-62c525e-20261015_recovery.json.gz": {
"bytes": 35026,
"sha256": "a06d4f65f1ed3002bbef0bf21786741276cf0a4a09888238354bf2aab8ae4722"
},
"review-jet-62c525e-20261015_removal.json": {
"bytes": 942,
"sha256": "cf62efc212a7211049ff2d5e338a29f838b741eebad7a23f756ee7d4c651de3f"
},
"review-jet-99ddb5f-20261016_recovery.json.gz": {
"bytes": 35321,
"sha256": "47bef4af7d27850a277603c5247ed9532534c90727e9870b8174ec38e45994ab"
},
"review-jet-99ddb5f-20261016_removal.json": {
"bytes": 942,
"sha256": "c2ef4fcf118fa0c0eb07ca48ad37c0fdcab50a85a2f7b53c1ccc9f1219fe1977"
},
"review-jet-f1e0342-20261015_recovery.json.gz": {
"bytes": 35320,
"sha256": "1444f7ca5825ce490660f38be89be0331f57a87a26828f9f25eaa123f3a93683"
},
"review-jet-f1e0342-20261015_removal.json": {
"bytes": 942,
"sha256": "00f9680a25e46a104e5eeb6dd42a762e9755964f4854d5312da51fa5c86d58e4"
},
"seal_receipt.py": {
"bytes": 4270,
"sha256": "3b71e9842c3f38a51fb359611dc5a4a1f5bfc389a997b8222f26ac02c808886a"
},
"source_objects_before.json.gz": {
"bytes": 144229,
"sha256": "b7eba34841f7cdb8b12718523233778ee241bd05a4cbdd2d3028e1dcc9d57bdf"
}
},
"final_prepublication_footprint": {
"output_bytes": 1805185024,
"git_management_bytes": 64356352,
"receipt_bytes": 6856704,
"total_bytes": 1869541376
},
"no_new_branch": true,
"no_force_push": true,
"no_GitHub_publication": true,
"no_source_history_pruning": true
}
@@ -1,13 +0,0 @@
Reviewed projected-pair chain integrated by ordinary fast-forward to Gitea dev.
Remote dev:eec4677db1308e2a9ce4e5f195c994356c11de13;main unchanged:eeda651626dbbc4d9fb2695ad069898b0bbcd5ab.
Commit source tree:f262316529a99eb922813212d0fbb0c6fb385590;constant default retained.
Local dev preserved clean atf75d543586315b6272cfdf23046aa7d4550f5fbe because it is not ancestor
of the remote baseline.No reset or unrelated local merge;all other local refs kept.
Six clean inactive detached Jet source copies removed only after exact Git-blob
recovery verification;all commits remain ancestors of remote dev.All source
objects,common refs,scientific evidence/original archives,user files/environments
and32 remaining worktrees preserved.Exact paths/commit IDs in JSON receipt.
No new GPU/test run.Historical TG constant failure/aggregatefalse,Jet-CV mismatch
and optional dependency issues kept separate from current LES pin resolution.
Full before/after inventories and per-file recovery maps remain at/home/frank14f/CelerisLab/output/dev-projected-integration-eec4677-20261018 with hashes.
Temporary footprint before this small receipt publication:1869541376bytes.
@@ -1,42 +0,0 @@
{
"files": {
"INTEGRATION_CLEANUP_RECEIPT.json": {
"bytes": 21807,
"sha256": "91e30b209c92ee6c117d78caba4c2a07d2b52979f25828e7613070d7eeb682a2"
},
"README.txt": {
"bytes": 1160,
"sha256": "83ddbac006c836319f7d7dcc54923a87a63ae6ba98b469e8a651aa473290b45b"
}
},
"candidate": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"source_scope": {
"chain": [
"ed9d8c937d446b854d6963bd92d718bb4fb98b96",
"a135252ae78b47b57d7e77d19001700b3bedac8b",
"1aa8110ec8caf04350638d2e07361ce72ba5d22e",
"2cf9853952e52f59bea63cf5c1d3a1cd76e53eed",
"eec4677db1308e2a9ce4e5f195c994356c11de13"
],
"production_src_tree": "f262316529a99eb922813212d0fbb0c6fb385590",
"constant_default": "constant",
"files": [
"docs/development/projected_pair_explosion.md",
"src/CelerisLab/lbm/kernels/blocks.cu",
"src/CelerisLab/lbm/refinement_stepper.py",
"src/CelerisLab/lbm/refinement_tables.py",
"tests/unit/test_les_flow_runner.py",
"tests/unit/test_projected_explosion.py",
"tests/unit/test_projected_pair_gate.py",
"tests/unit/test_projected_pair_stepper.py",
"tests/validation/data/les_flow/source_pins_a135252.json",
"tests/validation/multigrid/check_projected_pairs.py",
"tests/validation/run_uniform_les_flow.py",
"tests/validation/taylor_green/assess_projected_pairs.py",
"tests/validation/taylor_green/run_case.py",
"tests/validation/taylor_green/test_projected_pairs.py"
],
"diff_stat": " docs/development/projected_pair_explosion.md | 57 +++\n src/CelerisLab/lbm/kernels/blocks.cu | 33 ++\n src/CelerisLab/lbm/refinement_stepper.py | 29 +-\n src/CelerisLab/lbm/refinement_tables.py | 44 +++\n tests/unit/test_les_flow_runner.py | 57 ++-\n tests/unit/test_projected_explosion.py | 394 +++++++++++++++++++\n tests/unit/test_projected_pair_gate.py | 162 ++++++++\n tests/unit/test_projected_pair_stepper.py | 198 ++++++++++\n .../data/les_flow/source_pins_a135252.json | 110 ++++++\n .../validation/multigrid/check_projected_pairs.py | 425 ++++++++++++++++++++\n tests/validation/run_uniform_les_flow.py | 10 +-\n .../taylor_green/assess_projected_pairs.py | 208 ++++++++++\n tests/validation/taylor_green/run_case.py | 155 +++++++-\n .../taylor_green/test_projected_pairs.py | 434 +++++++++++++++++++++\n 14 files changed, 2269 insertions(+), 47 deletions(-)\n"
},
"original_archives_preserved": true
}
@@ -1,9 +0,0 @@
{
"archive": "CelerisLab_projected_grid_11901a7_complete_20261018.zip",
"bytes": 423726,
"sha256": "c20e364e72b96858bf7bc317cba3d02a40e03be74ab1816048e78f7e89678f47",
"source": "11901a7f77557a901e017a171eeae1758d584fa5",
"numerical_source": "519473a61c7b319183aa54e55b9f097499dde0bf",
"route": "ExistingGiteaevidencebranch fallback after explicitlyauthorized same-argumentDrive retry failed atOpenAI fileblob network transport;not an approval bypass",
"scope": "Evidence-only transport;no oldsource harness integration;all originalmember bytes retained"
}
@@ -1,6 +0,0 @@
Matched projected-G diagnostic onexact11901a7/519numerics.
Projected_linear passes allfrozen baselinegates;constantfailsvelocitygate;aggregatefails.
All fourcasecontrols valid;finestcontrols andearlypressuretransients reported separately.
Complete original receipts,failedattempts,recoveryauthorization,monitor drytests,source/build/PTX/runtime/protection records included.
No production/default change,convergence ornewalgorithm qualification.
ArchiveSHA256:c20e364e72b96858bf7bc317cba3d02a40e03be74ab1816048e78f7e89678f47
@@ -1,23 +0,0 @@
{
"archive": "CelerisLab_projected_pair_gate_1aa8110_20261018.zip",
"bytes": 4551692,
"sha256": "589a5537069cb7f10c6e349648aae2900b0af996b0dc1ac147a138581cb913e3",
"baseline": "ed9d8c937d446b854d6963bd92d718bb4fb98b96",
"candidate": "1aa8110ec8caf04350638d2e07361ce72ba5d22e",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"driver_sha256": "3dbaa6547cb0a4cb1541054f3b64ad8b6e18cc70527ac6166e56b944e9bd464a",
"route": "Authorized evidence-only fallback to existing Gitea branch after confirmed Drive blob transport failure",
"drive_failure": {
"action": "Drive upload of exact complete archive",
"folder_id": "1nMnnyD2UvwhdfNDHY_L1Bbn9LiDjr_WS",
"status": "confirmed_transport_failure",
"drive_file_id_returned": false,
"approval_denial": false,
"endpoint": "sdmntprcentralus.oaiusercontent.com",
"elapsed_ms": 216022,
"azure_client_request_id": "36a2db34-002d-432b-990c-66a228f87268",
"reason": "OpenAI file blob upload failed: error sending request",
"retry_attempted": false
},
"scope": "Complete original ZIP, no fragments; no source integration"
}
@@ -1,8 +0,0 @@
PASS: exact ed9d8c9 baseline versus exact 1aa8110 test-only candidate / a135252 production source.
Six host guards and both sequential GPU processes passed; 136.855 seconds total.
Six default bit-equivalence groups, six projected groups and two changed-remap groups passed.
112 actual compiler sidecars retained and source/config/PTX verified.
No production promotion/default change, main/dev update, LES re-pin or new conservation claim.
Complete original evidence in one ZIP; all 57 manifest payloads verified.
Drive blob ingress failed after 216022 ms before any Drive file ID; approved existing-branch fallback.
Archive SHA256: 589a5537069cb7f10c6e349648aae2900b0af996b0dc1ac147a138581cb913e3
@@ -1,24 +0,0 @@
{
"archive": "CelerisLab_projected_pairs_TG_2cf9853_20261018.zip",
"bytes": 4567931,
"sha256": "d312bfd0175e5a79d1a28a595ba229a6d8435ba13e3b9058c409fcc9737cafc1",
"candidate": "2cf9853952e52f59bea63cf5c1d3a1cd76e53eed",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_fingerprint": "a5dbfd804befce868067d79a23e5fd47dce7f505b3f9b1bb2145fb57cb5f2178",
"capture_helper_sha256": "3dbaa6547cb0a4cb1541054f3b64ad8b6e18cc70527ac6166e56b944e9bd464a",
"route": "Authorized evidence-only fallback to existing Gitea branch after confirmed Drive blob transport failure",
"drive_failure": {
"action": "Upload intact CelerisLab_projected_pairs_TG_2cf9853_20261018.zip",
"folder_id": "1nMnnyD2UvwhdfNDHY_L1Bbn9LiDjr_WS",
"status": "confirmed_transport_failure",
"drive_file_id_returned": false,
"approval_denial": false,
"endpoint": "sdmntprcentralus.oaiusercontent.com",
"elapsed_ms": 216449,
"azure_client_request_id": "2a1827d5-986d-4999-a920-9ea1bd63fba7",
"reason": "OpenAI file blob upload failed: error sending request",
"retry_attempted": false,
"archive_sha256": "d312bfd0175e5a79d1a28a595ba229a6d8435ba13e3b9058c409fcc9737cafc1"
},
"scope": "Complete original ZIP, no fragments; no source integration"
}
@@ -1,8 +0,0 @@
Exact2cf9853 generic projected-pair TG repeat / a135252 production source.
Four fresh cases and assessment completed,18.568578 seconds,589299712 active updates.
Projected_linear PASS;constant velocity relative gate FAIL;aggregate FALSE.
All absolute gates and case/control validity pass;all scalar samples identical to11901a7.
19 host tests and dry-run passed;initial external count assertion retained.
Six actual build sidecars/source/config/PTX verified;no tuning/default switch/source merge.
Complete intact ZIP with105manifest payloads;authorized existing Gitea evidence branch fallback.
Archive SHA256: d312bfd0175e5a79d1a28a595ba229a6d8435ba13e3b9058c409fcc9737cafc1
@@ -1,37 +0,0 @@
{
"archives": [
{
"name": "CelerisLab_equilibrium_DFG_92da2e8_complete_results_20261018.tar.xz",
"bytes": 637088,
"sha256": "f0d45630c7d72f795ceccfd60a49b29881530903aaeb7b0a655c549ad1b40cd4",
"credential_scan": "No credentials/private-key/access-token patterns,including decompressed protection inventories",
"metadata_paths": "Only explicitly authorized CelerisLab project,existing interpreter and system/ephemeral paths",
"source_fixture_literal": "/workspace/shared/dfg_research/20141124_dfg_bench2_official.zip",
"no_unrelated_private_paths": true,
"archive_bytes_unchanged": true,
"no_credentials_or_unrelated_private_paths": true,
"archive_member_bytes_preserved": true
},
{
"name": "CelerisLab_shifted_unshifted_tiny_e8b8c58_20261018.zip",
"bytes": 82506,
"sha256": "81e05cf4c606310c966f905864497f0254edb70c77b107a6e77af570c7c54efa",
"credential_scan": "No credentials/private-key/access-token patterns,including decompressed protection inventories",
"metadata_paths": "Only explicitly authorized CelerisLab project,existing interpreter and system/ephemeral paths",
"source_fixture_literal": null,
"no_unrelated_private_paths": true,
"archive_bytes_unchanged": true,
"no_credentials_or_unrelated_private_paths": true,
"archive_member_bytes_preserved": true
},
{
"name": "CelerisLab_FP64_predictor_pair_5468695_20261018.zip",
"bytes": 61110,
"sha256": "28b6ce8804e3c448f829ea3516f8dff893373c899eb6d7b0f6a1d0edf6ca772e",
"scope": "CPU scalar result only,source5468695 not merged into any GPU/production branch",
"no_credentials_or_unrelated_private_paths": true,
"archive_member_bytes_preserved": true
}
],
"scope": "Intact original archives,transport only via existing validation branch;original result and qualification hash bindings preserved"
}
@@ -1,30 +0,0 @@
{
"archive": "CelerisLab_uniform_LES_eec4677_20261018.zip",
"bytes": 4528905,
"sha256": "7b8e6951b24a8c2852387bc0a026e133c491931d97340056195a981fb51db879",
"candidate": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_fingerprint": "a5dbfd804befce868067d79a23e5fd47dce7f505b3f9b1bb2145fb57cb5f2178",
"capture_helper_sha256": "3dbaa6547cb0a4cb1541054f3b64ad8b6e18cc70527ac6166e56b944e9bd464a",
"route": "Authorized existing Gitea evidence branch fallback using documented current-session blob transport failures; no Drive submission for this archive",
"drive_failure": {
"status": "known_session_blob_transport_failure",
"approval_denial": false,
"this_archive_upload_attempted": false,
"basis": [
{
"archive": "CelerisLab_projected_pairs_TG_2cf9853_20261018.zip",
"status": "confirmed blob ingress transport failure",
"endpoint": "sdmntprcentralus.oaiusercontent.com",
"elapsed_ms": 216449,
"azure_client_request_id": "2a1827d5-986d-4999-a920-9ea1bd63fba7"
},
{
"archive": "CelerisLab_TG_2cf9853_REVIEW_SUBSET_20261018.zip",
"status": "MCP upload timeout,no ID returned,two folder lookups found no matches"
}
],
"current_archive_sha256": "7b8e6951b24a8c2852387bc0a026e133c491931d97340056195a981fb51db879"
},
"scope": "Complete original ZIP, no fragments; no source integration"
}
@@ -1,8 +0,0 @@
PASS: exacteec4677 existing uniform LES corrected regression / a135252 production source.
12 host runner/oracle checks and one actual corrected GPU run passed,exit0.
Three READY/reset records,DONEpassedtrue;Cs0/.16/1;6228 reported launches,10.535915seconds.
Manifest pins101 sources;historical profiles unchanged.Three actual build sidecars/PTX/source/config audits passed.
No baseline GPU,sweep,threshold/default/source integration changes;Cs1 amplified diagnostic only.
Complete intact archive with47manifest payloads;all original bytes verified.
Existing-session confirmed Drive blob failures used as authorized fallback basis;this archive not submitted to Drive.
Archive SHA256: 7b8e6951b24a8c2852387bc0a026e133c491931d97340056195a981fb51db879
@@ -1,22 +0,0 @@
{
"archive": "CelerisLab_axis_square_afa8f6a_20261019.zip",
"bytes": 170503,
"sha256": "e5348495e462973df35ab8675d456f024856397232010e276e132d5c21609c5c",
"candidate": "afa8f6aca10177d5901a9aeae650d3419212c6d0",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_branch": "tron/shear-probe-guards-caa573f",
"diagnostic": "axis_square_shear_n128",
"axis_module_sha256": "0baffa6eb99c268ce998d90300c993d45bb3b7b27c524b636874d75808bd0a8c",
"screening_pass": null,
"qualification_eligible": false,
"all_traces_complete": true,
"global_rows": 8,
"trace_times": 36,
"native_cell_time_triplets": 720,
"independently_verified_before_cleanup": true,
"matrix_assessor_run": false,
"late_fit_performed": false,
"physical_pass_claim": false,
"route": "Existing Gitea validation evidence branch",
"payload_scope": "Complete scientific ZIP, transport README and manifest only"
}
@@ -1,9 +0,0 @@
Short square shear orientation diagnostic: exact afa8f6aca10177d5901a9aeae650d3419212c6d0; production a135252ae78b47b57d7e77d19001700b3bedac8b unchanged.
Four fresh cases, root steps 0..8 only; no extra cases or broad test reruns.
axis_square_shear_n128; mode(2,0), phase pi/4, POST-G initialization, square(32,32,96,96).
8 global rows, 36 trace times, 720 native rho/ux/uy cell-time triplets; six build sidecars audited before cleanup.
screening_pass=null; qualification_eligible=false; no late fit or physical pass claim.
Signed unit-area native group moments retain actual centers, widths, areas and parity; no interpolation.
Root-sync samples do not resolve fine substeps. No snapshot, field dump, checkpoint or rerun.
Archive SHA256: e5348495e462973df35ab8675d456f024856397232010e276e132d5c21609c5c
Only intended scientific files; no task history or process listings.
@@ -1,32 +0,0 @@
{
"archive": "CelerisLab_centered_face_3552e6e_20261019.zip",
"bytes": 681926,
"sha256": "0cc8db143a72d6f3a2957a27279b4fa4a7b76d4d20a2da1ea48599e0f250eb79",
"candidate": "3552e6ee92696415491e756824887a3dbbbec492",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_branch": "experiment/centered-face-square",
"diagnostic": "centered_face_square_n128",
"advance_to_review": false,
"checks": {
"bottom_step1_clear": true,
"top_step1_nonworse": false,
"bottom_step8_nonworse": true,
"top_step8_nonworse": true,
"vertical_null": true,
"acoustic_nonworse": false,
"sampled_pressure_nonworse": true,
"step8_pressure_nonworse": true
},
"qualification_eligible": false,
"qualified": false,
"global_rows": 8,
"trace_times": 36,
"native_cell_time_triplets": 720,
"actual_source_config_ptx_captured_and_verified_before_cleanup": true,
"official_comparison_serialization_failed": true,
"recovered_unchanged_comparison": true,
"no_gpu_reruns": true,
"physical_pass_claim": false,
"route": "Existing Gitea validation evidence branch",
"payload_scope": "Complete scientific ZIP, transport README and manifest only"
}
@@ -1,8 +0,0 @@
Centered-face square experimental comparison: exact 3552e6ee92696415491e756824887a3dbbbec492; production a135252ae78b47b57d7e77d19001700b3bedac8b unchanged.
Four fresh sequential cases: U128/U256/current projected/centered_face_v1. Root steps 0..8 only.
1900544 ACTIVE updates, 8 global rows, 36 trace times, 720 native cell-time triplets; six actual source/config/PTX builds captured and audited before cleanup.
Recovered unchanged comparison: advance_to_review=false; top_step1_nonworse and acoustic_nonworse fail.
Official comparison CLI exit1 was a NumPy bool_ JSON serialization defect; partial output and traceback retained. Host-only comparison recovery converted scalar types only. No GPU or CLI reruns.
qualification_eligible=false; qualified=false; no physical pass or main promotion. Local arithmetic deadbands are not accumulated error bounds.
Archive SHA256: 0cc8db143a72d6f3a2957a27279b4fa4a7b76d4d20a2da1ea48599e0f250eb79
Only intended scientific files; no task history, process listings or approval exchanges.
@@ -1,13 +0,0 @@
{
"archive": "CelerisLab_nested_shear_335624c_20261019.zip",
"bytes": 2110640,
"sha256": "8ff04b86f58d5e863394fedf8a87648879cdf7277b6d1bb326208858322d3e04",
"snapshot_sha256": "4e8b8af02ba54db48dc2ea36f24c16fc6004f77e4c8f143fca809ec7fbaa7884",
"candidate": "335624c27b8fc9925e708fb61bde5eea5c04d2a4",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"diagnostic": "nested_shear_n128",
"scientific_status": "FAIL",
"contract_valid": true,
"route": "Existing authorized Gitea validation evidence branch",
"payload_scope": "Complete scientific ZIP, transport README and manifest only"
}
@@ -1,11 +0,0 @@
Nested shear validation: exact 335624c27b8fc9925e708fb61bde5eea5c04d2a4; production a135252ae78b47b57d7e77d19001700b3bedac8b unchanged.
57 host tests and four source-only dry runs passed. Four fresh GPU cases completed
sequentially; valid frozen scientific outcome: FAIL.
Both uniform controls pass; constant and projected depth-3 runs fail own pressure
and comparative rate/residual/pressure budgets. No rerun or tuning.
Eight actual build sidecars audited; one projected final macro snapshot, no
population dump or time series. Complete original archive with 66 intended members.
Archive SHA256: 8ff04b86f58d5e863394fedf8a87648879cdf7277b6d1bb326208858322d3e04
Snapshot SHA256: 4e8b8af02ba54db48dc2ea36f24c16fc6004f77e4c8f143fca809ec7fbaa7884
Archive excludes private task history, process listings and unrelated artifacts.
This evidence-only commit changes no source branch or source file.
@@ -1,19 +0,0 @@
{
"archive": "CelerisLab_postg_70c83b7_20261019.zip",
"bytes": 575798,
"sha256": "0e18ae96a1f3e87f0482385b8c683d9e8a349de39c4155dd7bcedc1686200cf6",
"candidate": "70c83b7233888cb7287c8d1905563590c9e72ef4",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_branch": "tron/shear-probe-guards-caa573f",
"diagnostic": "postg_shear_n128",
"initialization_id": "postg_first_gradient_v1",
"qualification_eligible": false,
"initializer_sha256": "9c909fa013c092490ee21532e3125b2a78a4c5102c7a1bdc0e76986d3f0ef903",
"probe_module_sha256": "e2e6490d281cc275f448dc6d6ea7b9b4407cc74a51e9256b86c08c8626b89b76",
"all_trace_complete": true,
"total_trace_rows": 774,
"independently_verified_before_cleanup": true,
"matrix_assessor_run": false,
"route": "Existing authorized Gitea validation evidence branch",
"payload_scope": "Complete scientific ZIP, transport README and manifest only"
}
@@ -1,10 +0,0 @@
POST-G startup counterfactual: exact 70c83b7233888cb7287c8d1905563590c9e72ef4; production a135252ae78b47b57d7e77d19001700b3bedac8b and equilibrium oracle unchanged.
76 host tests and three exact dry runs pass; three fresh serial cases, no matrix assessor.
postg_shear_n128; initialization_id=postg_first_gradient_v1; qualification_eligible=false.
All traces complete: True; total trace rows: 774.
15 main rows, 24 probes, five source/config/PTX sidecars independently verified before cleanup.
Equilibrium source1f64f7e cases are historical controls; per-time metrics compared without scalar-equality assertions.
Finite projected scalar failure retained. Startup compatibility diagnostic only, not a production fix or long-time qualification.
No extra cases, tuning, reruns, snapshots, field dumps or checkpoints. Fine substeps unresolved.
Archive SHA256: 0e18ae96a1f3e87f0482385b8c683d9e8a349de39c4155dd7bcedc1686200cf6
Only intended scientific files; no task history or process listings.
@@ -1,30 +0,0 @@
{
"archive": "CelerisLab_scaled_n256_92b8afe_20261019.zip",
"bytes": 4047594,
"sha256": "e1a970d0359c8a5f2df6a66bad4c8b8ab64e01fac4f7660ac8e604046f89abcb",
"candidate": "92b8afeeed66c8ac05b37e90d0a592b2b3d0ce01",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_fingerprint": "a5dbfd804befce868067d79a23e5fd47dce7f505b3f9b1bb2145fb57cb5f2178",
"capture_helper_sha256": "3dbaa6547cb0a4cb1541054f3b64ad8b6e18cc70527ac6166e56b944e9bd464a",
"route": "Authorized existing Gitea evidence branch fallback using documented current-session blob transport failures; no Drive submission for this archive",
"drive_failure": {
"status": "known_session_blob_transport_failure",
"approval_denial": false,
"this_archive_upload_attempted": false,
"basis": [
{
"archive": "CelerisLab_projected_pairs_TG_2cf9853_20261018.zip",
"status": "confirmed blob ingress transport failure",
"endpoint": "sdmntprcentralus.oaiusercontent.com",
"elapsed_ms": 216449,
"azure_client_request_id": "2a1827d5-986d-4999-a920-9ea1bd63fba7"
},
{
"archive": "CelerisLab_TG_2cf9853_REVIEW_SUBSET_20261018.zip",
"status": "MCP upload timeout,no ID returned,two folder lookups found no matches"
}
],
"current_archive_sha256": "e1a970d0359c8a5f2df6a66bad4c8b8ab64e01fac4f7660ac8e604046f89abcb"
},
"scope": "Complete original ZIP, no fragments; no source integration"
}
@@ -1,10 +0,0 @@
Exact92b8afe bounded scaled_n256 same-placement resolution diagnostic / unchangeda135252 production.
22 host tests and four dry guards passed;four fresh GPU cases+assessment completed41.122633seconds.
4714397696 active updates;constant/projected/aggregate frozen gates allPASS.
Uniform256 fresh/historical main+early bridge and recorded runtime identical.
AMR velocity/pressure/energy raw errors lower at all4postinitial times;mass errors higher.
Uniform512 controls not uniformly better;all6relative budgets floor-dominated;no convergence certificate.
Six actual build sidecars/source/config/PTX audits pass.Original pinned2cf references included separately.
Complete intact ZIP with117manifest payloads;no source push/default change/extra case/tuning.
Known session Drive blob transport failures used as authorized existing Gitea fallback;this archive not submitted to Drive.
Archive SHA256: e1a970d0359c8a5f2df6a66bad4c8b8ab64e01fac4f7660ac8e604046f89abcb
@@ -1,33 +0,0 @@
{
"archive": "CelerisLab_scaled_shear_9748ef9_20261019.zip",
"bytes": 4084568,
"sha256": "81db3d724a7de1d08202bf693d9ef94ff1a8ade086614b843868657d9de54dda",
"candidate": "9748ef91ef3bfd366756ef0c8a056df8faa75679",
"review_base": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"flow": "shear_wave",
"shear_wave_sha256": "81d5c8ee60864372887cddf9239580c82fb6750d956038f1e3ee9de61aa4e877",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_fingerprint": "a5dbfd804befce868067d79a23e5fd47dce7f505b3f9b1bb2145fb57cb5f2178",
"capture_helper_sha256": "3dbaa6547cb0a4cb1541054f3b64ad8b6e18cc70527ac6166e56b944e9bd464a",
"route": "Authorized existing Gitea evidence branch fallback using documented current-session blob transport failures; no Drive submission for this archive",
"drive_failure": {
"status": "known_session_blob_transport_failure",
"approval_denial": false,
"this_archive_upload_attempted": false,
"basis": [
{
"archive": "CelerisLab_projected_pairs_TG_2cf9853_20261018.zip",
"status": "confirmed blob ingress transport failure",
"endpoint": "sdmntprcentralus.oaiusercontent.com",
"elapsed_ms": 216449,
"azure_client_request_id": "2a1827d5-986d-4999-a920-9ea1bd63fba7"
},
{
"archive": "CelerisLab_TG_2cf9853_REVIEW_SUBSET_20261018.zip",
"status": "MCP upload timeout,no ID returned,two folder lookups found no matches"
}
],
"current_archive_sha256": "81db3d724a7de1d08202bf693d9ef94ff1a8ade086614b843868657d9de54dda"
},
"scope": "Complete original ZIP, no fragments; no source integration"
}
@@ -1,11 +0,0 @@
Exact9748ef9 scaled oblique(2,1) shear-wave diagnostic;production unchanged a135252.
51 host tests/four source-only preflights passed;four fixed fresh cases and assessment completed 19.712796s.
4714397696 active updates;contract_valid=True;scientificstatus=FAIL;passed=False.
Independent uniform256 bridge:complete scalar rows/build sidecars/runtime exact to retained de5b0cc.
Both uniform controls pass own screens;projected256 own/budget/controlled PASS.
Constant256 pressure own screen and rate/residual/pressure budgets FAIL;finite exit1 retained.
Signed rate bias,excess over BOTH controls,raw/scaled pressure,full modal/phase/mass and interval data retained.
All six actual sidecars independently audited;no tuning,retry,extra cases,source publication or integration.
Two resolutions/one phase and placement give descriptive trends,not an order or localization proof.
Known session Drive blob transport failure used for authorized Gitea fallback;this archive not submitted to Drive.
Complete original ZIP;archive SHA256:81db3d724a7de1d08202bf693d9ef94ff1a8ade086614b843868657d9de54dda
@@ -1,33 +0,0 @@
{
"archive": "CelerisLab_shear_wave_de5b0cc_20261019.zip",
"bytes": 4031180,
"sha256": "a8924472f25c61dc107f344a80cd8d07baa35772542bf76357475d0c3346cffa",
"candidate": "de5b0cc080794d0ce44d37f845aa8e8dbf8c2016",
"review_base": "eec4677db1308e2a9ce4e5f195c994356c11de13",
"flow": "shear_wave",
"shear_wave_sha256": "81d5c8ee60864372887cddf9239580c82fb6750d956038f1e3ee9de61aa4e877",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_fingerprint": "a5dbfd804befce868067d79a23e5fd47dce7f505b3f9b1bb2145fb57cb5f2178",
"capture_helper_sha256": "3dbaa6547cb0a4cb1541054f3b64ad8b6e18cc70527ac6166e56b944e9bd464a",
"route": "Authorized existing Gitea evidence branch fallback using documented current-session blob transport failures; no Drive submission for this archive",
"drive_failure": {
"status": "known_session_blob_transport_failure",
"approval_denial": false,
"this_archive_upload_attempted": false,
"basis": [
{
"archive": "CelerisLab_projected_pairs_TG_2cf9853_20261018.zip",
"status": "confirmed blob ingress transport failure",
"endpoint": "sdmntprcentralus.oaiusercontent.com",
"elapsed_ms": 216449,
"azure_client_request_id": "2a1827d5-986d-4999-a920-9ea1bd63fba7"
},
{
"archive": "CelerisLab_TG_2cf9853_REVIEW_SUBSET_20261018.zip",
"status": "MCP upload timeout,no ID returned,two folder lookups found no matches"
}
],
"current_archive_sha256": "a8924472f25c61dc107f344a80cd8d07baa35772542bf76357475d0c3346cffa"
},
"scope": "Complete original ZIP, no fragments; no source integration"
}
@@ -1,11 +0,0 @@
Exactde5b0cc first bounded oblique(2,1) shear-wave diagnostic / unchangeda135252 production.
43 host checks and four source-only preflights passed;four fresh physical cases+assessment completed12.081603seconds.
589299712 active updates;valid finite data,contract_validtrue,scientificassessmentFAIL.
Both uniform controls own screensPASS;constant pressure screenFAIL(exit1 retained).
Projected own screensPASS,but rate/residual controlled budgetsFAIL;no controlled-pass.
All fits available;modal/phase,fit/interval rates,residuals,raw/scaled spuriouspressure andmass retained.
Pressure usescontinuumA_exact^2/4,notTG pressure semantics;coefficient-one|kh|² screens diagnostic only.
Six actual sidecars/source/config/PTX audits pass;no tuning/retry/source publication/merge.
Complete intact ZIP with114manifest payloads;older92b8afe object/bundle/archive preserved.
Known session Drive blob transport failures used as authorized existing Gitea fallback;this archive not submitted to Drive.
Archive SHA256: a8924472f25c61dc107f344a80cd8d07baa35772542bf76357475d0c3346cffa
@@ -1,15 +0,0 @@
{
"archive": "CelerisLab_signed_probes_1f64f7e_20261019.zip",
"bytes": 777103,
"sha256": "3cc338af0bad8e44ff5bd89232f2981e513797875b58d8aa3ed3ae6d2ce7f97e",
"candidate": "1f64f7eb11c14ae1106136de941b74a02142382e",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_branch": "tron/shear-probe-guards-caa573f",
"probe_module_sha256": "e2e6490d281cc275f448dc6d6ea7b9b4407cc74a51e9256b86c08c8626b89b76",
"scalar_rows_and_checked_runtime_exact": true,
"mechanism_diagnostic_usable": true,
"independently_verified_before_cleanup": true,
"matrix_assessor_run": false,
"route": "Existing authorized Gitea validation evidence branch",
"payload_scope": "Complete scientific ZIP, transport README and manifest only"
}
@@ -1,9 +0,0 @@
Signed shear probes: exact 1f64f7eb11c14ae1106136de941b74a02142382e; production a135252ae78b47b57d7e77d19001700b3bedac8b unchanged.
68 host tests and four exact dry runs pass; four fresh serial cases; no matrix assessor.
20 main rows match audited previous rows. All four raw traces are retained when valid, with 258 root times and 24 probes.
Seven actual source/config/PTX sidecars independently verified before module load and compiler cleanup.
Scalar consistency: True; mechanism usable: True.
Nested projected finite scalar screen failure preserved. No algorithm changes, reruns, snapshots, populations or checkpoints.
Root-sync samples do not resolve fine substeps; actual centers and displacements retained.
Archive SHA256: 3cc338af0bad8e44ff5bd89232f2981e513797875b58d8aa3ed3ae6d2ce7f97e
Only intended scientific files; no task history or process listings; no source-branch changes in this evidence commit.
@@ -1,14 +0,0 @@
{
"archive": "CelerisLab_twin_shear_02bde0f_20261019.zip",
"bytes": 127830,
"sha256": "a93ec5a45868cc0c550588a0eacc6702f442d4b7675cff82608694bcf4117451",
"candidate": "02bde0f75187786a2ce10abc9a863f750b6343a8",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"diagnostic": "twin_shear_n128",
"scientific_status": "FAIL",
"contract_valid": true,
"audit_order_limitation": "Sidecars and PTX hashes were captured/verified before cleanup. Independent source/config reconstruction occurred after cleanup; the requested independent pre-cleanup source audit was not performed. No rerun or source fix.",
"independent_pre_cleanup_source_audit_complete": false,
"route": "Existing authorized Gitea validation evidence branch",
"payload_scope": "Complete scientific ZIP, transport README and manifest only"
}
@@ -1,9 +0,0 @@
Depth-2 twin shear validation: exact 02bde0f75187786a2ce10abc9a863f750b6343a8; production a135252ae78b47b57d7e77d19001700b3bedac8b unchanged.
61 host tests and four dry runs pass; four fresh serial cases; scientific FAIL, contract valid.
Controls pass. Constant fails own pressure and comparative rate/residual/pressure budgets.
Projected passes own screens and pressure budget, but fails comparative rate/residual budgets.
Six actual sidecars independently reconstructed after scratch cleanup; requested independent pre-cleanup audit was not performed.
No GPU rerun, tuning, snapshots, early traces, checkpoints or population dumps.
Audit-order limitation: Sidecars and PTX hashes were captured/verified before cleanup. Independent source/config reconstruction occurred after cleanup; the requested independent pre-cleanup source audit was not performed. No rerun or source fix.
Archive SHA256: a93ec5a45868cc0c550588a0eacc6702f442d4b7675cff82608694bcf4117451
Only intended scientific files; no task history or process listings; no source-branch changes.
@@ -1,16 +0,0 @@
{
"archive": "CelerisLab_wide_x_be8e6d6_20261019.zip",
"bytes": 260873,
"sha256": "ff50714f38df9c2ce37ce8e11bd88751477133a62b9fadd5da54a3be47705d1e",
"candidate": "be8e6d691d6d18baa8403f2d942b5aa382456ac1",
"production": "a135252ae78b47b57d7e77d19001700b3bedac8b",
"source_branch": "tron/shear-probe-guards-caa573f",
"preset_sha256": "13d16ba355117e2d074edccd9dc5d694c2fc13c673a0abdfca6401f6ed917733",
"probe_module_sha256": "e2e6490d281cc275f448dc6d6ea7b9b4407cc74a51e9256b86c08c8626b89b76",
"runner_screening_pass": false,
"mechanism_diagnostic_usable": true,
"independently_verified_before_cleanup": true,
"matrix_assessor_run": false,
"route": "Existing authorized Gitea validation evidence branch",
"payload_scope": "Complete scientific ZIP, transport README and manifest only"
}
@@ -1,9 +0,0 @@
Wide-x projected three-level shear: exact be8e6d691d6d18baa8403f2d942b5aa382456ac1; production a135252ae78b47b57d7e77d19001700b3bedac8b unchanged.
72 host tests and one exact dry run pass; one fresh GPU case, no controls or matrix assessor.
Runner screen pass: False; mechanism usable: True.
Five main rows, 258 root trace times, unchanged 24 targets and three independently verified pre-cleanup build sidecars.
Twenty probe locations match original nested, four horizontal probes shift; changed locations excluded from direct comparisons.
None crosses the new x=28 face. No qualification pass, reflection proof or pure gap-effect claim. Fine substeps unresolved.
No algorithm changes, reruns, snapshots, field dumps or checkpoints.
Archive SHA256: ff50714f38df9c2ce37ce8e11bd88751477133a62b9fadd5da54a3be47705d1e
Only intended scientific files; no task history or process listings.