19#include <petscblaslapack.h>
27typedef struct { PetscInt n, expected_n; PetscInt *comp, *
ci, *cj, *ck; }
DofMap;
29 PetscReal declared[3];
30 PetscReal ucat_global[3];
31 PetscReal ucat_ghost[3];
32 PetscReal ucont_global[3];
76 DMDALocalInfo info = user->
info;
77 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
78 const PetscInt lxs = 1, lxe = mx-1, lys = 1, lye = my-1, lzs = 1, lze = mz-1;
80 PetscFunctionBeginUser;
82 map->
n = (lxe-lxs)*(lye-lys)*(lze-lzs)*3;
83 PetscCall(PetscMalloc4(map->
n, &map->
comp, map->
n, &map->
ci, map->
n, &map->
cj, map->
n, &map->
ck));
84 for (PetscInt k = lzs; k < lze; k++)
85 for (PetscInt j = lys; j < lye; j++)
86 for (PetscInt i = lxs; i < lxe; i++)
87 for (PetscInt c = 0; c < 3; c++) {
88 map->
comp[cnt] = c; map->
ci[cnt] = i; map->
cj[cnt] = j; map->
ck[cnt] = k; cnt++;
90 PetscCheck(map->
n == map->
expected_n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
91 "periodic independent DOF count mismatch: got %" PetscInt_FMT
", expected %" PetscInt_FMT,
93 PetscFunctionReturn(0);
101 DMDALocalInfo info = user->
info;
102 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
103 const PetscInt xs = info.xs, xe = info.xs + info.xm;
104 const PetscInt ys = info.ys, ye = info.ys + info.ym;
105 const PetscInt zs = info.zs, ze = info.zs + info.zm;
106 const PetscInt lxs = PetscMax(xs, 1), lxe = PetscMin(xe, mx-1);
107 const PetscInt lys = PetscMax(ys, 1), lye = PetscMin(ye, my-1);
108 const PetscInt lzs = PetscMax(zs, 1), lze = PetscMin(ze, mz-1);
110 PetscFunctionBeginUser;
112 map->
n = PetscMax(0,lxe-lxs)*PetscMax(0,lye-lys)*PetscMax(0,lze-lzs)*3;
113 PetscCall(PetscMalloc4(map->
n, &map->
comp, map->
n, &map->
ci, map->
n, &map->
cj, map->
n, &map->
ck));
114 for (PetscInt k = lzs; k < lze; k++)
115 for (PetscInt j = lys; j < lye; j++)
116 for (PetscInt i = lxs; i < lxe; i++)
117 for (PetscInt c = 0; c < 3; c++) {
118 map->
comp[cnt] = c; map->
ci[cnt] = i; map->
cj[cnt] = j; map->
ck[cnt] = k; cnt++;
120 PetscFunctionReturn(0);
127{ PetscFunctionBeginUser; PetscCall(PetscFree4(map->
comp, map->
ci, map->
cj, map->
ck)); PetscFunctionReturn(0); }
130static inline PetscReal
CmpGet(
Cmpnts c, PetscInt comp) {
const PetscReal *p = (
const PetscReal*)&c;
return p[comp]; }
138 PetscFunctionBeginUser;
139 PetscCall(VecCopy(Ucont_in, user->
Ucont));
141 const char *fld[] = {
"Ucont"};
145 PetscCall(DMDAVecGetArrayRead(user->
fda, Rhs, &r));
146 for (PetscInt m = 0; m < map->
n; m++)
148 PetscCall(DMDAVecRestoreArrayRead(user->
fda, Rhs, &r));
149 PetscFunctionReturn(0);
156 PetscFunctionBeginUser;
157 PetscCall(DMDAVecGetArray(user->
fda, Ucont, &a));
158 { PetscReal *p = (PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]]; p[map->
comp[m]] += delta; }
159 PetscCall(DMDAVecRestoreArray(user->
fda, Ucont, &a));
160 PetscFunctionReturn(0);
169 PetscFunctionBeginUser;
170 PetscCall(DMDAVecGetArray(user->
fda, Ucont, &a));
171 {
const PetscReal *p = (
const PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]]; *val = p[map->
comp[m]]; }
172 PetscCall(DMDAVecRestoreArray(user->
fda, Ucont, &a));
173 PetscFunctionReturn(0);
186 const PetscInt nuniq = npts - 1;
187 const PetscInt ip = (idx == npts - 1) ? 0 : idx;
188 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
197 PetscInt ip = idx - 1;
198 if (idx == 0) ip = nuniq - 1;
199 else if (idx == npts - 1) ip = 0;
200 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
207 PetscInt mx, PetscInt my, PetscInt mz)
214 v.
x = 0.7; v.
y = -0.4; v.
z = 0.0;
216 v.
x = 0.7; v.
y = 0.0; v.
z = 0.0;
218 v.
x = 0.0; v.
y = -0.4; v.
z = 0.0;
220 (void)x; v.
x = 0.0; v.
y = 0.0; v.
z = 0.0;
222 v.
x = 1.0 + 0.5*PetscSinReal(y); v.
y = 0.0; v.
z = 0.0;
231 PetscInt mx, PetscInt my, PetscInt mz)
233 Cmpnts v = {0.0, 0.0, 0.0};
234 (void)j; (void)k; (void)my; (void)mz;
244 return PetscMax(PetscAbsReal(a.
x-b.
x), PetscMax(PetscAbsReal(a.
y-b.
y), PetscAbsReal(a.
z-b.
z)));
252 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
253 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
254 PetscFunctionBeginUser;
256 for (PetscInt k = 1; k < mz-1; k++)
257 for (PetscInt j = 1; j < my-1; j++) {
263 for (PetscInt k = 1; k < mz-1; k++)
264 for (PetscInt i = 1; i < mx-1; i++) {
270 for (PetscInt j = 1; j < my-1; j++)
271 for (PetscInt i = 1; i < mx-1; i++) {
278 for (PetscInt k = 0; k < mz; k++)
279 for (PetscInt j = 0; j < my; j++)
282 for (PetscInt k = 0; k < mz; k++)
283 for (PetscInt i = 0; i < mx; i++)
286 for (PetscInt j = 0; j < my; j++)
287 for (PetscInt i = 0; i < mx; i++)
291 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
292 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
293 PetscFunctionReturn(0);
299static inline PetscBool
InGhostRange(PetscInt idx, PetscInt lo, PetscInt n)
300{
return (PetscBool)(idx >= lo && idx < lo + n); }
307 DMDALocalInfo info = user->
info;
309 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
310 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
311 PetscFunctionBeginUser;
312 PetscCall(DMDAVecGetArrayRead(user->
fda, local, &a));
313#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
314#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
315#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
317 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
318 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
319 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][0], a[k][j][mx-2]));
321 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
322 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
323 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][mx-1], a[k][j][1]));
325 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
326 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
327 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][0][i], a[k][my-2][i]));
329 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
330 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
331 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][my-1][i], a[k][1][i]));
333 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
334 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
335 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[0][j][i], a[mz-2][j][i]));
337 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
338 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
339 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[mz-1][j][i], a[1][j][i]));
343 PetscCall(DMDAVecRestoreArrayRead(user->
fda, local, &a));
344 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
345 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
346 PetscFunctionReturn(0);
354 DMDALocalInfo info = user->
info;
356 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
357 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
358 PetscFunctionBeginUser;
359 PetscCall(DMDAVecGetArrayRead(user->
fda, local, &a));
360#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
361#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
362#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
364 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
365 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
366 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][-1], a[k][j][1]));
368 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
369 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
370 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][mx], a[k][j][mx-2]));
372 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
373 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
374 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][-1][i], a[k][1][i]));
376 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
377 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
378 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][my][i], a[k][my-2][i]));
380 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
381 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
382 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[-1][j][i], a[1][j][i]));
384 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
385 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
386 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[mz][j][i], a[mz-2][j][i]));
390 PetscCall(DMDAVecRestoreArrayRead(user->
fda, local, &a));
391 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
392 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
393 PetscFunctionReturn(0);
401 PetscFunctionBeginUser;
407 if (!user->
lNu_t) PetscCall(DMCreateLocalVector(user->
da, &user->
lNu_t));
409 PetscCall(VecSet(user->
lNvert, 0.0)); PetscCall(VecSet(user->
Nvert, 0.0));
410 PetscFunctionReturn(0);
417 DMDALocalInfo info = user->
info;
418 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
419 PetscFunctionBeginUser;
420 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &u));
422 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
423 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
424 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
427 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &u));
428 PetscFunctionReturn(0);
437 DMDALocalInfo info = user->
info;
438 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
439 PetscFunctionBeginUser;
440 PetscCall(VecSet(user->
Ucont, 0.0));
441 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucont, &u));
442 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
443 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
444 for (PetscInt i = info.xs; i < info.xs+info.xm; i++)
446 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucont, &u));
447 PetscFunctionReturn(0);
455 DMDALocalInfo info = user->
info;
456 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
458 PetscReal dv = 0.0, dv_global;
459 PetscFunctionBeginUser;
461 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lUcont, &uc));
462 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
463 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
464 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
465 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2)
continue;
466 const PetscReal d = (uc[k][j][i].
x - uc[k][j][i-1].
x)
467 + (uc[k][j][i].y - uc[k][j-1][i].y)
468 + (uc[k][j][i].
z - uc[k-1][j][i].
z);
469 dv = PetscMax(dv, PetscAbsReal(d));
471 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lUcont, &uc));
472 PetscCallMPI(MPI_Allreduce(&dv, &dv_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
474 PetscFunctionReturn(0);
480 PetscReal *repeat_inf, PetscReal *maxdiv,
483 DMDALocalInfo info = user->
info;
484 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
485 PetscReal err = 0.0, err_global;
488 PetscFunctionBeginUser;
490 PetscCall(VecDuplicate(user->
Ucat, &target));
495 const char *ufld[] = {
"Ucont"};
496 const char *cfld[] = {
"Ucat"};
499 PetscCall(VecCopy(user->
Ucont, Ubase));
503 PetscCall(VecCopy(user->
Ucat, target));
507 const char *cfld[] = {
"Ucat"};
508 const char *ufld[] = {
"Ucont"};
511 PetscCall(VecCopy(user->
Ucat, target));
514 PetscCall(VecCopy(user->
Ucont, Ubase));
526 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat, &ur));
527 PetscCall(DMDAVecGetArrayRead(user->
fda, target, &ut));
528 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
529 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
530 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
531 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2)
continue;
532 err = PetscMax(err, PetscAbsReal(ur[k][j][i].x - ut[k][j][i].x));
533 err = PetscMax(err, PetscAbsReal(ur[k][j][i].y - ut[k][j][i].y));
534 err = PetscMax(err, PetscAbsReal(ur[k][j][i].z - ut[k][j][i].z));
536 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat, &ur));
537 PetscCall(DMDAVecRestoreArrayRead(user->
fda, target, &ut));
538 PetscCall(VecDestroy(&target));
541 PetscCallMPI(MPI_Allreduce(&err, &err_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
543 *repeat_inf = err_global;
544 PetscFunctionReturn(0);
552 DMDALocalInfo info = user->
info;
553 Cmpnts ***ucat, ***csi, ***eta, ***zet;
555 PetscReal loc = 0.0, glo;
556 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
557 PetscFunctionBeginUser;
559 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lUcat, &ucat));
560 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi));
561 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta));
562 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet));
563 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, &aj));
564 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
565 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
566 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
567 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2)
continue;
568 const Cmpnts duc = { 0.5*(ucat[k][j][i+1].
x-ucat[k][j][i-1].
x),
569 0.5*(ucat[k][j][i+1].y-ucat[k][j][i-1].y),
570 0.5*(ucat[k][j][i+1].
z-ucat[k][j][i-1].
z) };
571 const Cmpnts due = { 0.5*(ucat[k][j+1][i].
x-ucat[k][j-1][i].
x),
572 0.5*(ucat[k][j+1][i].y-ucat[k][j-1][i].y),
573 0.5*(ucat[k][j+1][i].
z-ucat[k][j-1][i].
z) };
574 const Cmpnts duz = { 0.5*(ucat[k+1][j][i].
x-ucat[k-1][j][i].
x),
575 0.5*(ucat[k+1][j][i].y-ucat[k-1][j][i].y),
576 0.5*(ucat[k+1][j][i].
z-ucat[k-1][j][i].
z) };
577 const Cmpnts C = csi[k][j][i], E = eta[k][j][i], Z = zet[k][j][i];
578 const PetscReal Ajc = aj[k][j][i];
579#define ROWSUM(cmp) ( \
580 PetscAbsReal(Ajc*(C.x*duc.cmp + E.x*due.cmp + Z.x*duz.cmp)) + \
581 PetscAbsReal(Ajc*(C.y*duc.cmp + E.y*due.cmp + Z.y*duz.cmp)) + \
582 PetscAbsReal(Ajc*(C.z*duc.cmp + E.z*due.cmp + Z.z*duz.cmp)) )
586 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj));
587 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet));
588 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta));
589 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi));
590 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lUcat, &ucat));
591 PetscCallMPI(MPI_Allreduce(&loc, &glo, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
593 PetscFunctionReturn(0);
601 PetscReal *maxRealPart)
603 PetscBLASInt N, lda, lwork, info;
604 PetscReal *Acopy, *wr, *wi, *work, dummy = 0.0;
605 PetscFunctionBeginUser;
606 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N;
607 PetscCall(PetscMalloc4(n*n, &Acopy, n, &wr, n, &wi, (
size_t)lwork, &work));
608 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
611 LAPACKgeev_(&nochar, &nochar, &N, Acopy, &lda, wr, wi, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
613 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgeev failed: info=%d", (
int)info);
614 *rho = 0.0; *maxRealPart = -PETSC_MAX_REAL;
615 for (PetscInt t = 0; t < n; t++) {
616 *rho = PetscMax(*rho, PetscSqrtReal(wr[t]*wr[t] + wi[t]*wi[t]));
617 *maxRealPart = PetscMax(*maxRealPart, wr[t]);
619 PetscCall(PetscFree4(Acopy, wr, wi, work));
620 PetscFunctionReturn(0);
629 PetscReal *lamr, PetscReal *lami,
630 PetscReal *vr_out, PetscReal *vi_out)
632 PetscBLASInt N, lda, lwork, info;
633 PetscReal *Acopy, *wr, *wi, *vr, *work, dummy = 0.0;
634 PetscFunctionBeginUser;
635 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 16*N;
636 PetscCall(PetscMalloc5(n*n, &Acopy, n, &wr, n, &wi, n*n, &vr, (
size_t)lwork, &work));
637 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
639 char jobvl =
'N', jobvr =
'V';
640 LAPACKgeev_(&jobvl, &jobvr, &N, Acopy, &lda, wr, wi, &dummy, &lda, vr, &lda, work, &lwork, &info);
642 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgeev failed: info=%d", (
int)info);
644 for (PetscInt t = 1; t < n; t++)
if (wr[t] > wr[best]) best = t;
645 *lamr = wr[best]; *lami = wi[best];
646 if (PetscAbsReal(wi[best]) < 1e-14) {
647 for (PetscInt r = 0; r < n; r++) { vr_out[r] = vr[r + best*n]; vi_out[r] = 0.0; }
648 }
else if (wi[best] > 0.0) {
649 for (PetscInt r = 0; r < n; r++) { vr_out[r] = vr[r + best*n]; vi_out[r] = vr[r + (best+1)*n]; }
651 for (PetscInt r = 0; r < n; r++) { vr_out[r] = vr[r + (best-1)*n]; vi_out[r] = -vr[r + best*n]; }
653 PetscCall(PetscFree5(Acopy, wr, wi, vr, work));
654 PetscFunctionReturn(0);
661 PetscReal dtau, PetscReal *rho)
663 PetscBLASInt N, lda, lwork, info;
664 PetscReal *Jcopy, *wr, *wi, *work, dummy = 0.0;
665 PetscFunctionBeginUser;
666 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N;
667 PetscCall(PetscMalloc4(n*n, &Jcopy, n, &wr, n, &wi, (
size_t)lwork, &work));
668 for (PetscInt t = 0; t < n*n; t++) Jcopy[t] = J[t];
671 LAPACKgeev_(&nochar, &nochar, &N, Jcopy, &lda, wr, wi, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
673 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgeev failed: info=%d", (
int)info);
675 for (PetscInt t = 0; t < n; t++) {
676 const PetscReal zr = dtau*wr[t], zi = dtau*wi[t];
677 const PetscReal z2r = zr*zr - zi*zi, z2i = 2.0*zr*zi;
678 const PetscReal z3r = z2r*zr - z2i*zi, z3i = z2r*zi + z2i*zr;
679 const PetscReal z4r = z3r*zr - z3i*zi, z4i = z3r*zi + z3i*zr;
680 const PetscReal pr = 1.0 + zr + 0.5*z2r + z3r/6.0 + z4r/24.0;
681 const PetscReal pi = zi + 0.5*z2i + z3i/6.0 + z4i/24.0;
682 *rho = PetscMax(*rho, PetscSqrtReal(pr*pr + pi*pi));
684 PetscCall(PetscFree4(Jcopy, wr, wi, work));
685 PetscFunctionReturn(0);
689static PetscErrorCode
DenseSigmaMax(
const PetscReal *A, PetscInt n, PetscReal *smax, PetscReal *v1)
691 PetscBLASInt N, lda, lwork, info;
692 PetscReal *Acopy, *S, *VT, *work, ufake = 0.0;
693 PetscFunctionBeginUser;
694 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N + 4*N;
695 PetscCall(PetscMalloc4(n*n, &Acopy, n, &S, n*n, &VT, (
size_t)lwork, &work));
696 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
698 char jobu =
'N', jobvt = v1 ?
'S' :
'N';
699 LAPACKgesvd_(&jobu, &jobvt, &N, &N, Acopy, &lda, S, &ufake, &lda, VT, &lda, work, &lwork, &info);
701 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgesvd failed: info=%d", (
int)info);
703 if (v1) {
for (PetscInt r = 0; r < n; r++) v1[r] = VT[0 + r*n]; }
704 PetscCall(PetscFree4(Acopy, S, VT, work));
705 PetscFunctionReturn(0);
711 PetscReal fro2 = 0.0, comm = 0.0;
712 for (PetscInt t = 0; t < n*n; t++) fro2 += A[t]*A[t];
713 for (PetscInt p = 0; p < n; p++)
714 for (PetscInt q = 0; q < n; q++) {
715 PetscReal ata = 0.0, aat = 0.0;
716 for (PetscInt r = 0; r < n; r++) { ata += A[p + r*n]*A[q + r*n]; aat += A[r + p*n]*A[r + q*n]; }
717 const PetscReal d = ata - aat; comm += d*d;
719 return PetscSqrtReal(comm) / PetscMax(fro2, PETSC_MACHINE_EPSILON);
727 PetscReal fro2 = 0.0, sym2 = 0.0;
728 for (PetscInt i = 0; i < n*n; i++) fro2 += A[i]*A[i];
729 for (PetscInt c = 0; c < n; c++)
730 for (PetscInt r = 0; r < n; r++) {
731 const PetscReal s = A[r + c*n] + A[c + r*n];
734 return PetscSqrtReal(sym2) / PetscMax(PetscSqrtReal(fro2), PETSC_MACHINE_EPSILON);
742 PetscReal rho, maxre, smax;
743 PetscFunctionBeginUser;
746 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
747 " %-7s rho=%.6e sigma=%.6e max_real=%.6e skew=%.3e nonnormality=%.3e\n",
748 name, (
double)rho, (
double)smax, (
double)maxre,
750 PetscFunctionReturn(0);
753static void DenseMatVec(
const PetscReal *J,
const PetscReal *x, PetscReal *y, PetscInt n);
756 const PetscReal *x, PetscReal scale);
761static PetscErrorCode
DenseShiftIdentity(
const PetscReal *A, PetscInt n, PetscReal shift, PetscReal *B)
763 PetscFunctionBeginUser;
764 PetscCall(PetscArraycpy(B, A, (
size_t)n*n));
765 for (PetscInt d = 0; d < n; d++) B[d + d*n] += shift;
766 PetscFunctionReturn(0);
770static void MatMul(
const PetscReal *A,
const PetscReal *B, PetscReal *out, PetscInt n)
772 for (PetscInt c = 0; c < n; c++)
773 for (PetscInt r = 0; r < n; r++) {
775 for (PetscInt t = 0; t < n; t++) s += A[r + t*n]*B[t + c*n];
781static PetscErrorCode
RKPolynomial(
const PetscReal *J, PetscReal dtau, PetscInt n, PetscReal *P)
783 PetscReal *M, *T, *T2;
784 PetscFunctionBeginUser;
785 PetscCall(PetscMalloc3(n*n, &M, n*n, &T, n*n, &T2));
786 for (PetscInt t = 0; t < n*n; t++) M[t] = dtau*J[t];
788 for (PetscInt t = 0; t < n*n; t++) T[t] = M[t]/4.0;
789 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0;
790 const PetscReal coef[3] = {3.0, 2.0, 1.0};
791 for (
int s = 0; s < 3; s++) {
793 for (PetscInt t = 0; t < n*n; t++) T[t] = T2[t]/coef[s];
794 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0;
796 for (PetscInt t = 0; t < n*n; t++) P[t] = T[t];
797 PetscCall(PetscFree3(M, T, T2));
798 PetscFunctionReturn(0);
807 PMetric which, PetscReal *metric)
810 PetscFunctionBeginUser;
813 PetscFunctionReturn(0);
815 PetscCall(PetscMalloc1(n*n, &Pm));
818 PetscCall(PetscFree(Pm));
819 PetscFunctionReturn(0);
823static PetscErrorCode
StableCFL(
const PetscReal *J, PetscInt n, PetscReal lam,
PMetric which,
826 const PetscReal tol = 1e-8, probe = 1e-8, scan_step = 0.01, hi = 4.0;
827 const PetscReal probe_tol = 1e-12, min_positive_cfl = 1e-6;
829 PetscFunctionBeginUser;
833 PetscReal rhoJ, maxreJ;
835 if (maxreJ > 1e-8) PetscFunctionReturn(0);
838 if (met > 1.0 + probe_tol) PetscFunctionReturn(0);
840 PetscReal stable = probe, cross_b = -1.0;
841 for (PetscReal cfl = scan_step; cfl <= hi + 1e-12; cfl += scan_step) {
843 if (met > 1.0 + tol) { cross_b = cfl;
break; }
849 PetscFunctionReturn(0);
851 PetscReal cross_a = stable;
852 for (
int it = 0; it < 40; it++) {
853 const PetscReal mid = 0.5*(cross_a + cross_b);
855 if (met > 1.0 + tol) cross_b = mid;
else cross_a = mid;
857 if (cross_a < min_positive_cfl) PetscFunctionReturn(0);
859 result->
cfl = cross_a;
860 PetscFunctionReturn(0);
880 PetscFunctionBeginUser;
881 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" cand %s: eig %s", candidate,
StableCFLStatusText(eig)));
885 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
"\n"));
886 PetscFunctionReturn(0);
890static void ApplyP(
const PetscReal *P,
const PetscReal *x, PetscReal *out, PetscInt n)
892 for (PetscInt r = 0; r < n; r++) { PetscReal s = 0.0;
for (PetscInt c = 0; c < n; c++) s += P[r + c*n]*x[c]; out[r] = s; }
899 PetscInt n,
const PetscReal lams[3],
902 const PetscReal cfls[5] = {0.25, 0.50, 1.00, 1.50, 2.00};
904 PetscFunctionBeginUser;
905 PetscCall(PetscMalloc1(n*n, &Pm));
906 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
908 " candidate CFL dtau rho(P) sigma_max(P)\n", title));
909 for (
int c = 0; c < 3; c++) {
910 if (!(lams[c] > 0.0))
continue;
911 for (
int q = 0; q < 5; q++) {
912 const PetscReal dtau = cfls[q]/lams[c];
913 PetscReal rhoP, smaxP;
917 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
918 " %-9s %.2f %.6e %.6e %.6e\n",
919 cn[c], (
double)cfls[q], (
double)dtau, (
double)rhoP, (
double)smaxP));
922 PetscCall(PetscFree(Pm));
923 PetscFunctionReturn(0);
932 for (PetscInt i = 0; i < n; i++) s += x[i]*x[i];
933 return PetscSqrtReal(s);
942 for (PetscInt i = 0; i < n; i++) s = PetscMax(s, PetscAbsReal(x[i]));
952 for (PetscInt i = 0; i < n*n; i++) s += A[i]*A[i];
953 return PetscSqrtReal(s);
961 return (PetscBool)(map->
ci[m] == 1 || map->
ci[m] == info.mx-2 ||
962 map->
cj[m] == 1 || map->
cj[m] == info.my-2 ||
963 map->
ck[m] == 1 || map->
ck[m] == info.mz-2);
971 PetscInt count[3] = {0,0,0};
972 PetscInt min_i[3] = {PETSC_MAX_INT,PETSC_MAX_INT,PETSC_MAX_INT};
973 PetscInt min_j[3] = {PETSC_MAX_INT,PETSC_MAX_INT,PETSC_MAX_INT};
974 PetscInt min_k[3] = {PETSC_MAX_INT,PETSC_MAX_INT,PETSC_MAX_INT};
975 PetscInt max_i[3] = {-PETSC_MAX_INT,-PETSC_MAX_INT,-PETSC_MAX_INT};
976 PetscInt max_j[3] = {-PETSC_MAX_INT,-PETSC_MAX_INT,-PETSC_MAX_INT};
977 PetscInt max_k[3] = {-PETSC_MAX_INT,-PETSC_MAX_INT,-PETSC_MAX_INT};
978 PetscFunctionBeginUser;
979 for (PetscInt m = 0; m < map->
n; m++) {
980 const PetscInt c = map->
comp[m];
982 min_i[c] = PetscMin(min_i[c], map->
ci[m]); max_i[c] = PetscMax(max_i[c], map->
ci[m]);
983 min_j[c] = PetscMin(min_j[c], map->
cj[m]); max_j[c] = PetscMax(max_j[c], map->
cj[m]);
984 min_k[c] = PetscMin(min_k[c], map->
ck[m]); max_k[c] = PetscMax(max_k[c], map->
ck[m]);
989 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
990 " --- periodic independent-space audit ---\n"
991 " synchronization convention: duplicate planes 0<-m-2 and m-1<-1 in x/y/z for Ucont.\n"
992 " active rows and columns both use the same representatives i,j,k=1..m-2.\n"
993 " comp expected actual i-range j-range k-range\n"));
994 for (PetscInt c = 0; c < 3; c++) {
995 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
996 " %d %7d %6d [%d,%d] [%d,%d] [%d,%d]\n",
997 (
int)c, (
int)per_comp, (
int)count[c],
998 (
int)min_i[c], (
int)max_i[c], (
int)min_j[c], (
int)max_j[c], (
int)min_k[c], (
int)max_k[c]));
1000 PetscFunctionReturn(0);
1009 PetscReal block2[3][3] = {{0.0}}, sym2[3][3] = {{0.0}};
1012 PetscFunctionBeginUser;
1013 PetscCall(PetscMalloc1(map->
n, &row2));
1014 for (PetscInt r = 0; r < map->
n; r++) row2[r] = 0.0;
1015 for (PetscInt c = 0; c < map->
n; c++) {
1016 for (PetscInt r = 0; r < map->
n; r++) {
1017 const PetscInt rb = map->
comp[r], cb = map->
comp[c];
1018 const PetscReal a = J[r + c*map->
n];
1019 const PetscReal s = 0.5*(J[r + c*map->
n] + J[c + r*map->
n]);
1020 block2[rb][cb] += a*a;
1021 sym2[rb][cb] += s*s;
1025 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1026 " --- component block norms J_ab = dR_a/dU_b ---\n"
1027 " row-comp col-comp ||J_ab||F ||0.5(J+J^T)_ab||F\n"));
1028 for (PetscInt rb = 0; rb < 3; rb++)
1029 for (PetscInt cb = 0; cb < 3; cb++)
1030 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1031 " %d %d %.6e %.6e\n",
1032 (
int)rb, (
int)cb, (
double)PetscSqrtReal(block2[rb][cb]),
1033 (
double)PetscSqrtReal(sym2[rb][cb])));
1035 for (PetscInt q = 0; q < 8; q++) {
1037 for (PetscInt r = 0; r < map->
n; r++) {
1038 PetscBool used = PETSC_FALSE;
1039 for (PetscInt p = 0; p < q; p++)
if (top[p] == r) used = PETSC_TRUE;
1040 if (!used && (top[q] < 0 || row2[r] > row2[top[q]])) top[q] = r;
1043 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1044 " --- largest rows of S=0.5*(J+J^T) ---\n"
1045 " row comp (i,j,k) seam-adj ||S_row||2 largest symmetric columns\n"));
1046 for (PetscInt q = 0; q < 8; q++) {
1047 const PetscInt r = top[q];
1048 PetscInt best[3] = {-1,-1,-1};
1049 for (PetscInt pass = 0; pass < 3; pass++) {
1050 for (PetscInt c = 0; c < map->
n; c++) {
1051 PetscBool used = PETSC_FALSE;
1052 for (PetscInt p = 0; p < pass; p++)
if (best[p] == c) used = PETSC_TRUE;
1053 const PetscReal mag = PetscAbsReal(0.5*(J[r + c*map->
n] + J[c + r*map->
n]));
1054 if (!used && (best[pass] < 0 ||
1055 mag > PetscAbsReal(0.5*(J[r + best[pass]*map->
n] + J[best[pass] + r*map->
n])))) best[pass] = c;
1058 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1059 " %3d %d (%d,%d,%d) %s %.6e",
1060 (
int)r, (
int)map->
comp[r], (
int)map->
ci[r], (
int)map->
cj[r], (
int)map->
ck[r],
1062 (double)PetscSqrtReal(row2[r])));
1063 for (PetscInt p = 0; p < 3; p++) {
1064 const PetscInt c = best[p];
1065 const PetscReal s = 0.5*(J[r + c*map->
n] + J[c + r*map->
n]);
1066 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" | c%d:%d(%d,%d,%d)=%.3e",
1067 (
int)p, (
int)map->
comp[c], (
int)map->
ci[c], (
int)map->
cj[c],
1068 (
int)map->
ck[c], (
double)s));
1070 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
"\n"));
1072 PetscCall(PetscFree(row2));
1073 PetscFunctionReturn(0);
1083 for (PetscInt m = 0; m < map->
n; m++) nrep = PetscMax(nrep, map->
ci[m]);
1084 for (PetscInt q = 0; q < 6*map->
n; q++) Q[q] = 0.0;
1085 for (PetscInt m = 0; m < map->
n; m++) {
1086 const PetscInt comp = map->
comp[m];
1087 const PetscReal x = (PetscReal)(map->
ci[m]-1) - (comp == 0 ? 0.5 : 0.0);
1088 const PetscReal y = (PetscReal)(map->
cj[m]-1) - (comp == 1 ? 0.5 : 0.0);
1089 const PetscReal z = (PetscReal)(map->
ck[m]-1) - (comp == 2 ? 0.5 : 0.0);
1090 const PetscReal phase = 2.0*PETSC_PI*((PetscReal)wx*x + (PetscReal)wy*y + (PetscReal)wz*z)/(PetscReal)nrep;
1091 Q[m + (2*comp+0)*map->
n] = PetscCosReal(phase);
1092 Q[m + (2*comp+1)*map->
n] = PetscSinReal(phase);
1094 for (PetscInt q = 0; q < 6; q++) {
1096 for (PetscInt m = 0; m < map->
n; m++) n2 += Q[m + q*map->
n]*Q[m + q*map->
n];
1097 n2 = PetscSqrtReal(n2);
1098 if (n2 > 0.0)
for (PetscInt m = 0; m < map->
n; m++) Q[m + q*map->
n] /= n2;
1106 PetscInt wx, PetscInt wy, PetscInt wz,
1107 PetscReal A6[36], PetscReal *leak)
1110 PetscReal all2 = 0.0, leak2 = 0.0;
1111 PetscFunctionBeginUser;
1112 PetscCall(PetscMalloc2((
size_t)6*map->
n, &Q, (
size_t)6*map->
n, &JQ));
1114 for (PetscInt q = 0; q < 6; q++)
DenseMatVec(J, &Q[q*map->
n], &JQ[q*map->
n], map->
n);
1115 for (PetscInt c = 0; c < 6; c++)
1116 for (PetscInt r = 0; r < 6; r++) {
1118 for (PetscInt m = 0; m < map->
n; m++) s += Q[m + r*map->
n] * JQ[m + c*map->
n];
1121 for (PetscInt c = 0; c < 6; c++) {
1122 for (PetscInt m = 0; m < map->
n; m++) {
1123 PetscReal proj = 0.0;
1124 for (PetscInt r = 0; r < 6; r++) proj += Q[m + r*map->
n] * A6[r + c*6];
1125 const PetscReal d = JQ[m + c*map->
n] - proj;
1127 all2 += JQ[m + c*map->
n]*JQ[m + c*map->
n];
1130 *leak = PetscSqrtReal(leak2) / PetscMax(PETSC_MACHINE_EPSILON, PetscSqrtReal(all2));
1131 PetscCall(PetscFree2(Q, JQ));
1132 PetscFunctionReturn(0);
1139 PetscReal wr_out[6], PetscReal wi_out[6])
1141 PetscBLASInt N = 6, lda = 6, lwork = 128, info;
1142 PetscReal Acopy[36], work[128], dummy = 0.0;
1143 PetscFunctionBeginUser;
1144 for (PetscInt t = 0; t < 36; t++) Acopy[t] = A6[t];
1147 LAPACKgeev_(&nochar, &nochar, &N, Acopy, &lda, wr_out, wi_out, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
1149 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgeev failed for 6x6 symbol: info=%d", (
int)info);
1150 *maxre = -PETSC_MAX_REAL;
1151 for (PetscInt q = 0; q < 6; q++) *maxre = PetscMax(*maxre, wr_out[q]);
1152 PetscFunctionReturn(0);
1160 typedef struct {
const char *name; PetscInt wx, wy, wz; } Mode;
1161 const Mode modes[4] = {{
"x",1,0,0}, {
"y",0,1,0}, {
"xy",1,1,0}, {
"x-y",1,2,0}};
1162 PetscReal best_re = -PETSC_MAX_REAL, best_leak = 0.0;
1163 PetscInt best_wx = 0, best_wy = 0, best_wz = 0, nrep = 0;
1164 PetscFunctionBeginUser;
1165 for (PetscInt m = 0; m < map->
n; m++) nrep = PetscMax(nrep, map->
ci[m]);
1166 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1167 " --- staggered 6x6 Fourier-symbol check ---\n"
1168 " mode max_real leakage eigenvalues (real,imag)\n"));
1169 for (PetscInt im = 0; im < 4; im++) {
1170 PetscReal A6[36], wr[6], wi[6], maxre, leak;
1173 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1174 " %-5s(%d,%d,%d) %.6e %.3e",
1175 modes[im].name, (
int)modes[im].wx, (
int)modes[im].wy, (
int)modes[im].wz,
1176 (
double)maxre, (
double)leak));
1177 for (PetscInt q = 0; q < 6; q++) PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" %.3e%+.3ei", (
double)wr[q], (
double)wi[q]));
1178 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
"\n"));
1180 for (PetscInt wz = 0; wz < nrep; wz++)
1181 for (PetscInt wy = 0; wy < nrep; wy++)
1182 for (PetscInt wx = 0; wx < nrep; wx++) {
1183 if (wx == 0 && wy == 0 && wz == 0)
continue;
1184 PetscReal A6[36], wr[6], wi[6], maxre, leak;
1187 if (maxre > best_re) {
1188 best_re = maxre; best_leak = leak; best_wx = wx; best_wy = wy; best_wz = wz;
1191 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1192 " best scanned wavevector (%d,%d,%d): max_real=%.6e leakage=%.3e\n",
1193 (
int)best_wx, (
int)best_wy, (
int)best_wz, (
double)best_re, (
double)best_leak));
1194 PetscFunctionReturn(0);
1201 const DofMap *map,
const PetscReal *J)
1204 PetscReal *v, *ract;
1205 PetscReal seam_ucont[3], seam_ucat[3], conv2, convinf, rhs2, rhsinf;
1206 PetscInt active_rows[4] = {0,0,0,0};
1207 PetscFunctionBeginUser;
1208 PetscCall(VecDuplicate(Ubase, &Upert));
1209 PetscCall(VecDuplicate(user->
lUcont, &Conv));
1210 PetscCall(PetscMalloc2(map->
n, &v, map->
n, &ract));
1212 PetscCall(VecCopy(Ubase, Upert));
1214 PetscCall(VecCopy(Upert, user->
Ucont));
1216 const char *fld[] = {
"Ucont"};
1224 PetscCall(VecNorm(Conv, NORM_2, &conv2));
1225 PetscCall(VecNorm(Conv, NORM_INFINITY, &convinf));
1231 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, &nvert));
1232 for (PetscInt m = 0; m < map->
n; m++) {
1235 PETSC_FALSE, PETSC_FALSE, PETSC_FALSE, 0);
1236 if (rows & (1 << map->
comp[m])) active_rows[map->
comp[m]]++;
1237 else active_rows[3]++;
1239 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, &nvert));
1241 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1242 " --- observable State A residual trace (mixed perturbation, amp=1e-6) ---\n"
1243 " after Ucont periodic sync duplicate mismatch (x,y,z)=%.3e %.3e %.3e\n"
1244 " after Contra2Cart Ucat duplicate mismatch (x,y,z)=%.3e %.3e %.3e\n"
1245 " direct Convection() Cartesian norm: ||Conv||2=%.6e ||Conv||inf=%.6e\n"
1246 " final active ComputeRHS() norm: ||R||2=%.6e ||R||inf=%.6e\n"
1247 " active-row mask counts by component: u=%d v=%d w=%d discarded=%d\n"
1248 " final active-space skewness defect already reported from J: %.3e\n",
1249 (
double)seam_ucont[0], (
double)seam_ucont[1], (
double)seam_ucont[2],
1250 (
double)seam_ucat[0], (
double)seam_ucat[1], (
double)seam_ucat[2],
1251 (
double)conv2, (
double)convinf, (
double)rhs2, (
double)rhsinf,
1252 (
int)active_rows[0], (
int)active_rows[1], (
int)active_rows[2], (
int)active_rows[3],
1254 PetscCall(PetscFree2(v, ract));
1255 PetscCall(VecDestroy(&Upert));
1256 PetscCall(VecDestroy(&Conv));
1257 PetscFunctionReturn(0);
1263static PetscReal
DenseRelativeDiff(
const PetscReal *A,
const PetscReal *B, PetscInt n, PetscReal denom_ref)
1266 for (PetscInt i = 0; i < n*n; i++) {
1267 const PetscReal d = A[i] - B[i];
1270 return PetscSqrtReal(s) / PetscMax(1.0, denom_ref);
1277 const PetscReal *x, PetscReal scale)
1280 PetscFunctionBeginUser;
1281 PetscCall(DMDAVecGetArray(user->
fda, U, &a));
1282 for (PetscInt m = 0; m < map->
n; m++) {
1283 PetscReal *p = (PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]];
1284 p[map->
comp[m]] += scale*x[m];
1286 PetscCall(DMDAVecRestoreArray(user->
fda, U, &a));
1287 PetscFunctionReturn(0);
1296 PetscFunctionBeginUser;
1297 PetscCall(DMDAVecGetArrayRead(user->
fda, U, &a));
1298 for (PetscInt m = 0; m < map->
n; m++) {
1299 const PetscReal *p = (
const PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]];
1300 x[m] = p[map->
comp[m]];
1302 PetscCall(DMDAVecRestoreArrayRead(user->
fda, U, &a));
1303 PetscFunctionReturn(0);
1311 return 1.0 + 0.013*(PetscReal)(map->
comp[m]+1)
1312 + 0.017*(PetscReal)map->
ci[m]
1313 + 0.019*(PetscReal)map->
cj[m]
1314 + 0.023*(PetscReal)map->
ck[m];
1322 PetscReal loc2 = 0.0, locinf = 0.0, locsum = 0.0;
1323 PetscReal glo2, gloinf, glosum;
1324 PetscFunctionBeginUser;
1325 for (PetscInt m = 0; m < map->
n; m++) {
1327 locinf = PetscMax(locinf, PetscAbsReal(x[m]));
1330 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
1331 PetscCallMPI(MPI_Allreduce(&locinf, &gloinf, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
1332 PetscCallMPI(MPI_Allreduce(&locsum, &glosum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
1333 stats->
n2 = PetscSqrtReal(glo2); stats->
ninf = gloinf; stats->
checksum = glosum;
1334 PetscFunctionReturn(0);
1342 PetscReal loc2 = 0.0, glo2;
1343 PetscFunctionBeginUser;
1344 PetscCall(VecSet(V, 0.0));
1345 for (PetscInt m = 0; m < map->
n; m++) {
1346 x[m] = PetscSinReal(0.37*(PetscReal)(map->
ci[m]+1)
1347 + 0.51*(PetscReal)(map->
cj[m]+1)
1348 + 0.73*(PetscReal)(map->
ck[m]+1)
1349 + 0.29*(PetscReal)(map->
comp[m]+1));
1352 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
1353 const PetscReal invn = 1.0/PetscSqrtReal(glo2);
1354 for (PetscInt m = 0; m < map->
n; m++) x[m] *= invn;
1356 PetscFunctionReturn(0);
1364 PetscReal *Rscratch, Vec Uwork, Vec Uout)
1366 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1367 PetscFunctionBeginUser;
1368 PetscCall(VecCopy(U0full, Uwork));
1369 for (
int s = 0; s < 4; s++) {
1371 PetscCall(VecCopy(U0full, Uout));
1373 PetscCall(DMDAVecGetArray(user->
fda, Uout, &a));
1374 for (PetscInt m = 0; m < map->
n; m++) {
1375 PetscReal *p = (PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]];
1376 p[map->
comp[m]] += alfa[s]*dtau*Rscratch[m];
1378 PetscCall(DMDAVecRestoreArray(user->
fda, Uout, &a));
1379 PetscCall(VecCopy(Uout, Uwork));
1381 PetscFunctionReturn(0);
1388 const DofMap *map,
const PetscReal *Ract, Vec Ustage)
1390 PetscFunctionBeginUser;
1391 PetscCall(VecCopy(U0full, Ustage));
1393 PetscFunctionReturn(0);
1400 const DofMap *map, PetscReal *Rscratch,
1401 Vec Y1, Vec Y2, Vec Y3)
1403 const PetscReal alfa[3] = {0.25, 1.0/3.0, 0.5};
1404 PetscFunctionBeginUser;
1406 PetscCall(
SetAnchoredStage(user, U0full, alfa[0]*dtau, map, Rscratch, Y1));
1408 PetscCall(
SetAnchoredStage(user, U0full, alfa[1]*dtau, map, Rscratch, Y2));
1410 PetscCall(
SetAnchoredStage(user, U0full, alfa[2]*dtau, map, Rscratch, Y3));
1411 PetscFunctionReturn(0);
1418 const DofMap *map, PetscReal *Rp, PetscReal *Rm,
1419 Vec Uwork, PetscReal *J)
1421 PetscFunctionBeginUser;
1422 for (PetscInt col = 0; col < map->
n; col++) {
1424 PetscCall(
GetDof(user, Ucenter, map, col, &u0));
1425 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1426 PetscCall(VecCopy(Ucenter, Uwork));
1427 PetscCall(
PerturbDof(user, Uwork, map, col, +eps));
1429 PetscCall(VecCopy(Ucenter, Uwork));
1430 PetscCall(
PerturbDof(user, Uwork, map, col, -eps));
1432 for (PetscInt row = 0; row < map->
n; row++) J[row + col*map->
n] = (Rp[row]-Rm[row])/(2.0*eps);
1434 PetscFunctionReturn(0);
1440static void DenseMatVec(
const PetscReal *J,
const PetscReal *x, PetscReal *y, PetscInt n)
1442 for (PetscInt r = 0; r < n; r++) {
1444 for (PetscInt c = 0; c < n; c++) s += J[r + c*n]*x[c];
1455 for (PetscInt m = 0; m < map->
n; m++) {
1456 const PetscReal a = 0.31*(PetscReal)(map->
ci[m]+1)
1457 + 0.47*(PetscReal)(map->
cj[m]+1)
1458 + 0.59*(PetscReal)(map->
ck[m]+1)
1459 + 0.23*(PetscReal)(map->
comp[m]+1);
1460 if (kind == 0) x[m] = PetscSinReal(a);
1461 else if (kind == 1) x[m] = PetscCosReal(1.7*a) + 0.25*PetscSinReal(0.9*(PetscReal)(m+1));
1462 else x[m] = (map->
comp[m] == kind-2) ? PetscSinReal(a) : 0.0;
1465 n2 = PetscSqrtReal(n2);
1466 if (n2 > 0.0)
for (PetscInt m = 0; m < map->
n; m++) x[m] /= n2;
1473 const DofMap *map,
const PetscReal *J,
1477 PetscReal *v, *jd, *Rp, *Rm, *jmf;
1478 PetscFunctionBeginUser;
1479 PetscCall(VecDuplicate(Ubase, &Up));
1480 PetscCall(VecDuplicate(Ubase, &Um));
1481 PetscCall(PetscMalloc5(map->
n, &v, map->
n, &jd, map->
n, &Rp, map->
n, &Rm, map->
n, &jmf));
1482 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1483 " --- dense Jacobian action check against matrix-free production Jv ---\n"
1484 " direction rel_L2 rel_Linf ||Jv||2 ||Jv||inf\n"));
1485 const char *names[5] = {
"mixed-sin",
"mixed-cos",
"u-only",
"v-only",
"w-only"};
1486 for (PetscInt kind = 0; kind < 5; kind++) {
1489 PetscCall(VecCopy(Ubase, Up));
1490 PetscCall(VecCopy(Ubase, Um));
1495 for (PetscInt m = 0; m < map->
n; m++) jmf[m] = (Rp[m]-Rm[m])/(2.0*epsrel);
1496 PetscReal e2 = 0.0, einf = 0.0;
1497 for (PetscInt m = 0; m < map->
n; m++) {
1498 const PetscReal d = jd[m] - jmf[m];
1499 e2 += d*d; einf = PetscMax(einf, PetscAbsReal(d));
1503 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1504 " %-13s %.3e %.3e %.6e %.6e\n",
1505 names[kind], (
double)(PetscSqrtReal(e2)/PetscMax(PETSC_MACHINE_EPSILON,n2)),
1506 (
double)(einf/PetscMax(PETSC_MACHINE_EPSILON,ni)), (
double)n2, (
double)ni));
1509 PetscCall(PetscFree5(v, jd, Rp, Rm, jmf));
1510 PetscCall(VecDestroy(&Up));
1511 PetscCall(VecDestroy(&Um));
1512 PetscFunctionReturn(0);
1519 const PetscReal *v, PetscReal eps, PetscReal *jv)
1523 PetscFunctionBeginUser;
1524 PetscCall(VecDuplicate(Ubase, &Up));
1525 PetscCall(VecDuplicate(Ubase, &Um));
1526 PetscCall(PetscMalloc2(map->
n, &Rp, map->
n, &Rm));
1527 PetscCall(VecCopy(Ubase, Up));
1528 PetscCall(VecCopy(Ubase, Um));
1533 for (PetscInt m = 0; m < map->
n; m++) jv[m] = (Rp[m]-Rm[m])/(2.0*eps);
1534 PetscCall(PetscFree2(Rp, Rm));
1535 PetscCall(VecDestroy(&Up));
1536 PetscCall(VecDestroy(&Um));
1537 PetscFunctionReturn(0);
1544 const PetscReal *C, PetscInt n)
1546 PetscReal num = 0.0, den = 0.0;
1547 for (PetscInt t = 0; t < n*n; t++) {
1548 const PetscReal d = A[t] - B[t] - C[t];
1549 num += d*d; den += A[t]*A[t];
1551 return PetscSqrtReal(num) / PetscMax(1.0, PetscSqrtReal(den));
1559 PetscReal num = 0.0;
1560 for (PetscInt c = 0; c < n; c++) {
1561 for (PetscInt r = 0; r < n; r++) {
1562 PetscReal ab = 0.0, ba = 0.0;
1563 for (PetscInt q = 0; q < n; q++) {
1564 ab += A[r + q*n] * B[q + c*n];
1565 ba += B[r + q*n] * A[q + c*n];
1567 const PetscReal d = ab - ba;
1572 return PetscSqrtReal(num) / den;
1579 Vec Ubase_xy, Vec Rhs_xy,
1580 const DofMap *map_xy, PetscReal epsrel)
1583 Vec Ux, Uy, Rhs, Uwork;
1584 PetscReal *Rp, *Rm, *Jx, *Jy, *Jsum, *vr, *vi, *jdr, *jdi, *jmfr, *jmfi;
1585 PetscReal repeat_err, maxdiv, lamr, lami;
1587 PetscFunctionBeginUser;
1591 PetscCheck(map.
n == map_xy->
n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
"directional audit map size mismatch");
1592 PetscCall(VecDuplicate(user->
Ucont, &Ux));
1593 PetscCall(VecDuplicate(user->
Ucont, &Uy));
1594 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
1595 PetscCall(VecDuplicate(user->
Ucont, &Uwork));
1596 PetscCall(PetscMalloc5(map.
n, &Rp, map.
n, &Rm, (
size_t)map.
n*map.
n, &Jx,
1597 (
size_t)map.
n*map.
n, &Jy, (
size_t)map.
n*map.
n, &Jsum));
1599 PetscCall(
BuildFDJacobian(user, Ux, epsrel, Rhs, &map, Rp, Rm, Uwork, Jx));
1601 PetscCall(
BuildFDJacobian(user, Uy, epsrel, Rhs, &map, Rp, Rm, Uwork, Jy));
1602 for (PetscInt t = 0; t < map.
n*map.
n; t++) Jsum[t] = Jx[t] + Jy[t];
1606 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1607 " --- State A directional additivity / noncommutation audit ---\n"
1608 " ||Jxy-(Jx+Jy)||F/max(1,||Jxy||F) = %.3e\n"
1609 " ||Jx Jy - Jy Jx||F/(||Jx||F||Jy||F) = %.3e\n"
1610 " spectra:\n", (
double)add_err, (
double)comm));
1616 PetscCall(PetscMalloc6(map.
n, &vr, map.
n, &vi, map.
n, &jdr, map.
n, &jdi, map.
n, &jmfr, map.
n, &jmfi));
1620 PetscReal ed2 = 0.0, em2 = 0.0, v2 = 0.0;
1621 for (PetscInt m = 0; m < map.
n; m++) {
1622 const PetscReal rr = jdr[m] - (lamr*vr[m] - lami*vi[m]);
1623 const PetscReal ri = jdi[m] - (lami*vr[m] + lamr*vi[m]);
1624 ed2 += rr*rr + ri*ri;
1625 v2 += vr[m]*vr[m] + vi[m]*vi[m];
1627 PetscCall(
MatrixFreeJv(user_xy, Ubase_xy, Rhs_xy, map_xy, vr, epsrel, jmfr));
1628 PetscCall(
MatrixFreeJv(user_xy, Ubase_xy, Rhs_xy, map_xy, vi, epsrel, jmfi));
1629 for (PetscInt m = 0; m < map.
n; m++) {
1630 const PetscReal rr = jmfr[m] - (lamr*vr[m] - lami*vi[m]);
1631 const PetscReal ri = jmfi[m] - (lami*vr[m] + lamr*vi[m]);
1632 em2 += rr*rr + ri*ri;
1634 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1635 " --- State A unstable eigenpair verification ---\n"
1636 " lambda_max_real = %.12e%+.12ei\n"
1637 " ||Jdense v-lambda v||2/||v||2 = %.3e\n"
1638 " ||Jmf v-lambda v||2/||v||2 = %.3e\n",
1639 (
double)lamr, (
double)lami, (
double)(PetscSqrtReal(ed2)/PetscSqrtReal(v2)),
1640 (
double)(PetscSqrtReal(em2)/PetscSqrtReal(v2))));
1642 PetscCall(PetscFree6(vr, vi, jdr, jdi, jmfr, jmfi));
1643 PetscCall(PetscFree5(Rp, Rm, Jx, Jy, Jsum));
1644 PetscCall(VecDestroy(&Ux)); PetscCall(VecDestroy(&Uy)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
1647 PetscFunctionReturn(0);
1663 PetscFunctionBeginUser;
1664 PetscCall(DMDAVecGetArrayRead(user->
fda, local, &a));
1665 for (PetscInt m = 0; m < map->
n; m++) {
1666 const PetscReal *p = (
const PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]];
1667 x[m] = p[map->
comp[m]];
1669 PetscCall(DMDAVecRestoreArrayRead(user->
fda, local, &a));
1670 PetscFunctionReturn(0);
1678 DMDALocalInfo info = user->
info;
1679 const PetscInt xs = info.xs, xe = xs + info.xm, mx = info.mx;
1680 const PetscInt ys = info.ys, ye = ys + info.ym, my = info.my;
1681 const PetscInt zs = info.zs, ze = zs + info.zm, mz = info.mz;
1682 const PetscInt lxs = (xs==0) ? xs+1 : xs, lxe = (xe==mx) ? xe-1 : xe;
1683 const PetscInt lys = (ys==0) ? ys+1 : ys, lye = (ye==my) ? ye-1 : ye;
1684 const PetscInt lzs = (zs==0) ? zs+1 : zs, lze = (ze==mz) ? ze-1 : ze;
1685 Cmpnts ***csi, ***eta, ***zet, ***rc, ***rct;
1687 PetscFunctionBeginUser;
1688 PetscCall(VecSet(Rct, 0.0));
1689 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi));
1690 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta));
1691 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet));
1692 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, &aj));
1693 PetscCall(DMDAVecGetArrayRead(user->
fda, Rc, &rc));
1694 PetscCall(DMDAVecGetArray(user->
fda, Rct, &rct));
1695 for (PetscInt k = lzs; k < lze; k++)
1696 for (PetscInt j = lys; j < lye; j++)
1697 for (PetscInt i = lxs; i < lxe; i++) {
1698 rct[k][j][i].
x = aj[k][j][i] *
1699 (0.5 * (csi[k][j][i].
x + csi[k][j][i-1].
x) * rc[k][j][i].x +
1700 0.5 * (csi[k][j][i].y + csi[k][j][i-1].y) * rc[k][j][i].
y +
1701 0.5 * (csi[k][j][i].
z + csi[k][j][i-1].
z) * rc[k][j][i].z);
1702 rct[k][j][i].
y = aj[k][j][i] *
1703 (0.5 * (eta[k][j][i].
x + eta[k][j-1][i].
x) * rc[k][j][i].x +
1704 0.5 * (eta[k][j][i].y + eta[k][j-1][i].y) * rc[k][j][i].
y +
1705 0.5 * (eta[k][j][i].
z + eta[k][j-1][i].
z) * rc[k][j][i].z);
1706 rct[k][j][i].
z = aj[k][j][i] *
1707 (0.5 * (zet[k][j][i].
x + zet[k-1][j][i].
x) * rc[k][j][i].x +
1708 0.5 * (zet[k][j][i].y + zet[k-1][j][i].y) * rc[k][j][i].
y +
1709 0.5 * (zet[k][j][i].
z + zet[k-1][j][i].
z) * rc[k][j][i].z);
1711 PetscCall(DMDAVecRestoreArray(user->
fda, Rct, &rct));
1712 PetscCall(DMDAVecRestoreArrayRead(user->
fda, Rc, &rc));
1713 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj));
1714 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet));
1715 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta));
1716 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi));
1718 PetscFunctionReturn(0);
1727 PetscFunctionBeginUser;
1728 PetscCall(DMDAVecGetArrayRead(user->
fda, Rct, &rct));
1729 for (PetscInt m = 0; m < map->
n; m++) {
1730 const PetscInt i = map->
ci[m], j = map->
cj[m], k = map->
ck[m], c = map->
comp[m];
1731 if (c == 0) out[m] = 0.5*(rct[k][j][i].
x + rct[k][j][i+1].
x);
1732 else if (c == 1) out[m] = 0.5*(rct[k][j][i].
y + rct[k][j+1][i].
y);
1733 else out[m] = 0.5*(rct[k][j][i].
z + rct[k+1][j][i].
z);
1735 PetscCall(DMDAVecRestoreArrayRead(user->
fda, Rct, &rct));
1736 PetscFunctionReturn(0);
1746 PetscFunctionBeginUser;
1749 PetscFunctionReturn(0);
1751 PetscCall(VecCopy(Ucont_in, user->
Ucont));
1753 const char *fld[] = {
"Ucont"};
1760 PetscFunctionReturn(0);
1762 PetscCall(VecDuplicate(user->
lUcont, &Conv));
1763 PetscCall(VecDuplicate(user->
lUcont, &Rc));
1764 PetscCall(VecDuplicate(user->
lUcont, &Rct));
1766 PetscCall(VecSet(Rc, 0.0));
1767 PetscCall(VecAXPY(Rc, -1.0, Conv));
1774 PetscCall(VecDestroy(&Conv));
1775 PetscCall(VecDestroy(&Rc));
1776 PetscCall(VecDestroy(&Rct));
1777 PetscFunctionReturn(0);
1785 PetscReal *Rp, PetscReal *Rm, Vec Uwork, PetscReal *J)
1787 PetscFunctionBeginUser;
1788 for (PetscInt col = 0; col < map->
n; col++) {
1790 PetscCall(
GetDof(user, Ucenter, map, col, &u0));
1791 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1792 PetscCall(VecCopy(Ucenter, Uwork));
1793 PetscCall(
PerturbDof(user, Uwork, map, col, +eps));
1795 PetscCall(VecCopy(Ucenter, Uwork));
1796 PetscCall(
PerturbDof(user, Uwork, map, col, -eps));
1798 for (PetscInt row = 0; row < map->
n; row++) J[row + col*map->
n] = (Rp[row]-Rm[row])/(2.0*eps);
1800 PetscFunctionReturn(0);
1807 Vec Uwork,
const DofMap *map, PetscReal epsrel)
1809 const char *names[4] = {
"Contra2Cart Ucat",
"Cartesian Rc=-Conv",
"mapped local Rct",
"final active RHS"};
1810 PetscReal *Rp, *Rm, *J;
1811 PetscFunctionBeginUser;
1812 PetscCall(PetscMalloc3(map->
n, &Rp, map->
n, &Rm, (
size_t)map->
n*map->
n, &J));
1813 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1814 " --- State A residual-path stage Jacobians ---\n"
1815 " stage rho sigma max_real skew nonnormal\n"));
1816 for (PetscInt s = 0; s < 4; s++) {
1817 PetscReal rho, maxre, smax;
1821 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1822 " %-20s %.6e %.6e %.6e %.3e %.3e\n",
1823 names[s], (
double)rho, (
double)smax, (
double)maxre,
1826 PetscCall(PetscFree3(Rp, Rm, J));
1827 PetscFunctionReturn(0);
1834 const PetscReal *J2,
const PetscReal *J3,
1835 PetscReal dtau, PetscInt n, PetscReal *T4)
1837 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1838 PetscReal *T1, *T2, *T3, *Tmp;
1839 PetscFunctionBeginUser;
1840 PetscCall(PetscMalloc4(n*n, &T1, n*n, &T2, n*n, &T3, n*n, &Tmp));
1842 for (PetscInt i = 0; i < n*n; i++) T1[i] = alfa[0]*dtau*J0[i];
1843 for (PetscInt d = 0; d < n; d++) T1[d + d*n] += 1.0;
1846 for (PetscInt i = 0; i < n*n; i++) T2[i] = alfa[1]*dtau*Tmp[i];
1847 for (PetscInt d = 0; d < n; d++) T2[d + d*n] += 1.0;
1850 for (PetscInt i = 0; i < n*n; i++) T3[i] = alfa[2]*dtau*Tmp[i];
1851 for (PetscInt d = 0; d < n; d++) T3[d + d*n] += 1.0;
1854 for (PetscInt i = 0; i < n*n; i++) T4[i] = alfa[3]*dtau*Tmp[i];
1855 for (PetscInt d = 0; d < n; d++) T4[d + d*n] += 1.0;
1857 PetscCall(PetscFree4(T1, T2, T3, Tmp));
1858 PetscFunctionReturn(0);
1865 const DofMap *map, PetscReal *Rscratch,
1866 Vec Upert, Vec Ustage, Vec PhiP, Vec PhiM,
1867 PetscReal *xp, PetscReal *xm, PetscReal epsrel,
1870 PetscFunctionBeginUser;
1871 for (PetscInt col = 0; col < map->
n; col++) {
1873 PetscCall(
GetDof(user, Ucenter, map, col, &u0));
1874 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1875 PetscCall(VecCopy(Ucenter, Upert));
1876 PetscCall(
PerturbDof(user, Upert, map, col, +eps));
1877 PetscCall(
FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiP));
1878 PetscCall(VecCopy(Ucenter, Upert));
1879 PetscCall(
PerturbDof(user, Upert, map, col, -eps));
1880 PetscCall(
FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiM));
1883 for (PetscInt row = 0; row < map->
n; row++) JPhi[row + col*map->
n] = (xp[row]-xm[row])/(2.0*eps);
1885 PetscFunctionReturn(0);
1892 const DofMap *map, PetscReal epsrel,
1893 const PetscReal lams[3],
const char *cn[3],
1894 const PetscReal *J0)
1896 const PetscReal cflsB[4] = {0.1, 0.25, 0.5, 1.0};
1897 const PetscReal cflsOther[1] = {0.5};
1898 const PetscReal *cfls = (st ==
STATE_B) ? cflsB : cflsOther;
1899 const PetscInt ncfl = (st ==
STATE_B) ? 4 : 1;
1900 const PetscReal amps[3] = {1e-4, 1e-5, 1e-6};
1901 Vec Y1, Y2, Y3, Upert, Ustage, PhiP, PhiM, Phi0;
1902 PetscReal *Rtmp, *J1, *J2, *J3, *T4, *Pm, *JPhi, *v1, *xrand;
1903 PetscReal *meas, *phi0, *phip, *xscaled, *predP, *predT;
1904 PetscFunctionBeginUser;
1906 PetscCall(VecDuplicate(Ubase, &Y1));
1907 PetscCall(VecDuplicate(Ubase, &Y2));
1908 PetscCall(VecDuplicate(Ubase, &Y3));
1909 PetscCall(VecDuplicate(Ubase, &Upert));
1910 PetscCall(VecDuplicate(Ubase, &Ustage));
1911 PetscCall(VecDuplicate(Ubase, &PhiP));
1912 PetscCall(VecDuplicate(Ubase, &PhiM));
1913 PetscCall(VecDuplicate(Ubase, &Phi0));
1914 PetscCall(PetscMalloc5(map->
n, &Rtmp, (
size_t)map->
n*map->
n, &J1,
1915 (
size_t)map->
n*map->
n, &J2, (
size_t)map->
n*map->
n, &J3,
1916 (
size_t)map->
n*map->
n, &T4));
1917 PetscCall(PetscMalloc5((
size_t)map->
n*map->
n, &Pm, (
size_t)map->
n*map->
n, &JPhi,
1918 map->
n, &v1, map->
n, &xrand, map->
n, &meas));
1919 PetscCall(PetscMalloc5(map->
n, &phi0, map->
n, &phip, map->
n, &xscaled,
1920 map->
n, &predP, map->
n, &predT));
1922 PetscReal nrm = 0.0;
1923 for (PetscInt m = 0; m < map->
n; m++) {
1924 xrand[m] = PetscSinReal((PetscReal)(m+1)*1.2345);
1925 nrm += xrand[m]*xrand[m];
1927 nrm = PetscSqrtReal(nrm);
1928 for (PetscInt m = 0; m < map->
n; m++) xrand[m] /= nrm;
1930 for (
int cand = 0; cand < 3; cand++) {
1931 if (!(lams[cand] > 0.0))
continue;
1932 for (PetscInt icfl = 0; icfl < ncfl; icfl++) {
1933 const PetscReal cfl = cfls[icfl], dtau = cfl/lams[cand];
1934 PetscCall(
BuildStageStates(user, Ubase, dtau, Rhs, map, Rtmp, Y1, Y2, Y3));
1935 PetscCall(
BuildFDJacobian(user, Y1, epsrel, Rhs, map, phi0, phip, Upert, J1));
1936 PetscCall(
BuildFDJacobian(user, Y2, epsrel, Rhs, map, phi0, phip, Upert, J2));
1937 PetscCall(
BuildFDJacobian(user, Y3, epsrel, Rhs, map, phi0, phip, Upert, J3));
1941 Upert, Ustage, PhiP, PhiM, phip, phi0, epsrel, JPhi));
1948 PetscReal smaxT, rhoT, dummyT;
1952 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1953 " --- convection-only stage-dependent RK tangent (cand %s, CFL=%.2f, dtau=%.6e) ---\n"
1954 " rho(T4)=%.6e sigma_max(T4)=%.6e\n"
1955 " ||T4-P(hJ0)||F/max(1,||T4||F) = %.3e\n"
1956 " ||J_Phi-T4||F/max(1,||J_Phi||F) = %.3e\n"
1957 " ||J_Phi-P(hJ0)||F/max(1,||J_Phi||F)= %.3e\n",
1958 cn[cand], (
double)cfl, (
double)dtau, (
double)rhoT, (
double)smaxT,
1959 (
double)relTP, (
double)relPhiT, (
double)relPhiP));
1961 PetscCall(
FourStage(user, Ubase, dtau, Rhs, map, Rtmp, Ustage, Phi0));
1963 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1964 " direction amp amp(meas) amp(frozen) amp(stage) err(frozen) err(stage)\n"));
1965 for (
int dir = 0; dir < 2; dir++) {
1966 const PetscReal *xv = (dir == 0) ? xrand : v1;
1967 const char *dname = (dir == 0) ?
"random" :
"v1(T4)";
1968 for (
int a = 0; a < 3; a++) {
1969 const PetscReal amp = amps[a];
1970 PetscCall(VecCopy(Ubase, Upert));
1972 PetscCall(
FourStage(user, Upert, dtau, Rhs, map, Rtmp, Ustage, PhiP));
1974 for (PetscInt m = 0; m < map->
n; m++) meas[m] = phip[m] - phi0[m];
1975 for (PetscInt m = 0; m < map->
n; m++) xscaled[m] = amp*xv[m];
1976 ApplyP(Pm, xscaled, predP, map->
n);
1977 ApplyP(T4, xscaled, predT, map->
n);
1979 PetscReal eP = 0.0, eT = 0.0;
1980 for (PetscInt m = 0; m < map->
n; m++) {
1981 const PetscReal dP = meas[m] - predP[m];
1982 const PetscReal dT = meas[m] - predT[m];
1983 eP += dP*dP; eT += dT*dT;
1988 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1989 " %-8s %.0e %.6e %.6e %.6e %.3e %.3e\n",
1990 dname, (
double)amp, (
double)(nm/amp), (
double)(nP/amp), (
double)(nT/amp),
1991 (
double)(PetscSqrtReal(eP)/PetscMax(PETSC_MACHINE_EPSILON, nP)),
1992 (
double)(PetscSqrtReal(eT)/PetscMax(PETSC_MACHINE_EPSILON, nT))));
1997 "stage tangent matches direct finite-difference RK map"));
2000 "B: non-steady base makes frozen-Jacobian RK map measurably different"));
2002 "B: direct RK map confirms frozen-Jacobian error"));
2005 "steady base reduces stage tangent to frozen RK polynomial"));
2010 PetscCall(PetscFree5(Rtmp, J1, J2, J3, T4));
2011 PetscCall(PetscFree5(Pm, JPhi, v1, xrand, meas));
2012 PetscCall(PetscFree5(phi0, phip, xscaled, predP, predT));
2013 PetscCall(VecDestroy(&Y1)); PetscCall(VecDestroy(&Y2)); PetscCall(VecDestroy(&Y3));
2014 PetscCall(VecDestroy(&Upert)); PetscCall(VecDestroy(&Ustage));
2015 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Phi0));
2016 PetscFunctionReturn(0);
2025 Vec Ubase, Rhs, Uwork, Uout;
2026 PetscReal *Rref, *Rrep, *Jbest;
2027 PetscReal repeat_err, maxdiv, det_err;
2030 const PetscInt N = (st ==
STATE_C) ? 5 : 4;
2031 PetscFunctionBeginUser;
2038 PetscCall(VecDuplicate(user->
Ucont, &Ubase));
2039 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
2040 PetscCall(VecDuplicate(user->
Ucont, &Uwork));
2041 PetscCall(VecDuplicate(user->
Ucont, &Uout));
2042 PetscCall(PetscMalloc3(map.
n, &Rref, map.
n, &Rrep, (
size_t)map.
n*map.
n, &Jbest));
2044 PetscCall(
BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
2049 det_err = 0.0;
for (PetscInt m = 0; m < map.
n; m++) det_err = PetscMax(det_err, PetscAbsReal(Rref[m]-Rrep[m]));
2053 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2054 "\n================ STATE %s ================\n"
2055 " grid: DMDA %d^3 (periodic) | independent face DOFs: actual=%d expected=%d\n"
2056 " declared endpoint mismatch (x,y,z) = %.3e %.3e %.3e\n"
2057 " actual Ucat duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
2058 " local lUcat ghost mismatch (x,y,z) = %.3e %.3e %.3e\n"
2059 " actual Ucont duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
2060 " ||Ucat_repeat - Ucat_reference||inf = %.3e\n"
2061 " max|div_h Ucont| = %.3e\n"
2062 " ||R(U0)||2 = %.6e ||R(U0)||inf = %.6e\n"
2063 " residual determinism ||R_rep-R_ref||inf = %.3e\n",
2064 name, (
int)(N+1), (
int)map.
n,
2070 (
double)repeat_err, (
double)maxdiv,
2071 (
double)R0_2, (
double)R0_inf, (
double)det_err));
2075 const PetscReal epsrel[5] = {1e-4, 1e-5, 1e-6, 1e-7, 1e-8};
2076 PetscReal *Jprev, *Jcur;
2077 PetscCall(PetscMalloc2((
size_t)map.
n*map.
n, &Jprev, (
size_t)map.
n*map.
n, &Jcur));
2078 PetscReal best_rel = PETSC_MAX_REAL; PetscInt best_e = 2;
2079 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" epsilon-convergence (||J_e - J_e/10||_F / ||J||_F):\n"));
2080 for (
int e = 0; e < 5; e++) {
2082 for (PetscInt col = 0; col < map.
n; col++) {
2083 PetscReal u0; PetscCall(
GetDof(user, Ubase, &map, col, &u0));
2084 const PetscReal eps = epsrel[e]*PetscMax(1.0, PetscAbsReal(u0));
2085 PetscReal *Rp = Rref, *Rm = Rrep;
2086 PetscCall(VecCopy(Ubase, Uwork));
2087 PetscCall(
PerturbDof(user, Uwork, &map, col, +eps));
2089 PetscCall(VecCopy(Ubase, Uwork));
2090 PetscCall(
PerturbDof(user, Uwork, &map, col, -eps));
2092 for (PetscInt row = 0; row < map.
n; row++) Jcur[row + col*map.
n] = (Rp[row]-Rm[row])/(2.0*eps);
2095 PetscReal num = 0.0, den = 0.0;
2096 for (PetscInt t = 0; t < map.
n*map.
n; t++) {
const PetscReal d = Jprev[t]-Jcur[t]; num += d*d; den += Jcur[t]*Jcur[t]; }
2097 const PetscReal rel = PetscSqrtReal(num)/PetscMax(1.0, PetscSqrtReal(den));
2098 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" eps=%.0e -> %.0e : rel=%.3e\n",
2099 (
double)epsrel[e-1], (
double)epsrel[e], (
double)rel));
2100 if (rel < best_rel) { best_rel = rel; best_e = e; }
2103 PetscReal erho, emaxre, esmax;
2106 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2107 " eps=%.0e metrics: rho=%.6e sigma=%.6e max_real=%.6e fro=%.6e skew=%.3e\n",
2108 (
double)epsrel[e], (
double)erho, (
double)esmax, (
double)emaxre,
2111 PetscCall(PetscArraycpy(Jprev, Jcur, (
size_t)map.
n*map.
n));
2115 const PetscReal er = epsrel[best_e];
2116 for (PetscInt col = 0; col < map.
n; col++) {
2117 PetscReal u0; PetscCall(
GetDof(user, Ubase, &map, col, &u0));
2118 const PetscReal eps = er*PetscMax(1.0, PetscAbsReal(u0));
2119 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(
PerturbDof(user, Uwork, &map, col, +eps));
2121 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(
PerturbDof(user, Uwork, &map, col, -eps));
2123 for (PetscInt row = 0; row < map.
n; row++) Jbest[row + col*map.
n] = (Rref[row]-Rrep[row])/(2.0*eps);
2125 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" selected plateau eps = %.0e\n", (
double)er));
2127 PetscCall(PetscFree2(Jprev, Jcur));
2131 PetscCall(VecCopy(Ubase, user->
Ucont));
2133 const char *fld[] = {
"Ucont"};
2138 PetscBool eqbase; { Vec chk; PetscCall(VecDuplicate(Ubase,&chk)); PetscCall(VecCopy(user->
Ucont,chk));
2139 PetscCall(VecAXPY(chk, -1.0, Ubase)); PetscReal nb; PetscCall(VecNorm(chk, NORM_INFINITY, &nb));
2140 eqbase = (PetscBool)(nb < 1e-12); PetscCall(VecDestroy(&chk));
2141 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" base Ucont restored after Jacobian: %s\n", eqbase?
"yes":
"NO")); }
2144 PetscReal rho, maxre, smax;
2157 PetscReal gradmax = 0.0;
2160 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2161 " --- convective Jacobian spectrum ---\n"
2162 " rho(J)=%.6e sigma_max(J)=%.6e nonnormality=%.3e max_real_eig=%.3e\n"
2163 " --- candidate convective estimates ---\n"
2164 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n"
2165 " max local |grad u| row-sum contribution = %.6e\n"
2166 " rB/rho=%.3f rC/rho=%.3f rD/rho=%.3f | rB/smax=%.3f rC/smax=%.3f rD/smax=%.3f\n",
2167 (
double)rho, (
double)smax, (
double)eta, (
double)maxre,
2168 (
double)lcB, (
double)lcC, (
double)lcD,
2170 (
double)(lcB/rho), (
double)(lcC/rho), (
double)(lcD/rho),
2171 (
double)(lcB/smax), (
double)(lcC/smax), (
double)(lcD/smax)));
2182 const PetscReal lams[3] = {lcB, lcC, lcD};
const char *cn[3] = {
"B",
"C",
"D"};
2184 PetscCall(PetscMalloc1((
size_t)map.
n*map.
n, &Jpseudo));
2189 PetscCall(PetscFree(Jpseudo));
2191 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" --- RK stable pseudo-CFL (convective J) ---\n"));
2192 for (
int c = 0; c < 3; c++) {
2193 if (!(lams[c] > 0.0))
continue;
2202 epsrel[best_e], lams, cn, Jbest));
2205 PetscCall(
PicurvAssertBool(eqbase,
"base Ucont restored after Jacobian build"));
2206 PetscCall(
PicurvAssertBool((PetscBool)(det_err < 1e-10),
"residual evaluation deterministic"));
2207 PetscCall(
PicurvAssertBool((PetscBool)(rho > 0.0 && PetscIsNormalReal(rho)),
"finite rho(J)"));
2208 PetscCall(
PicurvAssertBool((PetscBool)(smax > 0.0 && PetscIsNormalReal(smax)),
"finite sigma_max(J)"));
2210 for (
int d = 0; d < 3; d++) {
2216 PetscCall(
PicurvAssertRealNear(repeat_err, 0.0, 1e-9,
"A: recovered Ucat repeat near roundoff"));
2218 PetscCall(
PicurvAssertRealNear(R0_inf, 0.0, 1e-12,
"A: base residual inf-norm near roundoff"));
2222 for (
int d = 0; d < 3; d++) {
2228 PetscCall(
PicurvAssertRealNear(repeat_err, 0.0, 1e-9,
"B: recovered Ucat repeat near roundoff"));
2229 PetscCall(
PicurvAssertBool((PetscBool)(maxdiv > 1e-3),
"B: nonzero discrete divergence"));
2230 PetscCall(
PicurvAssertBool((PetscBool)(R0_2 > 1e-3),
"B: materially nonzero base residual 2-norm"));
2231 PetscCall(
PicurvAssertBool((PetscBool)(R0_inf > 1e-3),
"B: materially nonzero base residual inf-norm"));
2234 for (
int d = 0; d < 3; d++) {
2240 PetscCall(
PicurvAssertRealNear(repeat_err, 0.0, 1e-9,
"C: recovered Ucat repeat near roundoff"));
2241 PetscCall(
PicurvAssertBool((PetscBool)(maxdiv < 1e-6),
"C: divergence near zero"));
2243 PetscCall(
PicurvAssertRealNear(R0_inf, 0.0, 1e-12,
"C: base residual inf-norm near roundoff"));
2244 PetscCall(
PicurvAssertBool((PetscBool)(PetscAbsReal(lcC-lcB) < 1e-6),
"C: C ~= B"));
2245 PetscCall(
PicurvAssertBool((PetscBool)(gradmax > 1e-6),
"C: canonical shear has nonzero local gradient contribution"));
2248 PetscCall(PetscFree3(Rref, Rrep, Jbest));
2249 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs));
2250 PetscCall(VecDestroy(&Uwork)); PetscCall(VecDestroy(&Uout));
2253 PetscFunctionReturn(0);
2277 Vec Ubase, Rhs, Uwork;
2278 PetscReal *Rp, *Rm, *J;
2279 PetscReal repeat_err, maxdiv;
2281 PetscFunctionBeginUser;
2285 PetscCall(VecDuplicate(user->
Ucont, &Ubase));
2286 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
2287 PetscCall(VecDuplicate(user->
Ucont, &Uwork));
2288 PetscCall(PetscMalloc3(map.
n, &Rp, map.
n, &Rm, (
size_t)map.
n*map.
n, &J));
2290 PetscCall(
BuildFDJacobian(user, Ubase, 1e-5, Rhs, &map, Rp, Rm, Uwork, J));
2291 PetscReal rho, maxre, smax;
2294 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2295 " State A grid audit: DMDA %d^3 independent=%d expected=%d max_real=%.6e rho=%.6e sigma=%.6e skew=%.3e nonnormality=%.3e repeat=%.3e\n",
2296 (
int)(N+1), (
int)map.
n, (
int)map.
expected_n, (
double)maxre, (
double)rho, (
double)smax,
2300 PetscReal lamr, lami, v2 = 0.0, seam2 = 0.0, maxabs = 0.0;
2301 PetscCall(PetscMalloc2(map.
n, &vr, map.
n, &vi));
2303 for (PetscInt m = 0; m < map.
n; m++) {
2304 const PetscReal a2 = vr[m]*vr[m] + vi[m]*vi[m];
2307 maxabs = PetscMax(maxabs, PetscSqrtReal(a2));
2309 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2310 " larger-grid eigenvector: lambda=%.6e%+.6ei seam_energy=%.3f max_entry/||v||=%.3e\n",
2311 (
double)lamr, (
double)lami, (
double)(seam2/PetscMax(v2, PETSC_MACHINE_EPSILON)),
2312 (
double)(maxabs/PetscSqrtReal(PetscMax(v2, PETSC_MACHINE_EPSILON)))));
2314 PetscCall(PetscFree2(vr, vi));
2316 PetscCall(PetscFree3(Rp, Rm, J));
2317 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
2320 PetscFunctionReturn(0);
2329 Vec Ubase, Rhs, Uwork;
2330 PetscReal *Rp, *Rm, *J;
2331 PetscReal repeat_err, maxdiv;
2333 PetscFunctionBeginUser;
2337 PetscCall(VecDuplicate(user->
Ucont, &Ubase));
2338 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
2339 PetscCall(VecDuplicate(user->
Ucont, &Uwork));
2340 PetscCall(PetscMalloc3(map.
n, &Rp, map.
n, &Rm, (
size_t)map.
n*map.
n, &J));
2341 PetscCall(
BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
2342 PetscCall(
BuildFDJacobian(user, Ubase, 1e-5, Rhs, &map, Rp, Rm, Uwork, J));
2343 PetscReal rho, maxre, smax;
2346 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2347 " %-4s rho=%.6e sigma=%.6e max_real=%.6e skew=%.3e nonnormality=%.3e div=%.3e repeat=%.3e\n",
2348 label, (
double)rho, (
double)smax, (
double)maxre,
2350 (
double)maxdiv, (
double)repeat_err));
2351 PetscCall(PetscFree3(Rp, Rm, J));
2352 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
2355 PetscFunctionReturn(0);
2363 PetscFunctionBeginUser;
2364 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2365 "\n================ STATE A GRID / ACTIVE-SPACE AUDIT ================\n"
2366 " residual sign convention: ComputeRHS returns the production convection residual used by pseudo-time updates.\n"
2367 " component-staggered periodic duplicate planes: 0<-m-2 and m-1<-1 in each direction.\n"
2368 " independent map: all three Ucont components use representatives i,j,k=1..m-2; count = 3*(m-2)^3.\n"));
2371 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2372 " State A transport-direction split on DMDA 5^3:\n"));
2376 PetscFunctionReturn(0);
2386 PetscFunctionBeginUser;
2388 PetscCheck(
g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
2389 "-candidate_ref_token is required when -candidate_ref_path is set");
2390 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2393 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"could not write State A MPI reference");
2394 fprintf(fp,
"PICURV_CANDIDATE_STATEA_REF_V2 %s\n",
g_ref_token);
2395 fprintf(fp,
"%.17e %.17e %.17e\n", (
double)r0.
n2, (
double)r0.
ninf, (
double)r0.
checksum);
2396 fprintf(fp,
"%.17e %.17e %.17e\n", (
double)jv.
n2, (
double)jv.
ninf, (
double)jv.
checksum);
2397 fprintf(fp,
"%.17e %.17e %.17e\n", (
double)phi.
n2, (
double)phi.
ninf, (
double)phi.
checksum);
2398 fprintf(fp,
"%.17e %.17e %.17e %d %d %d %d\n",
2405 PetscFunctionReturn(0);
2415 PetscReal vals[16] = {0.0};
2416 PetscFunctionBeginUser;
2418 "two-rank State A decomp check requires matching -candidate_ref_path and -candidate_ref_token from a preceding one-rank run");
2419 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
2421 char magic[64], token[128];
2423 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
2424 "State A one-rank decomp reference missing; run the Makefile target so -n 1 precedes -n 2");
2425 PetscCheck(fscanf(fp,
"%63s %127s", magic, token) == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference header");
2426 PetscCheck(strcmp(magic,
"PICURV_CANDIDATE_STATEA_REF_V2") == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
2427 "bad reference magic");
2428 PetscCheck(strcmp(token,
g_ref_token) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
2429 "State A one-rank decomp reference token mismatch");
2430 int active, cblock, ci, cj;
2431 PetscCheck(fscanf(fp,
"%le %le %le", &vals[0], &vals[1], &vals[2]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference R0");
2432 PetscCheck(fscanf(fp,
"%le %le %le", &vals[3], &vals[4], &vals[5]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference Jv");
2433 PetscCheck(fscanf(fp,
"%le %le %le", &vals[6], &vals[7], &vals[8]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference Phi");
2434 PetscCheck(fscanf(fp,
"%le %le %le %d %d %d %d", &vals[9], &vals[10], &vals[11],
2435 &active, &cblock, &ci, &cj) == 7, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference estimator");
2436 vals[12] = (PetscReal)active; vals[13] = (PetscReal)cblock; vals[14] = (PetscReal)ci; vals[15] = (PetscReal)cj;
2438 PetscCheck(remove(
g_ref_path) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
2439 "could not remove consumed State A MPI reference '%s'",
g_ref_path);
2441 PetscCallMPI(MPI_Bcast(vals, 16, MPIU_REAL, 0, PETSC_COMM_WORLD));
2455 PetscCall(
PicurvAssertBool((PetscBool)(rep->
cblock == (PetscInt)vals[13]),
"MPI State A controlling block"));
2456 PetscFunctionReturn(0);
2466 Vec V, Up, Um, PhiP, PhiM, Ustage;
2467 PetscReal *v, *R0, *Rp, *Rm, *ActP, *ActM, *Out;
2469 const PetscReal eps = 1e-6, dtau = 0.5/lcC;
2471 PetscFunctionBeginUser;
2472 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
2474 PetscCall(VecDuplicate(Ubase, &V)); PetscCall(VecDuplicate(Ubase, &Up));
2475 PetscCall(VecDuplicate(Ubase, &Um)); PetscCall(VecDuplicate(Ubase, &PhiP));
2476 PetscCall(VecDuplicate(Ubase, &PhiM)); PetscCall(VecDuplicate(Ubase, &Ustage));
2477 PetscCall(PetscMalloc6(map.
n, &v, map.
n, &R0, map.
n, &Rp, map.
n, &Rm, map.
n, &ActP, map.
n, &ActM));
2478 PetscCall(PetscMalloc1(map.
n, &Out));
2483 PetscCall(VecCopy(Ubase, Up)); PetscCall(VecAXPY(Up, eps, V));
2484 PetscCall(VecCopy(Ubase, Um)); PetscCall(VecAXPY(Um, -eps, V));
2487 for (PetscInt m = 0; m < map.
n; m++) Out[m] = (Rp[m]-Rm[m])/(2.0*eps);
2490 PetscCall(
FourStage(user, Up, dtau, Rhs, &map, Rp, Ustage, PhiP));
2491 PetscCall(
FourStage(user, Um, dtau, Rhs, &map, Rm, Ustage, PhiM));
2494 for (PetscInt m = 0; m < map.
n; m++) Out[m] = (ActP[m]-ActM[m])/(2.0*eps);
2497 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2498 " State A matrix-free MPI check: R0 L2=%.6e Linf=%.6e checksum=%.6e\n"
2499 " Jv L2=%.6e Linf=%.6e checksum=%.6e\n"
2500 " DPhi v L2=%.6e Linf=%.6e checksum=%.6e\n",
2507 PetscCall(PetscFree6(v, R0, Rp, Rm, ActP, ActM)); PetscCall(PetscFree(Out));
2508 PetscCall(VecDestroy(&V)); PetscCall(VecDestroy(&Up)); PetscCall(VecDestroy(&Um));
2509 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Ustage));
2511 PetscFunctionReturn(0);
2518 PetscReal expB, PetscReal expC, PetscReal expD)
2522 PetscReal repeat_err, maxdiv;
2525 const PetscInt N = 8;
2526 PetscFunctionBeginUser;
2530 PetscCall(VecDuplicate(user->
Ucont, &Ubase));
2531 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
2532 PetscCall(
BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
2538 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
2539 "\n================ DECOMP BASELINE %s ================\n"
2540 " active cells: %d | repeat=%.3e | max|div_h Ucont|=%.3e\n"
2541 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n",
2542 name, (
int)rep.
active_cells, (
double)repeat_err, (
double)maxdiv,
2543 (
double)lcB, (
double)lcC, (
double)lcD));
2546 PetscCall(
PicurvAssertRealNear(expB, lcB, 5e-7,
"decomp: lambda_cB matches one-rank baseline"));
2547 PetscCall(
PicurvAssertRealNear(expC, lcC, 5e-7,
"decomp: lambda_cC matches one-rank baseline"));
2548 PetscCall(
PicurvAssertRealNear(expD, lcD, 5e-7,
"decomp: lambda_cD matches one-rank baseline"));
2555 PetscCall(
PicurvAssertBool((PetscBool)(maxdiv > 1e-3),
"decomp B: nonzero divergence"));
2562 PetscCall(VecDestroy(&Ubase));
2563 PetscCall(VecDestroy(&Rhs));
2565 PetscFunctionReturn(0);
2588 PetscFunctionBeginUser;
2589 PetscCall(PetscOptionsGetString(NULL, NULL,
"-candidate_ref_path",
2591 PetscCall(PetscOptionsGetString(NULL, NULL,
"-candidate_ref_token",
2595 "-candidate_ref_path and -candidate_ref_token must be supplied together");
2597 PetscFunctionReturn(0);
2605 PetscErrorCode ierr;
2609 {
"candidate-state-B-divergence",
TestStateB},
2618 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv A4a convective-candidate study");
2619 if (ierr)
return (
int)ierr;
2621 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size);
if (ierr) { PetscFinalize();
return (
int)ierr; }
2623 ierr =
PicurvRunTests(
"unit-momentum-candidates", cases,
sizeof(cases)/
sizeof(cases[0]));
2624 if (!ierr) ierr =
PicurvRunTests(
"unit-momentum-candidates-decomp", decomp_cases,
sizeof(decomp_cases)/
sizeof(decomp_cases[0]));
2626 ierr =
PicurvRunTests(
"unit-momentum-candidates-decomp", decomp_cases,
sizeof(decomp_cases)/
sizeof(decomp_cases[0]));
2628 if (ierr) { PetscFinalize();
return (
int)ierr; }
2629 return (
int)PetscFinalize();
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode SynchronizePeriodicLocalStaggeredField(UserCtx *user, Vec local_field)
Synchronizes one local-only component-staggered periodic work field.
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
PetscInt MomCellActiveRows(PetscReal ***nvert, PetscInt k, PetscInt j, PetscInt i, PetscInt mx, PetscInt my, PetscInt mz, PetscBool np_x1, PetscBool np_y1, PetscBool np_z1, PetscInt twoD)
Active staggered-momentum row mask for a cell (exposed for unit testing).
PetscErrorCode ComputeMomentumStabilityEstimate(UserCtx *user, PetscInt block_number, PetscReal dt, MomStabCandidate candidate, MomStabilityReport *rep)
Compute the momentum pseudo-time stability estimate (shadow/diagnostic).
Diagnostic report produced by ComputeMomentumStabilityEstimate().
PetscErrorCode Convection(UserCtx *user, Vec Ucont, Vec Ucat, Vec Conv)
Computes the convective contribution to the contravariant momentum RHS.
PetscErrorCode ComputeRHS(UserCtx *user, Vec Rhs)
Computes the Right-Hand Side (RHS) of the momentum equations.
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
PetscErrorCode Cart2Contra(UserCtx *user)
Convert the ghosted Cartesian velocity field to contravariant face fluxes.
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
static void DenseMatVec(const PetscReal *J, const PetscReal *x, PetscReal *y, PetscInt n)
Applies a dense column-major matrix to an active-space vector.
static PetscErrorCode EvalConvResidual(UserCtx *user, Vec Ucont_in, Vec Rhs, const DofMap *map, PetscReal *Ract)
static PetscErrorCode TestDecompA(void)
Runs the State A decomposition baseline.
static Cmpnts DirectUcontVelocity(CandState st, PetscInt i, PetscInt j, PetscInt k, PetscInt mx, PetscInt my, PetscInt mz)
Evaluates the declared direct component-staggered State B Ucont field.
static PetscErrorCode ComputeMaxGradientContribution(UserCtx *user, PetscReal *gradmax)
Computes the global maximum Cartesian velocity-gradient row-sum used by Candidate D.
static PetscErrorCode RunRKTangentDiagnostics(UserCtx *user, CandState st, Vec Ubase, Vec Rhs, const DofMap *map, PetscReal epsrel, const PetscReal lams[3], const char *cn[3], const PetscReal *J0)
Runs stage-dependent RK tangent and direct nonlinear perturbation diagnostics.
static PetscErrorCode AmplificationMetric(const PetscReal *J, PetscInt n, PetscReal dtau, PMetric which, PetscReal *metric)
Evaluates either spectral-radius or 2-norm amplification for one pseudo-time step.
static PetscErrorCode SymbolEigenSummary(const PetscReal A6[36], PetscReal *maxre, PetscReal wr_out[6], PetscReal wi_out[6])
Eigenvalue summary for a 6x6 real symbol.
static PetscErrorCode GetDof(UserCtx *user, Vec Ucont, const DofMap *map, PetscInt m, PetscReal *val)
Reads one active contravariant component from a global vector.
static PetscBool DofTouchesPeriodicRepresentative(const DofMap *map, PetscInt m, DMDALocalInfo info)
True if an active representative lies on a plane adjacent to periodic duplicates.
static PetscErrorCode DofMapBuildOwned(UserCtx *user, DofMap *map)
Builds the rank-owned periodic independent face-DOF map for MPI checks.
static PetscErrorCode DofMapBuild(UserCtx *user, DofMap *map)
Builds the serial periodic independent face-DOF map used by dense Jacobians.
static PetscErrorCode StableCFL(const PetscReal *J, PetscInt n, PetscReal lam, PMetric which, StableCFLResult *result)
static void MatMul(const PetscReal *A, const PetscReal *B, PetscReal *out, PetscInt n)
static PetscReal PeriodicCellAngle(PetscInt idx, PetscInt npts)
Returns the cell-centered periodic angle using duplicated endpoint planes.
static PetscReal VecNorm2Array(const PetscReal *x, PetscInt n)
Computes the Euclidean norm of a dense vector.
int main(int argc, char **argv)
PETSc entry point for the focused convective-candidate harness.
static PetscErrorCode RunStateADirectionalMechanismAudit(const PetscReal *Jxy, UserCtx *user_xy, Vec Ubase_xy, Vec Rhs_xy, const DofMap *map_xy, PetscReal epsrel)
Builds Jx, Jy, Jxy and prints additivity/commutator/eigenpair diagnostics.
static PetscReal DenseRelativeDiff(const PetscReal *A, const PetscReal *B, PetscInt n, PetscReal denom_ref)
Computes a normalized Frobenius difference between two dense matrices.
static PetscErrorCode DenseSigmaMax(const PetscReal *A, PetscInt n, PetscReal *smax, PetscReal *v1)
static PetscBool g_ref_path_set
static PetscErrorCode PrintBlockAndSymmetricLocalization(UserCtx *user, const DofMap *map, const PetscReal *J)
Prints 3x3 component block norms and localized symmetric rows.
static PetscReal DenseFrobenius(const PetscReal *A, PetscInt n)
Computes the Frobenius norm of a dense column-major matrix.
static PetscErrorCode TestDecompB(void)
Runs the State B decomposition baseline.
static PetscErrorCode TestStateC(void)
Runs the State C candidate harness.
static PetscReal CmpDiffInf(Cmpnts a, Cmpnts b)
Computes the componentwise infinity norm of the difference between two vectors.
static PetscReal CmpGet(Cmpnts c, PetscInt comp)
static PetscBool InGhostRange(PetscInt idx, PetscInt lo, PetscInt n)
Reports whether a global index is present in a rank's local ghosted range.
static char g_ref_token[128]
static const char * StableCFLStatusText(StableCFLResult r)
Returns human-readable text for a stable-CFL search result.
static void FillAuditDirection(const DofMap *map, PetscInt kind, PetscReal *x)
Fills one deterministic active-space vector used by dense/matrix-free checks.
static PetscErrorCode DofMapDestroy(DofMap *map)
Releases storage owned by an active-DOF map.
static PetscErrorCode TestDecompC(void)
Runs the State C decomposition baseline.
static PetscReal DenseCommutatorNorm(const PetscReal *A, const PetscReal *B, PetscInt n)
Computes C = A*B - B*A and returns its normalized Frobenius norm.
static PetscInt PeriodicRepCount(PetscInt npts)
Returns the number of independent periodic representatives in one direction.
static PetscErrorCode BuildStageTangent(const PetscReal *J0, const PetscReal *J1, const PetscReal *J2, const PetscReal *J3, PetscReal dtau, PetscInt n, PetscReal *T4)
Builds the exact four-stage tangent from stage-dependent Jacobians.
static PetscErrorCode CheckDenseJacobianAction(UserCtx *user, Vec Ubase, Vec Rhs, Vec Uwork, const DofMap *map, const PetscReal *J, PetscReal epsrel)
Verifies that the assembled dense Jacobian has the same action as production FD Jv.
static PetscErrorCode ComputeDeclaredSeamMismatch(CandState st, DMDALocalInfo info, PetscReal seam[3])
Computes analytic periodic seam mismatches for each coordinate direction.
static PetscErrorCode DenseSpectralRadius(const PetscReal *A, PetscInt n, PetscReal *rho, PetscReal *maxRealPart)
static PetscErrorCode SetAnchoredStage(UserCtx *user, Vec U0full, PetscReal scale, const DofMap *map, const PetscReal *Ract, Vec Ustage)
Forms one anchored RK stage state from the base state and active residual.
static PetscErrorCode BuildFDJacobian(UserCtx *user, Vec Ucenter, PetscReal epsrel, Vec Rhs, const DofMap *map, PetscReal *Rp, PetscReal *Rm, Vec Uwork, PetscReal *J)
Builds a centered finite-difference Jacobian of the production convective residual.
static PetscErrorCode PrintFourierChecks(const DofMap *map, const PetscReal *J)
Projects production J on full staggered six-dimensional Fourier subspaces.
static void ApplyP(const PetscReal *P, const PetscReal *x, PetscReal *out, PetscInt n)
static PetscErrorCode DenseMaxRealRightEigenpair(const PetscReal *A, PetscInt n, PetscReal *lamr, PetscReal *lami, PetscReal *vr_out, PetscReal *vi_out)
Extracts the right eigenpair whose eigenvalue has largest real part.
static PetscErrorCode DenseShiftIdentity(const PetscReal *A, PetscInt n, PetscReal shift, PetscReal *B)
Copies a dense matrix and adds a scalar shift to its diagonal.
static PetscErrorCode EvalResidualStage(UserCtx *user, Vec Ucont_in, Vec Rhs, const DofMap *map, ResidualStage stage, PetscReal *out)
Evaluates one observable/mirrored residual-path stage for a Ucont input.
static PetscErrorCode PrintStableCFLLine(const char *candidate, StableCFLResult eig, StableCFLResult norm)
Prints one candidate's eigenvalue and norm stable-CFL statuses.
static PetscErrorCode TraceStateAResidualStages(UserCtx *user, Vec Ubase, Vec Rhs, const DofMap *map, const PetscReal *J)
Trace observable production residual stages for one deterministic perturbation.
static PetscErrorCode AverageRctToFinalActive(UserCtx *user, Vec Rct, const DofMap *map, PetscReal *out)
Mirrors ComputeRHS's final Rct face averaging and active cleanup for P=0/no body force.
static PetscErrorCode TestStateAGridAudit(void)
Runs the State A grid-dependence and active-space audit.
static PetscErrorCode ConfigureMPIReferenceOptions(void)
Reads optional paired-run MPI reference path and token.
static PetscReal DenseAdditivityError(const PetscReal *A, const PetscReal *B, const PetscReal *C, PetscInt n)
Normalized Frobenius norm of A - (B+C).
static PetscErrorCode WriteStateADecompReference(GlobalVecStats r0, GlobalVecStats jv, GlobalVecStats phi, const MomStabilityReport *rep)
Writes the one-rank State A matrix-free decomposition reference.
static PetscErrorCode RunStateAGridAuditOne(PetscInt N)
Runs one State A grid-size audit case.
static PetscErrorCode BuildStageJacobian(UserCtx *user, Vec Ucenter, PetscReal epsrel, Vec Rhs, const DofMap *map, ResidualStage stage, PetscReal *Rp, PetscReal *Rm, Vec Uwork, PetscReal *J)
Builds a finite-difference Jacobian for one residual-path stage.
static PetscErrorCode FillDeterministicDirection(UserCtx *user, Vec V, const DofMap *map, PetscReal *x)
Fills a globally normalized deterministic active-space perturbation direction.
static PetscBool g_ref_token_set
static PetscErrorCode ReadAndCompareStateADecompReference(GlobalVecStats r0, GlobalVecStats jv, GlobalVecStats phi, const MomStabilityReport *rep)
Compares a distributed State A matrix-free check against the one-rank reference.
static PetscErrorCode MapCartesianResidualToRct(UserCtx *user, Vec Rc, Vec Rct)
Mirrors ComputeRHS's Cartesian residual -> contravariant local Rct mapping.
static PetscReal DofWeight(const DofMap *map, PetscInt m)
Returns a deterministic checksum weight for an active DOF.
static PetscReal DenseNonNormality(const PetscReal *A, PetscInt n)
static PetscErrorCode PerturbDof(UserCtx *user, Vec Ucont, const DofMap *map, PetscInt m, PetscReal delta)
static PetscErrorCode RunState(CandState st, const char *name)
static PetscErrorCode AddActiveVector(UserCtx *user, Vec U, const DofMap *map, const PetscReal *x, PetscReal scale)
Adds a dense active-space vector into a global contravariant vector.
static PetscErrorCode ComputeLocalOuterGhostMismatch(UserCtx *user, Vec local, PetscReal seam[3])
Computes outer periodic ghost mismatch for local Ucat.
static PetscErrorCode BuildStageStates(UserCtx *user, Vec U0full, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Y1, Vec Y2, Vec Y3)
Builds the first three anchored RK stage states for a base vector.
static PetscErrorCode SetUcatField(UserCtx *user, CandState st)
static PetscErrorCode MatrixFreeJv(UserCtx *user, Vec Ubase, Vec Rhs, const DofMap *map, const PetscReal *v, PetscReal eps, PetscReal *jv)
Matrix-free production Jacobian-vector product on the active space.
static PetscErrorCode ExtractActiveVector(UserCtx *user, Vec U, const DofMap *map, PetscReal *x)
Extracts active-space entries from a global contravariant vector.
static PetscErrorCode RKPolynomial(const PetscReal *J, PetscReal dtau, PetscInt n, PetscReal *P)
static PetscErrorCode TestStateA(void)
Runs the State A candidate harness.
static PetscErrorCode BuildBaseState(UserCtx *user, CandState st, Vec Ubase, PetscReal *repeat_inf, PetscReal *maxdiv, SeamDiagnostics *seam)
static PetscErrorCode ComputeMaxDiscreteDivergence(UserCtx *user, PetscReal *maxdiv)
Computes max discrete divergence of the current local Ucont field.
static PetscErrorCode StateADecompDirectionalCheck(UserCtx *user, Vec Ubase, Vec Rhs, PetscReal lcC, const MomStabilityReport *rep)
Runs State A matrix-free residual, Jv, and four-stage MPI decomposition checks.
static PetscErrorCode SetDirectUcontField(UserCtx *user, CandState st)
Sets the direct State B component-staggered Ucont field on owned entries.
static PetscErrorCode StaggeredFourierSymbol(const DofMap *map, const PetscReal *J, PetscInt wx, PetscInt wy, PetscInt wz, PetscReal A6[36], PetscReal *leak)
Builds the 6x6 projected real symbol and leakage for one wavevector.
static PetscErrorCode PrintFrozenAmplificationTable(const char *title, const PetscReal *J, PetscInt n, const PetscReal lams[3], const char *cn[3])
Prints frozen RK amplification tables for the supplied operator and candidates.
static PetscErrorCode PrintPeriodicSpaceAudit(UserCtx *user, const DofMap *map)
Prints the component-wise periodic storage count actually used by the active map.
static PetscErrorCode ActiveStats(const DofMap *map, const PetscReal *x, GlobalVecStats *stats)
Computes global active-vector norms and checksum.
static PetscErrorCode ConfigureCandidateFixture(SimCtx *simCtx, UserCtx *user)
Configures the minimal context for centered inviscid periodic convection tests.
static PetscErrorCode FourStage(UserCtx *user, Vec U0full, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Uwork, Vec Uout)
static PetscErrorCode RunDecompBaseline(CandState st, const char *name, PetscReal expB, PetscReal expC, PetscReal expD)
Runs one decomp baseline and compares scalar estimates with regenerated references.
static char g_ref_path[PETSC_MAX_PATH_LEN]
static PetscReal VecNormInfArray(const PetscReal *x, PetscInt n)
Computes the infinity norm of a dense vector.
static void FillStaggeredFourierBasis(const DofMap *map, PetscInt wx, PetscInt wy, PetscInt wz, PetscReal *Q)
Fills the six real basis vectors for one staggered same-wavevector subspace.
static PetscErrorCode ExtractLocalActiveVector(UserCtx *user, Vec local, const DofMap *map, PetscReal *x)
Extract active-space entries from a local vector.
PetscReal ucont_global[3]
static PetscErrorCode TestStateB(void)
Runs the State B candidate harness.
static PetscReal PeriodicFaceAngle(PetscInt idx, PetscInt npts)
Returns a face-representative periodic angle for component-staggered Ucont.
static PetscErrorCode RunStateASplitOne(CandState st, const char *label)
Runs one State A transport-direction split.
static PetscReal DenseSkewnessDefect(const PetscReal *A, PetscInt n)
Computes the normalized Frobenius defect from skew symmetry.
static PetscErrorCode BuildPhiJacobian(UserCtx *user, Vec Ucenter, PetscReal dtau, Vec Rhs, const DofMap *map, PetscReal *Rscratch, Vec Upert, Vec Ustage, Vec PhiP, Vec PhiM, PetscReal *xp, PetscReal *xm, PetscReal epsrel, PetscReal *JPhi)
Builds a finite-difference Jacobian of the complete nonlinear four-stage map.
static PetscInt DofMapExpectedCount(DMDALocalInfo info)
Counts all independent component-staggered representatives used by ComputeRHS.
static PetscErrorCode RunStateAResidualPathIsolation(UserCtx *user, Vec Ubase, Vec Rhs, Vec Uwork, const DofMap *map, PetscReal epsrel)
Prints the stage where positive-real spectrum first appears.
static PetscErrorCode DenseRKPolynomialSpectralRadius(const PetscReal *J, PetscInt n, PetscReal dtau, PetscReal *rho)
Computes the spectral radius of the RK polynomial by applying it to eig(J).
@ STABLE_CFL_EXCEEDS_SCAN
static Cmpnts AnalyticVelocity(CandState st, PetscInt i, PetscInt j, PetscInt k, PetscInt mx, PetscInt my, PetscInt mz)
Evaluates one of the three analytic Cartesian candidate states.
static PetscErrorCode PrintSpectrumSummary(const char *name, const PetscReal *J, PetscInt n)
Prints eigenvalue and norm summary for one dense operator.
static PetscErrorCode ComputeLocalDuplicateMismatch(UserCtx *user, Vec local, PetscReal seam[3])
Computes duplicate-plane mismatch in a local vector view.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvCreateMinimalContextsWithPeriodicity(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz, PetscBool x_periodic, PetscBool y_periodic, PetscBool z_periodic)
Builds minimal SimCtx and UserCtx fixtures for C unit tests with configurable periodicity.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
Shared declarations for the PICurv C test fixture and assertion layer.
Named test case descriptor consumed by PicurvRunTests.
BoundaryFaceConfig boundary_faces[6]
PetscReal bulkVelocityCorrection
A 3D point or vector with PetscScalar components.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.