14#define MomentumSolver_NewtonKrylov MomentumSolver_NewtonKrylov_PrivateCopy
15#include "../../src/momentum_newton_krylov.c"
16#undef MomentumSolver_NewtonKrylov
19 "-Xi PERIODIC geometric\n"
20 "+Xi PERIODIC geometric\n"
23 "-Zeta INLET constant_velocity vx=0.0 vy=0.0 vz=1.5\n"
24 "+Zeta OUTLET conservation\n";
32 "+Zeta WALL noslip\n";
39 "-Zeta INLET parabolic v_max=1.5\n"
40 "+Zeta OUTLET conservation\n";
43 "-Xi PERIODIC geometric\n+Xi PERIODIC geometric\n"
44 "-Eta WALL noslip\n+Eta WALL noslip\n-Zeta WALL noslip\n+Zeta WALL noslip\n";
47 "-Xi WALL noslip\n+Xi WALL noslip\n"
48 "-Eta PERIODIC geometric\n+Eta PERIODIC geometric\n-Zeta WALL noslip\n+Zeta WALL noslip\n";
51 "-Xi WALL noslip\n+Xi WALL noslip\n-Eta WALL noslip\n+Eta WALL noslip\n"
52 "-Zeta PERIODIC geometric\n+Zeta PERIODIC geometric\n";
55 "-Xi PERIODIC geometric\n+Xi PERIODIC geometric\n"
56 "-Eta PERIODIC geometric\n+Eta PERIODIC geometric\n"
57 "-Zeta WALL noslip\n+Zeta WALL noslip\n";
60 "-Xi PERIODIC geometric\n+Xi PERIODIC geometric\n"
61 "-Eta PERIODIC geometric\n+Eta PERIODIC geometric\n"
62 "-Zeta PERIODIC geometric\n+Zeta PERIODIC geometric\n";
74 char *tmpdir,
size_t tmpdir_len)
76 PetscFunctionBeginUser;
81 "Newton fixture must enter with no persistent Rhs workspace"));
82 PetscFunctionReturn(PETSC_SUCCESS);
93 PetscFunctionBeginUser;
96 PetscFunctionReturn(PETSC_SUCCESS);
108 PetscFunctionBeginUser;
109 fd = fopen(path,
"w");
110 PetscCheck(fd != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
111 "Could not create Newton test PICSLICE %s.", path);
112 PetscCheck(fprintf(fd,
"PICSLICE\n1\n5 5\n") >= 0,
113 PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
"Could not write PICSLICE header.");
114 for (PetscInt row = 0; row < 25; ++row) {
115 PetscCheck(fprintf(fd,
"%.16e\n", 1.0 + 0.01 * (
double)row) >= 0,
116 PETSC_COMM_SELF, PETSC_ERR_FILE_WRITE,
"Could not write PICSLICE value.");
119 PetscFunctionReturn(PETSC_SUCCESS);
132 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
133 Vec x = NULL, x_copy = NULL, f1 = NULL, f2 = NULL, delta = NULL;
134 PetscReal norm = 0.0;
137 PetscFunctionBeginUser;
139 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
140 PetscCall(VecDuplicate(user->
Ucont, &x));
141 PetscCall(VecDuplicate(user->
Ucont, &x_copy));
142 PetscCall(VecDuplicate(user->
Ucont, &f1));
143 PetscCall(VecDuplicate(user->
Ucont, &f2));
144 PetscCall(VecDuplicate(user->
Ucont, &delta));
145 PetscCall(VecCopy(user->
Ucont, x));
146 PetscCall(VecShift(x, 0.125));
147 PetscCall(VecCopy(x, x_copy));
156 PetscCall(VecWAXPY(delta, -1.0, f1, f2));
157 PetscCall(VecNorm(delta, NORM_INFINITY, &norm));
158 PetscCheck(norm <= 1.0e-12, PETSC_COMM_WORLD, PETSC_ERR_PLIB,
159 "%s residual changed between identical evaluations (norm=%g).", label, (
double)norm);
160 PetscCall(VecWAXPY(delta, -1.0, x_copy, x));
161 PetscCall(VecNorm(delta, NORM_INFINITY, &norm));
162 PetscCheck(norm == 0.0, PETSC_COMM_WORLD, PETSC_ERR_PLIB,
163 "%s residual callback modified X (norm=%g).", label, (
double)norm);
165 PetscCall(VecDestroy(&delta));
166 PetscCall(VecDestroy(&f2));
167 PetscCall(VecDestroy(&f1));
168 PetscCall(VecDestroy(&x_copy));
169 PetscCall(VecDestroy(&x));
170 PetscCall(VecDestroy(&user->
Rhs));
172 PetscFunctionReturn(PETSC_SUCCESS);
178 return (PetscBool)(i >= user->
info.xs && i < user->
info.xs + user->
info.xm &&
179 j >= user->
info.ys && j < user->
info.ys + user->
info.ym &&
180 k >= user->
info.zs && k < user->
info.zs + user->
info.zm);
195 PetscInt k, PetscInt component, PetscScalar delta)
199 PetscFunctionBeginUser;
201 PetscCall(DMDAVecGetArray(user->
fda, vec, &a));
202 if (component == 0) a[k][j][i].
x += delta;
203 else if (component == 1) a[k][j][i].
y += delta;
204 else a[k][j][i].
z += delta;
205 PetscCall(DMDAVecRestoreArray(user->
fda, vec, &a));
207 PetscFunctionReturn(PETSC_SUCCESS);
222 PetscInt k, PetscInt component, PetscScalar *value)
225 PetscScalar local = 0.0;
227 PetscFunctionBeginUser;
229 PetscCall(DMDAVecGetArrayRead(user->
fda, vec, &a));
230 local = component == 0 ? a[k][j][i].
x : (component == 1 ? a[k][j][i].
y : a[k][j][i].
z);
231 PetscCall(DMDAVecRestoreArrayRead(user->
fda, vec, &a));
233 PetscCallMPI(MPI_Allreduce(&local, value, 1, MPIU_SCALAR, MPIU_SUM, PETSC_COMM_WORLD));
234 PetscFunctionReturn(PETSC_SUCCESS);
255 PetscInt row_i, PetscInt row_j, PetscInt row_k,
256 PetscInt row_component, PetscInt col_i, PetscInt col_j,
257 PetscInt col_k, PetscInt col_component,
258 PetscReal expected, PetscReal tolerance,
const char *label)
260 const PetscReal epsilon = 1.0e-6;
261 Vec f0 = NULL, fp = NULL, xp = NULL;
262 PetscScalar base_value = 0.0, perturbed_value = 0.0;
265 PetscFunctionBeginUser;
266 PetscCall(VecDuplicate(x, &f0));
267 PetscCall(VecDuplicate(x, &fp));
268 PetscCall(VecDuplicate(x, &xp));
271 PetscCall(VecCopy(x, xp));
274 PetscCall(
GetStoredValue(user, f0, row_i, row_j, row_k, row_component, &base_value));
275 PetscCall(
GetStoredValue(user, fp, row_i, row_j, row_k, row_component, &perturbed_value));
277 PetscRealPart((perturbed_value - base_value) / epsilon), tolerance, label));
278 PetscCall(VecDestroy(&xp));
279 PetscCall(VecDestroy(&fp));
280 PetscCall(VecDestroy(&f0));
281 PetscFunctionReturn(PETSC_SUCCESS);
287 char profile_dir[PETSC_MAX_PATH_LEN] =
"";
288 char profile_path[PETSC_MAX_PATH_LEN];
289 char file_bcs[2 * PETSC_MAX_PATH_LEN];
291 PetscFunctionBeginUser;
301 PetscCall(PetscSNPrintf(profile_path,
sizeof(profile_path),
"%s/inlet.picslice", profile_dir));
303 PetscCall(PetscSNPrintf(file_bcs,
sizeof(file_bcs),
304 "-Xi WALL noslip\n+Xi WALL noslip\n-Eta WALL noslip\n+Eta WALL noslip\n"
305 "-Zeta INLET prescribed_flow source_file=%s\n+Zeta OUTLET conservation\n", profile_path));
308 PetscFunctionReturn(PETSC_SUCCESS);
316 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
317 Vec x = NULL, f = NULL;
318 Cmpnts ***xa = NULL, ***fa = NULL, ***conditioned = NULL, ***rhs = NULL;
321 PetscFunctionBeginUser;
323 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
324 PetscCall(VecDuplicate(user->
Ucont, &x));
325 PetscCall(VecDuplicate(user->
Ucont, &f));
326 PetscCall(VecSet(x, 0.25));
327 PetscCall(DMDAVecGetArray(user->
fda, x, &xa));
328 if (user->
info.xs == 0 && 2 >= user->
info.ys && 2 < user->
info.ys + user->
info.ym &&
329 2 >= user->
info.zs && 2 < user->
info.zs + user->
info.zm) xa[2][2][0].
x = 3.0;
331 2 >= user->
info.ys && 2 < user->
info.ys + user->
info.ym &&
332 2 >= user->
info.zs && 2 < user->
info.zs + user->
info.zm) xa[2][2][user->
info.mx - 2].
x = 1.25;
333 PetscCall(DMDAVecRestoreArray(user->
fda, x, &xa));
337 PetscCall(DMDAVecGetArrayRead(user->
fda, x, &xa));
338 PetscCall(DMDAVecGetArrayRead(user->
fda, f, &fa));
339 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Ucont, &conditioned));
340 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
Rhs, &rhs));
341 if (user->
info.xs == 0 && 2 >= user->
info.ys && 2 < user->
info.ys + user->
info.ym &&
342 2 >= user->
info.zs && 2 < user->
info.zs + user->
info.zm) {
344 "periodic duplicate row must be Xdup-Xrep"));
346 if (user->
info.ys == 0 && 2 >= user->
info.xs && 2 < user->
info.xs + user->
info.xm &&
347 2 >= user->
info.zs && 2 < user->
info.zs + user->
info.zm) {
349 fa[2][0][2].y, 1.0e-12,
350 "fixed wall row must be X minus conditioned boundary value"));
352 if (2 >= user->
info.xs && 2 < user->
info.xs + user->
info.xm &&
353 2 >= user->
info.ys && 2 < user->
info.ys + user->
info.ym &&
354 2 >= user->
info.zs && 2 < user->
info.zs + user->
info.zm) {
356 "unconstrained interior row must retain the physical residual"));
358 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Rhs, &rhs));
359 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
Ucont, &conditioned));
360 PetscCall(DMDAVecRestoreArrayRead(user->
fda, f, &fa));
361 PetscCall(DMDAVecRestoreArrayRead(user->
fda, x, &xa));
363 PetscCall(VecDestroy(&f));
364 PetscCall(VecDestroy(&x));
365 PetscCall(VecDestroy(&user->
Rhs));
367 PetscFunctionReturn(PETSC_SUCCESS);
375 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
377 const PetscInt size[3] = {7, 7, 7};
379 PetscFunctionBeginUser;
381 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
382 PetscCall(VecDuplicate(user->
Ucont, &x));
383 PetscCall(VecSet(x, 0.2));
385 for (PetscInt axis = 0; axis < 3; ++axis) {
386 PetscInt coord[3] = {2, 2, 2}, ri, rj, rk;
387 PetscInt tangent = (axis + 1) % 3;
393 "negative face normal row classification"));
395 coord[0], coord[1], coord[2], axis, 1.0, 1.0e-8,
396 "negative face normal fixed derivative"));
400 "negative face tangential row classification"));
402 coord[0], coord[1], coord[2], tangent, 1.0, 1.0e-8,
403 "negative face tangential homogeneous derivative"));
405 coord[axis] = size[axis] - 2;
408 "positive physical normal row classification"));
410 coord[0], coord[1], coord[2], axis, 1.0, 1.0e-8,
411 "positive physical normal fixed derivative"));
414 "positive physical tangential row classification"));
416 coord[axis] = size[axis] - 1;
417 for (PetscInt component = 0; component < 3; ++component) {
420 "positive dummy row classification"));
422 coord[0], coord[1], coord[2], component, 1.0, 1.0e-8,
423 "positive dummy homogeneous derivative"));
427 PetscCall(VecDestroy(&x));
428 PetscCall(VecDestroy(&user->
Rhs));
430 PetscFunctionReturn(PETSC_SUCCESS);
438 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
441 PetscFunctionBeginUser;
443 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
444 PetscCall(VecDuplicate(user->
Ucont, &x));
445 PetscCall(VecCopy(user->
Ucont, x));
446 PetscCall(VecShift(x, 0.1));
447 PetscCall(
CheckStoredDerivative(user, x, 2, 2, 0, 2, 2, 2, 0, 2,
448 1.0, 1.0e-8,
"constant inlet fixed derivative"));
450 2, 2, user->
info.mz - 2, 2,
451 1.0, 5.0e-6,
"conservation outlet fixed derivative"));
452 PetscCall(VecDestroy(&x));
453 PetscCall(VecDestroy(&user->
Rhs));
455 PetscFunctionReturn(PETSC_SUCCESS);
468 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
470 PetscInt size[3], dup[3] = {2, 2, 2}, rep[3] = {2, 2, 2}, unrelated[3] = {3, 3, 3};
472 PetscFunctionBeginUser;
474 size[0] = user->
info.mx; size[1] = user->
info.my; size[2] = user->
info.mz;
475 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
476 PetscCall(VecDuplicate(user->
Ucont, &x));
477 PetscCall(VecSet(x, 0.15));
478 for (PetscInt side = 0; side < 2; ++side) {
479 dup[axis] = side == 0 ? 0 : size[axis] - 1;
480 rep[axis] = side == 0 ? size[axis] - 2 : 1;
481 for (PetscInt component = 0; component < 3; ++component) {
483 dup[0], dup[1], dup[2], component, 1.0, 1.0e-8,
484 "periodic duplicate self derivative"));
486 rep[0], rep[1], rep[2], component, -1.0, 1.0e-8,
487 "periodic representative derivative"));
489 unrelated[0], unrelated[1], unrelated[2], (component + 1) % 3, 0.0, 1.0e-8,
490 "periodic constraint unrelated derivative"));
493 PetscCall(VecDestroy(&x));
494 PetscCall(VecDestroy(&user->
Rhs));
496 PetscFunctionReturn(PETSC_SUCCESS);
504 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
505 Vec x = NULL, f = NULL;
507 PetscScalar xdup, synced, residual;
509 PetscFunctionBeginUser;
515 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
516 PetscCall(VecDuplicate(user->
Ucont, &x));
517 PetscCall(VecDuplicate(user->
Ucont, &f));
518 PetscCall(VecSet(x, 0.0));
521 PetscCall(VecCopy(x, user->
Ucont));
529 "doubly periodic edge must use production synchronized representative"));
530 PetscCall(
CheckStoredDerivative(user, x, 0, 0, 2, 0, 0, 0, 2, 0, 1.0, 1.0e-8,
531 "doubly periodic edge self derivative"));
533 user->
info.mx - 2, user->
info.my - 2, 2, 0, -1.0, 1.0e-8,
534 "doubly periodic edge representative derivative"));
535 PetscCall(VecDestroy(&f)); PetscCall(VecDestroy(&x)); PetscCall(VecDestroy(&user->
Rhs));
540 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
541 PetscCall(VecDuplicate(user->
Ucont, &x)); PetscCall(VecSet(x, 0.1));
542 PetscCall(
CheckStoredDerivative(user, x, 0, 0, 0, 2, 0, 0, 0, 2, 1.0, 1.0e-8,
543 "fully periodic corner self derivative"));
545 user->
info.mx - 2, user->
info.my - 2, user->
info.mz - 2, 2,
546 -1.0, 1.0e-8,
"fully periodic corner representative derivative"));
547 PetscCall(VecDestroy(&x)); PetscCall(VecDestroy(&user->
Rhs));
552 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs)); PetscCall(VecDuplicate(user->
Ucont, &x));
553 PetscCall(VecSet(x, 0.1));
554 PetscCall(
CheckStoredDerivative(user, x, 0, 0, 2, 1, 0, 0, 2, 1, 1.0, 1.0e-8,
555 "periodic-wall intersection self derivative"));
557 user->
info.mx - 2, 0, 2, 1, -1.0, 1.0e-8,
558 "periodic-wall intersection representative derivative"));
559 PetscCall(VecDestroy(&x)); PetscCall(VecDestroy(&user->
Rhs));
561 PetscFunctionReturn(PETSC_SUCCESS);
569 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
572 Vec x = NULL, xp = NULL, f0 = NULL, fp = NULL, v = NULL, jv = NULL, fd = NULL;
573 PetscReal h = 0.0, error = 0.0, scale = 0.0;
576 PetscFunctionBeginUser;
578 PetscCall(VecDuplicate(user->
Ucont, &user->
Rhs));
579 PetscCall(VecDuplicate(user->
Ucont, &x));
580 PetscCall(VecDuplicate(user->
Ucont, &xp));
581 PetscCall(VecDuplicate(user->
Ucont, &f0));
582 PetscCall(VecDuplicate(user->
Ucont, &fp));
583 PetscCall(VecDuplicate(user->
Ucont, &v));
584 PetscCall(VecDuplicate(user->
Ucont, &jv));
585 PetscCall(VecDuplicate(user->
Ucont, &fd));
586 PetscCall(VecCopy(user->
Ucont, x));
587 PetscCall(VecShift(x, 0.05));
588 PetscCall(VecSet(v, 0.5));
591 PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
592 PetscCall(SNESSetDM(snes, user->
fda));
594 PetscCall(MatCreateSNESMF(snes, &J));
596 PetscCall(MatMFFDSetBase(J, x, f0));
597 PetscCall(MatMult(J, v, jv));
598 PetscCall(MatMFFDGetH(J, &h));
599 PetscCall(VecWAXPY(xp, h, v, x));
601 PetscCall(VecWAXPY(fd, -1.0, f0, fp));
602 PetscCall(VecScale(fd, 1.0 / h));
603 PetscCall(VecAXPY(fd, -1.0, jv));
604 PetscCall(VecNorm(fd, NORM_2, &error));
605 PetscCall(VecNorm(jv, NORM_2, &scale));
606 PetscCall(
PicurvAssertBool((PetscBool)(error <= 1.0e-9 * PetscMax(1.0, scale)),
607 "matrix-free Jv must match direct differencing"));
609 PetscCall(VecDestroy(&fd));
610 PetscCall(VecDestroy(&jv));
611 PetscCall(VecDestroy(&v));
612 PetscCall(VecDestroy(&fp));
613 PetscCall(VecDestroy(&f0));
614 PetscCall(VecDestroy(&xp));
615 PetscCall(VecDestroy(&x));
616 PetscCall(MatDestroy(&J));
617 PetscCall(SNESDestroy(&snes));
618 PetscCall(VecDestroy(&user->
Rhs));
620 PetscFunctionReturn(PETSC_SUCCESS);
631 PetscBool x_periodic)
633 PetscFunctionBeginUser;
637 simCtx, user, 6, 6, 6, PETSC_TRUE, PETSC_TRUE, PETSC_TRUE));
638 (*simCtx)->i_periodic = x_periodic ? 1 : 0;
639 (*simCtx)->j_periodic = (*simCtx)->k_periodic = 0;
641 (*simCtx)->invicid = 1;
644 (*simCtx)->StartStep = 0;
645 PetscCall(VecSet((*user)->Ucont, 0.0));
646 PetscCall(VecSet((*user)->Ucont_o, 0.0));
647 PetscCall(VecSet((*user)->Ucont_rm1, 0.0));
648 for (PetscInt face = 0; face < 6; ++face) {
649 PetscBool periodic_face = (PetscBool)(x_periodic &&
651 (*user)->boundary_faces[face].face_id = (
BCFace)face;
652 (*user)->boundary_faces[face].mathematical_type = periodic_face ?
PERIODIC :
WALL;
653 (*user)->boundary_faces[face].handler_type = periodic_face ?
656 &(*user)->boundary_faces[face].handler));
658 PetscFunctionReturn(PETSC_SUCCESS);
670 Vec x = NULL, xp = NULL, f0 = NULL, fp = NULL, column = NULL, square = NULL;
671 Vec row_norm_sq = NULL, v[2] = {NULL, NULL}, dense_v[2] = {NULL, NULL};
672 Vec mffd_v = NULL, error_vec = NULL;
673 PetscInt n_global, lo, hi;
674 PetscReal min_row_sq = 0.0, error = 0.0, reference = 0.0;
675 const PetscReal epsilon = 1.0e-7;
678 PetscFunctionBeginUser;
680 PetscCall(VecDuplicate(user->
Ucont, &x)); PetscCall(VecSet(x, 0.0));
681 PetscCall(VecDuplicate(x, &xp)); PetscCall(VecDuplicate(x, &f0));
682 PetscCall(VecDuplicate(x, &fp)); PetscCall(VecDuplicate(x, &column));
683 PetscCall(VecDuplicate(x, &square)); PetscCall(VecDuplicate(x, &row_norm_sq));
684 PetscCall(VecDuplicate(x, &v[0])); PetscCall(VecDuplicate(x, &v[1]));
685 PetscCall(VecDuplicate(x, &dense_v[0])); PetscCall(VecDuplicate(x, &dense_v[1]));
686 PetscCall(VecDuplicate(x, &mffd_v)); PetscCall(VecDuplicate(x, &error_vec));
687 PetscCall(VecZeroEntries(row_norm_sq)); PetscCall(VecZeroEntries(dense_v[0]));
688 PetscCall(VecZeroEntries(dense_v[1]));
689 PetscCall(VecGetSize(x, &n_global));
690 PetscCall(VecGetOwnershipRange(x, &lo, &hi));
691 for (PetscInt which = 0; which < 2; ++which) {
692 PetscScalar *a = NULL;
693 PetscCall(VecGetArray(v[which], &a));
694 for (PetscInt local = 0; local < hi - lo; ++local) {
695 PetscInt global = lo + local;
696 a[local] = which == 0 ? (PetscScalar)(1.0 + 0.05 * (global % 9))
697 : (PetscScalar)(((global % 2) ? -1.0 : 1.0) * (0.5 + 0.03 * (global % 7)));
699 PetscCall(VecRestoreArray(v[which], &a));
705 for (PetscInt col = 0; col < n_global; ++col) {
706 PetscScalar coeff[2] = {
707 (PetscScalar)(1.0 + 0.05 * (col % 9)),
708 (PetscScalar)(((col % 2) ? -1.0 : 1.0) * (0.5 + 0.03 * (col % 7)))
710 PetscCall(VecCopy(x, xp));
711 if (col >= lo && col < hi) PetscCall(VecSetValue(xp, col, epsilon, ADD_VALUES));
712 PetscCall(VecAssemblyBegin(xp)); PetscCall(VecAssemblyEnd(xp));
714 PetscCall(VecWAXPY(column, -1.0, f0, fp));
715 PetscCall(VecScale(column, 1.0 / epsilon));
716 PetscCall(VecPointwiseMult(square, column, column));
717 PetscCall(VecAXPY(row_norm_sq, 1.0, square));
718 PetscCall(VecAXPY(dense_v[0], coeff[0], column));
719 PetscCall(VecAXPY(dense_v[1], coeff[1], column));
721 PetscCall(VecMin(row_norm_sq, NULL, &min_row_sq));
722 PetscCheck(min_row_sq > 0.5, PETSC_COMM_WORLD, PETSC_ERR_PLIB,
723 "Complete Newton Jacobian contains an unexplained zero/weak row (min squared norm=%g).",
725 PetscCall(
CheckStoredDerivative(user, x, 2, 2, 2, 0, 2, 2, 2, 0,
726 10.0, 1.0e-5,
"interior BDF1 temporal diagonal"));
728 PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
729 PetscCall(SNESSetDM(snes, user->
fda));
731 PetscCall(MatCreateSNESMF(snes, &J));
732 PetscCall(MatMFFDSetBase(J, x, f0));
733 for (PetscInt which = 0; which < 2; ++which) {
734 PetscCall(MatMult(J, v[which], mffd_v));
735 PetscCall(VecWAXPY(error_vec, -1.0, dense_v[which], mffd_v));
736 PetscCall(VecNorm(error_vec, NORM_2, &error));
737 PetscCall(VecNorm(dense_v[which], NORM_2, &reference));
738 PetscCheck(error <= 2.0e-5 * PetscMax(1.0, reference), PETSC_COMM_WORLD, PETSC_ERR_PLIB,
739 "Independent dense FD Jv differs from PETSc MFFD action %d: error=%g reference=%g.",
740 which, (
double)error, (
double)reference);
743 for (PetscInt which = 0; which < 2; ++which) {
744 const PetscReal steps[3] = {1.0e-4, 1.0e-6, 1.0e-8};
745 PetscReal best = PETSC_MAX_REAL;
746 for (PetscInt s = 0; s < 3; ++s) {
747 PetscCall(VecWAXPY(xp, steps[s], v[which], x));
749 PetscCall(VecWAXPY(column, -1.0, f0, fp));
750 PetscCall(VecScale(column, 1.0 / steps[s]));
751 PetscCall(VecAXPY(column, -1.0, dense_v[which]));
752 PetscCall(VecNorm(column, NORM_2, &error));
753 best = PetscMin(best, error);
755 PetscCall(VecNorm(dense_v[which], NORM_2, &reference));
756 PetscCheck(best <= 2.0e-5 * PetscMax(1.0, reference), PETSC_COMM_WORLD, PETSC_ERR_PLIB,
757 "Direct directional differences show no accuracy plateau for vector %d (best=%g).",
758 which, (
double)best);
761 PetscCall(MatDestroy(&J)); PetscCall(SNESDestroy(&snes));
762 PetscCall(VecDestroy(&error_vec)); PetscCall(VecDestroy(&mffd_v));
763 PetscCall(VecDestroy(&dense_v[1])); PetscCall(VecDestroy(&dense_v[0]));
764 PetscCall(VecDestroy(&v[1])); PetscCall(VecDestroy(&v[0]));
765 PetscCall(VecDestroy(&row_norm_sq)); PetscCall(VecDestroy(&square));
766 PetscCall(VecDestroy(&column)); PetscCall(VecDestroy(&fp)); PetscCall(VecDestroy(&f0));
767 PetscCall(VecDestroy(&xp)); PetscCall(VecDestroy(&x));
770 PetscFunctionReturn(PETSC_SUCCESS);
778 Vec x = NULL, xp = NULL, f0 = NULL, fp = NULL, column = NULL;
779 Vec square = NULL, row_norm_sq = NULL;
780 PetscInt n_global, lo, hi;
781 PetscReal min_row_sq = 0.0;
782 const PetscReal epsilon = 1.0e-7;
785 PetscFunctionBeginUser;
787 PetscCall(VecDuplicate(user->
Ucont, &x)); PetscCall(VecSet(x, 0.0));
788 PetscCall(VecDuplicate(x, &xp)); PetscCall(VecDuplicate(x, &f0));
789 PetscCall(VecDuplicate(x, &fp)); PetscCall(VecDuplicate(x, &column));
790 PetscCall(VecDuplicate(x, &square)); PetscCall(VecDuplicate(x, &row_norm_sq));
791 PetscCall(VecZeroEntries(row_norm_sq));
792 PetscCall(VecGetSize(x, &n_global)); PetscCall(VecGetOwnershipRange(x, &lo, &hi));
796 for (PetscInt col = 0; col < n_global; ++col) {
797 PetscCall(VecCopy(x, xp));
798 if (col >= lo && col < hi) PetscCall(VecSetValue(xp, col, epsilon, ADD_VALUES));
799 PetscCall(VecAssemblyBegin(xp)); PetscCall(VecAssemblyEnd(xp));
801 PetscCall(VecWAXPY(column, -1.0, f0, fp)); PetscCall(VecScale(column, 1.0 / epsilon));
802 PetscCall(VecPointwiseMult(square, column, column));
803 PetscCall(VecAXPY(row_norm_sq, 1.0, square));
805 PetscCall(VecMin(row_norm_sq, NULL, &min_row_sq));
806 PetscCheck(min_row_sq > 0.5, PETSC_COMM_WORLD, PETSC_ERR_PLIB,
807 "Periodic Newton Jacobian contains a zero/weak row (min squared norm=%g).",
809 PetscCall(VecDestroy(&row_norm_sq)); PetscCall(VecDestroy(&square));
810 PetscCall(VecDestroy(&column)); PetscCall(VecDestroy(&fp)); PetscCall(VecDestroy(&f0));
811 PetscCall(VecDestroy(&xp)); PetscCall(VecDestroy(&x));
814 PetscFunctionReturn(PETSC_SUCCESS);
822 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
823 Vec entry = NULL, delta = NULL;
824 PetscErrorCode solve_ierr;
825 PetscReal norm = 0.0;
826 const char *fields[] = {
"Ucont"};
828 PetscFunctionBeginUser;
830 PetscCall(PetscOptionsSetValue(NULL,
"-mom_nk_snes_rtol",
"1e-4"));
831 PetscCall(PetscOptionsSetValue(NULL,
"-mom_nk_snes_max_it",
"20"));
832 PetscCall(PetscOptionsSetValue(NULL,
"-mom_nk_ksp_rtol",
"1e-6"));
835 PetscCall(
PicurvAssertBool((PetscBool)(user->
Rhs == NULL),
"successful solve must release Rhs"));
840 PetscCall(VecSet(user->
Ucont, 0.2));
843 PetscCall(VecDuplicate(user->
Ucont, &entry));
844 PetscCall(VecDuplicate(user->
Ucont, &delta));
845 PetscCall(VecCopy(user->
Ucont, entry));
846 PetscCall(PetscOptionsSetValue(NULL,
"-mom_nk_snes_max_it",
"0"));
847 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
849 PetscCall(PetscPopErrorHandler());
851 "forced nonconvergence must report PETSC_ERR_CONV_FAILED"));
852 PetscCall(VecWAXPY(delta, -1.0, entry, user->
Ucont));
853 PetscCall(VecNorm(delta, NORM_INFINITY, &norm));
855 "failed Newton solve must restore the canonical entry state"));
856 PetscCall(
PicurvAssertBool((PetscBool)(user->
Rhs == NULL),
"failed solve must release Rhs"));
858 PetscCall(PetscOptionsClearValue(NULL,
"-mom_nk_snes_rtol"));
859 PetscCall(PetscOptionsClearValue(NULL,
"-mom_nk_snes_max_it"));
860 PetscCall(PetscOptionsClearValue(NULL,
"-mom_nk_ksp_rtol"));
861 PetscCall(VecDestroy(&delta));
862 PetscCall(VecDestroy(&entry));
864 PetscFunctionReturn(PETSC_SUCCESS);
872 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
873 PetscErrorCode solve_ierr;
875 PetscFunctionBeginUser;
878 PetscInt *unsupported_flags[] = {
883 for (
size_t flag = 0; flag <
sizeof(unsupported_flags) /
sizeof(unsupported_flags[0]); ++flag) {
884 *unsupported_flags[flag] = 1;
885 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
887 PetscCall(PetscPopErrorHandler());
889 "unsupported Newton feature flag must fail"));
891 "feature validation must precede workspace allocation"));
892 *unsupported_flags[flag] = 0;
896 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
898 PetscCall(PetscPopErrorHandler());
899 PetscCall(
PicurvAssertBool((PetscBool)(solve_ierr != PETSC_SUCCESS),
"multiblock must fail"));
902 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
904 PetscCall(PetscPopErrorHandler());
905 PetscCall(
PicurvAssertBool((PetscBool)(solve_ierr != PETSC_SUCCESS),
"restart must fail"));
907 PetscCall(VecSet(user->
Nvert, 1.0));
908 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
910 PetscCall(PetscPopErrorHandler());
911 PetscCall(
PicurvAssertBool((PetscBool)(solve_ierr != PETSC_SUCCESS),
"masked rows must fail"));
912 PetscCall(VecSet(user->
Nvert, 0.0));
915 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
917 PetscCall(PetscPopErrorHandler());
919 "driven constant-flux controller must fail"));
922 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
924 PetscCall(PetscPopErrorHandler());
926 "unimplemented interpolated-file inlet must fail"));
928 "all validation failures must precede workspace allocation"));
930 PetscFunctionReturn(PETSC_SUCCESS);
938 char tmpdir[PETSC_MAX_PATH_LEN] =
"";
939 Vec entry = NULL, delta = NULL;
940 PetscErrorCode solve_ierr;
941 PetscReal norm = 0.0;
942 const char *fields[] = {
"Ucont"};
944 PetscFunctionBeginUser;
946 PetscCall(VecSet(user->
Ucont, 0.2));
949 PetscCall(VecDuplicate(user->
Ucont, &entry)); PetscCall(VecCopy(user->
Ucont, entry));
950 PetscCall(VecDuplicate(user->
Ucont, &delta));
951 PetscCall(PetscOptionsSetValue(NULL,
"-mom_nk_pc_type",
"jacobi"));
952 PetscCall(PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL));
954 PetscCall(PetscPopErrorHandler());
955 PetscCall(PetscOptionsClearValue(NULL,
"-mom_nk_pc_type"));
957 "non-PCNONE option must fail after setup"));
959 "post-allocation failure must destroy Rhs"));
960 PetscCall(VecWAXPY(delta, -1.0, entry, user->
Ucont));
961 PetscCall(VecNorm(delta, NORM_INFINITY, &norm));
963 "post-allocation failure must restore canonical entry"));
964 PetscCall(VecDestroy(&delta)); PetscCall(VecDestroy(&entry));
966 PetscFunctionReturn(PETSC_SUCCESS);
992 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv Newton Krylov tests");
993 if (ierr)
return (
int)ierr;
994 ierr =
PicurvRunTests(
"unit-newton-krylov", cases,
sizeof(cases) /
sizeof(cases[0]));
995 if (PetscFinalize())
return 1;
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const char *field_names[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode BoundaryCondition_Create(BCHandlerType handler_type, BoundaryCondition **new_bc_ptr)
(Private) Creates and configures a specific BoundaryCondition handler object.
PetscErrorCode ApplyBoundaryConditions(UserCtx *user)
Main boundary-condition orchestrator executed during solver timestepping.
PetscErrorCode BoundarySystem_Destroy(UserCtx *user)
Cleans up and destroys all boundary system resources.
PetscErrorCode InitializeEulerianState(SimCtx *simCtx)
High-level orchestrator to set the complete initial state of the Eulerian solver.
static MomentumNewtonKrylovRowType MomentumNewtonKrylov_ClassifyRow(UserCtx *user, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscInt *ri, PetscInt *rj, PetscInt *rk)
Classifies one stored staggered component row and its periodic representative.
MomentumNewtonKrylovRowType
@ MOM_NK_ROW_FIXED_HOMOGENEOUS
@ MOM_NK_ROW_FIXED_CONDITIONED
static PetscErrorCode MomentumNewtonKrylov_FormResidual(SNES snes, Vec X, Vec F, void *ctx)
Adapts a PETSc trial vector to the existing momentum residual path.
static const char * fixed_wall_bcs
static PetscErrorCode BuildNewtonFixture(const char *bcs, SimCtx **simCtx, UserCtx **user, char *tmpdir, size_t tmpdir_len)
Builds and initializes a small runtime context for Newton tests.
static PetscErrorCode TestUnsupportedConfigurationFailsBeforeAllocation(void)
Confirms unsupported features fail before workspace allocation.
static PetscErrorCode TestPeriodicOperatorHasNoZeroRows(void)
Audits every row of a complete operator containing periodic duplicates.
static PetscErrorCode TestSmallSolveAndRollback(void)
Exercises a converged solve, forced rollback, and per-call cleanup.
static const char * periodic_xy_bcs
static PetscErrorCode TestConstraintRows(void)
Verifies fixed, periodic-duplicate, and interior residual rows.
static const char * periodic_xyz_bcs
static const char * periodic_x_bcs
static const char * periodic_y_bcs
#define MomentumSolver_NewtonKrylov
static const char * periodic_z_bcs
int main(int argc, char **argv)
Runs the focused Newton–Krylov unit suite.
static PetscErrorCode WriteNewtonPicSlice(const char *path)
Writes one static 5x5 PICSLICE profile used by the full runtime fixture.
static PetscBool OwnsStoredPoint(UserCtx *user, PetscInt i, PetscInt j, PetscInt k)
Returns whether this rank owns one global DMDA grid point.
static PetscErrorCode CheckSingleAxisPeriodicDerivatives(const char *bcs, PetscInt axis)
Checks one periodic configuration's endpoint derivatives on every component.
static PetscErrorCode TestResidualRepeatabilityAndInputIntegrity(void)
Verifies repeatable callback output and read-only trial input.
static PetscErrorCode TestPeriodicConstraintDerivativesAndIntersections(void)
Proves single-, double-, triple-, and mixed-boundary periodic equations.
static const char * geometric_periodic_bcs
static PetscErrorCode TestWholeOperatorDirectJacobian(void)
Forms the complete direct FD Jacobian, checks every row, and compares MFFD actions.
static PetscErrorCode TestFixedConstraintDerivativesAllFaces(void)
Proves unit derivatives for every nonperiodic stored-row category and face.
static PetscErrorCode TestPostAllocationFailureCleanup(void)
Verifies cleanup and rollback after an options failure following asset creation.
static PetscErrorCode CheckStoredDerivative(UserCtx *user, Vec x, PetscInt row_i, PetscInt row_j, PetscInt row_k, PetscInt row_component, PetscInt col_i, PetscInt col_j, PetscInt col_k, PetscInt col_component, PetscReal expected, PetscReal tolerance, const char *label)
Finite-differences one callback row with respect to one stored unknown.
static const char * parabolic_bcs
static PetscErrorCode GetStoredValue(UserCtx *user, Vec vec, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscScalar *value)
Reads one globally indexed stored component on any MPI decomposition.
static PetscErrorCode TestMatrixFreeDerivative(void)
Compares PETSc's matrix-free action with direct differencing.
static PetscErrorCode PerturbStoredValue(UserCtx *user, Vec vec, PetscInt i, PetscInt j, PetscInt k, PetscInt component, PetscScalar delta)
Adds a scalar perturbation to one stored staggered component.
static PetscErrorCode DestroyNewtonFixture(SimCtx **simCtx, char *tmpdir)
Destroys a Newton test fixture and its temporary files.
static PetscErrorCode BuildMinimalWallOperatorFixture(SimCtx **simCtx, UserCtx **user, PetscBool x_periodic)
Builds a compact all-wall operator fixture through real boundary handlers.
static PetscErrorCode CheckResidualRepeatabilityForBC(const char *bcs, const char *label)
Checks callback repeatability, diagnostic-state independence, and X integrity.
static PetscErrorCode TestInletOutletConstraintDerivatives(void)
Proves admitted inlet and outlet face-normal rows have unit self derivatives.
PetscErrorCode PicurvMakeTempDir(char *path, size_t path_len)
Creates a unique temporary directory for one test case.
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 PicurvDestroyRuntimeContext(SimCtx **simCtx_ptr)
Finalizes and frees a runtime context built by PicurvBuildTinyRuntimeContext.
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 PicurvBuildTinyRuntimeContext(const char *bcs_contents, PetscBool enable_particles, SimCtx **simCtx_out, UserCtx **user_out, char *tmpdir, size_t tmpdir_len)
Builds a tiny runtime context through the real setup path for behavior-level tests.
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
PetscErrorCode PicurvRemoveTempDir(const char *path)
Recursively removes a temporary directory created by PicurvMakeTempDir.
Shared declarations for the PICurv C test fixture and assertion layer.
Named test case descriptor consumed by PicurvRunTests.
BoundaryFaceConfig boundary_faces[6]
PetscBool mom_last_converged
@ BC_HANDLER_PERIODIC_GEOMETRIC
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
@ BC_HANDLER_INLET_INTERP_FROM_FILE
BCHandlerType handler_type
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
BCFace
Identifies the six logical faces of a structured computational block.
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.