diff --git a/README.md b/README.md index 5d2102e..8155b20 100644 --- a/README.md +++ b/README.md @@ -669,7 +669,7 @@ streak.render("streakline.png") - [Smagorinsky helper comparison](docs/validation/les_helpers.md): pinned baseline versus an output-local two-coefficient candidate, without production edits. - [Jet-circle control volume](docs/validation/jet_circle_cv.md): bounded AMR versus uniform-grid conservation diagnostic. -The runners are in `tests/validation`, their CPU tests in `tests/unit`, and compact reference/source guards in `tests/validation/data`. These campaigns preserve pinned production code; successful CPU checks alone do not establish GPU or physical validation. Keep generated results outside tracked files. +The runners are in `tests/validation`, their CPU tests in `tests/unit`, and compact reference/source guards in `tests/validation/data`. Current Re100/Jet source guards explicitly pin the reviewed AMR-channel experiment; historical d79 evidence remains tied to its original checkpoint commits. New runs record actual Git HEAD separately from source origin. These campaigns preserve pinned production code; successful CPU checks alone do not establish GPU or physical validation. Keep generated results outside tracked files. ## Citation diff --git a/docs/validation/dfg_re100.md b/docs/validation/dfg_re100.md index 6f26868..837b083 100644 --- a/docs/validation/dfg_re100.md +++ b/docs/validation/dfg_re100.md @@ -1,8 +1,16 @@ # DFG 2D-2 Re100 GPU campaign (validation-only) +## Current experimental source provenance + +This development branch now includes the reviewed AMR-channel source changes originating in `5338864748ac67fe2544487c059ba149ebf916da` and `47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5`. The current full-source manifest pins the latter reviewed source snapshot, including the new channel files. This is an explicit new experiment; neither source review nor host tests transfer historical d79 GPU/flow acceptance to it. The channel GPU gate has not yet run at integration time. + +New run JSON records the source-origin pin plus `checkout_revision` (actual Git HEAD), `checkout_dirty`, and the experimental-source label. The origin pin is not claimed to be the run's checkout commit. Numerical definitions and thresholds are unchanged. Runs require a Git checkout for this runtime identity; source hash checks remain active. + +Historical d79 Re100/Jet execution stays reproducible at `69e9b78de9483a5ff21e2d0c74311d240bfaf88c`; the d79 LES diagnostic checkpoint is `20ae6770924df15f31305aad56e44a54a3dd4d88`. Their manifests and existing result files are not rewritten. Use those commits to reproduce or interpret old d79 evidence. The current AMR-channel experiment requires its own GPU and applicable flow evidence. + ## Scope and locked definitions -Unchanged d79e3f6 production sources. Uniform D2Q9/MRT, shifted FP32, double buffer, no LES, stationary cylinder and no-slip walls. This is not an AMR, jet, or full canonical-outlet certification. +Explicitly pinned AMR-channel experimental production snapshot (see provenance below). Uniform D2Q9/MRT, shifted FP32, double buffer, no LES, stationary cylinder and no-slip walls. This is not an AMR, jet, or full canonical-outlet certification. Physical geometry: [0,2.2] × [0,0.41], center (0.2,0.2), radius .05, rho=1, nu=.001, inlet mean=1 and peak=1.5. D is lattice diameter; dx=.1/D, dt=U_lattice*dx, nu_lattice=U_lattice*D/100. U_lattice=.01 gives peak inlet Mach .02598. Existing local Zou–He inlet is selected in validation config only. Existing pressure-NEQ outlet is unclamped: **it does not impose the canonical vector do-nothing condition nu*d_n(u)-p*n=0**. The existing production channel-flow initial condition is used, not zero velocity. Periodic eligibility is delayed to t*=250 (25 physical seconds), with fixed end t*=300 (30 seconds). @@ -49,4 +57,4 @@ Ten tests cover geometry/units/config, pressure scaling, periodic and nonperiodi ## Reference provenance and reproduction -Only the compact derived cycle is versioned. Its source URL, official ZIP SHA-256, column selection, and cycle-selection description are embedded in reference_cycle.json. Raw archives and GPU results are not repository inputs. To reproduce it, obtain the exact archive identified there, verify its SHA-256, and extract logs/results_cc2d_bench2_referencenew/bdforces_q2_lv6_dt4 and pointvalues_q2_lv6_dt4. Use physical time column 2 multiplied by 10, drag/lift columns 4/5, and pressure columns 7 minus 12 (one-based columns). Build rows with mass=flux_in=flux_out=1, then call periodic.extract(rows, min_time=0) and select the last complete cycle. The source guard is tests/validation/data/dfg_re100/source_manifest.json; it deliberately verifies unchanged d79 production content rather than the validation branch HEAD. +Only the compact derived cycle is versioned. Its source URL, official ZIP SHA-256, column selection, and cycle-selection description are embedded in reference_cycle.json. Raw archives and GPU results are not repository inputs. To reproduce it, obtain the exact archive identified there, verify its SHA-256, and extract logs/results_cc2d_bench2_referencenew/bdforces_q2_lv6_dt4 and pointvalues_q2_lv6_dt4. Use physical time column 2 multiplied by 10, drag/lift columns 4/5, and pressure columns 7 minus 12 (one-based columns). Build rows with mass=flux_in=flux_out=1, then call periodic.extract(rows, min_time=0) and select the last complete cycle. The source guard is tests/validation/data/dfg_re100/source_manifest.json; it verifies the current reviewed production snapshot rather than equating its origin with the validation branch HEAD. diff --git a/docs/validation/jet_circle_cv.md b/docs/validation/jet_circle_cv.md index a87b308..1e9b6db 100644 --- a/docs/validation/jet_circle_cv.md +++ b/docs/validation/jet_circle_cv.md @@ -1,6 +1,14 @@ # Jet-circle closed-control-volume pilot -Status: CPU preparation only. No GPU run or production change. Pinned unchanged production source: d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2. tests/validation/data/jet_circle_cv/source_manifest.json checks all tracked source file hashes before importing GPU code. +## Current experimental source provenance + +This development branch now includes the reviewed AMR-channel source changes originating in `5338864748ac67fe2544487c059ba149ebf916da` and `47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5`. The current full-source manifest pins the latter reviewed source snapshot, including the new channel files. This is an explicit new experiment; neither source review nor host tests transfer historical d79 GPU/flow acceptance to it. The channel GPU gate has not yet run at integration time. + +New run JSON records the source-origin pin plus `checkout_revision` (actual Git HEAD), `checkout_dirty`, and the experimental-source label. The origin pin is not claimed to be the run's checkout commit. Numerical definitions and thresholds are unchanged. Runs require a Git checkout for this runtime identity; source hash checks remain active. + +Historical d79 Re100/Jet execution stays reproducible at `69e9b78de9483a5ff21e2d0c74311d240bfaf88c`; the d79 LES diagnostic checkpoint is `20ae6770924df15f31305aad56e44a54a3dd4d88`. Their manifests and existing result files are not rewritten. Use those commits to reproduce or interpret old d79 evidence. The current AMR-channel experiment requires its own GPU and applicable flow evidence. + +Status: CPU preparation only. No GPU run or production change. Current source origin: reviewed AMR-channel snapshot 47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5; this new experiment has no inherited d79 GPU acceptance. tests/validation/data/jet_circle_cv/source_manifest.json checks all tracked source file hashes before importing GPU code. ## Execute only after root-owned GPU serialization @@ -55,4 +63,4 @@ Both Jet amplitudes are constant throughout the run and every fine substep; geom Every case records actual tau_root and tau_fine. For this fixed s=1 geometry and speed, Re400 would give nu=.0018063, tau_root=.5054189 and tau_fine=.5108378, close to the SRT limit .5. The implemented Re choices are a bounded campaign menu, not a universal physical Reynolds-number ceiling. Higher-Re evidence may require a larger initial resolved geometry or a different justified grid/relaxation design before launch. Diffusive refinement at constant lattice nu improves spatial/Mach resolution but does not move tau farther from .5; simply selecting scale=2 does not cure a poor tau. No all-Re, LES or three-dimensional realism claim follows from this pilot. -The source guard checks production file content against d79, not validation-branch HEAD. This runner is validation-only; generated results and frozen execution-package archives are not committed. +The source guard checks production file content against the current reviewed source origin, not validation-branch HEAD. This runner is validation-only; generated results and frozen execution-package archives are not committed. diff --git a/tests/unit/test_validation_source_provenance.py b/tests/unit/test_validation_source_provenance.py new file mode 100644 index 0000000..d184e1a --- /dev/null +++ b/tests/unit/test_validation_source_provenance.py @@ -0,0 +1,74 @@ +"""Explicit experimental repin and historical-source provenance contracts.""" + +import hashlib +import json +from pathlib import Path +import subprocess +import sys + +ROOT = Path(__file__).resolve().parents[2] +sys.path.insert(0, str(ROOT / "tests/validation")) +from source_provenance import checkout_provenance +import re100_helpers +import run_jet_circle_cv + +ORIGIN = "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5" + + +def test_manifests_cover_current_source_and_preserve_origin(): + names = subprocess.check_output( + ["git", "-C", str(ROOT), "ls-files", "src"], text=True + ).splitlines() + for group, hashes_key, revision_key in ( + ("dfg_re100", "production_sha256", "commit"), + ("jet_circle_cv", "files", "revision"), + ): + manifest = json.loads( + ( + ROOT / "tests/validation/data" / group / "source_manifest.json" + ).read_text() + ) + assert manifest[revision_key] == ORIGIN + assert set(manifest[hashes_key]) == set(names) + assert manifest["source_origin_commits"][-1] == ORIGIN + assert ( + manifest["historical_checkpoints"]["production"] + == "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2" + ) + assert "not inherited from d79" in manifest["experiment"] + for name, expected in manifest[hashes_key].items(): + assert ( + hashlib.sha256((ROOT / name).read_bytes()).hexdigest() == expected + ), name + assert re100_helpers.PIN == run_jet_circle_cv.PIN == ORIGIN + + +def test_runtime_checkout_identity_is_separate_from_source_origin(tmp_path): + subprocess.run(["git", "init", "-q", str(tmp_path)], check=True) + (tmp_path / "test.txt").write_text("tracked\n") + subprocess.run(["git", "-C", str(tmp_path), "add", "test.txt"], check=True) + subprocess.run( + [ + "git", + "-C", + str(tmp_path), + "-c", + "user.name=Test", + "-c", + "user.email=test@example.invalid", + "commit", + "-qm", + "fixture", + ], + check=True, + ) + expected = subprocess.check_output( + ["git", "-C", str(tmp_path), "rev-parse", "HEAD"], text=True + ).strip() + assert checkout_provenance(tmp_path) == dict( + checkout_revision=expected, checkout_dirty=False + ) + (tmp_path / "test.txt").write_text("changed\n") + assert checkout_provenance(tmp_path) == dict( + checkout_revision=expected, checkout_dirty=True + ) diff --git a/tests/validation/data/dfg_re100/source_manifest.json b/tests/validation/data/dfg_re100/source_manifest.json index 029a4d3..fc83ef3 100644 --- a/tests/validation/data/dfg_re100/source_manifest.json +++ b/tests/validation/data/dfg_re100/source_manifest.json @@ -1,5 +1,5 @@ { - "commit": "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2", + "commit": "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5", "production_sha256": { "src/CelerisLab/__init__.py": "21cc469bd6e970a1f9ff5970c8eea4602065e41fc881854759ee565ee55c10c6", "src/CelerisLab/body/__init__.py": "e4e0e8f0769a94428d5b02fac790443997556cfc5515a5f1ed1595d2c694d69d", @@ -42,31 +42,32 @@ "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/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": "72d7803c859c974c24ed16b36df43d9e5799828be0fe589cd5bf7a0a5e5cf485", + "src/CelerisLab/lbm/kernels/blocks.cu": "e3b9606f861bfea8c4b0f34e8356bb230081f899c584f67be89178d889099b17", "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", "src/CelerisLab/lbm/kernels/boundary/ibm_kernels.cuh": "e6909b547dc8d64cdd8a76a90660243a8f5fee535caa161b52b4dd8b7c29934b", "src/CelerisLab/lbm/kernels/boundary/inlet/channel_stabilized.cuh": "efe077afcbb6b731256a987c2fd79a1dbc470c902f87070d60421ea6cb13d4e2", - "src/CelerisLab/lbm/kernels/boundary/inlet/common.cuh": "f3cec54c8873c65b3dca4375605d2c89a8727765884d3954c235242fdff9c6ba", + "src/CelerisLab/lbm/kernels/boundary/inlet/common.cuh": "59b38a89439878e00de7de16b9c7b03feff443fcc5a421593f7d2536dcbb7ab8", "src/CelerisLab/lbm/kernels/boundary/inlet/equilibrium.cuh": "f0964c811b2c41a5aaa1c6d99c490b06e850c634eb8749f1f05ef61f93c2de1d", "src/CelerisLab/lbm/kernels/boundary/inlet/regularized.cuh": "943d4a571818bacb89c70bccfaac202691121e3e385803ce6309123a0a03ddaf", "src/CelerisLab/lbm/kernels/boundary/inlet/zou_he_local.cuh": "e73e66b853b1e4e0e30d8f4185d832aa414ce670a1813ce2b5459f2887f71f89", "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,6 +84,7 @@ "src/CelerisLab/lbm/kernels/operators/turbulence_smag.cuh": "ff7f000297ee0817e255ad9fcb6a13b647e3ddd5b206518d35f38d2895a9f501", "src/CelerisLab/lbm/kernels/refinement.cu": "129f3d91da93b4324f88a0da73a4da1e5390f72c14cce574ee63306712da9895", "src/CelerisLab/lbm/kernels/step/aux_kernels.cu": "578a5b20a157241ee678547059abb1372dd5a589ad06bb2c15b987eb01ca1013", + "src/CelerisLab/lbm/kernels/step/block_channel.cu": "befbf6d757e532a59c166d41f920d16d71557cd3a574478e7aa83da737c48cbd", "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", @@ -95,10 +97,20 @@ "src/CelerisLab/lbm/population_storage.py": "a6a86c29c52c892edfe4802fb773c387212e3f4cc86708d80e154986ddf88044", "src/CelerisLab/lbm/raw_exchange.py": "8694202466eba848563e298656353b0f5db94e21a01fa05f51aad6dc2b9fd311", "src/CelerisLab/lbm/refinement.py": "08c2a0557276a98cbcaa459d9bb7a9735d8bbbf64a6114c57af2fda61481a687", - "src/CelerisLab/lbm/refinement_stepper.py": "16f778522c8e4dbb444b84d6381e94c047e0e05299541e589f0f365fb9a89c4e", + "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" + }, + "experiment": "AMR-channel development source; GPU/flow validation not inherited from d79", + "source_origin_commits": [ + "5338864748ac67fe2544487c059ba149ebf916da", + "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5" + ], + "historical_checkpoints": { + "production": "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2", + "re100_jet": "69e9b78de9483a5ff21e2d0c74311d240bfaf88c", + "les_diagnostic": "20ae6770924df15f31305aad56e44a54a3dd4d88" } -} \ No newline at end of file +} diff --git a/tests/validation/data/jet_circle_cv/source_manifest.json b/tests/validation/data/jet_circle_cv/source_manifest.json index a86b589..8f20ed6 100644 --- a/tests/validation/data/jet_circle_cv/source_manifest.json +++ b/tests/validation/data/jet_circle_cv/source_manifest.json @@ -1,5 +1,5 @@ { - "revision": "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2", + "revision": "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5", "files": { "src/CelerisLab/__init__.py": "21cc469bd6e970a1f9ff5970c8eea4602065e41fc881854759ee565ee55c10c6", "src/CelerisLab/body/__init__.py": "e4e0e8f0769a94428d5b02fac790443997556cfc5515a5f1ed1595d2c694d69d", @@ -42,19 +42,20 @@ "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/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": "72d7803c859c974c24ed16b36df43d9e5799828be0fe589cd5bf7a0a5e5cf485", + "src/CelerisLab/lbm/kernels/blocks.cu": "e3b9606f861bfea8c4b0f34e8356bb230081f899c584f67be89178d889099b17", "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", "src/CelerisLab/lbm/kernels/boundary/ibm_kernels.cuh": "e6909b547dc8d64cdd8a76a90660243a8f5fee535caa161b52b4dd8b7c29934b", "src/CelerisLab/lbm/kernels/boundary/inlet/channel_stabilized.cuh": "efe077afcbb6b731256a987c2fd79a1dbc470c902f87070d60421ea6cb13d4e2", - "src/CelerisLab/lbm/kernels/boundary/inlet/common.cuh": "f3cec54c8873c65b3dca4375605d2c89a8727765884d3954c235242fdff9c6ba", + "src/CelerisLab/lbm/kernels/boundary/inlet/common.cuh": "59b38a89439878e00de7de16b9c7b03feff443fcc5a421593f7d2536dcbb7ab8", "src/CelerisLab/lbm/kernels/boundary/inlet/equilibrium.cuh": "f0964c811b2c41a5aaa1c6d99c490b06e850c634eb8749f1f05ef61f93c2de1d", "src/CelerisLab/lbm/kernels/boundary/inlet/regularized.cuh": "943d4a571818bacb89c70bccfaac202691121e3e385803ce6309123a0a03ddaf", "src/CelerisLab/lbm/kernels/boundary/inlet/zou_he_local.cuh": "e73e66b853b1e4e0e30d8f4185d832aa414ce670a1813ce2b5459f2887f71f89", @@ -83,6 +84,7 @@ "src/CelerisLab/lbm/kernels/operators/turbulence_smag.cuh": "ff7f000297ee0817e255ad9fcb6a13b647e3ddd5b206518d35f38d2895a9f501", "src/CelerisLab/lbm/kernels/refinement.cu": "129f3d91da93b4324f88a0da73a4da1e5390f72c14cce574ee63306712da9895", "src/CelerisLab/lbm/kernels/step/aux_kernels.cu": "578a5b20a157241ee678547059abb1372dd5a589ad06bb2c15b987eb01ca1013", + "src/CelerisLab/lbm/kernels/step/block_channel.cu": "befbf6d757e532a59c166d41f920d16d71557cd3a574478e7aa83da737c48cbd", "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", @@ -95,10 +97,20 @@ "src/CelerisLab/lbm/population_storage.py": "a6a86c29c52c892edfe4802fb773c387212e3f4cc86708d80e154986ddf88044", "src/CelerisLab/lbm/raw_exchange.py": "8694202466eba848563e298656353b0f5db94e21a01fa05f51aad6dc2b9fd311", "src/CelerisLab/lbm/refinement.py": "08c2a0557276a98cbcaa459d9bb7a9735d8bbbf64a6114c57af2fda61481a687", - "src/CelerisLab/lbm/refinement_stepper.py": "16f778522c8e4dbb444b84d6381e94c047e0e05299541e589f0f365fb9a89c4e", + "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" + }, + "experiment": "AMR-channel development source; GPU/flow validation not inherited from d79", + "source_origin_commits": [ + "5338864748ac67fe2544487c059ba149ebf916da", + "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5" + ], + "historical_checkpoints": { + "production": "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2", + "re100_jet": "69e9b78de9483a5ff21e2d0c74311d240bfaf88c", + "les_diagnostic": "20ae6770924df15f31305aad56e44a54a3dd4d88" } } diff --git a/tests/validation/re100_helpers.py b/tests/validation/re100_helpers.py index 4392ba7..e537e36 100644 --- a/tests/validation/re100_helpers.py +++ b/tests/validation/re100_helpers.py @@ -1,7 +1,8 @@ """DFG Re100 periodic reference comparison with declared pressure-NEQ outlet, not exact do-nothing. -CPU helpers import without CUDA. GPU execution uses unchanged d79e3f6 production -sources. Default pilot is deliberately too short to certify periodic convergence. +CPU helpers import without CUDA. GPU execution verifies the explicitly pinned +AMR-channel experimental source snapshot. Historical d79 evidence remains tied to +its original commits. Default pilot is too short to certify periodic convergence. """ import argparse @@ -16,7 +17,7 @@ from tempfile import TemporaryDirectory import numpy as np ROOT = Path(__file__).resolve().parents[2] -PIN = "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2" +PIN = "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5" def geometry(n): diff --git a/tests/validation/run_dfg_re100.py b/tests/validation/run_dfg_re100.py index 78ba385..061da6e 100644 --- a/tests/validation/run_dfg_re100.py +++ b/tests/validation/run_dfg_re100.py @@ -6,6 +6,7 @@ from tempfile import TemporaryDirectory import numpy as np from re100_helpers import ROOT, PIN, make_config, pressure_probes, outlet_diagnostic from periodic import assess, compare, GATES, REFERENCE_GATES +from source_provenance import checkout_provenance def run(a): @@ -30,6 +31,8 @@ def run(a): result = dict( case="DFG 2D-2 Re100, pressure-NEQ outlet deviation", pin=PIN, + source_experiment=manifest["experiment"], + **checkout_provenance(ROOT), production_verified=True, parameters=p, mode=a.mode, diff --git a/tests/validation/run_jet_circle_cv.py b/tests/validation/run_jet_circle_cv.py index ef4c109..4beab4c 100644 --- a/tests/validation/run_jet_circle_cv.py +++ b/tests/validation/run_jet_circle_cv.py @@ -9,8 +9,9 @@ from pathlib import Path import sys import time import numpy as np +from source_provenance import checkout_provenance -PIN = "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2" +PIN = "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5" HERE = Path(__file__).resolve().parent CX = np.array([0, 1, -1, 0, 0, 1, -1, 1, -1]) CY = np.array([0, 0, 0, 1, -1, 1, -1, -1, 1]) @@ -201,7 +202,7 @@ def verify(repo): return manifest -def run_case(c, ctx, output): +def run_case(c, ctx, output, provenance): from CelerisLab.body.geometry.circle import CircleGeometry from CelerisLab.body.objects import SimObject from CelerisLab.body.jets import Jet, Sector, Radial @@ -471,6 +472,7 @@ def run_case(c, ctx, output): payload = dict( case=c, source_revision=PIN, + **provenance, status="PILOT_DIAGNOSTIC_ONLY", windows=rows, physics_validation_pass=False, @@ -529,7 +531,10 @@ def main(): ): p.error("Root must select one verified idle GPU via CUDA_VISIBLE_DEVICES") repo = a.repo.resolve() - verify(repo) + source = verify(repo) + provenance = dict( + source_experiment=source["experiment"], **checkout_provenance(repo) + ) sys.path.insert(0, str(repo / "src")) import CelerisLab @@ -545,7 +550,7 @@ def main(): free, total = cuda.mem_get_info() if free < max(1024, 2 * plan["estimated_peak_device_mib"]) * 1024**2: raise RuntimeError("Insufficient free device memory") - run_case(c, ctx, a.output) + run_case(c, ctx, a.output, provenance) print( json.dumps( dict(status="COMPLETE_DIAGNOSTIC_ONLY", physics_validation_pass=False) diff --git a/tests/validation/source_provenance.py b/tests/validation/source_provenance.py new file mode 100644 index 0000000..fd4072c --- /dev/null +++ b/tests/validation/source_provenance.py @@ -0,0 +1,15 @@ +"""Record runtime checkout identity separately from the reviewed source origin.""" + +import subprocess + + +def checkout_provenance(repo): + """Require a Git checkout; never label changed-source runs as historical evidence.""" + revision = subprocess.check_output( + ["git", "-C", str(repo), "rev-parse", "HEAD"], text=True + ).strip() + dirty = subprocess.check_output( + ["git", "-C", str(repo), "status", "--porcelain", "--untracked-files=normal"], + text=True, + ) + return dict(checkout_revision=revision, checkout_dirty=bool(dirty))