Retain shifted density perturbation in opt-in blocked collision

This commit is contained in:
Codex
2026-10-16 23:28:29 -07:00
parent aaf35c6505
commit c33caf636d
7 changed files with 154 additions and 13 deletions
+8 -2
View File
@@ -18,8 +18,8 @@
#include "boundary/curved_boundary.cuh"
#include "boundary/planar_velocity.cuh"
#if DIM != 2 || NQ != 9 || COLLISION_MODEL != 0 || STORE_PRECISION != 0 || USE_DDF_SHIFTING || USE_LES || STREAMING_MODEL != 0
#error "Blocks require unshifted FP32 D2Q9 SRT double buffers without LES"
#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"
#endif
// Fixed-patch cell kinds, matching refinement.py ACTIVE/INNER_GHOST/OUTER_GHOST.
@@ -143,7 +143,13 @@ extern "C" __global__ void BlockStep(const fpxx* in, fpxx* out, unsigned int hal
}
float rho, ux, uy, feq[NQ];
compute_rho_u(f, rho, ux, uy);
#if USE_DDF_SHIFTING
// Preserve the density perturbation before adding the unit reference.
const float drho = f[0]+f[1]+f[2]+f[3]+f[4]+f[5]+f[6]+f[7]+f[8];
compute_feq(rho, ux, uy, feq, drho);
#else
compute_feq(rho, ux, uy, feq);
#endif
collide_srt_no_force(f, feq, d_params.omega);
}
}
@@ -1,6 +1,6 @@
// On-site D2Q9 Zou-He velocity closure, paired lattice ordering.
// Input is poststream f at the arrival time. Only unknown populations change;
// the caller owns collision/store. No force, shifting or off-lattice walls.
// the caller owns collision/store. No force or off-lattice walls. Shifted storage uses unit reference density.
#ifndef CELERIS_BOUNDARY_PLANAR_VELOCITY_CUH
#define CELERIS_BOUNDARY_PLANAR_VELOCITY_CUH
#include <math.h>
@@ -28,7 +28,11 @@ __device__ __forceinline__ float bottom_wall_normal_velocity(unsigned int x)
__device__ __forceinline__ void reconstruct_bottom_velocity(float* f, float u, float v)
{
const float rho = (f[0] + f[1] + f[2] + 2.0f*(f[4] + f[6] + f[7])) / (1.0f-v);
const float rho = (
#if USE_DDF_SHIFTING
1.0f +
#endif
f[0] + f[1] + f[2] + 2.0f*(f[4] + f[6] + f[7])) / (1.0f-v);
f[3] = f[4] + (2.0f/3.0f)*rho*v;
f[5] = f[6] + 0.5f*(f[2]-f[1]) + 0.5f*rho*u + (1.0f/6.0f)*rho*v;
f[8] = f[7] + 0.5f*(f[1]-f[2]) - 0.5f*rho*u + (1.0f/6.0f)*rho*v;
@@ -36,7 +40,11 @@ __device__ __forceinline__ void reconstruct_bottom_velocity(float* f, float u, f
__device__ __forceinline__ void reconstruct_top_velocity(float* f, float u, float v)
{
const float rho = (f[0] + f[1] + f[2] + 2.0f*(f[3] + f[5] + f[8])) / (1.0f+v);
const float rho = (
#if USE_DDF_SHIFTING
1.0f +
#endif
f[0] + f[1] + f[2] + 2.0f*(f[3] + f[5] + f[8])) / (1.0f+v);
f[4] = f[3] - (2.0f/3.0f)*rho*v;
f[6] = f[5] + 0.5f*(f[1]-f[2]) - 0.5f*rho*u - (1.0f/6.0f)*rho*v;
f[7] = f[8] + 0.5f*(f[2]-f[1]) + 0.5f*rho*u - (1.0f/6.0f)*rho*v;
@@ -46,7 +54,12 @@ __device__ __forceinline__ void reconstruct_top_velocity(float* f, float u, floa
// J_y=rho*v follows from known poststream populations (ordinary D2Q9).
__device__ __forceinline__ void reconstruct_top_reservoir(float* f, float rho)
{
const float jy = f[0]+f[1]+f[2]+2.0f*(f[3]+f[5]+f[8])-rho;
#if USE_DDF_SHIFTING
const float density_offset = rho - 1.0f;
#else
const float density_offset = rho;
#endif
const float jy = f[0]+f[1]+f[2]+2.0f*(f[3]+f[5]+f[8])-density_offset;
f[4] = f[3] - (2.0f/3.0f)*jy;
f[6] = f[5] + 0.5f*(f[1]-f[2]) - (1.0f/6.0f)*jy;
f[7] = f[8] + 0.5f*(f[2]-f[1]) - (1.0f/6.0f)*jy;
+14 -3
View File
@@ -64,11 +64,12 @@ __device__ __forceinline__ void compute_rho_u(const float* __restrict__ f,
#if LATTICE_MODEL == LATTICE_D2Q9
__device__ __forceinline__ void compute_feq(float rho, float ux, float uy,
float* __restrict__ feq)
{
float* __restrict__ feq
#if USE_DDF_SHIFTING
const float rhom1 = rho - 1.0f; // perturbation density
, float rhom1
#endif
)
{
const float ux3 = 3.0f * ux;
const float uy3 = 3.0f * uy;
const float c3 = -1.5f * (ux * ux + uy * uy); // = -|u|²/(2cs²)
@@ -112,6 +113,16 @@ __device__ __forceinline__ void compute_feq(float rho, float ux, float uy,
#undef FEQ_CORE
}
#if USE_DDF_SHIFTING
// Existing callers recover the offset from rho; blocked shifted collision
// supplies sum(g) directly to the overload above, retaining small perturbations.
__device__ __forceinline__ void compute_feq(float rho, float ux, float uy,
float* __restrict__ feq)
{
compute_feq(rho, ux, uy, feq, rho - 1.0f);
}
#endif
#elif LATTICE_MODEL == LATTICE_D3Q19
__device__ __forceinline__ void compute_feq(float rho, float ux, float uy, float uz,
+4 -4
View File
@@ -52,7 +52,7 @@ 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/unshifted/double_buffer,
The initial backend contract is D2Q9/SRT/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.
"""
@@ -61,8 +61,8 @@ class FixedPatch2D:
if (not checked.is_d2q9 or checked.collision != "SRT"
or checked.streaming != "double_buffer"
or checked.store_precision != "FP32"
or checked.ddf_shifting or checked.les_enabled):
raise ValueError("FixedPatch2D requires D2Q9/SRT/FP32/unshifted/double_buffer without LES")
or checked.les_enabled):
raise ValueError("FixedPatch2D requires D2Q9/SRT/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):
@@ -452,7 +452,7 @@ def prepare_fine_boundary(cfg, patch, objects, *, wall_aware=False, jets=(),
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.store_precision != "FP32" or checked.ddf_shifting or checked.les_enabled
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")
from ..body.geometry.circle import CircleGeometry