test: integrate explicitly repinned uniform LES shear diagnostic
This commit is contained in:
1 parent
cd3a657f9d
commit
af984eab37
7 files changed
+755
No files matched your search
@@ -0,0 +1,110 @@
|
||||
{
|
||||
"base_commit": "cd3a657f9d3833e812c3cca173525f165b48710a",
|
||||
"sources": {
|
||||
"src/CelerisLab/__init__.py": "21cc469bd6e970a1f9ff5970c8eea4602065e41fc881854759ee565ee55c10c6",
|
||||
"src/CelerisLab/body/__init__.py": "e4e0e8f0769a94428d5b02fac790443997556cfc5515a5f1ed1595d2c694d69d",
|
||||
"src/CelerisLab/body/action_smoother.py": "b1a23ee6bbd4850b172cb8738c5c3546ee465a54189e6af9d8044f023d4687dc",
|
||||
"src/CelerisLab/body/coupling/__init__.py": "c931f7eb318d48408c3e2febcc6917c88c8dcc1697cbf4329b1f340d94c35763",
|
||||
"src/CelerisLab/body/coupling/soa_packer.py": "8ec26fd55ef74801bbd5ab6bd3d0a7dabc750cbd498aaac2ca4c61a0108ad3c9",
|
||||
"src/CelerisLab/body/ddf_patch.py": "60fcfb7441e73bf290bcff41ca3a83da3e7ddad765d7247464e8f02e3043b4e2",
|
||||
"src/CelerisLab/body/geometry/__init__.py": "ada88980ab672959aca9aa3a4c4aade3219524b2ab68110cd2a2f41e3e0ca90a",
|
||||
"src/CelerisLab/body/geometry/base.py": "cceca14361ca2f34d34a3e43730e1a79b8ca81be00f0dd62e884db32b479419f",
|
||||
"src/CelerisLab/body/geometry/circle.py": "7605ca7c21103f1d801ac73ab8dd18dffbdac425b2dee7b8858b283628a9e436",
|
||||
"src/CelerisLab/body/jets.py": "4104c24af4651f4bb4f8d8fd36fb6d88f41c6e4469822f36e22e74c9ede31dac",
|
||||
"src/CelerisLab/body/manager.py": "01b653d25bd9b4333379c8bfd12383596b686d2029f2e91b1c91b618540ec6b3",
|
||||
"src/CelerisLab/body/objects.py": "8e63cee8faa9cc6243bcff428be628dfad73a02a9a3b8ece7d78c0a63406a08d",
|
||||
"src/CelerisLab/body/preprocess/__init__.py": "dfd9d58bc07f626ab23a70053e31b88a6d9165d2e4c76a4e9f48abe674d3d2ec",
|
||||
"src/CelerisLab/body/preprocess/flag_overlay.py": "831fc9e9736b758847759a085ff133eb49ec91318ace4fda76f85960138ee300",
|
||||
"src/CelerisLab/body/registry.py": "fbb7327780adbdc6da15ebdb799980daf32df22ee974af0893d7409f177bbb68",
|
||||
"src/CelerisLab/body/sync_plan.py": "3a15bfe9ebeb91482dbfc68850761ef39c872cc12d2efc795babd0c01e392323",
|
||||
"src/CelerisLab/common/__init__.py": "d4dbde78bc97fccc9eabac9abae8f0f15c112c10ff8e9b45bd9401d4723df1ef",
|
||||
"src/CelerisLab/common/_types.py": "aad2ff1a9033d4fd68783ad7123afb47201ddc58785cb6dc0246947037072a5f",
|
||||
"src/CelerisLab/common/checkpoint.py": "b2f960aecd5ac27a3a7130b809ffad4709c44d522edef0359ab952654625410b",
|
||||
"src/CelerisLab/common/pathline.py": "a1b6efcc0a076d0f1dc8d49a595779426d7d5626b00072a59bac710ff02ad046",
|
||||
"src/CelerisLab/common/preprocess.py": "7fc78a08857cf8e98519500b094a1d896af189b6b15658ff9b388ed51bed4515",
|
||||
"src/CelerisLab/common/render.py": "0e055476257eb2bcd11e733766e52195de02f8fad228f570a3511a7c831bdc29",
|
||||
"src/CelerisLab/common/streakline/__init__.py": "13ff1cfa416fdd721a08a659e76b5a5a99b8d3201add10a83b7b0bc654bc1eec",
|
||||
"src/CelerisLab/common/streakline/_config.py": "a9185ef68e9c7b5d5a1dc0b04a28341e2ad91d13c145a7c106636a878cf0a605",
|
||||
"src/CelerisLab/common/streakline/_integrate.py": "3fbd4368b2c8d0e7fda40dc65aac5df02b085008b4c68acd83cb7ae45d33a13b",
|
||||
"src/CelerisLab/common/streakline/_render.py": "236cd637414ee318c4d66f9aed32110d8dc42a100d65fde06172f7cd0ba62c65",
|
||||
"src/CelerisLab/common/streakline/_streakline.py": "1a3e08daa706b5f83cdeb337e9a945a36ddf7583c40af1d0bb9d825ac954df37",
|
||||
"src/CelerisLab/config.py": "2f1bba7515f5bc08cb3a8d140bcafe7fa0689e01b3b06494697bb2956a71530e",
|
||||
"src/CelerisLab/configs/CONFIG.md": "41cafdbe525366c08aa9d0416ea026ccf0026ba7123b8a9b65f968a80d928e3a",
|
||||
"src/CelerisLab/configs/config_body.json": "055f261f0828ca1d4f2bb694bd15b72bbcabe31d552326208f28e37f761adab1",
|
||||
"src/CelerisLab/configs/config_lbm.json": "17e4311f1f250c6ece59177a8b6ff856b69a016c7c10267e774b030a0a390865",
|
||||
"src/CelerisLab/configs/config_lbm_flume_mrt_zouhe.json": "8f593321db05a563a42931603a228d61cbcba06dfbe113262d5cd0ad93c0fe79",
|
||||
"src/CelerisLab/configs/config_lbm_flume_trt_regularized.json": "f4bba8e6a4339fc3c4eb14f6e2f57c4b22993c73703c773d853edfbe34736e56",
|
||||
"src/CelerisLab/configs/config_lbm_three_cylinder_triangle.json": "eeb8e7149dbe4aa6b3a9562802735aa950750dfbe2d972a0727e788573afa817",
|
||||
"src/CelerisLab/cuda/__init__.py": "0d01dff9f0399c8baba822aab5ca0122a135f011008ed8a499ebd9f7e5b06aea",
|
||||
"src/CelerisLab/cuda/compiler_v2.py": "c4cc3ec4445c8d75e6a253dd87963877117a722bc73b9d4811806fc6045d08c1",
|
||||
"src/CelerisLab/cuda/context.py": "013dd4ec6d01d2fbd11afdfb103eac6a273bd9f798d663d761b851eeb27885e9",
|
||||
"src/CelerisLab/cuda/obs_layout.py": "5ffb2c3aeeaaaaeb64f2cd8febfbcf4ad9919e5414020ad753cfade0683b21c2",
|
||||
"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": "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": "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/core/descriptors.cuh": "8440bc14857da9007982650f828a23608eec9f7cc4bf772e8c8dc1239cb45356",
|
||||
"src/CelerisLab/lbm/kernels/core/flags.cuh": "0025705f24710330d9d9195f713879bfb650a85a3449baef0e196b831af104ab",
|
||||
"src/CelerisLab/lbm/kernels/core/layout.cuh": "1fbd820021c89ac3efcde24145996cb0147769e607e498e61f308ed3e0b13706",
|
||||
"src/CelerisLab/lbm/kernels/core/obs.cuh": "b742b77c9f61e1f020fe9922c3838ae9d855e17b381154958b58f10a22938922",
|
||||
"src/CelerisLab/lbm/kernels/core/params.cuh": "6e18bf730d936d940e3d85452f0714a2eaae31bf41002f9fd520ec5b372878dd",
|
||||
"src/CelerisLab/lbm/kernels/core/precision.cuh": "849df14b4cce50af52399e4b8f3e997196f3ae5f1163f68e28df3e6b2507a8c4",
|
||||
"src/CelerisLab/lbm/kernels/kernel_v2.cu": "c7bd3fb705b77261ba2441c52a24a7e6a7865c165cba088a1b75201c4d29c408",
|
||||
"src/CelerisLab/lbm/kernels/operators/collision_mrt.cuh": "aee444eb60c47a3fd518dca975d1af05425a0818a0ec6c3fb3f6150f60c2cb44",
|
||||
"src/CelerisLab/lbm/kernels/operators/collision_srt.cuh": "6b7ff842f392c8f853d2d1a97cc69bfe50f21283f73e659404da07cf6c95f5e1",
|
||||
"src/CelerisLab/lbm/kernels/operators/collision_trt.cuh": "9725b9840b9ad8b4ec7be61ff5d06d3151e86d1a87585c13f2fbf934d0d2c5f6",
|
||||
"src/CelerisLab/lbm/kernels/operators/forcing_guo.cuh": "969a430c1af03f32e3bd0df95d805e64f56334717c44dd4ba208ba503062a24b",
|
||||
"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/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",
|
||||
"src/CelerisLab/lbm/kernels/step/init_flow.cu": "305be3bb12fc0d039acec1701baabcf0e8a35e683c49c34f2af8ca9867d2b29c",
|
||||
"src/CelerisLab/lbm/kernels/step/one_step_double.cu": "f9f8242b38e8e0cf8425b75e2b0215bc15363c62eaa0fb43c761b8e0931bfdc9",
|
||||
"src/CelerisLab/lbm/kernels/step/one_step_esopull.cu": "aa223b2744ae6c9125673df311a96ce588032c1ba58bebb11fd33ecb990f8ed4",
|
||||
"src/CelerisLab/lbm/kernels/streaming/esopull_semantic_helpers.cuh": "dd5a9091628b079efd97e53fd49e52d09dcee88529235db77a5648e02937af6e",
|
||||
"src/CelerisLab/lbm/kernels/streaming/esopull_single_buffer.cuh": "77ed4ab9a0ebc5ff62a91a7c39066ef395391ae36e9040a69fb2bd8b1626dc79",
|
||||
"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_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"
|
||||
},
|
||||
"candidate_header_sha256": "a3db46c2e7d27530b2d1436e65cdbed0b72cc7e047bfbeef2a640877271b51aa",
|
||||
"production_origin_commit": "47b05bc8abfc957fe876b0c63bdb386e3c6cbaa5",
|
||||
"source_experiment": "Explicit channel47/cd3 source experiment; not inherited d79 GPU acceptance. Corrected variant permits only the reviewed Smagorinsky header patch.",
|
||||
"historical_preparation_commit": "d79e3f6f0a424f5bcc3a1a6d610313e49daf97a2"
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Independent 1D continuum oracle; no LBM closure/header or GPU imports."""
|
||||
|
||||
import numpy as np
|
||||
|
||||
H, U, NU, DELTA = 32.0, 0.04, 0.02, 1.0
|
||||
TIMES = tuple(round(v * H**2 / (np.pi**2 * NU)) for v in (0.1, 0.2, 0.4))
|
||||
|
||||
|
||||
def solve(cs, n=256, times=TIMES, *, h=H, u0=U, nu=NU, delta=DELTA, cfl=0.4):
|
||||
"""FV centered face flux plus SSPRK2, zero Dirichlet at 0,h.
|
||||
|
||||
du/dt = d/dy[(nu + (cs*delta)^2*|du/dy|) du/dy].
|
||||
The oracle refinement dx=h/n MUST NOT replace the LES filter delta.
|
||||
"""
|
||||
if not np.isfinite(cfl) or not 0 < cfl <= 0.4:
|
||||
raise ValueError("cfl must be finite and in (0, .4]")
|
||||
dx = h / n
|
||||
y = (np.arange(n) + 0.5) * dx
|
||||
u = u0 * np.sin(np.pi * y / h)
|
||||
a = (cs * delta) ** 2
|
||||
|
||||
def gradients(v):
|
||||
g = np.empty(n + 1)
|
||||
g[1:-1] = np.diff(v) / dx
|
||||
g[0], g[-1] = 2 * v[0] / dx, -2 * v[-1] / dx
|
||||
return g
|
||||
|
||||
def rhs(v):
|
||||
g = gradients(v)
|
||||
flux = (nu + a * np.abs(g)) * g
|
||||
return np.diff(flux) / dx
|
||||
|
||||
t = 0.0
|
||||
out = {}
|
||||
for target in times:
|
||||
if target < t:
|
||||
raise ValueError("times must be nondecreasing and nonnegative")
|
||||
while t < target:
|
||||
# Nonlinear flux derivative is nu+2*a*abs(gradient).
|
||||
dt = min(
|
||||
target - t, cfl * dx * dx / (nu + 2 * a * np.max(np.abs(gradients(u))))
|
||||
)
|
||||
v = u + dt * rhs(u)
|
||||
u = 0.5 * u + 0.5 * (v + dt * rhs(v))
|
||||
t += dt
|
||||
out[int(target)] = u.copy()
|
||||
return y, out
|
||||
|
||||
|
||||
def amplitude(y, u, h=H):
|
||||
s = np.sin(np.pi * y / h)
|
||||
return float(np.dot(u, s) / np.dot(s, s))
|
||||
|
||||
|
||||
def relative(a, b):
|
||||
return float(np.linalg.norm(a - b) / np.linalg.norm(b))
|
||||
@@ -0,0 +1,321 @@
|
||||
"""Bounded SRT/DB uniform-grid wall-bounded shear validation, Horsea only.
|
||||
|
||||
Uses production Simulation/collision/streaming. Test-only raw population/flag
|
||||
adapter follows tests/integration/test_numerical_gpu.py; no periodic-y API.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
from tempfile import TemporaryDirectory
|
||||
import time
|
||||
import numpy as np
|
||||
from les_flow_oracle import H, U, NU, DELTA, TIMES, solve, amplitude, relative
|
||||
|
||||
HERE = Path(__file__).resolve().parent
|
||||
HEADER = "src/CelerisLab/lbm/kernels/operators/turbulence_smag.cuh"
|
||||
LIMITS = dict(
|
||||
linear_relative_l2=0.003,
|
||||
les_relative_l2=0.005,
|
||||
sgs_increment_relative_error=0.15,
|
||||
oracle_grid_relative=0.00008,
|
||||
mass_drift=0.00005,
|
||||
max_transverse=0.00001,
|
||||
x_invariance=0.000001,
|
||||
initial_relative_l2=0.00001,
|
||||
)
|
||||
|
||||
|
||||
def decode_macros(data, w, cx, cy):
|
||||
"""Reject invalid physical populations/density/macros before reporting norms."""
|
||||
with np.errstate(over="ignore", invalid="ignore", divide="ignore"):
|
||||
f = data.astype(np.float64) + w[:, None, None].astype(np.float64)
|
||||
if not np.isfinite(f).all():
|
||||
raise RuntimeError("Nonfinite populations")
|
||||
f = f[:, 1:-1, :]
|
||||
rho = f.sum(axis=0)
|
||||
if not np.isfinite(rho).all() or np.any(rho <= 0):
|
||||
raise RuntimeError("Nonpositive or nonfinite fluid density")
|
||||
vx = np.einsum("q,qyx->yx", cx, f) / rho
|
||||
vy = np.einsum("q,qyx->yx", cy, f) / rho
|
||||
profile = vx.mean(axis=1)
|
||||
if not (
|
||||
np.isfinite(vx).all()
|
||||
and np.isfinite(vy).all()
|
||||
and np.isfinite(profile).all()
|
||||
):
|
||||
raise RuntimeError("Nonfinite decoded velocity/profile")
|
||||
metrics = (
|
||||
float(rho.mean()),
|
||||
float(np.max(np.abs(vy))),
|
||||
float(np.max(np.ptp(vx, axis=1))),
|
||||
)
|
||||
if not np.isfinite(metrics).all():
|
||||
raise RuntimeError("Nonfinite decoded diagnostics")
|
||||
return profile, *metrics
|
||||
|
||||
|
||||
def source_guard(root, variant):
|
||||
manifest = json.loads((HERE / "data/les_flow/source_pins.json").read_text())
|
||||
for name, sha in manifest["sources"].items():
|
||||
expected = (
|
||||
manifest["candidate_header_sha256"]
|
||||
if name == HEADER and variant == "corrected"
|
||||
else sha
|
||||
)
|
||||
if hashlib.sha256((root / name).read_bytes()).hexdigest() != expected:
|
||||
raise RuntimeError("Source pin mismatch: " + name)
|
||||
return dict(
|
||||
base_commit=manifest["base_commit"],
|
||||
production_origin_commit=manifest["production_origin_commit"],
|
||||
source_experiment=manifest["source_experiment"],
|
||||
checkout_commit=subprocess.check_output(
|
||||
["git", "-C", str(root), "rev-parse", "HEAD"], text=True
|
||||
).strip(),
|
||||
source_file_count=len(manifest["sources"]),
|
||||
header_sha256=hashlib.sha256((root / HEADER).read_bytes()).hexdigest(),
|
||||
variant=variant,
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("--root", type=Path, required=True)
|
||||
ap.add_argument("--variant", choices=["baseline", "corrected"], required=True)
|
||||
ap.add_argument("--output", type=Path, required=True)
|
||||
ap.add_argument(
|
||||
"--device", type=int, default=0, help="Logical device in CUDA_VISIBLE_DEVICES"
|
||||
)
|
||||
ap.add_argument("--run-gpu", action="store_true")
|
||||
args = ap.parse_args()
|
||||
if not args.run_gpu:
|
||||
ap.error("Explicit --run-gpu is required; authorized Horsea executor only")
|
||||
if not os.environ.get("CUDA_VISIBLE_DEVICES"):
|
||||
ap.error("Explicit CUDA_VISIBLE_DEVICES required")
|
||||
if args.output.exists():
|
||||
ap.error("Output exists; choose a new evidence path")
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
root = args.root.resolve()
|
||||
pins = source_guard(root, args.variant)
|
||||
# Refuse installed-package shadowing; import only after explicit GPU opt-in.
|
||||
sys.path.insert(0, str(root / "src"))
|
||||
import CelerisLab
|
||||
|
||||
if Path(CelerisLab.__file__).resolve() != root / "src/CelerisLab/__init__.py":
|
||||
raise RuntimeError("Wrong CelerisLab import")
|
||||
import pycuda.driver as cuda
|
||||
from CelerisLab.simulation import Simulation
|
||||
from CelerisLab.lbm.descriptors import D2Q9_EX, D2Q9_EY, FLUID, SOLID, BC_WALL
|
||||
|
||||
cx = np.asarray(D2Q9_EX)
|
||||
cy = np.asarray(D2Q9_EY)
|
||||
w = np.asarray([4 / 9] + [1 / 9] * 4 + [1 / 36] * 4, dtype=np.float32)
|
||||
h = int(H)
|
||||
nx = 8
|
||||
ny = h + 2
|
||||
y = np.arange(h) + 0.5
|
||||
report = dict(
|
||||
source=pins,
|
||||
package=CelerisLab.__file__,
|
||||
cuda_visible_devices=os.environ["CUDA_VISIBLE_DEVICES"],
|
||||
logical_device=args.device,
|
||||
geometry=dict(nx=nx, ny=ny, halfway_wall_height=H),
|
||||
parameters=dict(
|
||||
nu=NU,
|
||||
U=U,
|
||||
delta_lattice=DELTA,
|
||||
tau0=0.5 + 3 * NU,
|
||||
re_height=U * H / NU,
|
||||
ma=U * np.sqrt(3),
|
||||
),
|
||||
limits=LIMITS,
|
||||
criterion="standard |S|=sqrt(2 S:S); no baseline-failure masking",
|
||||
cases=[],
|
||||
)
|
||||
|
||||
def save():
|
||||
args.output.write_text(json.dumps(report, indent=2, allow_nan=False) + "\n")
|
||||
|
||||
started = time.monotonic()
|
||||
for cs in (0.0, 0.16, 1.0):
|
||||
cfg = json.loads((root / "src/CelerisLab/configs/config_lbm.json").read_text())
|
||||
cfg["grid"].update(nx=nx, ny=ny, nz=1, lattice_model="D2Q9")
|
||||
cfg["physics"].update(viscosity=NU, velocity=0.0, rho=1.0)
|
||||
cfg["method"].update(
|
||||
collision="SRT",
|
||||
streaming="double_buffer",
|
||||
store_precision="FP32",
|
||||
ddf_shifting=True,
|
||||
y_wall_bc="bounce_back",
|
||||
)
|
||||
cfg["method"]["les"].update(enabled=True, cs=cs, closed_form=True)
|
||||
with TemporaryDirectory(prefix="uniform-les-flow-") as temp:
|
||||
lbm = Path(temp) / "lbm.json"
|
||||
bodies = Path(temp) / "bodies.json"
|
||||
lbm.write_text(json.dumps(cfg))
|
||||
bodies.write_text('{"objects":[]}')
|
||||
sim = Simulation(str(lbm), str(bodies), device_id=args.device)
|
||||
try:
|
||||
sim.initialize()
|
||||
# Exactly the existing integration-test spatial postcollision contract.
|
||||
# y-wall ghosts stay zero velocity; x edge fluid gives modulo x streaming.
|
||||
ux = np.zeros((ny, nx))
|
||||
ux[1:-1] = U * np.sin(np.pi * y / H)[:, None]
|
||||
cu = cx[:, None, None] * ux[None, :, :]
|
||||
physical = w[:, None, None] * (
|
||||
1 + 3 * cu + 4.5 * cu * cu - 1.5 * ux[None, :, :] ** 2
|
||||
)
|
||||
shifted = np.ascontiguousarray(
|
||||
physical - w[:, None, None], dtype=np.float32
|
||||
)
|
||||
|
||||
def install_initial():
|
||||
with sim.ctx.activate():
|
||||
cuda.memcpy_htod(sim.field.ddf_gpu, shifted)
|
||||
cuda.memcpy_htod(sim.field.temp_gpu, shifted)
|
||||
sim.stepper._step_count = (
|
||||
1 # count metadata; physical elapsed time is 0
|
||||
)
|
||||
sim.field.invalidate_host_ddf_cache()
|
||||
flags = sim.field.flag.reshape(ny, nx)
|
||||
flags[:] = FLUID
|
||||
flags[[0, -1], :] = SOLID | BC_WALL
|
||||
sim.field.upload_flags()
|
||||
sim.field.update_params(fx=0.0, fy=0.0, fz=0.0)
|
||||
|
||||
def observe():
|
||||
data = np.empty((9, ny, nx), np.float32)
|
||||
with sim.ctx.activate():
|
||||
cuda.memcpy_dtoh(data, sim.field.ddf_gpu)
|
||||
return decode_macros(data, w, cx, cy)
|
||||
|
||||
install_initial()
|
||||
observe() # reject invalid state before any advancing launch
|
||||
sim.run(1) # exercise the actual advancing kernel before claiming READY
|
||||
observe() # also require valid density/macros after the warm-up launch
|
||||
install_initial() # restore both (possibly swapped) DB buffers, flags and count
|
||||
initial, rho0, _, _ = observe()
|
||||
initial_error = relative(initial, U * np.sin(np.pi * y / H))
|
||||
if (
|
||||
not np.isfinite(initial_error)
|
||||
or initial_error > LIMITS["initial_relative_l2"]
|
||||
):
|
||||
raise RuntimeError("Initial state adapter failed")
|
||||
with sim.ctx.activate():
|
||||
device_name = cuda.Context.get_device().name()
|
||||
cuda.Context.synchronize()
|
||||
print(
|
||||
json.dumps(
|
||||
dict(
|
||||
status="READY",
|
||||
cs=cs,
|
||||
device=device_name,
|
||||
variant=args.variant,
|
||||
source=pins,
|
||||
warmup_steps=1,
|
||||
initial_state_restored=True,
|
||||
initial_relative_l2=initial_error,
|
||||
max_steps=TIMES[-1],
|
||||
mode="SRT double_buffer shifted FP32",
|
||||
)
|
||||
),
|
||||
flush=True,
|
||||
)
|
||||
yf, ref = solve(cs, n=256)
|
||||
yc, coarse = solve(cs, n=128)
|
||||
_, wrong = solve(cs * 2 ** (-0.25), n=256) if cs else (yf, ref)
|
||||
case = dict(
|
||||
cs=cs,
|
||||
device=device_name,
|
||||
warmup_steps=1,
|
||||
initial_state_restored=True,
|
||||
configuration=cfg,
|
||||
initial_relative_l2=initial_error,
|
||||
observations=[],
|
||||
)
|
||||
report["cases"].append(case)
|
||||
elapsed = 0
|
||||
for target in TIMES:
|
||||
sim.run(target - elapsed)
|
||||
elapsed = target
|
||||
profile, mass, transverse, xspread = observe()
|
||||
standard = np.interp(y, yf, ref[target])
|
||||
analytic = (
|
||||
U * np.sin(np.pi * y / H) * np.exp(-NU * (np.pi / H) ** 2 * target)
|
||||
)
|
||||
oracle_grid = relative(np.interp(yc, yf, ref[target]), coarse[target])
|
||||
reference = standard if cs else analytic
|
||||
error = relative(profile, reference)
|
||||
obs = dict(
|
||||
elapsed_steps=elapsed,
|
||||
completed_count=sim.stepper.step_count,
|
||||
relative_l2=error,
|
||||
oracle_grid_relative=oracle_grid,
|
||||
mass_drift=abs(mass - rho0),
|
||||
max_transverse=transverse,
|
||||
x_invariance=xspread,
|
||||
amplitude=amplitude(y, profile),
|
||||
reference_amplitude=amplitude(y, reference),
|
||||
wrong_convention_relative_l2=relative(
|
||||
profile, np.interp(y, yf, wrong[target])
|
||||
),
|
||||
profile=profile.tolist(),
|
||||
reference_profile=reference.tolist(),
|
||||
)
|
||||
obs["passed"] = bool(
|
||||
error <= LIMITS["les_relative_l2" if cs else "linear_relative_l2"]
|
||||
and oracle_grid <= LIMITS["oracle_grid_relative"]
|
||||
and abs(mass - rho0) <= LIMITS["mass_drift"]
|
||||
and transverse <= LIMITS["max_transverse"]
|
||||
and xspread <= LIMITS["x_invariance"]
|
||||
)
|
||||
case["observations"].append(obs)
|
||||
save()
|
||||
print(
|
||||
json.dumps(
|
||||
{k: v for k, v in obs.items() if not k.endswith("profile")}
|
||||
),
|
||||
flush=True,
|
||||
)
|
||||
finally:
|
||||
sim.close()
|
||||
# Cancel the common molecular lattice error using the actual Cs=0 run.
|
||||
increments = []
|
||||
for zero, les in zip(
|
||||
report["cases"][0]["observations"], report["cases"][-1]["observations"]
|
||||
):
|
||||
measured = zero["amplitude"] - les["amplitude"]
|
||||
expected = zero["reference_amplitude"] - les["reference_amplitude"]
|
||||
increments.append(
|
||||
dict(
|
||||
elapsed_steps=zero["elapsed_steps"],
|
||||
measured=measured,
|
||||
expected=expected,
|
||||
relative_error=abs(measured - expected) / abs(expected),
|
||||
)
|
||||
)
|
||||
report.update(sgs_increments=increments, seconds=time.monotonic() - started)
|
||||
# Last two times are the declared signal gate; earliest is transient diagnostic.
|
||||
report["passed"] = bool(
|
||||
all(o["passed"] for c in report["cases"] for o in c["observations"])
|
||||
and all(
|
||||
v["relative_error"] <= LIMITS["sgs_increment_relative_error"]
|
||||
for v in increments[1:]
|
||||
)
|
||||
)
|
||||
save()
|
||||
print(
|
||||
json.dumps(
|
||||
dict(status="DONE", passed=report["passed"], output=str(args.output))
|
||||
),
|
||||
flush=True,
|
||||
)
|
||||
return 0 if report["passed"] else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user