Pure column helpers that merge vanished (sub-H_VANISHED) layers into a
“massive” grid (nzc <= nz) so the column solver never divides by a
vanished thickness: thickness-weighted means onto the merged grid, plus
the inverse interpolation of an interface quantity back to the original
interfaces. Reference: Jackson, Hallberg & Legg (2008), JPO 38, 1033.
ORDERING (load-bearing): LOCAL SURFACE-DOWN indices — local k=1 =
surface, k=nz = bed; interfaces K=1 (surface) … K=nz+1 (bed).
The consumer does the global(bed-up) <-> local(surface-down) flip; the
helper never sees global indices.
MERGE DIRECTION (do not invent a symmetric rule): walking surface-down, a merged layer opens only when the current cluster already has mass AND the incoming layer is massive (> h_min). So a vanished layer folds into the preceding (surfaceward) massive layer; a leading surface run folds into the first massive layer beneath; a trailing bed run folds into the last massive layer above.
GPU NOTE: !$acc routine seq, callable cross-module from the kappa-shear
do concurrent column kernel. NVHPC will NOT inline across the module
boundary, but these run once per column per compute (thermo cadence), so
the divergence cost is acceptable. All arrays are fixed-size
NZ_STACK_MAX(+1) explicit-shape locals (no descriptor walk, no alloc).
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private, | parameter | :: | NZL | = | NZ_STACK_MAX |
Layer-array dimension (must match the consumer’s NZL). |
| integer, | private, | parameter | :: | NZLI | = | NZ_STACK_MAX+1 |
Interface-array dimension (= NZL + 1). |
Build the merged massive-layer grid and the maps kc, kf.
kc(k) (k=1..nz) = merged-layer index original layer k folds into;
kc(nz+1) = nzc+1 is the bed sentinel. kf(K) = fractional position
of original interface K inside merged layer kc(K) (0 = coincides
with a merged interface -> pure lookup; (0,1) = interior -> linear
blend in massless_interp_back).
Identity case (no layer < h_min): nzc==nz, kc(k)==k, kf(k)==0,
hc==h bit-for-bit.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h(NZL) |
Local surface-down layer thicknesses (m), >= 0. |
||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_min |
Merge threshold (H_VANISHED). |
||
| integer, | intent(out) | :: | nzc |
Number of merged massive layers (<= nz). |
||
| real(kind=wp), | intent(out) | :: | hc(NZL) |
Merged thicknesses (m), valid 1..nzc. |
||
| integer, | intent(out) | :: | kc(NZLI) |
Layer/interface -> merged index, valid 1..nz+1 (sentinel at nz+1). |
||
| real(kind=wp), | intent(out) | :: | kf(NZLI) |
Fractional interface weight, valid 1..nz+1. |
Inverse map: interpolate an interface quantity qc(1:nzc+1) on the
merged grid back to the original nz+1 interfaces. kf==0 takes a
pure lookup; interior interfaces take the linear blend between merged
interfaces kc(K) and kc(K)+1 (in range since kf>0 only when
kc(K) < nzc+1). Identity case: kf==0 everywhere -> q==qc.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | qc(NZLI) |
Interface quantity on the merged grid (valid 1..nzc+1). |
||
| integer, | intent(in) | :: | kc(NZLI) | |||
| real(kind=wp), | intent(in) | :: | kf(NZLI) | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(out) | :: | q(NZLI) |
Interface quantity on the original grid (filled 1..nz+1). |
Thickness-weighted merged means for u, v, T, S — the solver receives
MEANS, not integrals, and must not re-divide. Accumulation runs in the
same surface-down k order as massless_build_maps so the
column-integral conservation holds to round-off.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h(NZL) | |||
| integer, | intent(in) | :: | kc(NZLI) | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | nzc | |||
| real(kind=wp), | intent(in) | :: | u(NZL) | |||
| real(kind=wp), | intent(in) | :: | v(NZL) | |||
| real(kind=wp), | intent(in) | :: | t(NZL) | |||
| real(kind=wp), | intent(in) | :: | s(NZL) | |||
| real(kind=wp), | intent(out) | :: | uc(NZL) | |||
| real(kind=wp), | intent(out) | :: | vc(NZL) | |||
| real(kind=wp), | intent(out) | :: | tc(NZL) | |||
| real(kind=wp), | intent(out) | :: | sc(NZL) |