26#define POISSON_SOLID_THRESHOLD 0.1
31 { 1, 0, 0}, {-1, 0, 0}, { 0, 1, 0}, { 0, -1, 0},
32 { 0, 0, 1}, { 0, 0, -1},
33 { 1, 1, 0}, { 1, -1, 0}, {-1, 1, 0}, {-1, -1, 0},
34 { 0, 1, 1}, { 0, 1, -1}, { 0, -1, 1}, { 0, -1, -1},
35 { 1, 0, 1}, { 1, 0, -1}, {-1, 0, 1}, {-1, 0, -1},
61 const PetscReal ***aj[3];
77 for (PetscInt s = 0; s < 19; s++) {
88 return field[c[2] + d[2]][c[1] + d[1]][c[0] + d[0]];
109 const PetscReal ***nvert,
const PetscInt c[3], PetscInt n, PetscInt t,
110 const PetscInt m[3],
const PetscBool periodic[3])
113 PetscInt plus[3] = {0, 0, 0}, plus_n[3] = {0, 0, 0};
114 PetscInt minus[3] = {0, 0, 0}, minus_n[3] = {0, 0, 0};
115 const PetscInt s = c[t];
117 plus[t] = 1; plus_n[t] = 1; plus_n[n] = 1;
118 minus[t] = -1; minus_n[t] = -1; minus_n[n] = 1;
131 diff.
lo = -1; diff.
hi = 1; diff.
weight = 0.25;
142 PetscInt n,
const PetscInt m[3],
const PetscBool periodic[3])
145 const Cmpnts normal = metrics->
metric[n][n][c[2]][c[1]][c[0]];
147 face.
aj = metrics->
aj[n][c[2]][c[1]][c[0]];
148 for (PetscInt b = 0; b < 3; b++) {
149 const Cmpnts base = metrics->
metric[n][b][c[2]][c[1]][c[0]];
150 face.
dot[b] = base.
x * normal.
x + base.
y * normal.
y + base.
z * normal.
z;
165 PetscFunctionBeginUser;
166 for (PetscInt n = 0; n < 3; n++) {
167 for (PetscInt b = 0; b < 3; b++) {
169 PetscCall(DMDAVecGetArrayRead(view.
dm, view.
local_vec, (
void *)&metrics->
metric[n][b]));
172 PetscCall(DMDAVecGetArrayRead(view.
dm, view.
local_vec, (
void *)&metrics->
aj[n]));
174 PetscFunctionReturn(0);
182 PetscFunctionBeginUser;
183 for (PetscInt n = 0; n < 3; n++) {
184 for (PetscInt b = 0; b < 3; b++) {
186 PetscCall(DMDAVecRestoreArrayRead(view.
dm, view.
local_vec, (
void *)&metrics->
metric[n][b]));
189 PetscCall(DMDAVecRestoreArrayRead(view.
dm, view.
local_vec, (
void *)&metrics->
aj[n]));
191 PetscFunctionReturn(0);
200 if (periodic && d == 1 && v == m - 2)
return 1;
201 if (periodic && d == -1 && v == 1)
return m - 2;
215 PetscInt n, PetscReal sign, PetscScalar coefficients[19])
217 for (PetscInt b = 0; b < 3; b++) {
218 const PetscReal g = face->
dot[b] * face->
aj;
219 PetscInt lower[3] = {own[0], own[1], own[2]};
220 PetscInt upper[3] = {own[0], own[1], own[2]};
230 if (diff.
weight == 0.0)
continue;
231 const PetscReal term = g * diff.
weight;
232 PetscInt hi_lower[3] = {lower[0], lower[1], lower[2]}, hi_upper[3] = {upper[0], upper[1], upper[2]};
233 PetscInt lo_lower[3] = {lower[0], lower[1], lower[2]}, lo_upper[3] = {upper[0], upper[1], upper[2]};
234 hi_lower[b] += diff.
hi; hi_upper[b] += diff.
hi;
235 lo_lower[b] += diff.
lo; lo_upper[b] += diff.
lo;
244#define __FUNCT__ "AssemblePoissonOperator"
253 const DMDALocalInfo info = user->
info;
254 const PetscInt m[3] = {info.mx, info.my, info.mz};
255 PetscBool periodic[3];
257 const PetscReal ***nvert, ***aj;
260 PetscFunctionBeginUser;
265 PetscCall(VecGetLocalSize(user->
Phi, &local_rows));
266 PetscCall(MatCreateAIJ(PETSC_COMM_WORLD, local_rows, local_rows, m[0] * m[1] * m[2], m[0] * m[1] * m[2],
267 19, NULL, 19, NULL, &user->
A));
269 PetscCall(MatZeroEntries(user->
A));
272 PetscCall(DMDAGetAO(user->
da, &ao));
274 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
275 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, (
void *)&aj));
277 for (PetscInt k = info.zs; k < info.zs + info.zm; k++) {
278 for (PetscInt j = info.ys; j < info.ys + info.ym; j++) {
279 for (PetscInt i = info.xs; i < info.xs + info.xm; i++) {
280 const PetscInt c[3] = {i, j, k};
281 PetscInt row = i + j * m[0] + k * m[0] * m[1];
282 PetscInt columns[19];
283 PetscScalar coefficients[19] = {0.0};
285 PetscCall(AOApplicationToPetsc(ao, 1, &row));
286 if (i == 0 || i == m[0] - 1 || j == 0 || j == m[1] - 1 || k == 0 || k == m[2] - 1) {
287 const PetscScalar one = 1.0;
288 PetscCall(MatSetValues(user->
A, 1, &row, 1, &row, &one, INSERT_VALUES));
292 for (PetscInt s = 0; s < 19; s++) {
298 PetscCall(AOApplicationToPetsc(ao, 19, columns));
303 coefficients[0] = 1.0;
304 PetscCall(MatSetValues(user->
A, 1, &row, 19, columns, coefficients, INSERT_VALUES));
310 for (PetscInt n = 0; n < 3; n++) {
311 const PetscInt first = periodic[n] ? 0 : 1;
312 const PetscInt last = periodic[n] ? m[n] - 1 : m[n] - 2;
313 for (PetscInt side = 0; side < 2; side++) {
314 PetscInt across[3] = {0, 0, 0}, own[3] = {0, 0, 0}, face_cell[3] = {i, j, k};
315 const PetscBool upper = (PetscBool)(side == 0);
317 across[n] = upper ? 1 : -1;
319 if (c[n] == (upper ? last : first))
continue;
320 if (!upper) { own[n] = -1; face_cell[n] -= 1; }
328 for (PetscInt s = 0; s < 19; s++) coefficients[s] *= -aj[k][j][i];
329 PetscCall(MatSetValues(user->
A, 1, &row, 19, columns, coefficients, INSERT_VALUES));
334 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, (
void *)&aj));
335 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
337 PetscCall(MatAssemblyBegin(user->
A, MAT_FINAL_ASSEMBLY));
338 PetscCall(MatAssemblyEnd(user->
A, MAT_FINAL_ASSEMBLY));
342 PetscFunctionReturn(0);
346#define __FUNCT__ "ComputePoissonRHS"
356 const DMDALocalInfo info = user->
info;
357 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
358 const PetscReal dt = simCtx->
dt;
360 const PetscReal ***nvert, ***aj;
362 PetscReal local_sum = 0.0, global_sum = 0.0;
364 PetscFunctionBeginUser;
366 PetscCall(DMDAVecGetArray(user->
da, B, &rhs));
367 PetscCall(DMDAVecGetArrayRead(user->
fda, user->
lUcont, (
void *)&ucont));
368 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
369 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lAj, (
void *)&aj));
371 for (PetscInt k = info.zs; k < info.zs + info.zm; k++) {
372 for (PetscInt j = info.ys; j < info.ys + info.ym; j++) {
373 for (PetscInt i = info.xs; i < info.xs + info.xm; i++) {
374 if (i == 0 || i == mx - 1 || j == 0 || j == my - 1 || k == 0 || k == mz - 1 ||
378 rhs[k][j][i] = -(ucont[k][j][i].
x - ucont[k][j][i-1].
x +
379 ucont[k][j][i].
y - ucont[k][j-1][i].
y +
389 for (PetscInt k = info.zs; k < info.zs + info.zm; k++) {
390 for (PetscInt j = info.ys; j < info.ys + info.ym; j++) {
391 for (PetscInt i = info.xs; i < info.xs + info.xm; i++) {
396 PetscCallMPI(MPI_Allreduce(&local_sum, &global_sum, 1, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)B)));
400 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lAj, (
void *)&aj));
401 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
402 PetscCall(DMDAVecRestoreArrayRead(user->
fda, user->
lUcont, (
void *)&ucont));
403 PetscCall(DMDAVecRestoreArray(user->
da, B, &rhs));
405 PetscFunctionReturn(0);
409#define __FUNCT__ "UpdatePressure"
420 PetscFunctionBeginUser;
422 PetscCall(VecAXPY(user->
P, 1.0, user->
Phi));
427 PetscFunctionReturn(0);
431#define __FUNCT__ "ProjectVelocity"
441 const DMDALocalInfo info = user->
info;
442 const PetscInt m[3] = {info.mx, info.my, info.mz};
443 const PetscInt start[3] = {info.xs, info.ys, info.zs};
444 const PetscInt end[3] = {info.xs + info.xm, info.ys + info.ym, info.zs + info.zm};
447 PetscBool periodic[3];
448 PetscInt interior_start[3], interior_end[3];
450 const PetscReal ***nvert, ***phi;
453 PetscFunctionBeginUser;
456 for (PetscInt a = 0; a < 3; a++) {
457 interior_start[a] = (start[a] == 0) ? 1 : start[a];
458 interior_end[a] = (end[a] == m[a]) ? m[a] - 1 : end[a];
462 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
463 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lPhi, (
void *)&phi));
464 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucont, &ucont));
468 for (PetscInt n = 0; n < 3; n++) {
469 PetscInt lo[3], hi[3];
470 for (PetscInt a = 0; a < 3; a++) { lo[a] = interior_start[a]; hi[a] = interior_end[a]; }
471 if (periodic[n] && start[n] == 0) lo[n] = 0;
472 hi[n] = PetscMin(hi[n], periodic[n] ? m[n] - 1 : m[n] - 2);
474 for (PetscInt k = lo[2]; k < hi[2]; k++) {
475 for (PetscInt j = lo[1]; j < hi[1]; j++) {
476 for (PetscInt i = lo[0]; i < hi[0]; i++) {
477 const PetscInt c[3] = {i, j, k};
478 PetscInt across[3] = {0, 0, 0};
479 PetscReal difference[3];
487 for (PetscInt b = 0; b < 3; b++) {
493 PetscInt hi_lower[3] = {0, 0, 0}, hi_upper[3] = {0, 0, 0};
494 PetscInt lo_lower[3] = {0, 0, 0}, lo_upper[3] = {0, 0, 0};
495 hi_lower[b] = diff.
hi; hi_upper[b] = diff.
hi; hi_upper[n] = 1;
496 lo_lower[b] = diff.
lo; lo_upper[b] = diff.
lo; lo_upper[n] = 1;
497 difference[b] = (diff.
weight == 0.0) ? 0.0 :
502 const PetscReal flux = difference[0] * face.
dot[0] * face.
aj +
503 difference[1] * face.
dot[1] * face.
aj +
504 difference[2] * face.
dot[2] * face.
aj;
505 const PetscReal correction = flux * scale;
506 if (n == 0) ucont[k][j][i].
x -= correction;
507 else if (n == 1) ucont[k][j][i].
y -= correction;
508 else ucont[k][j][i].
z -= correction;
514 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucont, &ucont));
515 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lPhi, (
void *)&phi));
516 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
523 PetscFunctionReturn(0);
536 const DMDALocalInfo info = user->
info;
537 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
538 const PetscInt xs = info.xs, xe = info.xs + info.xm;
539 const PetscInt ys = info.ys, ye = info.ys + info.ym;
540 const PetscInt zs = info.zs, ze = info.zs + info.zm;
541 const PetscInt lxs = (xs == 0) ? 1 : xs, lxe = (xe == mx) ? mx - 1 : xe;
542 const PetscInt lys = (ys == 0) ? 1 : ys, lye = (ye == my) ? my - 1 : ye;
543 const PetscInt lzs = (zs == 0) ? 1 : zs, lze = (ze == mz) ? mz - 1 : ze;
544 const PetscReal ***nvert;
546 PetscReal local[2] = {0.0, 0.0}, global[2];
547 MPI_Comm comm = PetscObjectComm((PetscObject)X);
549 PetscFunctionBeginUser;
551 PetscCall(DMDAVecGetArray(user->
da, X, &x));
552 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
554 for (PetscInt k = lzs; k < lze; k++) {
555 for (PetscInt j = lys; j < lye; j++) {
556 for (PetscInt i = lxs; i < lxe; i++) {
558 local[0] += x[k][j][i];
564 PetscCallMPI(MPI_Allreduce(&local[0], &global[0], 1, MPIU_REAL, MPI_SUM, comm));
565 PetscCallMPI(MPI_Allreduce(&local[1], &global[1], 1, MPIU_REAL, MPI_SUM, comm));
566 const PetscReal shift = global[0] / (-1.0 * global[1]);
567 for (PetscInt k = lzs; k < lze; k++) {
568 for (PetscInt j = lys; j < lye; j++) {
569 for (PetscInt i = lxs; i < lxe; i++) {
575 for (PetscInt k = zs; k < ze; k++) {
576 for (PetscInt j = ys; j < ye; j++) {
577 for (PetscInt i = xs; i < xe; i++) {
578 if (i == 0 || i == mx - 1 || j == 0 || j == my - 1 || k == 0 || k == mz - 1 ||
584 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
585 PetscCall(DMDAVecRestoreArray(user->
da, X, &x));
586 PetscFunctionReturn(0);
597 PetscInt *coarse, PetscInt *direction)
604 *coarse = (f + 1) / 2;
605 *direction = (f - 2 * (*coarse)) == 0 ? 1 : -1;
606 if (f == 1 || f == m - 2) *direction = 0;
618 const PetscReal ***x, ***nvert, ***nvert_c;
621 PetscFunctionBeginUser;
622 PetscCall(MatShellGetContext(P, &user));
625 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
626 const PetscInt xs = info.xs, xe = info.xs + info.xm;
627 const PetscInt ys = info.ys, ye = info.ys + info.ym;
628 const PetscInt zs = info.zs, ze = info.zs + info.zm;
629 const PetscInt lxs = (xs == 0) ? 1 : xs, lxe = (xe == mx) ? mx - 1 : xe;
630 const PetscInt lys = (ys == 0) ? 1 : ys, lye = (ye == my) ? my - 1 : ye;
631 const PetscInt lzs = (zs == 0) ? 1 : zs, lze = (ze == mz) ? mz - 1 : ze;
633 PetscCall(DMGetLocalVector(coarse->
da, &lX));
634 PetscCall(DMGlobalToLocalBegin(coarse->
da, X, INSERT_VALUES, lX));
635 PetscCall(DMGlobalToLocalEnd(coarse->
da, X, INSERT_VALUES, lX));
636 PetscCall(DMDAVecGetArrayRead(coarse->
da, lX, (
void *)&x));
637 PetscCall(DMDAVecGetArrayRead(coarse->
da, coarse->
lNvert, (
void *)&nvert_c));
638 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
639 PetscCall(DMDAVecGetArray(user->
da, F, &f));
641 for (PetscInt k = lzs; k < lze; k++) {
642 for (PetscInt j = lys; j < lye; j++) {
643 for (PetscInt i = lxs; i < lxe; i++) {
644 PetscInt ic, jc, kc, ia, ja, ka;
656 f[k][j][i] = (x[kc ][jc ][ic ] * 9 +
657 x[kc ][jc+ja][ic ] * 3 +
658 x[kc ][jc ][ic+ia] * 3 +
659 x[kc ][jc+ja][ic+ia]) * 3./64. +
660 (x[kc+ka][jc ][ic ] * 9 +
661 x[kc+ka][jc+ja][ic ] * 3 +
662 x[kc+ka][jc ][ic+ia] * 3 +
663 x[kc+ka][jc+ja][ic+ia]) / 64.;
667 for (PetscInt k = zs; k < ze; k++) {
668 for (PetscInt j = ys; j < ye; j++) {
669 for (PetscInt i = xs; i < xe; i++) {
670 if (i == 0 || i == mx - 1 || j == 0 || j == my - 1 || k == 0 || k == mz - 1 ||
676 PetscCall(DMDAVecRestoreArray(user->
da, F, &f));
677 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
678 PetscCall(DMDAVecRestoreArrayRead(coarse->
da, coarse->
lNvert, (
void *)&nvert_c));
679 PetscCall(DMDAVecRestoreArrayRead(coarse->
da, lX, (
void *)&x));
680 PetscCall(DMRestoreLocalVector(coarse->
da, &lX));
681 PetscFunctionReturn(0);
696 const PetscReal ***x, ***nvert, ***nvert_f;
699 PetscFunctionBeginUser;
700 PetscCall(MatShellGetContext(R, &user));
703 const PetscInt mx = info.mx, my = info.my, mz = info.mz;
704 const PetscInt ia = user->
isc ? 0 : 1, ja = user->
jsc ? 0 : 1, ka = user->
ksc ? 0 : 1;
706 PetscCall(DMGetLocalVector(fine->
da, &lX));
707 PetscCall(DMGlobalToLocalBegin(fine->
da, X, INSERT_VALUES, lX));
708 PetscCall(DMGlobalToLocalEnd(fine->
da, X, INSERT_VALUES, lX));
709 PetscCall(DMDAVecGetArrayRead(fine->
da, lX, (
void *)&x));
710 PetscCall(DMDAVecGetArrayRead(fine->
da, fine->
lNvert, (
void *)&nvert_f));
711 PetscCall(DMDAVecGetArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
712 PetscCall(DMDAVecGetArray(user->
da, F, &f));
714 for (PetscInt k = info.zs; k < info.zs + info.zm; k++) {
715 for (PetscInt j = info.ys; j < info.ys + info.ym; j++) {
716 for (PetscInt i = info.xs; i < info.xs + info.xm; i++) {
717 if (i == 0 || i == mx - 1 || j == 0 || j == my - 1 || k == 0 || k == mz - 1 ||
722 const PetscInt ih = user->
isc ? i : 2 * i;
723 const PetscInt jh = user->
jsc ? j : 2 * j;
724 const PetscInt kh = user->
ksc ? k : 2 * k;
726 (x[kh ][jh ][ih ] * PetscMax(0., 1 - nvert_f[kh ][jh ][ih ]) +
727 x[kh ][jh ][ih-ia] * PetscMax(0., 1 - nvert_f[kh ][jh ][ih-ia]) +
728 x[kh ][jh-ja][ih ] * PetscMax(0., 1 - nvert_f[kh ][jh-ja][ih ]) +
729 x[kh-ka][jh ][ih ] * PetscMax(0., 1 - nvert_f[kh-ka][jh ][ih ]) +
730 x[kh ][jh-ja][ih-ia] * PetscMax(0., 1 - nvert_f[kh ][jh-ja][ih-ia]) +
731 x[kh-ka][jh-ja][ih ] * PetscMax(0., 1 - nvert_f[kh-ka][jh-ja][ih ]) +
732 x[kh-ka][jh ][ih-ia] * PetscMax(0., 1 - nvert_f[kh-ka][jh ][ih-ia]) +
733 x[kh-ka][jh-ja][ih-ia] * PetscMax(0., 1 - nvert_f[kh-ka][jh-ja][ih-ia]));
738 PetscCall(DMDAVecRestoreArray(user->
da, F, &f));
739 PetscCall(DMDAVecRestoreArrayRead(user->
da, user->
lNvert, (
void *)&nvert));
740 PetscCall(DMDAVecRestoreArrayRead(fine->
da, fine->
lNvert, (
void *)&nvert_f));
741 PetscCall(DMDAVecRestoreArrayRead(fine->
da, lX, (
void *)&x));
742 PetscCall(DMRestoreLocalVector(fine->
da, &lX));
743 PetscFunctionReturn(0);
754 PCType level_pc_type;
755 PetscBool is_bjacobi = PETSC_FALSE;
759 PetscFunctionBeginUser;
760 PetscCall(KSPGetPC(level_ksp, &level_pc));
761 PetscCall(PCGetType(level_pc, &level_pc_type));
762 if (level_pc_type) PetscCall(PetscStrcmp(level_pc_type, PCBJACOBI, &is_bjacobi));
763 if (!is_bjacobi) PetscFunctionReturn(0);
765 PetscCall(KSPSetUp(level_ksp));
766 PetscCall(PCBJacobiGetSubKSP(level_pc, &nblocks, NULL, &block_ksp));
767 for (PetscInt b = 0; b < nblocks; b++) {
769 PetscCall(KSPGetPC(block_ksp[b], &block_pc));
770 PetscCall(PCFactorSetShiftAmount(block_pc, 1.e-10));
772 PetscFunctionReturn(0);
776#define __FUNCT__ "PoissonMultigrid_Build"
796 const PetscInt levels = usermg->
mglevels;
803 PetscFunctionBeginUser;
809 PetscCall(KSPCreate(PETSC_COMM_WORLD, &ksp));
810 PetscCall(KSPAppendOptionsPrefix(ksp,
"ps_"));
814 PetscCall(PetscNew(&monitor));
819 PetscCall(KSPGetPC(ksp, &pc));
820 PetscCall(PCSetType(pc, PCMG));
821 PetscCall(PCMGSetLevels(pc, levels, NULL));
822 PetscCall(PCMGSetCycleType(pc, PC_MG_CYCLE_V));
823 PetscCall(PCMGSetType(pc, PC_MG_MULTIPLICATIVE));
824 PetscCall(PCMGSetNumberSmooth(pc, simCtx->
mg_preItr));
826 for (PetscInt l = levels - 1; l > 0; l--) {
829 const PetscInt m_c = coarse->
info.xm * coarse->
info.ym * coarse->
info.zm;
830 const PetscInt m_f = fine->
info.xm * fine->
info.ym * fine->
info.zm;
831 const PetscInt M_c = coarse->
info.mx * coarse->
info.my * coarse->
info.mz;
832 const PetscInt M_f = fine->
info.mx * fine->
info.my * fine->
info.mz;
834 PetscCall(MatCreateShell(PETSC_COMM_WORLD, m_c, m_f, M_c, M_f, coarse, &fine->
MR));
835 PetscCall(MatCreateShell(PETSC_COMM_WORLD, m_f, m_c, M_f, M_c, fine, &fine->
MP));
838 PetscCall(PCMGSetRestriction(pc, l, fine->
MR));
839 PetscCall(PCMGSetInterpolation(pc, l, fine->
MP));
842 for (PetscInt l = levels - 1; l >= 0; l--) {
848 PetscCall(PCMGGetSmoother(pc, l, &level_ksp));
850 PetscCall(PCMGGetCoarseSolve(pc, &level_ksp));
851 PetscCall(KSPSetTolerances(level_ksp, 1.e-8, PETSC_DEFAULT, PETSC_DEFAULT, 40));
853 PetscCall(KSPSetOperators(level_ksp, level->
A, level->
A));
854 PetscCall(KSPGetPC(level_ksp, &level_pc));
855 PetscCall(PCSetType(level_pc, PCBJACOBI));
856 PetscCall(KSPSetFromOptions(level_ksp));
859 PetscCall(MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, NULL, &level->
nullsp));
861 PetscCall(MatSetNullSpace(level->
A, level->
nullsp));
862 PetscCall(PCMGSetResidual(pc, l, PCMGResidualDefault, level->
A));
863 PetscCall(KSPSetUp(level_ksp));
870 PetscCall(PCMGGetSmootherUp(pc, l, &post_smoother));
871 PetscCall(KSPAppendOptionsPrefix(post_smoother,
"up_"));
872 PetscCall(KSPSetOperators(post_smoother, level->
A, level->
A));
873 PetscCall(KSPSetTolerances(post_smoother, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, simCtx->
mg_poItr));
874 PetscCall(KSPSetFromOptions(post_smoother));
876 PetscCall(KSPSetUp(post_smoother));
879 if (l < levels - 1) {
880 PetscCall(MatCreateVecs(level->
A, &level->
R, NULL));
881 PetscCall(PCMGSetRhs(pc, l, level->
R));
885 PetscCall(KSPSetOperators(ksp, finest->
A, finest->
A));
886 PetscCall(MatSetNullSpace(finest->
A, finest->
nullsp));
887 PetscCall(KSPSetFromOptions(ksp));
888 PetscCall(KSPSetUp(ksp));
889 PetscCall(VecDuplicate(finest->
P, &finest->
B));
893 PetscFunctionReturn(0);
905 const PetscBool first_step = (PetscBool)(simCtx->
step == simCtx->
StartStep + 1);
907 PetscFunctionBeginUser;
908 PetscCall(KSPGetMonitorContext(ksp, &monitor));
912 if (simCtx->
rank == 0) {
913 char filename[PETSC_MAX_PATH_LEN + 128];
915 PetscCall(PetscSNPrintf(filename,
sizeof(filename),
916 "%s/Poisson_Solver_Convergence_History_Block_%d.log", simCtx->
log_dir, bi));
918 PetscCheck(monitor->
file_handle, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
919 "Could not open KSP monitor log file: %s", filename);
921 PetscCall(PetscFPrintf(PETSC_COMM_SELF, monitor->
file_handle,
922 "# Continuation from step %" PetscInt_FMT
"\n", simCtx->
StartStep));
924 PetscCall(PetscFPrintf(PETSC_COMM_SELF, monitor->
file_handle,
925 "--- Convergence for Timestep %d, Block %d ---\n", (
int)simCtx->
step, bi));
927 PetscFunctionReturn(0);
935 PetscFunctionBeginUser;
936 PetscCall(KSPGetMonitorContext(ksp, &monitor));
941 PetscFunctionReturn(0);
945#define __FUNCT__ "PoissonSolver_Multigrid"
957 PetscFunctionBeginUser;
961 for (PetscInt bi = 0; bi < simCtx->
block_number; bi++) {
963 KSPConvergedReason reason;
971 PetscCall(KSPSolve(user->
ksp, user->
B, user->
Phi));
979 PetscCall(KSPGetConvergedReason(user->
ksp, &reason));
980 PetscCheck(reason != KSP_DIVERGED_NANORINF && reason != KSP_DIVERGED_PC_FAILED,
981 PETSC_COMM_WORLD, PETSC_ERR_NOT_CONVERGED,
982 "Pressure Poisson solve on block %" PetscInt_FMT
" failed at step %" PetscInt_FMT
983 " (KSP reason %s). Known causes: a multigrid hierarchy coarsened too far "
984 "(reduce poisson_solver.multigrid.levels or refine the grid), or a momentum "
985 "field that has already diverged, such as an explicit time step beyond its "
987 bi, simCtx->
step, KSPConvergedReasons[reason]);
988 if (reason < 0 && reason != KSP_DIVERGED_ITS) {
990 " diverged at step %" PetscInt_FMT
" (KSP reason %s); the projection uses the last iterate.\n",
991 bi, simCtx->
step, KSPConvergedReasons[reason]);
997 PetscFunctionReturn(0);
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode FinalizePostProjectionCellFields(UserCtx *user)
Finalizes cell-centered fields after the projection step.
PetscErrorCode SynchronizePeriodicCellFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes periodic endpoint cells for a list of cell-centered fields.
PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
Resolve the existing DM and global/local vectors for one field.
FieldId
Compile-time identity for a catalogued Eulerian field.
Non-owning runtime objects resolved for one field and UserCtx.
Logging utilities and macros for PETSc-based applications.
PetscErrorCode DualMonitorDestroy(void **ctx)
Destroys the DualMonitorCtx.
#define GLOBAL
Scope for global logging across all processes.
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
PetscErrorCode DualKSPMonitor(KSP ksp, PetscInt it, PetscReal rnorm, void *ctx)
A custom KSP monitor that logs to a file and optionally to the console.
@ LOG_INFO
Informational messages about program execution.
@ LOG_WARNING
Non-critical issues that warrant attention.
@ LOG_DEBUG
Detailed debugging information.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Context for a dual-purpose KSP monitor.
static PetscErrorCode PoissonMultigrid_Restrict(Mat R, Vec X, Vec F)
Restricts a fine-level residual to the next coarser level (MatShell multiply).
const PetscReal *** aj[3]
static PoissonTransverseDifference PoissonOperator_TransverseDifference(const PetscReal ***nvert, const PetscInt c[3], PetscInt n, PetscInt t, const PetscInt m[3], const PetscBool periodic[3])
Chooses the transverse difference along axis t at the face between cell c and c + e_n.
static PetscInt PoissonOperator_NeighborIndex(PetscInt v, PetscInt d, PetscInt m, PetscBool periodic)
Index of the neighbour at offset d (-1, 0, +1) from v on an axis of m points, wrapping between the in...
PetscReal aj
Inverse Jacobian on the face.
PetscReal weight
0.25 central, 0.5 one-sided, 0 when no fluid side remains.
const Cmpnts *** metric[3][3]
PoissonTransverseDifference diff[3]
Transverse differences; diff[n] is unused.
static PetscErrorCode PoissonMultigrid_CloseConvergenceLog(KSP ksp)
Closes the log file opened by PoissonMultigrid_OpenConvergenceLog().
PetscErrorCode AssemblePoissonOperator(UserCtx *user)
Implementation of AssemblePoissonOperator().
static PetscErrorCode PoissonOperator_RestoreFaceMetrics(UserCtx *user, PoissonFaceMetrics *metrics)
Returns the arrays borrowed by PoissonOperator_GetFaceMetrics().
static const PetscInt POISSON_STENCIL_OFFSETS[19][3]
Offsets of the 19 stencil points, in the column order used to insert each row.
PetscInt hi
Transverse offset of the added row pair.
static void PoissonOperator_AddFaceFlux(const PoissonFaceGradient *face, const PetscInt own[3], PetscInt n, PetscReal sign, PetscScalar coefficients[19])
Adds the signed gradient flux through one face to a row's stencil coefficients.
#define POISSON_SOLID_THRESHOLD
Cells whose nvert exceeds this value are solid.
static const FieldId POISSON_FACE_AJ_FIELDS[3]
static void PoissonMultigrid_InterpolationParent(PetscInt f, PetscInt m, PetscInt semi, PetscInt *coarse, PetscInt *direction)
Coarse cell and interpolation direction along one axis for fine index f.
static PetscReal PoissonOperator_At(const PetscReal ***field, const PetscInt c[3], const PetscInt d[3])
Value of a cell-centred array at cell c displaced by d.
static PetscErrorCode PoissonMultigrid_ShiftBlockFactors(KSP level_ksp)
Gives each block factor of a block-Jacobi level solver a small diagonal shift, so the factorization o...
static PetscErrorCode PoissonOperator_GetFaceMetrics(UserCtx *user, PoissonFaceMetrics *metrics)
Borrows read access to the face metric arrays of user.
PetscErrorCode UpdatePressure(UserCtx *user)
Implementation of UpdatePressure().
static PetscErrorCode PoissonMultigrid_Interpolate(Mat P, Vec X, Vec F)
Prolongs a coarse-level correction to the next finer level (MatShell multiply).
PetscErrorCode ProjectVelocity(UserCtx *user)
Implementation of ProjectVelocity().
static PetscInt PoissonOperator_StencilSlot(const PetscInt d[3])
Maps the 19 stencil offsets to their slots; corners of the 3x3x3 block are -1.
static PetscErrorCode PoissonMultigrid_RemoveNullSpace(MatNullSpace nullsp, Vec X, void *ctx)
Removes the null space of the Neumann pressure problem from a level vector.
static void PoissonOperator_PeriodicAxes(const UserCtx *user, PetscBool periodic[3])
Records which axes are periodic, from the negative face of each axis.
PetscErrorCode PoissonSolver_Multigrid(UserMG *usermg)
Implementation of PoissonSolver_Multigrid().
static const FieldId POISSON_FACE_METRIC_FIELDS[3][3]
Field IDs of the face metric vectors, indexed as PoissonFaceMetrics.
PetscInt lo
Transverse offset of the subtracted row pair.
static PetscErrorCode PoissonMultigrid_OpenConvergenceLog(KSP ksp, SimCtx *simCtx, PetscInt bi)
Prepares the convergence monitor for one solve and opens its log file on rank 0.
PetscErrorCode ComputePoissonRHS(UserCtx *user, Vec B)
Implementation of ComputePoissonRHS().
static PoissonFaceGradient PoissonOperator_FaceGradientStencil(const PoissonFaceMetrics *metrics, const PetscReal ***nvert, const PetscInt c[3], PetscInt n, const PetscInt m[3], const PetscBool periodic[3])
Gathers the metric coefficients and transverse differences of the gradient flux through the face betw...
static PetscErrorCode PoissonMultigrid_Build(UserMG *usermg, PetscInt bi)
Builds the multigrid solver for block bi and stores it in the finest level.
Everything needed to evaluate the gradient flux through one face.
Read-only face metric arrays: metric[n][b] is F_b on the n-faces.
Transverse difference used at one face.
Pressure-Poisson projection: the multigrid pressure-correction solve, the pressure update,...
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
BoundaryFaceConfig boundary_faces[6]
SimCtx * simCtx
Back-pointer to the master simulation context.
PetscReal poissonSourceImbalance
char log_dir[PETSC_MAX_PATH_LEN]
PetscBool ps_ksp_pic_monitor_true_residual
#define COEF_TIME_ACCURACY
Coefficient controlling the temporal accuracy scheme (e.g., 1.5 for 2nd Order Backward Difference).
A 3D point or vector with PetscScalar components.
Context for Multigrid operations.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.
User-level context for managing the entire multigrid hierarchy.