26 import test_scalar_cutcell_gates
as g
27 cs, made, its, res = [], [], [], []
29 class Rec(g.pf.Solver):
30 def __init__(self, *a, **k):
31 super().__init__(*a, **k)
34 def advance_scalars(self, *a, **k):
35 r = super().advance_scalars(*a, **k)
36 cs.append(np.array(self.get_field(
"c")))
37 cen = self.diagnostics.scalar_census(
"c")
38 its.append(int(cen[
"krylov_iterations"]))
39 res.append(float(cen[
"krylov_residual"]))
44 g.g9_case(Rh, g.g9_offsets(Rh)[0], os.environ.get(
"SCHEME",
"koren"), 0.5, nsteps=nsteps)
47 fx, fy = g.annulus_fluxes(s, h)
48 geo = s.diagnostics.scalar_geometry(
"c")
49 np.savez_compressed(path, c=np.stack(cs), unk=np.asarray(geo[
"unknown"]),
50 kappa=np.asarray(geo[
"kappa"]), fx=fx, fy=fy, its=np.asarray(its),
52 print(f
"wrote {path}: {len(cs)} steps")
56 """Per low face of every cell along axis a (periodic): the koren branch code on c^n for the
57 sign of f: 0 ratio, 1 |den| < 1e-10 (r = 0), 2 both < 1e-10 (r = 1); and the upwind-pair /
58 downwind unknown flags handled by the caller."""
59 cm1, cm2, cp1 = (np.roll(c, 1, axis=a), np.roll(c, 2, axis=a), np.roll(c, -1, axis=a))
61 num = np.where(pos, cm1 - cm2, c - cp1)
62 den = np.where(pos, c - cm1, cm1 - c)
63 small_d = np.abs(den) < 1e-10
64 small_n = np.abs(num) < 1e-10
65 code = np.where(small_d & small_n, 2, np.where(small_d, 1, 0))
70 A, B = np.load(pa), np.load(pb)
72 cA, cB = A[
"c"], B[
"c"]
73 n = min(len(cA), len(cB))
74 d = np.array([np.max(np.abs(cA[k] - cB[k])[unk])
for k
in range(n)])
75 cmax = float(np.max(np.abs(cA[0])))
76 jump = next((k
for k
in range(1, n)
if d[k] > 1e3 * max(d[k - 1], 1e-30)
and d[k] > 1e-14),
78 print(
"per-step max|cA - cB| (absolute; max c ~ %.3g):" % cmax)
80 if k < 3
or (jump
is not None and abs(k - jump) <= 2)
or k == n - 1:
81 print(f
" step {k + 1:4d}: {d[k]:.3e}")
83 print(
"no jump found")
86 cnA, cnB = cA[k - 1], cB[k - 1]
87 loc = np.unravel_index(np.argmax(np.where(unk, np.abs(cA[k] - cB[k]), 0.0)), unk.shape)
88 print(f
"jump at step {k + 1}: argmax cell {tuple(int(v) for v in loc)}, c^n there "
89 f
"{cnA[loc]:.3e}, |dc^n| there {abs(cnA[loc] - cnB[loc]):.3e}; "
90 f
"after: |dc| {abs(cA[k][loc] - cB[k][loc]):.3e}")
91 for a, f
in ((0, A[
"fx"]), (1, A[
"fy"])):
92 u0, um1, um2, up1 = unk, np.roll(unk, 1, a), np.roll(unk, 2, a), np.roll(unk, -1, a)
93 koren = (f != 0.0) & u0 & um1 & np.where(f > 0.0, um2, up1)
94 bA, nA, dA =
branch(cnA, f, a)
95 bB, nB, dB =
branch(cnB, f, a)
96 diff = koren & (bA != bB)
97 for idx
in zip(*np.nonzero(diff)):
98 dist = max(abs(int(idx[0]) - int(loc[0])), abs(int(idx[1]) - int(loc[1])))
99 print(f
" axis {a} face {tuple(int(v) for v in idx)} (cheb. distance {dist} to the "
100 f
"jump): branch A {bA[idx]} B {bB[idx]}; num {nA[idx]:.17e} / {nB[idx]:.17e}; "
101 f
"den {dA[idx]:.17e} / {dB[idx]:.17e}; F/V {f[idx]:.3e}")
102 print(f
"axis {a}: koren faces {int(koren.sum())}, branch differs on {int(diff.sum())}")
104 near = unk & (np.abs(cnA) < 1e-8) & (np.abs(cnA) > 1e-12)
106 rel = np.abs(cnA - cnB)[near]
107 print(f
"cells with 1e-12 < c^n < 1e-8: {int(near.sum())}, max |dc^n| {rel.max():.3e}")
111 """Re-run step k+1 alone from run `src`'s c after step k, on a fresh solver (same setup as
112 g9_case), and store c after it: two thread counts from the SAME c^n isolate what the step
113 itself generates from what it amplifies."""
114 import test_scalar_cutcell_gates
as g
116 s, h = g.annulus_case(Rh, g.g9_offsets(Rh)[0],
"koren")
117 geo = s.diagnostics.scalar_geometry(
"c")
118 unk = geo[
"unknown"] > 0.5
120 ax, ay = geo[
"aperture_x"], geo[
"aperture_y"]
121 full = unk & (kap >= 1.0)
122 for a, ap
in ((0, ax), (1, ay), (2, geo[
"aperture_z"])):
123 full &= (ap >= 1.0) & (np.roll(ap, -1, axis=a) >= 1.0)
124 fx, fy = g.annulus_fluxes(s, h)
125 o = (np.maximum(np.roll(fx, -1, axis=0), 0) + np.maximum(-fx, 0) +
126 np.maximum(np.roll(fy, -1, axis=1), 0) + np.maximum(-fy, 0))
128 nrev = int(math.ceil(T * float(np.max(o[full])) / 0.5))
130 g.set_annulus_velocity(s, fx, fy)
132 s.set_scalar_tolerance(
"c", rtol)
133 s.set_field(
"c", np.asfortranarray(np.load(src)[
"c"][k - 1]))
135 cen = s.diagnostics.scalar_census(
"c")
136 np.savez_compressed(out, c=np.array(s.get_field(
"c")), its=cen[
"krylov_iterations"],
137 res=cen[
"krylov_residual"])
138 print(f
"step {k + 1} from {src}: its {cen['krylov_iterations']} res "
139 f
"{cen['krylov_residual']:.17e}")