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];
75 DMDALocalInfo info = user->
info;
76 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
77 const PetscInt lxs = 1, lxe = mx-1, lys = 1, lye = my-1, lzs = 1, lze = mz-1;
79 PetscFunctionBeginUser;
81 map->
n = (lxe-lxs)*(lye-lys)*(lze-lzs)*3;
82 PetscCall(PetscMalloc4(map->
n, &map->
comp, map->
n, &map->
ci, map->
n, &map->
cj, map->
n, &map->
ck));
83 for (PetscInt k = lzs; k < lze; k++)
84 for (PetscInt j = lys; j < lye; j++)
85 for (PetscInt i = lxs; i < lxe; i++)
86 for (PetscInt c = 0; c < 3; c++) {
87 map->
comp[cnt] = c; map->
ci[cnt] = i; map->
cj[cnt] = j; map->
ck[cnt] = k; cnt++;
89 PetscCheck(map->
n == map->
expected_n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
90 "periodic independent DOF count mismatch: got %" PetscInt_FMT
", expected %" PetscInt_FMT,
92 PetscFunctionReturn(0);
100 DMDALocalInfo info = user->
info;
101 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
102 const PetscInt xs = info.xs, xe = info.xs + info.xm;
103 const PetscInt ys = info.ys, ye = info.ys + info.ym;
104 const PetscInt zs = info.zs, ze = info.zs + info.zm;
105 const PetscInt lxs = PetscMax(xs, 1), lxe = PetscMin(xe, mx-1);
106 const PetscInt lys = PetscMax(ys, 1), lye = PetscMin(ye, my-1);
107 const PetscInt lzs = PetscMax(zs, 1), lze = PetscMin(ze, mz-1);
109 PetscFunctionBeginUser;
111 map->
n = PetscMax(0,lxe-lxs)*PetscMax(0,lye-lys)*PetscMax(0,lze-lzs)*3;
112 PetscCall(PetscMalloc4(map->
n, &map->
comp, map->
n, &map->
ci, map->
n, &map->
cj, map->
n, &map->
ck));
113 for (PetscInt k = lzs; k < lze; k++)
114 for (PetscInt j = lys; j < lye; j++)
115 for (PetscInt i = lxs; i < lxe; i++)
116 for (PetscInt c = 0; c < 3; c++) {
117 map->
comp[cnt] = c; map->
ci[cnt] = i; map->
cj[cnt] = j; map->
ck[cnt] = k; cnt++;
119 PetscFunctionReturn(0);
126{ PetscFunctionBeginUser; PetscCall(PetscFree4(map->
comp, map->
ci, map->
cj, map->
ck)); PetscFunctionReturn(0); }
129static inline PetscReal
CmpGet(
Cmpnts c, PetscInt comp) {
const PetscReal *p = (
const PetscReal*)&c;
return p[comp]; }
137 PetscFunctionBeginUser;
138 PetscCall(VecCopy(Ucont_in, user->
Ucont));
140 const char *fld[] = {
"Ucont"};
144 PetscCall(DMDAVecGetArrayRead(user->
fda, Rhs, &r));
145 for (PetscInt m = 0; m < map->
n; m++)
147 PetscCall(DMDAVecRestoreArrayRead(user->
fda, Rhs, &r));
148 PetscFunctionReturn(0);
155 PetscFunctionBeginUser;
156 PetscCall(DMDAVecGetArray(user->
fda, Ucont, &a));
157 { PetscReal *p = (PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]]; p[map->
comp[m]] += delta; }
158 PetscCall(DMDAVecRestoreArray(user->
fda, Ucont, &a));
159 PetscFunctionReturn(0);
168 PetscFunctionBeginUser;
169 PetscCall(DMDAVecGetArray(user->
fda, Ucont, &a));
170 {
const PetscReal *p = (
const PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]]; *val = p[map->
comp[m]]; }
171 PetscCall(DMDAVecRestoreArray(user->
fda, Ucont, &a));
172 PetscFunctionReturn(0);
185 const PetscInt nuniq = npts - 1;
186 const PetscInt ip = (idx == npts - 1) ? 0 : idx;
187 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
196 PetscInt ip = idx - 1;
197 if (idx == 0) ip = nuniq - 1;
198 else if (idx == npts - 1) ip = 0;
199 return 2.0*PETSC_PI*((PetscReal)ip)/((PetscReal)nuniq);
206 PetscInt mx, PetscInt my, PetscInt mz)
213 v.
x = 0.7; v.
y = -0.4; v.
z = 0.0;
215 (void)x; v.
x = 0.0; v.
y = 0.0; v.
z = 0.0;
217 v.
x = 1.0 + 0.5*PetscSinReal(y); v.
y = 0.0; v.
z = 0.0;
226 PetscInt mx, PetscInt my, PetscInt mz)
228 Cmpnts v = {0.0, 0.0, 0.0};
229 (void)j; (void)k; (void)my; (void)mz;
239 return PetscMax(PetscAbsReal(a.
x-b.
x), PetscMax(PetscAbsReal(a.
y-b.
y), PetscAbsReal(a.
z-b.
z)));
247 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
248 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
249 PetscFunctionBeginUser;
251 for (PetscInt k = 1; k < mz-1; k++)
252 for (PetscInt j = 1; j < my-1; j++) {
258 for (PetscInt k = 1; k < mz-1; k++)
259 for (PetscInt i = 1; i < mx-1; i++) {
265 for (PetscInt j = 1; j < my-1; j++)
266 for (PetscInt i = 1; i < mx-1; i++) {
273 for (PetscInt k = 0; k < mz; k++)
274 for (PetscInt j = 0; j < my; j++)
277 for (PetscInt k = 0; k < mz; k++)
278 for (PetscInt i = 0; i < mx; i++)
281 for (PetscInt j = 0; j < my; j++)
282 for (PetscInt i = 0; i < mx; i++)
286 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
287 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
288 PetscFunctionReturn(0);
294static inline PetscBool
InGhostRange(PetscInt idx, PetscInt lo, PetscInt n)
295{
return (PetscBool)(idx >= lo && idx < lo + n); }
302 DMDALocalInfo info = user->
info;
304 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
305 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
306 PetscFunctionBeginUser;
307 PetscCall(DMDAVecGetArrayRead(user->
fda, local, &a));
308#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
309#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
310#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
312 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
313 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
314 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][0], a[k][j][mx-2]));
316 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
317 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
318 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][mx-1], a[k][j][1]));
320 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
321 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
322 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][0][i], a[k][my-2][i]));
324 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
325 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
326 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][my-1][i], a[k][1][i]));
328 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
329 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
330 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[0][j][i], a[mz-2][j][i]));
332 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
333 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
334 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[mz-1][j][i], a[1][j][i]));
338 PetscCall(DMDAVecRestoreArrayRead(user->
fda, local, &a));
339 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
340 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
341 PetscFunctionReturn(0);
349 DMDALocalInfo info = user->
info;
351 PetscReal loc[3] = {0.0, 0.0, 0.0}, glo[3];
352 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
353 PetscFunctionBeginUser;
354 PetscCall(DMDAVecGetArrayRead(user->
fda, local, &a));
355#define HAVE_I(ii) InGhostRange((ii), info.gxs, info.gxm)
356#define HAVE_J(jj) InGhostRange((jj), info.gys, info.gym)
357#define HAVE_K(kk) InGhostRange((kk), info.gzs, info.gzm)
359 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
360 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
361 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][-1], a[k][j][1]));
363 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
364 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
365 loc[0] = PetscMax(loc[0],
CmpDiffInf(a[k][j][mx], a[k][j][mx-2]));
367 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
368 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
369 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][-1][i], a[k][1][i]));
371 for (PetscInt k = 1; k < mz-1; k++)
if (
HAVE_K(k))
372 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
373 loc[1] = PetscMax(loc[1],
CmpDiffInf(a[k][my][i], a[k][my-2][i]));
375 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
376 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
377 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[-1][j][i], a[1][j][i]));
379 for (PetscInt j = 1; j < my-1; j++)
if (
HAVE_J(j))
380 for (PetscInt i = 1; i < mx-1; i++)
if (
HAVE_I(i))
381 loc[2] = PetscMax(loc[2],
CmpDiffInf(a[mz][j][i], a[mz-2][j][i]));
385 PetscCall(DMDAVecRestoreArrayRead(user->
fda, local, &a));
386 PetscCallMPI(MPI_Allreduce(loc, glo, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
387 seam[0] = glo[0]; seam[1] = glo[1]; seam[2] = glo[2];
388 PetscFunctionReturn(0);
396 PetscFunctionBeginUser;
402 if (!user->
lNu_t) PetscCall(DMCreateLocalVector(user->
da, &user->
lNu_t));
404 PetscCall(VecSet(user->
lNvert, 0.0)); PetscCall(VecSet(user->
Nvert, 0.0));
405 PetscFunctionReturn(0);
412 DMDALocalInfo info = user->
info;
413 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
414 PetscFunctionBeginUser;
415 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat, &u));
417 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
418 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
419 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
422 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat, &u));
423 PetscFunctionReturn(0);
432 DMDALocalInfo info = user->
info;
433 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
434 PetscFunctionBeginUser;
435 PetscCall(VecSet(user->
Ucont, 0.0));
436 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucont, &u));
437 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
438 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
439 for (PetscInt i = info.xs; i < info.xs+info.xm; i++)
441 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucont, &u));
442 PetscFunctionReturn(0);
450 DMDALocalInfo info = user->
info;
451 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
453 PetscReal dv = 0.0, dv_global;
454 PetscFunctionBeginUser;
456 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lUcont, &uc));
457 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
458 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
459 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
460 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2)
continue;
461 const PetscReal d = (uc[k][j][i].
x - uc[k][j][i-1].
x)
462 + (uc[k][j][i].y - uc[k][j-1][i].y)
463 + (uc[k][j][i].
z - uc[k-1][j][i].
z);
464 dv = PetscMax(dv, PetscAbsReal(d));
466 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lUcont, &uc));
467 PetscCallMPI(MPI_Allreduce(&dv, &dv_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
469 PetscFunctionReturn(0);
475 PetscReal *repeat_inf, PetscReal *maxdiv,
478 DMDALocalInfo info = user->
info;
479 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
480 PetscReal err = 0.0, err_global;
483 PetscFunctionBeginUser;
485 PetscCall(VecDuplicate(user->
Ucat, &target));
490 const char *ufld[] = {
"Ucont"};
491 const char *cfld[] = {
"Ucat"};
494 PetscCall(VecCopy(user->
Ucont, Ubase));
498 PetscCall(VecCopy(user->
Ucat, target));
502 const char *cfld[] = {
"Ucat"};
503 const char *ufld[] = {
"Ucont"};
506 PetscCall(VecCopy(user->
Ucat, target));
509 PetscCall(VecCopy(user->
Ucont, Ubase));
521 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucat, &ur));
522 PetscCall(DMDAVecGetArrayRead(user->
fda, target, &ut));
523 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
524 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
525 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
526 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2)
continue;
527 err = PetscMax(err, PetscAbsReal(ur[k][j][i].x - ut[k][j][i].x));
528 err = PetscMax(err, PetscAbsReal(ur[k][j][i].y - ut[k][j][i].y));
529 err = PetscMax(err, PetscAbsReal(ur[k][j][i].z - ut[k][j][i].z));
531 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucat, &ur));
532 PetscCall(DMDAVecRestoreArrayRead(user->
fda, target, &ut));
533 PetscCall(VecDestroy(&target));
536 PetscCallMPI(MPI_Allreduce(&err, &err_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
538 *repeat_inf = err_global;
539 PetscFunctionReturn(0);
547 DMDALocalInfo info = user->
info;
548 Cmpnts ***ucat, ***csi, ***eta, ***zet;
550 PetscReal loc = 0.0, glo;
551 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
552 PetscFunctionBeginUser;
554 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lUcat, &ucat));
555 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lCsi, &csi));
556 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lEta, &eta));
557 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lZet, &zet));
558 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, &aj));
559 for (PetscInt k = info.zs; k < info.zs+info.zm; k++)
560 for (PetscInt j = info.ys; j < info.ys+info.ym; j++)
561 for (PetscInt i = info.xs; i < info.xs+info.xm; i++) {
562 if (i<1||i>mx-2||j<1||j>my-2||k<1||k>mz-2)
continue;
563 const Cmpnts duc = { 0.5*(ucat[k][j][i+1].
x-ucat[k][j][i-1].
x),
564 0.5*(ucat[k][j][i+1].y-ucat[k][j][i-1].y),
565 0.5*(ucat[k][j][i+1].
z-ucat[k][j][i-1].
z) };
566 const Cmpnts due = { 0.5*(ucat[k][j+1][i].
x-ucat[k][j-1][i].
x),
567 0.5*(ucat[k][j+1][i].y-ucat[k][j-1][i].y),
568 0.5*(ucat[k][j+1][i].
z-ucat[k][j-1][i].
z) };
569 const Cmpnts duz = { 0.5*(ucat[k+1][j][i].
x-ucat[k-1][j][i].
x),
570 0.5*(ucat[k+1][j][i].y-ucat[k-1][j][i].y),
571 0.5*(ucat[k+1][j][i].
z-ucat[k-1][j][i].
z) };
572 const Cmpnts C = csi[k][j][i], E = eta[k][j][i], Z = zet[k][j][i];
573 const PetscReal Ajc = aj[k][j][i];
574#define ROWSUM(cmp) ( \
575 PetscAbsReal(Ajc*(C.x*duc.cmp + E.x*due.cmp + Z.x*duz.cmp)) + \
576 PetscAbsReal(Ajc*(C.y*duc.cmp + E.y*due.cmp + Z.y*duz.cmp)) + \
577 PetscAbsReal(Ajc*(C.z*duc.cmp + E.z*due.cmp + Z.z*duz.cmp)) )
581 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, &aj));
582 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lZet, &zet));
583 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lEta, &eta));
584 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lCsi, &csi));
585 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lUcat, &ucat));
586 PetscCallMPI(MPI_Allreduce(&loc, &glo, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
588 PetscFunctionReturn(0);
596 PetscReal *maxRealPart)
598 PetscBLASInt N, lda, lwork, info;
599 PetscReal *Acopy, *wr, *wi, *work, dummy = 0.0;
600 PetscFunctionBeginUser;
601 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N;
602 PetscCall(PetscMalloc4(n*n, &Acopy, n, &wr, n, &wi, (
size_t)lwork, &work));
603 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
606 LAPACKgeev_(&nochar, &nochar, &N, Acopy, &lda, wr, wi, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
608 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgeev failed: info=%d", (
int)info);
609 *rho = 0.0; *maxRealPart = -PETSC_MAX_REAL;
610 for (PetscInt t = 0; t < n; t++) {
611 *rho = PetscMax(*rho, PetscSqrtReal(wr[t]*wr[t] + wi[t]*wi[t]));
612 *maxRealPart = PetscMax(*maxRealPart, wr[t]);
614 PetscCall(PetscFree4(Acopy, wr, wi, work));
615 PetscFunctionReturn(0);
622 PetscReal dtau, PetscReal *rho)
624 PetscBLASInt N, lda, lwork, info;
625 PetscReal *Jcopy, *wr, *wi, *work, dummy = 0.0;
626 PetscFunctionBeginUser;
627 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N;
628 PetscCall(PetscMalloc4(n*n, &Jcopy, n, &wr, n, &wi, (
size_t)lwork, &work));
629 for (PetscInt t = 0; t < n*n; t++) Jcopy[t] = J[t];
632 LAPACKgeev_(&nochar, &nochar, &N, Jcopy, &lda, wr, wi, &dummy, &lda, &dummy, &lda, work, &lwork, &info);
634 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgeev failed: info=%d", (
int)info);
636 for (PetscInt t = 0; t < n; t++) {
637 const PetscReal zr = dtau*wr[t], zi = dtau*wi[t];
638 const PetscReal z2r = zr*zr - zi*zi, z2i = 2.0*zr*zi;
639 const PetscReal z3r = z2r*zr - z2i*zi, z3i = z2r*zi + z2i*zr;
640 const PetscReal z4r = z3r*zr - z3i*zi, z4i = z3r*zi + z3i*zr;
641 const PetscReal pr = 1.0 + zr + 0.5*z2r + z3r/6.0 + z4r/24.0;
642 const PetscReal pi = zi + 0.5*z2i + z3i/6.0 + z4i/24.0;
643 *rho = PetscMax(*rho, PetscSqrtReal(pr*pr + pi*pi));
645 PetscCall(PetscFree4(Jcopy, wr, wi, work));
646 PetscFunctionReturn(0);
650static PetscErrorCode
DenseSigmaMax(
const PetscReal *A, PetscInt n, PetscReal *smax, PetscReal *v1)
652 PetscBLASInt N, lda, lwork, info;
653 PetscReal *Acopy, *S, *VT, *work, ufake = 0.0;
654 PetscFunctionBeginUser;
655 PetscCall(PetscBLASIntCast(n, &N)); lda = N; lwork = 8*N + 4*N;
656 PetscCall(PetscMalloc4(n*n, &Acopy, n, &S, n*n, &VT, (
size_t)lwork, &work));
657 for (PetscInt t = 0; t < n*n; t++) Acopy[t] = A[t];
659 char jobu =
'N', jobvt = v1 ?
'S' :
'N';
660 LAPACKgesvd_(&jobu, &jobvt, &N, &N, Acopy, &lda, S, &ufake, &lda, VT, &lda, work, &lwork, &info);
662 PetscCheck(info == 0, PETSC_COMM_SELF, PETSC_ERR_LIB,
"LAPACK dgesvd failed: info=%d", (
int)info);
664 if (v1) {
for (PetscInt r = 0; r < n; r++) v1[r] = VT[0 + r*n]; }
665 PetscCall(PetscFree4(Acopy, S, VT, work));
666 PetscFunctionReturn(0);
672 PetscReal fro2 = 0.0, comm = 0.0;
673 for (PetscInt t = 0; t < n*n; t++) fro2 += A[t]*A[t];
674 for (PetscInt p = 0; p < n; p++)
675 for (PetscInt q = 0; q < n; q++) {
676 PetscReal ata = 0.0, aat = 0.0;
677 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]; }
678 const PetscReal d = ata - aat; comm += d*d;
680 return PetscSqrtReal(comm) / PetscMax(fro2, PETSC_MACHINE_EPSILON);
688 PetscReal fro2 = 0.0, sym2 = 0.0;
689 for (PetscInt i = 0; i < n*n; i++) fro2 += A[i]*A[i];
690 for (PetscInt c = 0; c < n; c++)
691 for (PetscInt r = 0; r < n; r++) {
692 const PetscReal s = A[r + c*n] + A[c + r*n];
695 return PetscSqrtReal(sym2) / PetscMax(PetscSqrtReal(fro2), PETSC_MACHINE_EPSILON);
701static PetscErrorCode
DenseShiftIdentity(
const PetscReal *A, PetscInt n, PetscReal shift, PetscReal *B)
703 PetscFunctionBeginUser;
704 PetscCall(PetscArraycpy(B, A, (
size_t)n*n));
705 for (PetscInt d = 0; d < n; d++) B[d + d*n] += shift;
706 PetscFunctionReturn(0);
710static void MatMul(
const PetscReal *A,
const PetscReal *B, PetscReal *out, PetscInt n)
712 for (PetscInt c = 0; c < n; c++)
713 for (PetscInt r = 0; r < n; r++) {
715 for (PetscInt t = 0; t < n; t++) s += A[r + t*n]*B[t + c*n];
721static PetscErrorCode
RKPolynomial(
const PetscReal *J, PetscReal dtau, PetscInt n, PetscReal *P)
723 PetscReal *M, *T, *T2;
724 PetscFunctionBeginUser;
725 PetscCall(PetscMalloc3(n*n, &M, n*n, &T, n*n, &T2));
726 for (PetscInt t = 0; t < n*n; t++) M[t] = dtau*J[t];
728 for (PetscInt t = 0; t < n*n; t++) T[t] = M[t]/4.0;
729 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0;
730 const PetscReal coef[3] = {3.0, 2.0, 1.0};
731 for (
int s = 0; s < 3; s++) {
733 for (PetscInt t = 0; t < n*n; t++) T[t] = T2[t]/coef[s];
734 for (PetscInt d = 0; d < n; d++) T[d + d*n] += 1.0;
736 for (PetscInt t = 0; t < n*n; t++) P[t] = T[t];
737 PetscCall(PetscFree3(M, T, T2));
738 PetscFunctionReturn(0);
747 PMetric which, PetscReal *metric)
750 PetscFunctionBeginUser;
753 PetscFunctionReturn(0);
755 PetscCall(PetscMalloc1(n*n, &Pm));
758 PetscCall(PetscFree(Pm));
759 PetscFunctionReturn(0);
763static PetscErrorCode
StableCFL(
const PetscReal *J, PetscInt n, PetscReal lam,
PMetric which,
766 const PetscReal tol = 1e-8, probe = 1e-8, scan_step = 0.01, hi = 4.0;
767 const PetscReal probe_tol = 1e-12, min_positive_cfl = 1e-6;
769 PetscFunctionBeginUser;
773 PetscReal rhoJ, maxreJ;
775 if (maxreJ > 1e-8) PetscFunctionReturn(0);
778 if (met > 1.0 + probe_tol) PetscFunctionReturn(0);
780 PetscReal stable = probe, cross_b = -1.0;
781 for (PetscReal cfl = scan_step; cfl <= hi + 1e-12; cfl += scan_step) {
783 if (met > 1.0 + tol) { cross_b = cfl;
break; }
789 PetscFunctionReturn(0);
791 PetscReal cross_a = stable;
792 for (
int it = 0; it < 40; it++) {
793 const PetscReal mid = 0.5*(cross_a + cross_b);
795 if (met > 1.0 + tol) cross_b = mid;
else cross_a = mid;
797 if (cross_a < min_positive_cfl) PetscFunctionReturn(0);
799 result->
cfl = cross_a;
800 PetscFunctionReturn(0);
820 PetscFunctionBeginUser;
821 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" cand %s: eig %s", candidate,
StableCFLStatusText(eig)));
825 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
"\n"));
826 PetscFunctionReturn(0);
830static void ApplyP(
const PetscReal *P,
const PetscReal *x, PetscReal *out, PetscInt n)
832 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; }
839 PetscInt n,
const PetscReal lams[3],
842 const PetscReal cfls[5] = {0.25, 0.50, 1.00, 1.50, 2.00};
844 PetscFunctionBeginUser;
845 PetscCall(PetscMalloc1(n*n, &Pm));
846 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
848 " candidate CFL dtau rho(P) sigma_max(P)\n", title));
849 for (
int c = 0; c < 3; c++) {
850 if (!(lams[c] > 0.0))
continue;
851 for (
int q = 0; q < 5; q++) {
852 const PetscReal dtau = cfls[q]/lams[c];
853 PetscReal rhoP, smaxP;
857 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
858 " %-9s %.2f %.6e %.6e %.6e\n",
859 cn[c], (
double)cfls[q], (
double)dtau, (
double)rhoP, (
double)smaxP));
862 PetscCall(PetscFree(Pm));
863 PetscFunctionReturn(0);
872 for (PetscInt i = 0; i < n; i++) s += x[i]*x[i];
873 return PetscSqrtReal(s);
882 for (PetscInt i = 0; i < n; i++) s = PetscMax(s, PetscAbsReal(x[i]));
892 for (PetscInt i = 0; i < n*n; i++) s += A[i]*A[i];
893 return PetscSqrtReal(s);
899static PetscReal
DenseRelativeDiff(
const PetscReal *A,
const PetscReal *B, PetscInt n, PetscReal denom_ref)
902 for (PetscInt i = 0; i < n*n; i++) {
903 const PetscReal d = A[i] - B[i];
906 return PetscSqrtReal(s) / PetscMax(1.0, denom_ref);
913 const PetscReal *x, PetscReal scale)
916 PetscFunctionBeginUser;
917 PetscCall(DMDAVecGetArray(user->
fda, U, &a));
918 for (PetscInt m = 0; m < map->
n; m++) {
919 PetscReal *p = (PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]];
920 p[map->
comp[m]] += scale*x[m];
922 PetscCall(DMDAVecRestoreArray(user->
fda, U, &a));
923 PetscFunctionReturn(0);
932 PetscFunctionBeginUser;
933 PetscCall(DMDAVecGetArrayRead(user->
fda, U, &a));
934 for (PetscInt m = 0; m < map->
n; m++) {
935 const PetscReal *p = (
const PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]];
936 x[m] = p[map->
comp[m]];
938 PetscCall(DMDAVecRestoreArrayRead(user->
fda, U, &a));
939 PetscFunctionReturn(0);
947 return 1.0 + 0.013*(PetscReal)(map->
comp[m]+1)
948 + 0.017*(PetscReal)map->
ci[m]
949 + 0.019*(PetscReal)map->
cj[m]
950 + 0.023*(PetscReal)map->
ck[m];
958 PetscReal loc2 = 0.0, locinf = 0.0, locsum = 0.0;
959 PetscReal glo2, gloinf, glosum;
960 PetscFunctionBeginUser;
961 for (PetscInt m = 0; m < map->
n; m++) {
963 locinf = PetscMax(locinf, PetscAbsReal(x[m]));
966 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
967 PetscCallMPI(MPI_Allreduce(&locinf, &gloinf, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD));
968 PetscCallMPI(MPI_Allreduce(&locsum, &glosum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
969 stats->
n2 = PetscSqrtReal(glo2); stats->
ninf = gloinf; stats->
checksum = glosum;
970 PetscFunctionReturn(0);
978 PetscReal loc2 = 0.0, glo2;
979 PetscFunctionBeginUser;
980 PetscCall(VecSet(V, 0.0));
981 for (PetscInt m = 0; m < map->
n; m++) {
982 x[m] = PetscSinReal(0.37*(PetscReal)(map->
ci[m]+1)
983 + 0.51*(PetscReal)(map->
cj[m]+1)
984 + 0.73*(PetscReal)(map->
ck[m]+1)
985 + 0.29*(PetscReal)(map->
comp[m]+1));
988 PetscCallMPI(MPI_Allreduce(&loc2, &glo2, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD));
989 const PetscReal invn = 1.0/PetscSqrtReal(glo2);
990 for (PetscInt m = 0; m < map->
n; m++) x[m] *= invn;
992 PetscFunctionReturn(0);
1000 PetscReal *Rscratch, Vec Uwork, Vec Uout)
1002 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1003 PetscFunctionBeginUser;
1004 PetscCall(VecCopy(U0full, Uwork));
1005 for (
int s = 0; s < 4; s++) {
1007 PetscCall(VecCopy(U0full, Uout));
1009 PetscCall(DMDAVecGetArray(user->
fda, Uout, &a));
1010 for (PetscInt m = 0; m < map->
n; m++) {
1011 PetscReal *p = (PetscReal*)&a[map->
ck[m]][map->
cj[m]][map->
ci[m]];
1012 p[map->
comp[m]] += alfa[s]*dtau*Rscratch[m];
1014 PetscCall(DMDAVecRestoreArray(user->
fda, Uout, &a));
1015 PetscCall(VecCopy(Uout, Uwork));
1017 PetscFunctionReturn(0);
1024 const DofMap *map,
const PetscReal *Ract, Vec Ustage)
1026 PetscFunctionBeginUser;
1027 PetscCall(VecCopy(U0full, Ustage));
1029 PetscFunctionReturn(0);
1036 const DofMap *map, PetscReal *Rscratch,
1037 Vec Y1, Vec Y2, Vec Y3)
1039 const PetscReal alfa[3] = {0.25, 1.0/3.0, 0.5};
1040 PetscFunctionBeginUser;
1042 PetscCall(
SetAnchoredStage(user, U0full, alfa[0]*dtau, map, Rscratch, Y1));
1044 PetscCall(
SetAnchoredStage(user, U0full, alfa[1]*dtau, map, Rscratch, Y2));
1046 PetscCall(
SetAnchoredStage(user, U0full, alfa[2]*dtau, map, Rscratch, Y3));
1047 PetscFunctionReturn(0);
1054 const DofMap *map, PetscReal *Rp, PetscReal *Rm,
1055 Vec Uwork, PetscReal *J)
1057 PetscFunctionBeginUser;
1058 for (PetscInt col = 0; col < map->
n; col++) {
1060 PetscCall(
GetDof(user, Ucenter, map, col, &u0));
1061 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1062 PetscCall(VecCopy(Ucenter, Uwork));
1063 PetscCall(
PerturbDof(user, Uwork, map, col, +eps));
1065 PetscCall(VecCopy(Ucenter, Uwork));
1066 PetscCall(
PerturbDof(user, Uwork, map, col, -eps));
1068 for (PetscInt row = 0; row < map->
n; row++) J[row + col*map->
n] = (Rp[row]-Rm[row])/(2.0*eps);
1070 PetscFunctionReturn(0);
1077 const PetscReal *J2,
const PetscReal *J3,
1078 PetscReal dtau, PetscInt n, PetscReal *T4)
1080 const PetscReal alfa[4] = {0.25, 1.0/3.0, 0.5, 1.0};
1081 PetscReal *T1, *T2, *T3, *Tmp;
1082 PetscFunctionBeginUser;
1083 PetscCall(PetscMalloc4(n*n, &T1, n*n, &T2, n*n, &T3, n*n, &Tmp));
1085 for (PetscInt i = 0; i < n*n; i++) T1[i] = alfa[0]*dtau*J0[i];
1086 for (PetscInt d = 0; d < n; d++) T1[d + d*n] += 1.0;
1089 for (PetscInt i = 0; i < n*n; i++) T2[i] = alfa[1]*dtau*Tmp[i];
1090 for (PetscInt d = 0; d < n; d++) T2[d + d*n] += 1.0;
1093 for (PetscInt i = 0; i < n*n; i++) T3[i] = alfa[2]*dtau*Tmp[i];
1094 for (PetscInt d = 0; d < n; d++) T3[d + d*n] += 1.0;
1097 for (PetscInt i = 0; i < n*n; i++) T4[i] = alfa[3]*dtau*Tmp[i];
1098 for (PetscInt d = 0; d < n; d++) T4[d + d*n] += 1.0;
1100 PetscCall(PetscFree4(T1, T2, T3, Tmp));
1101 PetscFunctionReturn(0);
1108 const DofMap *map, PetscReal *Rscratch,
1109 Vec Upert, Vec Ustage, Vec PhiP, Vec PhiM,
1110 PetscReal *xp, PetscReal *xm, PetscReal epsrel,
1113 PetscFunctionBeginUser;
1114 for (PetscInt col = 0; col < map->
n; col++) {
1116 PetscCall(
GetDof(user, Ucenter, map, col, &u0));
1117 const PetscReal eps = epsrel*PetscMax(1.0, PetscAbsReal(u0));
1118 PetscCall(VecCopy(Ucenter, Upert));
1119 PetscCall(
PerturbDof(user, Upert, map, col, +eps));
1120 PetscCall(
FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiP));
1121 PetscCall(VecCopy(Ucenter, Upert));
1122 PetscCall(
PerturbDof(user, Upert, map, col, -eps));
1123 PetscCall(
FourStage(user, Upert, dtau, Rhs, map, Rscratch, Ustage, PhiM));
1126 for (PetscInt row = 0; row < map->
n; row++) JPhi[row + col*map->
n] = (xp[row]-xm[row])/(2.0*eps);
1128 PetscFunctionReturn(0);
1135 const DofMap *map, PetscReal epsrel,
1136 const PetscReal lams[3],
const char *cn[3],
1137 const PetscReal *J0)
1139 const PetscReal cflsB[4] = {0.1, 0.25, 0.5, 1.0};
1140 const PetscReal cflsOther[1] = {0.5};
1141 const PetscReal *cfls = (st ==
STATE_B) ? cflsB : cflsOther;
1142 const PetscInt ncfl = (st ==
STATE_B) ? 4 : 1;
1143 const PetscReal amps[3] = {1e-4, 1e-5, 1e-6};
1144 Vec Y1, Y2, Y3, Upert, Ustage, PhiP, PhiM, Phi0;
1145 PetscReal *Rtmp, *J1, *J2, *J3, *T4, *Pm, *JPhi, *v1, *xrand;
1146 PetscReal *meas, *phi0, *phip, *xscaled, *predP, *predT;
1147 PetscFunctionBeginUser;
1149 PetscCall(VecDuplicate(Ubase, &Y1));
1150 PetscCall(VecDuplicate(Ubase, &Y2));
1151 PetscCall(VecDuplicate(Ubase, &Y3));
1152 PetscCall(VecDuplicate(Ubase, &Upert));
1153 PetscCall(VecDuplicate(Ubase, &Ustage));
1154 PetscCall(VecDuplicate(Ubase, &PhiP));
1155 PetscCall(VecDuplicate(Ubase, &PhiM));
1156 PetscCall(VecDuplicate(Ubase, &Phi0));
1157 PetscCall(PetscMalloc5(map->
n, &Rtmp, (
size_t)map->
n*map->
n, &J1,
1158 (
size_t)map->
n*map->
n, &J2, (
size_t)map->
n*map->
n, &J3,
1159 (
size_t)map->
n*map->
n, &T4));
1160 PetscCall(PetscMalloc5((
size_t)map->
n*map->
n, &Pm, (
size_t)map->
n*map->
n, &JPhi,
1161 map->
n, &v1, map->
n, &xrand, map->
n, &meas));
1162 PetscCall(PetscMalloc5(map->
n, &phi0, map->
n, &phip, map->
n, &xscaled,
1163 map->
n, &predP, map->
n, &predT));
1165 PetscReal nrm = 0.0;
1166 for (PetscInt m = 0; m < map->
n; m++) {
1167 xrand[m] = PetscSinReal((PetscReal)(m+1)*1.2345);
1168 nrm += xrand[m]*xrand[m];
1170 nrm = PetscSqrtReal(nrm);
1171 for (PetscInt m = 0; m < map->
n; m++) xrand[m] /= nrm;
1173 for (
int cand = 0; cand < 3; cand++) {
1174 if (!(lams[cand] > 0.0))
continue;
1175 for (PetscInt icfl = 0; icfl < ncfl; icfl++) {
1176 const PetscReal cfl = cfls[icfl], dtau = cfl/lams[cand];
1177 PetscCall(
BuildStageStates(user, Ubase, dtau, Rhs, map, Rtmp, Y1, Y2, Y3));
1178 PetscCall(
BuildFDJacobian(user, Y1, epsrel, Rhs, map, phi0, phip, Upert, J1));
1179 PetscCall(
BuildFDJacobian(user, Y2, epsrel, Rhs, map, phi0, phip, Upert, J2));
1180 PetscCall(
BuildFDJacobian(user, Y3, epsrel, Rhs, map, phi0, phip, Upert, J3));
1184 Upert, Ustage, PhiP, PhiM, phip, phi0, epsrel, JPhi));
1191 PetscReal smaxT, rhoT, dummyT;
1195 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1196 " --- convection-only stage-dependent RK tangent (cand %s, CFL=%.2f, dtau=%.6e) ---\n"
1197 " rho(T4)=%.6e sigma_max(T4)=%.6e\n"
1198 " ||T4-P(hJ0)||F/max(1,||T4||F) = %.3e\n"
1199 " ||J_Phi-T4||F/max(1,||J_Phi||F) = %.3e\n"
1200 " ||J_Phi-P(hJ0)||F/max(1,||J_Phi||F)= %.3e\n",
1201 cn[cand], (
double)cfl, (
double)dtau, (
double)rhoT, (
double)smaxT,
1202 (
double)relTP, (
double)relPhiT, (
double)relPhiP));
1204 PetscCall(
FourStage(user, Ubase, dtau, Rhs, map, Rtmp, Ustage, Phi0));
1206 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1207 " direction amp amp(meas) amp(frozen) amp(stage) err(frozen) err(stage)\n"));
1208 for (
int dir = 0; dir < 2; dir++) {
1209 const PetscReal *xv = (dir == 0) ? xrand : v1;
1210 const char *dname = (dir == 0) ?
"random" :
"v1(T4)";
1211 for (
int a = 0; a < 3; a++) {
1212 const PetscReal amp = amps[a];
1213 PetscCall(VecCopy(Ubase, Upert));
1215 PetscCall(
FourStage(user, Upert, dtau, Rhs, map, Rtmp, Ustage, PhiP));
1217 for (PetscInt m = 0; m < map->
n; m++) meas[m] = phip[m] - phi0[m];
1218 for (PetscInt m = 0; m < map->
n; m++) xscaled[m] = amp*xv[m];
1219 ApplyP(Pm, xscaled, predP, map->
n);
1220 ApplyP(T4, xscaled, predT, map->
n);
1222 PetscReal eP = 0.0, eT = 0.0;
1223 for (PetscInt m = 0; m < map->
n; m++) {
1224 const PetscReal dP = meas[m] - predP[m];
1225 const PetscReal dT = meas[m] - predT[m];
1226 eP += dP*dP; eT += dT*dT;
1231 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1232 " %-8s %.0e %.6e %.6e %.6e %.3e %.3e\n",
1233 dname, (
double)amp, (
double)(nm/amp), (
double)(nP/amp), (
double)(nT/amp),
1234 (
double)(PetscSqrtReal(eP)/PetscMax(PETSC_MACHINE_EPSILON, nP)),
1235 (
double)(PetscSqrtReal(eT)/PetscMax(PETSC_MACHINE_EPSILON, nT))));
1240 "stage tangent matches direct finite-difference RK map"));
1243 "B: non-steady base makes frozen-Jacobian RK map measurably different"));
1245 "B: direct RK map confirms frozen-Jacobian error"));
1248 "steady base reduces stage tangent to frozen RK polynomial"));
1253 PetscCall(PetscFree5(Rtmp, J1, J2, J3, T4));
1254 PetscCall(PetscFree5(Pm, JPhi, v1, xrand, meas));
1255 PetscCall(PetscFree5(phi0, phip, xscaled, predP, predT));
1256 PetscCall(VecDestroy(&Y1)); PetscCall(VecDestroy(&Y2)); PetscCall(VecDestroy(&Y3));
1257 PetscCall(VecDestroy(&Upert)); PetscCall(VecDestroy(&Ustage));
1258 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Phi0));
1259 PetscFunctionReturn(0);
1268 Vec Ubase, Rhs, Uwork, Uout;
1269 PetscReal *Rref, *Rrep, *Jbest;
1270 PetscReal repeat_err, maxdiv, det_err;
1273 const PetscInt N = (st ==
STATE_C) ? 5 : 4;
1274 PetscFunctionBeginUser;
1281 PetscCall(VecDuplicate(user->
Ucont, &Ubase));
1282 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
1283 PetscCall(VecDuplicate(user->
Ucont, &Uwork));
1284 PetscCall(VecDuplicate(user->
Ucont, &Uout));
1285 PetscCall(PetscMalloc3(map.
n, &Rref, map.
n, &Rrep, (
size_t)map.
n*map.
n, &Jbest));
1287 PetscCall(
BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
1292 det_err = 0.0;
for (PetscInt m = 0; m < map.
n; m++) det_err = PetscMax(det_err, PetscAbsReal(Rref[m]-Rrep[m]));
1296 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1297 "\n================ STATE %s ================\n"
1298 " grid: DMDA %d^3 (periodic) | independent face DOFs: actual=%d expected=%d\n"
1299 " declared endpoint mismatch (x,y,z) = %.3e %.3e %.3e\n"
1300 " actual Ucat duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
1301 " local lUcat ghost mismatch (x,y,z) = %.3e %.3e %.3e\n"
1302 " actual Ucont duplicate mismatch (x,y,z) = %.3e %.3e %.3e\n"
1303 " ||Ucat_repeat - Ucat_reference||inf = %.3e\n"
1304 " max|div_h Ucont| = %.3e\n"
1305 " ||R(U0)||2 = %.6e ||R(U0)||inf = %.6e\n"
1306 " residual determinism ||R_rep-R_ref||inf = %.3e\n",
1307 name, (
int)(N+1), (
int)map.
n,
1313 (
double)repeat_err, (
double)maxdiv,
1314 (
double)R0_2, (
double)R0_inf, (
double)det_err));
1317 const PetscReal epsrel[5] = {1e-4, 1e-5, 1e-6, 1e-7, 1e-8};
1318 PetscReal *Jprev, *Jcur;
1319 PetscCall(PetscMalloc2((
size_t)map.
n*map.
n, &Jprev, (
size_t)map.
n*map.
n, &Jcur));
1320 PetscReal best_rel = PETSC_MAX_REAL; PetscInt best_e = 2;
1321 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" epsilon-convergence (||J_e - J_e/10||_F / ||J||_F):\n"));
1322 for (
int e = 0; e < 5; e++) {
1324 for (PetscInt col = 0; col < map.
n; col++) {
1325 PetscReal u0; PetscCall(
GetDof(user, Ubase, &map, col, &u0));
1326 const PetscReal eps = epsrel[e]*PetscMax(1.0, PetscAbsReal(u0));
1327 PetscReal *Rp = Rref, *Rm = Rrep;
1328 PetscCall(VecCopy(Ubase, Uwork));
1329 PetscCall(
PerturbDof(user, Uwork, &map, col, +eps));
1331 PetscCall(VecCopy(Ubase, Uwork));
1332 PetscCall(
PerturbDof(user, Uwork, &map, col, -eps));
1334 for (PetscInt row = 0; row < map.
n; row++) Jcur[row + col*map.
n] = (Rp[row]-Rm[row])/(2.0*eps);
1337 PetscReal num = 0.0, den = 0.0;
1338 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]; }
1339 const PetscReal rel = PetscSqrtReal(num)/PetscMax(1.0, PetscSqrtReal(den));
1340 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" eps=%.0e -> %.0e : rel=%.3e\n",
1341 (
double)epsrel[e-1], (
double)epsrel[e], (
double)rel));
1342 if (rel < best_rel) { best_rel = rel; best_e = e; }
1345 PetscReal erho, emaxre, esmax;
1348 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1349 " eps=%.0e metrics: rho=%.6e sigma=%.6e max_real=%.6e fro=%.6e skew=%.3e\n",
1350 (
double)epsrel[e], (
double)erho, (
double)esmax, (
double)emaxre,
1353 PetscCall(PetscArraycpy(Jprev, Jcur, (
size_t)map.
n*map.
n));
1357 const PetscReal er = epsrel[best_e];
1358 for (PetscInt col = 0; col < map.
n; col++) {
1359 PetscReal u0; PetscCall(
GetDof(user, Ubase, &map, col, &u0));
1360 const PetscReal eps = er*PetscMax(1.0, PetscAbsReal(u0));
1361 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(
PerturbDof(user, Uwork, &map, col, +eps));
1363 PetscCall(VecCopy(Ubase, Uwork)); PetscCall(
PerturbDof(user, Uwork, &map, col, -eps));
1365 for (PetscInt row = 0; row < map.
n; row++) Jbest[row + col*map.
n] = (Rref[row]-Rrep[row])/(2.0*eps);
1367 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" selected plateau eps = %.0e\n", (
double)er));
1369 PetscCall(PetscFree2(Jprev, Jcur));
1373 PetscCall(VecCopy(Ubase, user->
Ucont));
1375 const char *fld[] = {
"Ucont"};
1380 PetscBool eqbase; { Vec chk; PetscCall(VecDuplicate(Ubase,&chk)); PetscCall(VecCopy(user->
Ucont,chk));
1381 PetscCall(VecAXPY(chk, -1.0, Ubase)); PetscReal nb; PetscCall(VecNorm(chk, NORM_INFINITY, &nb));
1382 eqbase = (PetscBool)(nb < 1e-12); PetscCall(VecDestroy(&chk));
1383 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" base Ucont restored after Jacobian: %s\n", eqbase?
"yes":
"NO")); }
1386 PetscReal rho, maxre, smax;
1399 PetscReal gradmax = 0.0;
1402 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1403 " --- convective Jacobian spectrum ---\n"
1404 " rho(J)=%.6e sigma_max(J)=%.6e nonnormality=%.3e max_real_eig=%.3e\n"
1405 " --- candidate convective estimates ---\n"
1406 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n"
1407 " max local |grad u| row-sum contribution = %.6e\n"
1408 " rB/rho=%.3f rC/rho=%.3f rD/rho=%.3f | rB/smax=%.3f rC/smax=%.3f rD/smax=%.3f\n",
1409 (
double)rho, (
double)smax, (
double)eta, (
double)maxre,
1410 (
double)lcB, (
double)lcC, (
double)lcD,
1412 (
double)(lcB/rho), (
double)(lcC/rho), (
double)(lcD/rho),
1413 (
double)(lcB/smax), (
double)(lcC/smax), (
double)(lcD/smax)));
1416 const PetscReal lams[3] = {lcB, lcC, lcD};
const char *cn[3] = {
"B",
"C",
"D"};
1418 PetscCall(PetscMalloc1((
size_t)map.
n*map.
n, &Jpseudo));
1423 PetscCall(PetscFree(Jpseudo));
1425 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
" --- RK stable pseudo-CFL (convective J) ---\n"));
1426 for (
int c = 0; c < 3; c++) {
1427 if (!(lams[c] > 0.0))
continue;
1436 epsrel[best_e], lams, cn, Jbest));
1439 PetscCall(
PicurvAssertBool(eqbase,
"base Ucont restored after Jacobian build"));
1440 PetscCall(
PicurvAssertBool((PetscBool)(det_err < 1e-10),
"residual evaluation deterministic"));
1441 PetscCall(
PicurvAssertBool((PetscBool)(rho > 0.0 && PetscIsNormalReal(rho)),
"finite rho(J)"));
1442 PetscCall(
PicurvAssertBool((PetscBool)(smax > 0.0 && PetscIsNormalReal(smax)),
"finite sigma_max(J)"));
1444 for (
int d = 0; d < 3; d++) {
1450 PetscCall(
PicurvAssertRealNear(repeat_err, 0.0, 1e-9,
"A: recovered Ucat repeat near roundoff"));
1452 PetscCall(
PicurvAssertRealNear(R0_inf, 0.0, 1e-12,
"A: base residual inf-norm near roundoff"));
1456 for (
int d = 0; d < 3; d++) {
1462 PetscCall(
PicurvAssertRealNear(repeat_err, 0.0, 1e-9,
"B: recovered Ucat repeat near roundoff"));
1463 PetscCall(
PicurvAssertBool((PetscBool)(maxdiv > 1e-3),
"B: nonzero discrete divergence"));
1464 PetscCall(
PicurvAssertBool((PetscBool)(R0_2 > 1e-3),
"B: materially nonzero base residual 2-norm"));
1465 PetscCall(
PicurvAssertBool((PetscBool)(R0_inf > 1e-3),
"B: materially nonzero base residual inf-norm"));
1468 for (
int d = 0; d < 3; d++) {
1474 PetscCall(
PicurvAssertRealNear(repeat_err, 0.0, 1e-9,
"C: recovered Ucat repeat near roundoff"));
1475 PetscCall(
PicurvAssertBool((PetscBool)(maxdiv < 1e-6),
"C: divergence near zero"));
1477 PetscCall(
PicurvAssertRealNear(R0_inf, 0.0, 1e-12,
"C: base residual inf-norm near roundoff"));
1478 PetscCall(
PicurvAssertBool((PetscBool)(PetscAbsReal(lcC-lcB) < 1e-6),
"C: C ~= B"));
1479 PetscCall(
PicurvAssertBool((PetscBool)(gradmax > 1e-6),
"C: canonical shear has nonzero local gradient contribution"));
1482 PetscCall(PetscFree3(Rref, Rrep, Jbest));
1483 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs));
1484 PetscCall(VecDestroy(&Uwork)); PetscCall(VecDestroy(&Uout));
1487 PetscFunctionReturn(0);
1511 Vec Ubase, Rhs, Uwork;
1512 PetscReal *Rp, *Rm, *J;
1513 PetscReal repeat_err, maxdiv;
1515 PetscFunctionBeginUser;
1519 PetscCall(VecDuplicate(user->
Ucont, &Ubase));
1520 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
1521 PetscCall(VecDuplicate(user->
Ucont, &Uwork));
1522 PetscCall(PetscMalloc3(map.
n, &Rp, map.
n, &Rm, (
size_t)map.
n*map.
n, &J));
1524 PetscCall(
BuildFDJacobian(user, Ubase, 1e-5, Rhs, &map, Rp, Rm, Uwork, J));
1525 PetscReal rho, maxre, smax;
1528 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1529 " 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",
1530 (
int)(N+1), (
int)map.
n, (
int)map.
expected_n, (
double)maxre, (
double)rho, (
double)smax,
1532 PetscCall(PetscFree3(Rp, Rm, J));
1533 PetscCall(VecDestroy(&Ubase)); PetscCall(VecDestroy(&Rhs)); PetscCall(VecDestroy(&Uwork));
1536 PetscFunctionReturn(0);
1544 PetscFunctionBeginUser;
1545 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1546 "\n================ STATE A GRID / ACTIVE-SPACE AUDIT ================\n"
1547 " residual sign convention: ComputeRHS returns the production convection residual used by pseudo-time updates.\n"
1548 " component-staggered periodic duplicate planes: 0<-m-2 and m-1<-1 in each direction.\n"
1549 " independent map: all three Ucont components use representatives i,j,k=1..m-2; count = 3*(m-2)^3.\n"));
1552 PetscFunctionReturn(0);
1562 PetscFunctionBeginUser;
1564 PetscCheck(
g_ref_token_set, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
1565 "-candidate_ref_token is required when -candidate_ref_path is set");
1566 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1569 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"could not write State A MPI reference");
1570 fprintf(fp,
"PICURV_CANDIDATE_STATEA_REF_V2 %s\n",
g_ref_token);
1571 fprintf(fp,
"%.17e %.17e %.17e\n", (
double)r0.
n2, (
double)r0.
ninf, (
double)r0.
checksum);
1572 fprintf(fp,
"%.17e %.17e %.17e\n", (
double)jv.
n2, (
double)jv.
ninf, (
double)jv.
checksum);
1573 fprintf(fp,
"%.17e %.17e %.17e\n", (
double)phi.
n2, (
double)phi.
ninf, (
double)phi.
checksum);
1574 fprintf(fp,
"%.17e %.17e %.17e %d %d %d %d\n",
1581 PetscFunctionReturn(0);
1591 PetscReal vals[16] = {0.0};
1592 PetscFunctionBeginUser;
1594 "two-rank State A decomp check requires matching -candidate_ref_path and -candidate_ref_token from a preceding one-rank run");
1595 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1597 char magic[64], token[128];
1599 PetscCheck(fp != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
1600 "State A one-rank decomp reference missing; run the Makefile target so -n 1 precedes -n 2");
1601 PetscCheck(fscanf(fp,
"%63s %127s", magic, token) == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference header");
1602 PetscCheck(strcmp(magic,
"PICURV_CANDIDATE_STATEA_REF_V2") == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
1603 "bad reference magic");
1604 PetscCheck(strcmp(token,
g_ref_token) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
1605 "State A one-rank decomp reference token mismatch");
1606 int active, cblock, ci, cj;
1607 PetscCheck(fscanf(fp,
"%le %le %le", &vals[0], &vals[1], &vals[2]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference R0");
1608 PetscCheck(fscanf(fp,
"%le %le %le", &vals[3], &vals[4], &vals[5]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference Jv");
1609 PetscCheck(fscanf(fp,
"%le %le %le", &vals[6], &vals[7], &vals[8]) == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference Phi");
1610 PetscCheck(fscanf(fp,
"%le %le %le %d %d %d %d", &vals[9], &vals[10], &vals[11],
1611 &active, &cblock, &ci, &cj) == 7, PETSC_COMM_SELF, PETSC_ERR_FILE_READ,
"bad reference estimator");
1612 vals[12] = (PetscReal)active; vals[13] = (PetscReal)cblock; vals[14] = (PetscReal)ci; vals[15] = (PetscReal)cj;
1614 PetscCheck(remove(
g_ref_path) == 0, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
1615 "could not remove consumed State A MPI reference '%s'",
g_ref_path);
1617 PetscCallMPI(MPI_Bcast(vals, 16, MPIU_REAL, 0, PETSC_COMM_WORLD));
1631 PetscCall(
PicurvAssertBool((PetscBool)(rep->
cblock == (PetscInt)vals[13]),
"MPI State A controlling block"));
1632 PetscFunctionReturn(0);
1642 Vec V, Up, Um, PhiP, PhiM, Ustage;
1643 PetscReal *v, *R0, *Rp, *Rm, *ActP, *ActM, *Out;
1645 const PetscReal eps = 1e-6, dtau = 0.5/lcC;
1647 PetscFunctionBeginUser;
1648 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
1650 PetscCall(VecDuplicate(Ubase, &V)); PetscCall(VecDuplicate(Ubase, &Up));
1651 PetscCall(VecDuplicate(Ubase, &Um)); PetscCall(VecDuplicate(Ubase, &PhiP));
1652 PetscCall(VecDuplicate(Ubase, &PhiM)); PetscCall(VecDuplicate(Ubase, &Ustage));
1653 PetscCall(PetscMalloc6(map.
n, &v, map.
n, &R0, map.
n, &Rp, map.
n, &Rm, map.
n, &ActP, map.
n, &ActM));
1654 PetscCall(PetscMalloc1(map.
n, &Out));
1659 PetscCall(VecCopy(Ubase, Up)); PetscCall(VecAXPY(Up, eps, V));
1660 PetscCall(VecCopy(Ubase, Um)); PetscCall(VecAXPY(Um, -eps, V));
1663 for (PetscInt m = 0; m < map.
n; m++) Out[m] = (Rp[m]-Rm[m])/(2.0*eps);
1666 PetscCall(
FourStage(user, Up, dtau, Rhs, &map, Rp, Ustage, PhiP));
1667 PetscCall(
FourStage(user, Um, dtau, Rhs, &map, Rm, Ustage, PhiM));
1670 for (PetscInt m = 0; m < map.
n; m++) Out[m] = (ActP[m]-ActM[m])/(2.0*eps);
1673 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1674 " State A matrix-free MPI check: R0 L2=%.6e Linf=%.6e checksum=%.6e\n"
1675 " Jv L2=%.6e Linf=%.6e checksum=%.6e\n"
1676 " DPhi v L2=%.6e Linf=%.6e checksum=%.6e\n",
1683 PetscCall(PetscFree6(v, R0, Rp, Rm, ActP, ActM)); PetscCall(PetscFree(Out));
1684 PetscCall(VecDestroy(&V)); PetscCall(VecDestroy(&Up)); PetscCall(VecDestroy(&Um));
1685 PetscCall(VecDestroy(&PhiP)); PetscCall(VecDestroy(&PhiM)); PetscCall(VecDestroy(&Ustage));
1687 PetscFunctionReturn(0);
1694 PetscReal expB, PetscReal expC, PetscReal expD)
1698 PetscReal repeat_err, maxdiv;
1701 const PetscInt N = 8;
1702 PetscFunctionBeginUser;
1706 PetscCall(VecDuplicate(user->
Ucont, &Ubase));
1707 PetscCall(VecDuplicate(user->
Ucont, &Rhs));
1708 PetscCall(
BuildBaseState(user, st, Ubase, &repeat_err, &maxdiv, &seam));
1714 PetscCall(PetscPrintf(PETSC_COMM_WORLD,
1715 "\n================ DECOMP BASELINE %s ================\n"
1716 " active cells: %d | repeat=%.3e | max|div_h Ucont|=%.3e\n"
1717 " lambda_cB=%.6e lambda_cC=%.6e lambda_cD=%.6e\n",
1718 name, (
int)rep.
active_cells, (
double)repeat_err, (
double)maxdiv,
1719 (
double)lcB, (
double)lcC, (
double)lcD));
1722 PetscCall(
PicurvAssertRealNear(expB, lcB, 5e-7,
"decomp: lambda_cB matches one-rank baseline"));
1723 PetscCall(
PicurvAssertRealNear(expC, lcC, 5e-7,
"decomp: lambda_cC matches one-rank baseline"));
1724 PetscCall(
PicurvAssertRealNear(expD, lcD, 5e-7,
"decomp: lambda_cD matches one-rank baseline"));
1731 PetscCall(
PicurvAssertBool((PetscBool)(maxdiv > 1e-3),
"decomp B: nonzero divergence"));
1738 PetscCall(VecDestroy(&Ubase));
1739 PetscCall(VecDestroy(&Rhs));
1741 PetscFunctionReturn(0);
1764 PetscFunctionBeginUser;
1765 PetscCall(PetscOptionsGetString(NULL, NULL,
"-candidate_ref_path",
1767 PetscCall(PetscOptionsGetString(NULL, NULL,
"-candidate_ref_token",
1771 "-candidate_ref_path and -candidate_ref_token must be supplied together");
1773 PetscFunctionReturn(0);
1781 PetscErrorCode ierr;
1785 {
"candidate-state-B-divergence",
TestStateB},
1794 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv A4a convective-candidate study");
1795 if (ierr)
return (
int)ierr;
1797 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size);
if (ierr) { PetscFinalize();
return (
int)ierr; }
1799 ierr =
PicurvRunTests(
"unit-momentum-candidates", cases,
sizeof(cases)/
sizeof(cases[0]));
1800 if (!ierr) ierr =
PicurvRunTests(
"unit-momentum-candidates-decomp", decomp_cases,
sizeof(decomp_cases)/
sizeof(decomp_cases[0]));
1802 ierr =
PicurvRunTests(
"unit-momentum-candidates-decomp", decomp_cases,
sizeof(decomp_cases)/
sizeof(decomp_cases[0]));
1804 if (ierr) { PetscFinalize();
return (
int)ierr; }
1805 return (
int)PetscFinalize();
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
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 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 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 GetDof(UserCtx *user, Vec Ucont, const DofMap *map, PetscInt m, PetscReal *val)
Reads one active contravariant component from a global vector.
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 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 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 PetscErrorCode DofMapDestroy(DofMap *map)
Releases storage owned by an active-DOF map.
static PetscErrorCode TestDecompC(void)
Runs the State C decomposition baseline.
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 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 void ApplyP(const PetscReal *P, const PetscReal *x, PetscReal *out, PetscInt n)
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 PrintStableCFLLine(const char *candidate, StableCFLResult eig, StableCFLResult norm)
Prints one candidate's eigenvalue and norm stable-CFL statuses.
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 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 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 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 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 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 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.
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 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 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 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.