PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Macros | Functions
poisson.c File Reference
#include "poisson.h"
#include "logging.h"
#include "solvers.h"
Include dependency graph for poisson.c:

Go to the source code of this file.

Macros

#define GridInterpolation(i, j, k, ic, jc, kc, ia, ja, ka, user)
 
#define __FUNCT__   "GridRestriction"
 
#define __FUNCT__   "CorrectChannelFluxProfile"
 
#define CP   0
 
#define EP   1
 
#define WP   2
 
#define NP   3
 
#define SP   4
 
#define TP   5
 
#define BP   6
 
#define NE   7
 
#define SE   8
 
#define NW   9
 
#define SW   10
 
#define TN   11
 
#define BN   12
 
#define TS   13
 
#define BS   14
 
#define TE   15
 
#define BE   16
 
#define TW   17
 
#define BW   18
 
#define __FUNCT__   "Projection"
 
#define __FUNCT__   "UpdatePressure"
 
#define __FUNCT__   "PoissonNullSpaceFunction"
 
#define __FUNCT__   "PoissonLHSNew"
 
#define __FUNCT__   "PoissonRHS"
 
#define __FUNCT__   "PoissonSolver_MG"
 

Functions

static PetscInt Gidx (PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
 Internal helper implementation: Gidx().
 
static PetscErrorCode GridRestriction (PetscInt i, PetscInt j, PetscInt k, PetscInt *ih, PetscInt *jh, PetscInt *kh, UserCtx *user)
 Internal helper implementation: GridRestriction().
 
PetscErrorCode CorrectChannelFluxProfile (UserCtx *user)
 Internal helper implementation: CorrectChannelFluxProfile().
 
PetscErrorCode Projection (UserCtx *user)
 Implementation of Projection().
 
PetscErrorCode UpdatePressure (UserCtx *user)
 Implementation of UpdatePressure().
 
PetscErrorCode PoissonNullSpaceFunction (MatNullSpace nullsp, Vec X, void *ctx)
 Implementation of PoissonNullSpaceFunction().
 
PetscErrorCode MyInterpolation (Mat A, Vec X, Vec F)
 Implementation of MyInterpolation().
 
static PetscErrorCode RestrictResidual_SolidAware (Mat A, Vec X, Vec F)
 Internal helper implementation: RestrictResidual_SolidAware().
 
PetscErrorCode MyRestriction (Mat A, Vec X, Vec F)
 Implementation of MyRestriction().
 
PetscErrorCode PoissonLHSNew (UserCtx *user)
 Internal helper implementation: PoissonLHSNew().
 
PetscErrorCode PoissonRHS (UserCtx *user, Vec B)
 Implementation of PoissonRHS().
 
PetscErrorCode VolumeFlux_rev (UserCtx *user, PetscReal *ibm_Flux, PetscReal *ibm_Area, PetscInt flg)
 Implementation of VolumeFlux_rev().
 
PetscErrorCode VolumeFlux (UserCtx *user, PetscReal *ibm_Flux, PetscReal *ibm_Area, PetscInt flg)
 Implementation of VolumeFlux().
 
static PetscErrorCode FullyBlocked (UserCtx *user)
 Internal helper implementation: FullyBlocked().
 
static PetscErrorCode MyNvertRestriction (UserCtx *user_h, UserCtx *user_c)
 Internal helper implementation: MyNvertRestriction().
 
PetscErrorCode PoissonSolver_MG (UserMG *usermg)
 Implementation of PoissonSolver_MG().
 

Macro Definition Documentation

◆ GridInterpolation

#define GridInterpolation (   i,
  j,
  k,
  ic,
  jc,
  kc,
  ia,
  ja,
  ka,
  user 
)

Definition at line 5 of file poisson.c.

6 { \
7 ic = i; \
8 ia = 0; \
9 } \
10 else { \
11 ic = (i+1) / 2; \
12 ia = (i - 2 * (ic)) == 0 ? 1 : -1; \
13 if (i==1 || i==mx-2) ia = 0; \
14 }\
15 if ((user->jsc)) { \
16 jc = j; \
17 ja = 0; \
18 } \
19 else { \
20 jc = (j+1) / 2; \
21 ja = (j - 2 * (jc)) == 0 ? 1 : -1; \
22 if (j==1 || j==my-2) ja = 0; \
23 } \
24 if ((user->ksc)) { \
25 kc = k; \
26 ka = 0; \
27 } \
28 else { \
29 kc = (k+1) / 2; \
30 ka = (k - 2 * (kc)) == 0 ? 1 : -1; \
31 if (k==1 || k==mz-2) ka = 0; \
32 } \
33 if (ka==-1 && nvert_c[kc-1][jc][ic] > 0.1) ka = 0; \
34 else if (ka==1 && nvert_c[kc+1][jc][ic] > 0.1) ka = 0; \
35 if (ja==-1 && nvert_c[kc][jc-1][ic] > 0.1) ja = 0; \
36 else if (ja==1 && nvert_c[kc][jc+1][ic] > 0.1) ja = 0; \
37 if (ia==-1 && nvert_c[kc][jc][ic-1] > 0.1) ia = 0; \
38 else if (ia==1 && nvert_c[kc][jc][ic+1] > 0.1) ia = 0;

◆ __FUNCT__ [1/8]

#define __FUNCT__   "GridRestriction"

Definition at line 62 of file poisson.c.

◆ __FUNCT__ [2/8]

#define __FUNCT__   "CorrectChannelFluxProfile"

Definition at line 62 of file poisson.c.

◆ CP

#define CP   0

Definition at line 297 of file poisson.c.

◆ EP

#define EP   1

Definition at line 299 of file poisson.c.

◆ WP

#define WP   2

Definition at line 300 of file poisson.c.

◆ NP

#define NP   3

Definition at line 301 of file poisson.c.

◆ SP

#define SP   4

Definition at line 302 of file poisson.c.

◆ TP

#define TP   5

Definition at line 303 of file poisson.c.

◆ BP

#define BP   6

Definition at line 304 of file poisson.c.

◆ NE

#define NE   7

Definition at line 307 of file poisson.c.

◆ SE

#define SE   8

Definition at line 308 of file poisson.c.

◆ NW

#define NW   9

Definition at line 309 of file poisson.c.

◆ SW

#define SW   10

Definition at line 310 of file poisson.c.

◆ TN

#define TN   11

Definition at line 311 of file poisson.c.

◆ BN

#define BN   12

Definition at line 312 of file poisson.c.

◆ TS

#define TS   13

Definition at line 313 of file poisson.c.

◆ BS

#define BS   14

Definition at line 314 of file poisson.c.

◆ TE

#define TE   15

Definition at line 315 of file poisson.c.

◆ BE

#define BE   16

Definition at line 316 of file poisson.c.

◆ TW

#define TW   17

Definition at line 317 of file poisson.c.

◆ BW

#define BW   18

Definition at line 318 of file poisson.c.

◆ __FUNCT__ [3/8]

#define __FUNCT__   "Projection"

Definition at line 62 of file poisson.c.

◆ __FUNCT__ [4/8]

#define __FUNCT__   "UpdatePressure"

Definition at line 62 of file poisson.c.

◆ __FUNCT__ [5/8]

#define __FUNCT__   "PoissonNullSpaceFunction"

Definition at line 62 of file poisson.c.

◆ __FUNCT__ [6/8]

#define __FUNCT__   "PoissonLHSNew"

Definition at line 62 of file poisson.c.

◆ __FUNCT__ [7/8]

#define __FUNCT__   "PoissonRHS"

Definition at line 62 of file poisson.c.

◆ __FUNCT__ [8/8]

#define __FUNCT__   "PoissonSolver_MG"

Definition at line 62 of file poisson.c.

Function Documentation

◆ Gidx()

static PetscInt Gidx ( PetscInt  i,
PetscInt  j,
PetscInt  k,
UserCtx user 
)
static

Internal helper implementation: Gidx().

Local to this translation unit.

Definition at line 44 of file poisson.c.

46{
47 PetscInt nidx;
48 DMDALocalInfo info = user->info;
49
50 PetscInt mx = info.mx, my = info.my;
51
52 AO ao;
53 DMDAGetAO(user->da, &ao);
54 nidx=i+j*mx+k*mx*my;
55
56 AOApplicationToPetsc(ao,1,&nidx);
57
58 return (nidx);
59}
DMDALocalInfo info
Definition variables.h:818
Here is the caller graph for this function:

◆ GridRestriction()

static PetscErrorCode GridRestriction ( PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscInt *  ih,
PetscInt *  jh,
PetscInt *  kh,
UserCtx user 
)
static

Internal helper implementation: GridRestriction().

Local to this translation unit.

Definition at line 68 of file poisson.c.

71{
72 PetscFunctionBeginUser;
74 if ((user->isc)) {
75 *ih = i;
76 }
77 else {
78 *ih = 2 * i;
79 }
80
81 if ((user->jsc)) {
82 *jh = j;
83 }
84 else {
85 *jh = 2 * j;
86 }
87
88 if ((user->ksc)) {
89 *kh = k;
90 }
91 else {
92 *kh = 2 * k;
93 }
94
96 PetscFunctionReturn(0);
97}
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:779
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:770
PetscInt isc
Definition variables.h:824
PetscInt ksc
Definition variables.h:824
PetscInt jsc
Definition variables.h:824
Here is the caller graph for this function:

◆ CorrectChannelFluxProfile()

PetscErrorCode CorrectChannelFluxProfile ( UserCtx user)

Internal helper implementation: CorrectChannelFluxProfile().

Enforces a constant volumetric flux profile along the entire length of a driven periodic channel.

Local to this translation unit.

Definition at line 107 of file poisson.c.

108{
109 PetscErrorCode ierr;
110 SimCtx *simCtx = user->simCtx;
111
112 PetscFunctionBeginUser;
113
114 // --- Step 1: Discover if and where a driven flow is active ---
115 char drivenDirection = ' ';
116 for (int i = 0; i < 6; i++) {
117 BCHandlerType handler_type = user->boundary_faces[i].handler_type;
118 if (handler_type == BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX ||
120 {
121 switch (user->boundary_faces[i].face_id) {
122 case BC_FACE_NEG_X: case BC_FACE_POS_X: drivenDirection = 'X'; break;
123 case BC_FACE_NEG_Y: case BC_FACE_POS_Y: drivenDirection = 'Y'; break;
124 case BC_FACE_NEG_Z: case BC_FACE_POS_Z: drivenDirection = 'Z'; break;
125 }
126 break;
127 }
128 }
129
130 // --- Step 2: Early exit if no driven flow is configured ---
131 if (drivenDirection == ' ') {
132 PetscFunctionReturn(0);
133 }
134
135 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d, Block %d: Starting channel flux profile correction in '%c' direction...\n",
136 simCtx->rank, user->_this, drivenDirection);
137
138 // --- Step 3: Setup and Get PETSc Array Pointers ---
139 DMDALocalInfo info = user->info;
140 PetscInt i, j, k;
141 PetscInt mx = info.mx, my = info.my, mz = info.mz;
142 PetscInt lxs = (info.xs == 0) ? 1 : info.xs;
143 PetscInt lys = (info.ys == 0) ? 1 : info.ys;
144 PetscInt lzs = (info.zs == 0) ? 1 : info.zs;
145 PetscInt lxe = (info.xs + info.xm == mx) ? mx - 1 : info.xs + info.xm;
146 PetscInt lye = (info.ys + info.ym == my) ? my - 1 : info.ys + info.ym;
147 PetscInt lze = (info.zs + info.zm == mz) ? mz - 1 : info.zs + info.zm;
148
149 Cmpnts ***ucont, ***csi, ***eta, ***zet;
150 PetscReal ***nvert;
151 ierr = DMDAVecGetArray(user->fda, user->lUcont, &ucont); CHKERRQ(ierr);
152 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
153 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
154 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
155 ierr = DMDAVecGetArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
156
157 // --- Step 4: Allocate Memory for Profile Arrays based on direction ---
158 PetscInt n_planes = 0;
159 switch (drivenDirection) {
160 case 'X': n_planes = mx - 1; break;
161 case 'Y': n_planes = my - 1; break;
162 case 'Z': n_planes = mz - 1; break;
163 }
164
165 PetscReal *localFluxProfile, *globalFluxProfile, *correctionProfile;
166 ierr = PetscMalloc1(n_planes, &localFluxProfile); CHKERRQ(ierr);
167 ierr = PetscMalloc1(n_planes, &globalFluxProfile); CHKERRQ(ierr);
168 ierr = PetscMalloc1(n_planes, &correctionProfile); CHKERRQ(ierr);
169 ierr = PetscMemzero(localFluxProfile, n_planes * sizeof(PetscReal)); CHKERRQ(ierr);
170
171 // --- Step 5: Calculate Total Cross-Sectional Area and Measure Flux Profile ---
172 PetscReal localArea = 0.0, globalArea = 0.0;
173
174 switch (drivenDirection) {
175 case 'X':
176 if (info.xs == 0) { // Area is calculated by rank(s) on the negative face
177 i = 0;
178 for (k = lzs; k < lze; k++) for (j = lys; j < lye; j++) {
179 if (nvert[k][j][i + 1] < 0.1)
180 localArea += sqrt(csi[k][j][i].x*csi[k][j][i].x + csi[k][j][i].y*csi[k][j][i].y + csi[k][j][i].z*csi[k][j][i].z);
181 }
182 }
183 for (i = info.xs; i < lxe; i++) {
184 for (k = lzs; k < lze; k++) for (j = lys; j < lye; j++) {
185 if (nvert[k][j][i + 1] < 0.1) localFluxProfile[i] += ucont[k][j][i].x;
186 }
187 }
188 break;
189 case 'Y':
190 if (info.ys == 0) {
191 j = 0;
192 for (k = lzs; k < lze; k++) for (i = lxs; i < lxe; i++) {
193 if (nvert[k][j + 1][i] < 0.1)
194 localArea += sqrt(eta[k][j][i].x*eta[k][j][i].x + eta[k][j][i].y*eta[k][j][i].y + eta[k][j][i].z*eta[k][j][i].z);
195 }
196 }
197 for (j = info.ys; j < lye; j++) {
198 for (k = lzs; k < lze; k++) for (i = lxs; i < lxe; i++) {
199 if (nvert[k][j + 1][i] < 0.1) localFluxProfile[j] += ucont[k][j][i].y;
200 }
201 }
202 break;
203 case 'Z':
204 if (info.zs == 0) {
205 k = 0;
206 for (j = lys; j < lye; j++) for (i = lxs; i < lxe; i++) {
207 if (nvert[k + 1][j][i] < 0.1)
208 localArea += sqrt(zet[k][j][i].x*zet[k][j][i].x + zet[k][j][i].y*zet[k][j][i].y + zet[k][j][i].z*zet[k][j][i].z);
209 }
210 }
211 for (k = info.zs; k < lze; k++) {
212 for (j = lys; j < lye; j++) for (i = lxs; i < lxe; i++) {
213 if (nvert[k + 1][j][i] < 0.1) localFluxProfile[k] += ucont[k][j][i].z;
214 }
215 }
216 break;
217 }
218
219 ierr = MPI_Allreduce(&localArea, &globalArea, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
220 ierr = MPI_Allreduce(localFluxProfile, globalFluxProfile, n_planes, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
221
222 // --- Step 6: Calculate Correction Profile ---
223 PetscReal targetFlux = simCtx->targetVolumetricFlux;
224 if (globalArea > 1.0e-12) {
225 for (i = 0; i < n_planes; i++) {
226 correctionProfile[i] = (targetFlux - globalFluxProfile[i]) / globalArea;
227 }
228 } else {
229 ierr = PetscMemzero(correctionProfile, n_planes * sizeof(PetscReal)); CHKERRQ(ierr);
230 }
231
232 LOG_ALLOW(GLOBAL, LOG_INFO, "Channel Flux Profile Corrector Update (Dir %c):\n", drivenDirection);
233 LOG_ALLOW(GLOBAL, LOG_INFO, " - Target Flux for all planes: %.6e\n", targetFlux);
234 LOG_ALLOW(GLOBAL, LOG_INFO, " - Measured Flux at plane 0: %.6e (Correction Velocity: %.6e)\n", globalFluxProfile[0], correctionProfile[0]);
235 LOG_ALLOW(GLOBAL, LOG_INFO, " - Measured Flux at plane %d: %.6e (Correction Velocity: %.6e)\n", (n_planes-1)/2, globalFluxProfile[(n_planes-1)/2], correctionProfile[(n_planes-1)/2]);
236
237 /* TURNED OFF IN LEGACY
238 // --- Step 7: Apply Correction to Velocity Profile ---
239 switch (drivenDirection) {
240 case 'X':
241 for (i = info.xs; i < info.xs + info.xm - 1; i++) {
242 if (PetscAbs(correctionProfile[i]) > 1e-12) {
243 for (k = lzs; k < lze; k++) for (j = lys; j < lye; j++) {
244 if (nvert[k][j][i] < 0.1) {
245 PetscReal faceArea = sqrt(csi[k][j][i].x*csi[k][j][i].x + csi[k][j][i].y*csi[k][j][i].y + csi[k][j][i].z*csi[k][j][i].z);
246 ucont[k][j][i].x += correctionProfile[i] * faceArea;
247 }
248 }
249 }
250 }
251 break;
252 case 'Y':
253 for (j = info.ys; j < info.ys + info.ym - 1; j++) {
254 if (PetscAbs(correctionProfile[j]) > 1e-12) {
255 for (k = lzs; k < lze; k++) for (i = lxs; i < lxe; i++) {
256 if (nvert[k][j][i] < 0.1) {
257 PetscReal faceArea = sqrt(eta[k][j][i].x*eta[k][j][i].x + eta[k][j][i].y*eta[k][j][i].y + eta[k][j][i].z*eta[k][j][i].z);
258 ucont[k][j][i].y += correctionProfile[j] * faceArea;
259 }
260 }
261 }
262 }
263 break;
264 case 'Z':
265 for (k = info.zs; k < info.zs + info.zm - 1; k++) {
266 if (PetscAbs(correctionProfile[k]) > 1e-12) {
267 for (j = lys; j < lye; j++) for (i = lxs; i < lxe; i++) {
268 if (nvert[k][j][i] < 0.1) {
269 PetscReal faceArea = sqrt(zet[k][j][i].x*zet[k][j][i].x + zet[k][j][i].y*zet[k][j][i].y + zet[k][j][i].z*zet[k][j][i].z);
270 ucont[k][j][i].z += correctionProfile[k] * faceArea;
271 }
272 }
273 }
274 }
275 break;
276 }
277 */
278
279 // --- Step 8: Cleanup and Restore ---
280 ierr = PetscFree(localFluxProfile); CHKERRQ(ierr);
281 ierr = PetscFree(globalFluxProfile); CHKERRQ(ierr);
282 ierr = PetscFree(correctionProfile); CHKERRQ(ierr);
283
284 ierr = DMDAVecRestoreArray(user->fda, user->lUcont, &ucont); CHKERRQ(ierr);
285 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, (const Cmpnts***)&csi); CHKERRQ(ierr);
286 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, (const Cmpnts***)&eta); CHKERRQ(ierr);
287 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, (const Cmpnts***)&zet); CHKERRQ(ierr);
288 ierr = DMDAVecRestoreArrayRead(user->da, user->lNvert, (const PetscReal***)&nvert); CHKERRQ(ierr);
289
290 //LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d, Block %d: Channel flux profile correction complete.\n",
291 // simCtx->rank, user->_this);
292
293 PetscFunctionReturn(0);
294}
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:199
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:31
PetscMPIInt rank
Definition variables.h:646
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:829
PetscReal targetVolumetricFlux
Definition variables.h:724
Vec lNvert
Definition variables.h:837
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:814
Vec lZet
Definition variables.h:858
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:271
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:287
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:286
BCHandlerType handler_type
Definition variables.h:337
PetscInt _this
Definition variables.h:824
PetscScalar x
Definition variables.h:101
Vec lCsi
Definition variables.h:858
PetscScalar z
Definition variables.h:101
Vec lUcont
Definition variables.h:837
PetscScalar y
Definition variables.h:101
Vec lEta
Definition variables.h:858
@ BC_FACE_NEG_X
Definition variables.h:245
@ BC_FACE_POS_Z
Definition variables.h:247
@ BC_FACE_POS_Y
Definition variables.h:246
@ BC_FACE_NEG_Z
Definition variables.h:247
@ BC_FACE_POS_X
Definition variables.h:245
@ BC_FACE_NEG_Y
Definition variables.h:246
A 3D point or vector with PetscScalar components.
Definition variables.h:100
The master context for the entire simulation.
Definition variables.h:643
Here is the caller graph for this function:

◆ Projection()

PetscErrorCode Projection ( UserCtx user)

Implementation of Projection().

Corrects the contravariant velocity field Ucont to be divergence-free using the gradient of the pressure correction field Phi.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
Projection()

Definition at line 328 of file poisson.c.

329{
330 PetscFunctionBeginUser;
332 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Entering Projection step to correct velocity field.\n");
333
334 //================================================================================
335 // Section 1: Initialization and Data Acquisition
336 //================================================================================
337
338 // --- Get simulation and grid context ---
339 SimCtx *simCtx = user->simCtx;
340 DM da = user->da, fda = user->fda;
341 DMDALocalInfo info = user->info;
342
343 // --- Grid dimensions ---
344 PetscInt mx = info.mx, my = info.my, mz = info.mz;
345 PetscInt xs = info.xs, xe = info.xs + info.xm;
346 PetscInt ys = info.ys, ye = info.ys + info.ym;
347 PetscInt zs = info.zs, ze = info.zs + info.zm;
348
349 // --- Loop bounds (excluding outer ghost layers) ---
350 PetscInt lxs = (xs == 0) ? xs + 1 : xs;
351 PetscInt lxe = (xe == mx) ? xe - 1 : xe;
352 PetscInt lys = (ys == 0) ? ys + 1 : ys;
353 PetscInt lye = (ye == my) ? ye - 1 : ye;
354 PetscInt lzs = (zs == 0) ? zs + 1 : zs;
355 PetscInt lze = (ze == mz) ? ze - 1 : ze;
356
357 // --- Get direct pointer access to grid metric and field data ---
358 Cmpnts ***icsi, ***ieta, ***izet, ***jcsi, ***jeta, ***jzet, ***kcsi, ***keta, ***kzet;
359 PetscReal ***iaj, ***jaj, ***kaj, ***p, ***nvert;
360 Cmpnts ***ucont;
361 DMDAVecGetArray(fda, user->lICsi, &icsi); DMDAVecGetArray(fda, user->lIEta, &ieta); DMDAVecGetArray(fda, user->lIZet, &izet);
362 DMDAVecGetArray(fda, user->lJCsi, &jcsi); DMDAVecGetArray(fda, user->lJEta, &jeta); DMDAVecGetArray(fda, user->lJZet, &jzet);
363 DMDAVecGetArray(fda, user->lKCsi, &kcsi); DMDAVecGetArray(fda, user->lKEta, &keta); DMDAVecGetArray(fda, user->lKZet, &kzet);
364 DMDAVecGetArray(da, user->lIAj, &iaj); DMDAVecGetArray(da, user->lJAj, &jaj); DMDAVecGetArray(da, user->lKAj, &kaj);
365 DMDAVecGetArray(da, user->lNvert, &nvert);
366 DMDAVecGetArray(da, user->lPhi, &p); // Note: using lPhi, which is the pressure correction
367 //DMDAVecGetArray(da,user->lP,&p);
368 DMDAVecGetArray(fda, user->Ucont, &ucont);
369
370 // --- Constants for clarity ---
371 const PetscReal IBM_FLUID_THRESHOLD = 0.1;
372 const PetscReal scale = simCtx->dt * 1.0 / COEF_TIME_ACCURACY; // simCtx->st replaced by 1.0.
373
374 LOG_ALLOW(GLOBAL,LOG_DEBUG," Starting velocity correction: Scale = %le .\n",scale);
375
376 //================================================================================
377 // Section 2: Correct Velocity Components
378 //================================================================================
379 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Calculating pressure gradients and correcting velocity components.\n");
380
381 // --- Main loop over interior domain points ---
382 for (PetscInt k = lzs; k < lze; k++) {
383 for (PetscInt j = lys; j < lye; j++) {
384 for (PetscInt i = lxs; i < lxe; i++) {
385
386 // --- Correct U_contravariant (x-component of velocity) ---
387 PetscInt i_end = (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC) ? mx - 1 : mx - 2;
388 if (i < i_end) {
389
390 if (!(nvert[k][j][i] > IBM_FLUID_THRESHOLD || nvert[k][j][i + 1] > IBM_FLUID_THRESHOLD)) {
391 // Compute pressure derivatives (dp/d_csi, dp/d_eta, dp/d_zet) at the i-face
392
393 PetscReal dpdc = p[k][j][i + 1] - p[k][j][i];
394 PetscReal dpde = 0.0, dpdz = 0.0;
395
396 // Boundary-aware stencil for dp/d_eta
397 if ((j==my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j+1][i]+nvert[k][j+1][i+1] > 0.1) {
398 if (nvert[k][j-1][i] + nvert[k][j-1][i+1] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) {
399 dpde = (p[k][j][i] + p[k][j][i+1] -
400 p[k][j-1][i] - p[k][j-1][i+1]) * 0.5;
401 }
402 }
403
404 else if ((j==my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i]+nvert[k][j+1][i+1] > 0.1) {
405 if (nvert[k][j-1][i] + nvert[k][j-1][i+1] < 0.1) { dpde = (p[k][j][i] + p[k][j][i+1] - p[k][j-1][i] - p[k][j-1][i+1]) * 0.5; }
406 }
407
408 else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) || nvert[k][j-1][i] + nvert[k][j-1][i+1] > 0.1) {
409 if (nvert[k][j+1][i] + nvert[k][j+1][i+1] < 0.1) { dpde = (p[k][j+1][i] + p[k][j+1][i+1] - p[k][j][i] - p[k][j][i+1]) * 0.5; }
410 }
411
412 else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k][j-1][i+1] > 0.1) {
413 if (nvert[k][j+1][i] + nvert[k][j+1][i+1] < 0.1) { dpde = (p[k][j+1][i] + p[k][j+1][i+1] - p[k][j][i] - p[k][j][i+1]) * 0.5; }
414 }
415
416 else { dpde = (p[k][j+1][i] + p[k][j+1][i+1] - p[k][j-1][i] - p[k][j-1][i+1]) * 0.25; }
417
418 // Boundary-aware stencil for dp/d_zet
419 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) || nvert[k+1][j][i] + nvert[k+1][j][i+1] > 0.1) {
420 if (nvert[k-1][j][i] + nvert[k-1][j][i+1] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) { dpdz = (p[k][j][i] + p[k][j][i+1] - p[k-1][j][i] - p[k-1][j][i+1]) * 0.5; }
421 }
422
423 else if ((k == mz-2 || k==1) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j][i+1] > 0.1) {
424 if (nvert[k-1][j][i] + nvert[k-1][j][i+1] < 0.1) { dpdz = (p[k][j][i] + p[k][j][i+1] - p[k-1][j][i] - p[k-1][j][i+1]) * 0.5; }
425 }
426
427 else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k-1][j][i] + nvert[k-1][j][i+1] > 0.1) {
428 if (nvert[k+1][j][i] + nvert[k+1][j][i+1] < 0.1) { dpdz = (p[k+1][j][i] + p[k+1][j][i+1] - p[k][j][i] - p[k][j][i+1]) * 0.5; }
429 }
430
431 else if ((k == 1 || k==mz-2) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j][i+1] > 0.1) {
432 if (nvert[k+1][j][i] + nvert[k+1][j][i+1] < 0.1) { dpdz = (p[k+1][j][i] + p[k+1][j][i+1] - p[k][j][i] - p[k][j][i+1]) * 0.5; }
433 }
434
435 else { dpdz = (p[k+1][j][i] + p[k+1][j][i+1] - p[k-1][j][i] - p[k-1][j][i+1]) * 0.25; }
436
437 // Apply the correction: U_new = U_old - dt * (g11*dpdc + g12*dpde + g13*dpdz)
438
439
440
441 PetscReal grad_p_x = (dpdc * (icsi[k][j][i].x * icsi[k][j][i].x + icsi[k][j][i].y * icsi[k][j][i].y
442 + icsi[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i] +
443 dpde * (ieta[k][j][i].x * icsi[k][j][i].x + ieta[k][j][i].y * icsi[k][j][i].y
444 + ieta[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i] +
445 dpdz * (izet[k][j][i].x * icsi[k][j][i].x + izet[k][j][i].y * icsi[k][j][i].y
446 + izet[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i]);
447
448 PetscReal correction = grad_p_x*scale;
449 //LOG_LOOP_ALLOW_EXACT(GLOBAL,LOG_DEBUG,k,5," Flux correction in Csi Direction: %le.\n",correction);
450 ucont[k][j][i].x -= correction;
451
452 }
453 }
454
455 // --- Correct V_contravariant (y-component of velocity) ---
456 PetscInt j_end = (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC) ? my - 1 : my - 2;
457 if (j < j_end) {
458 if (!(nvert[k][j][i] > IBM_FLUID_THRESHOLD || nvert[k][j + 1][i] > IBM_FLUID_THRESHOLD)) {
459 PetscReal dpdc = 0.0, dpde = 0.0, dpdz = 0.0;
460 dpde = p[k][j + 1][i] - p[k][j][i];
461
462 // Boundary-aware stencil for dp/d_csi
463 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) || nvert[k][j][i+1] + nvert[k][j+1][i+1] > 0.1) {
464 if (nvert[k][j][i-1] + nvert[k][j+1][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) { dpdc = (p[k][j][i] + p[k][j+1][i] - p[k][j][i-1] - p[k][j+1][i-1]) * 0.5; }
465 } else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k][j+1][i+1] > 0.1) {
466 if (nvert[k][j][i-1] + nvert[k][j+1][i-1] < 0.1) { dpdc = (p[k][j][i] + p[k][j+1][i] - p[k][j][i-1] - p[k][j+1][i-1]) * 0.5; }
467 } else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i-1] + nvert[k][j+1][i-1] > 0.1) {
468 if (nvert[k][j][i+1] + nvert[k][j+1][i+1] < 0.1) { dpdc = (p[k][j][i+1] + p[k][j+1][i+1] - p[k][j][i] - p[k][j+1][i]) * 0.5; }
469 } else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k][j+1][i-1] > 0.1) {
470 if (nvert[k][j][i+1] + nvert[k][j+1][i+1] < 0.1) { dpdc = (p[k][j][i+1] + p[k][j+1][i+1] - p[k][j][i] - p[k][j+1][i]) * 0.5; }
471 } else { dpdc = (p[k][j][i+1] + p[k][j+1][i+1] - p[k][j][i-1] - p[k][j+1][i-1]) * 0.25; }
472
473 // Boundary-aware stencil for dp/d_zet
474 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k+1][j][i] + nvert[k+1][j+1][i] > 0.1) {
475 if (nvert[k-1][j][i] + nvert[k-1][j+1][i] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) { dpdz = (p[k][j][i] + p[k][j+1][i] - p[k-1][j][i] - p[k-1][j+1][i]) * 0.5; }
476 } else if ((k == mz-2 || k==1 ) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j+1][i] > 0.1) {
477 if (nvert[k-1][j][i] + nvert[k-1][j+1][i] < 0.1) { dpdz = (p[k][j][i] + p[k][j+1][i] - p[k-1][j][i] - p[k-1][j+1][i]) * 0.5; }
478 } else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k-1][j][i] + nvert[k-1][j+1][i] > 0.1) {
479 if (nvert[k+1][j][i] + nvert[k+1][j+1][i] < 0.1) { dpdz = (p[k+1][j][i] + p[k+1][j+1][i] - p[k][j][i] - p[k][j+1][i]) * 0.5; }
480 } else if ((k == 1 || k==mz-2) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j+1][i] > 0.1) {
481 if (nvert[k+1][j][i] + nvert[k+1][j+1][i] < 0.1) { dpdz = (p[k+1][j][i] + p[k+1][j+1][i] - p[k][j][i] - p[k][j+1][i]) * 0.5; }
482 } else { dpdz = (p[k+1][j][i] + p[k+1][j+1][i] - p[k-1][j][i] - p[k-1][j+1][i]) * 0.25; }
483
484 PetscReal grad_p_y = (dpdc * (jcsi[k][j][i].x * jeta[k][j][i].x + jcsi[k][j][i].y * jeta[k][j][i].y + jcsi[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i] +
485 dpde * (jeta[k][j][i].x * jeta[k][j][i].x + jeta[k][j][i].y * jeta[k][j][i].y + jeta[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i] +
486 dpdz * (jzet[k][j][i].x * jeta[k][j][i].x + jzet[k][j][i].y * jeta[k][j][i].y + jzet[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i]);
487
488 PetscReal correction = grad_p_y*scale;
489 //LOG_LOOP_ALLOW_EXACT(GLOBAL,LOG_DEBUG,k,5," Flux correction in Eta Direction: %le.\n",correction);
490 ucont[k][j][i].y -= correction;
491 }
492 }
493
494 // --- Correct W_contravariant (z-component of velocity) ---
495 PetscInt k_end = (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC) ? mz - 1 : mz - 2;
496 if (k < k_end) {
497 if (!(nvert[k][j][i] > IBM_FLUID_THRESHOLD || nvert[k + 1][j][i] > IBM_FLUID_THRESHOLD)) {
498 PetscReal dpdc = 0.0, dpde = 0.0, dpdz = 0.0;
499 dpdz = p[k + 1][j][i] - p[k][j][i];
500
501 // Boundary-aware stencil for dp/d_csi
502 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i+1] + nvert[k+1][j][i+1] > 0.1) {
503 if (nvert[k][j][i-1] + nvert[k+1][j][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) { dpdc = (p[k][j][i] + p[k+1][j][i] - p[k][j][i-1] - p[k+1][j][i-1]) * 0.5; }
504 } else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k+1][j][i+1] > 0.1) {
505 if (nvert[k][j][i-1] + nvert[k+1][j][i-1] < 0.1) { dpdc = (p[k][j][i] + p[k+1][j][i] - p[k][j][i-1] - p[k+1][j][i-1]) * 0.5; }
506 } else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i-1] + nvert[k+1][j][i-1] > 0.1) {
507 if (nvert[k][j][i+1] + nvert[k+1][j][i+1] < 0.1) { dpdc = (p[k][j][i+1] + p[k+1][j][i+1] - p[k][j][i] - p[k+1][j][i]) * 0.5; }
508 } else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k+1][j][i-1] > 0.1) {
509 if (nvert[k][j][i+1] + nvert[k+1][j][i+1] < 0.1) { dpdc = (p[k][j][i+1] + p[k+1][j][i+1] - p[k][j][i] - p[k+1][j][i]) * 0.5; }
510 } else { dpdc = (p[k][j][i+1] + p[k+1][j][i+1] - p[k][j][i-1] - p[k+1][j][i-1]) * 0.25; }
511
512 // Boundary-aware stencil for dp/d_eta
513 if ((j == my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j+1][i] + nvert[k+1][j+1][i] > 0.1) {
514 if (nvert[k][j-1][i] + nvert[k+1][j-1][i] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) { dpde = (p[k][j][i] + p[k+1][j][i] - p[k][j-1][i] - p[k+1][j-1][i]) * 0.5; }
515 } else if ((j == my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i] + nvert[k+1][j+1][i] > 0.1) {
516 if (nvert[k][j-1][i] + nvert[k+1][j-1][i] < 0.1) { dpde = (p[k][j][i] + p[k+1][j][i] - p[k][j-1][i] - p[k+1][j-1][i]) * 0.5; }
517 } else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j-1][i] + nvert[k+1][j-1][i] > 0.1) {
518 if (nvert[k][j+1][i] + nvert[k+1][j+1][i] < 0.1) { dpde = (p[k][j+1][i] + p[k+1][j+1][i] - p[k][j][i] - p[k+1][j][i]) * 0.5; }
519 } else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k+1][j-1][i] > 0.1) {
520 if (nvert[k][j+1][i] + nvert[k+1][j+1][i] < 0.1) { dpde = (p[k][j+1][i] + p[k+1][j+1][i] - p[k][j][i] - p[k+1][j][i]) * 0.5; }
521 } else { dpde = (p[k][j+1][i] + p[k+1][j+1][i] - p[k][j-1][i] - p[k+1][j-1][i]) * 0.25; }
522
523 PetscReal grad_p_z = (dpdc * (kcsi[k][j][i].x * kzet[k][j][i].x + kcsi[k][j][i].y * kzet[k][j][i].y + kcsi[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i] +
524 dpde * (keta[k][j][i].x * kzet[k][j][i].x + keta[k][j][i].y * kzet[k][j][i].y + keta[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i] +
525 dpdz * (kzet[k][j][i].x * kzet[k][j][i].x + kzet[k][j][i].y * kzet[k][j][i].y + kzet[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i]);
526
527 // ========================= DEBUG PRINT =========================
529 "[k=%d, j=%d, i=%d] ---- Neighbor Pressures ----\n"
530 " Central Z-Neighbors: p[k+1][j][i] = %g | p[k][j][i] = %g\n"
531 " Eta-Stencil (Y-dir): p[k][j-1][i] = %g, p[k+1][j-1][i] = %g | p[k][j+1][i] = %g, p[k+1][j+1][i] = %g\n"
532 " Csi-Stencil (X-dir): p[k][j][i-1] = %g, p[k+1][j][i-1] = %g | p[k][j][i+1] = %g, p[k+1][j][i+1] = %g\n",
533 k, j, i,
534 p[k + 1][j][i], p[k][j][i],
535 p[k][j - 1][i], p[k + 1][j - 1][i], p[k][j + 1][i], p[k + 1][j + 1][i],
536 p[k][j][i - 1], p[k + 1][j][i - 1], p[k][j][i + 1], p[k + 1][j][i + 1]);
537 // ======================= END DEBUG PRINT =======================
538
539 LOG_LOOP_ALLOW_EXACT(GLOBAL,LOG_DEBUG,k,5," dpdc: %le | dpde: %le | dpdz: %le.\n",dpdc,dpde,dpdz);
540 PetscReal correction = grad_p_z*scale;
541 //LOG_LOOP_ALLOW_EXACT(GLOBAL,LOG_DEBUG,k,5," Flux correction in Zet Direction: %le.\n",correction);
542 ucont[k][j][i].z -= correction;
543 }
544 }
545 }
546 }
547 }
548
549 // --- Explicit correction for periodic boundaries (if necessary) ---
550 // The main loop handles the interior, but this handles the first physical layer at periodic boundaries.
551 // Note: This logic is largely duplicated from the main loop and could be merged, but is preserved for fidelity.
552 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && xs == 0) {
553 for (PetscInt k=lzs; k<lze; k++) {
554 for (PetscInt j=lys; j<lye; j++) {
555 PetscInt i=xs;
556
557 PetscReal dpdc = p[k][j][i+1] - p[k][j][i];
558
559 PetscReal dpde = 0.;
560 PetscReal dpdz = 0.;
561
562 if ((j==my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j+1][i]+nvert[k][j+1][i+1] > 0.1) {
563 if (nvert[k][j-1][i] + nvert[k][j-1][i+1] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) {
564 dpde = (p[k][j ][i] + p[k][j ][i+1] -
565 p[k][j-1][i] - p[k][j-1][i+1]) * 0.5;
566 }
567 }
568 else if ((j==my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i]+nvert[k][j+1][i+1] > 0.1) {
569 if (nvert[k][j-1][i] + nvert[k][j-1][i+1] < 0.1) {
570 dpde = (p[k][j ][i] + p[k][j ][i+1] -
571 p[k][j-1][i] - p[k][j-1][i+1]) * 0.5;
572 }
573 }
574 else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) || nvert[k][j-1][i] + nvert[k][j-1][i+1] > 0.1) {
575 if (nvert[k][j+1][i] + nvert[k][j+1][i+1] < 0.1) {
576 dpde = (p[k][j+1][i] + p[k][j+1][i+1] -
577 p[k][j ][i] - p[k][j ][i+1]) * 0.5;
578 }
579 }
580 else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k][j-1][i+1] > 0.1) {
581 if (nvert[k][j+1][i] + nvert[k][j+1][i+1] < 0.1) {
582 dpde = (p[k][j+1][i] + p[k][j+1][i+1] -
583 p[k][j ][i] - p[k][j ][i+1]) * 0.5;
584 }
585 }
586 else {
587 dpde = (p[k][j+1][i] + p[k][j+1][i+1] -
588 p[k][j-1][i] - p[k][j-1][i+1]) * 0.25;
589 }
590
591 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) || nvert[k+1][j][i] + nvert[k+1][j][i+1] > 0.1) {
592 if (nvert[k-1][j][i] + nvert[k-1][j][i+1] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) {
593 dpdz = (p[k ][j][i] + p[k ][j][i+1] -
594 p[k-1][j][i] - p[k-1][j][i+1]) * 0.5;
595 }
596 }
597 else if ((k == mz-2 || k==1) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j][i+1] > 0.1) {
598 if (nvert[k-1][j][i] + nvert[k-1][j][i+1] < 0.1) {
599 dpdz = (p[k ][j][i] + p[k ][j][i+1] -
600 p[k-1][j][i] - p[k-1][j][i+1]) * 0.5;
601 }
602 }
603 else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k-1][j][i] + nvert[k-1][j][i+1] > 0.1) {
604 if (nvert[k+1][j][i] + nvert[k+1][j][i+1] < 0.1) {
605 dpdz = (p[k+1][j][i] + p[k+1][j][i+1] -
606 p[k ][j][i] - p[k ][j][i+1]) * 0.5;
607 }
608 }
609 else if ((k == 1 || k==mz-2) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j][i+1] > 0.1) {
610 if (nvert[k+1][j][i] + nvert[k+1][j][i+1] < 0.1) {
611 dpdz = (p[k+1][j][i] + p[k+1][j][i+1] -
612 p[k ][j][i] - p[k ][j][i+1]) * 0.5;
613 }
614 }
615 else {
616 dpdz = (p[k+1][j][i] + p[k+1][j][i+1] -
617 p[k-1][j][i] - p[k-1][j][i+1]) * 0.25;
618 }
619
620
621
622 if (!(nvert[k][j][i] + nvert[k][j][i+1])) {
623 ucont[k][j][i].x -=
624 (dpdc * (icsi[k][j][i].x * icsi[k][j][i].x +
625 icsi[k][j][i].y * icsi[k][j][i].y +
626 icsi[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i] +
627 dpde * (ieta[k][j][i].x * icsi[k][j][i].x +
628 ieta[k][j][i].y * icsi[k][j][i].y +
629 ieta[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i] +
630 dpdz * (izet[k][j][i].x * icsi[k][j][i].x +
631 izet[k][j][i].y * icsi[k][j][i].y +
632 izet[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i])
633 * scale;
634
635 }
636 }
637 }
638 }
639 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && ys == 0) {
640
641 for (PetscInt k=lzs; k<lze; k++) {
642 for (PetscInt i=lxs; i<lxe; i++) {
643 PetscInt j=ys;
644
645 PetscReal dpdc = 0.;
646 PetscReal dpdz = 0.;
647 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) || nvert[k][j][i+1] + nvert[k][j+1][i+1] > 0.1) {
648 if (nvert[k][j][i-1] + nvert[k][j+1][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) {
649 dpdc = (p[k][j][i ] + p[k][j+1][i ] -
650 p[k][j][i-1] - p[k][j+1][i-1]) * 0.5;
651 }
652 }
653 else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k][j+1][i+1] > 0.1) {
654 if (nvert[k][j][i-1] + nvert[k][j+1][i-1] < 0.1) {
655 dpdc = (p[k][j][i ] + p[k][j+1][i ] -
656 p[k][j][i-1] - p[k][j+1][i-1]) * 0.5;
657 }
658 }
659 else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i-1] + nvert[k][j+1][i-1] > 0.1) {
660 if (nvert[k][j][i+1] + nvert[k][j+1][i+1] < 0.1) {
661 dpdc = (p[k][j][i+1] + p[k][j+1][i+1] -
662 p[k][j][i ] - p[k][j+1][i ]) * 0.5;
663 }
664 }
665 else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k][j+1][i-1] > 0.1) {
666 if (nvert[k][j][i+1] + nvert[k][j+1][i+1] < 0.1) {
667 dpdc = (p[k][j][i+1] + p[k][j+1][i+1] -
668 p[k][j][i ] - p[k][j+1][i ]) * 0.5;
669 }
670 }
671 else {
672 dpdc = (p[k][j][i+1] + p[k][j+1][i+1] -
673 p[k][j][i-1] - p[k][j+1][i-1]) * 0.25;
674 }
675
676 PetscReal dpde = p[k][j+1][i] - p[k][j][i];
677
678 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k+1][j][i] + nvert[k+1][j+1][i] > 0.1) {
679 if (nvert[k-1][j][i] + nvert[k-1][j+1][i] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) {
680 dpdz = (p[k ][j][i] + p[k ][j+1][i] -
681 p[k-1][j][i] - p[k-1][j+1][i]) * 0.5;
682 }
683 }
684 else if ((k == mz-2 || k==1 ) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j+1][i] > 0.1) {
685 if (nvert[k-1][j][i] + nvert[k-1][j+1][i] < 0.1) {
686 dpdz = (p[k ][j][i] + p[k ][j+1][i] -
687 p[k-1][j][i] - p[k-1][j+1][i]) * 0.5;
688 }
689 }
690 else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k-1][j][i] + nvert[k-1][j+1][i] > 0.1) {
691 if (nvert[k+1][j][i] + nvert[k+1][j+1][i] < 0.1) {
692 dpdz = (p[k+1][j][i] + p[k+1][j+1][i] -
693 p[k ][j][i] - p[k ][j+1][i]) * 0.5;
694 }
695 }
696 else if ((k == 1 || k==mz-2) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j+1][i] > 0.1) {
697 if (nvert[k+1][j][i] + nvert[k+1][j+1][i] < 0.1) {
698 dpdz = (p[k+1][j][i] + p[k+1][j+1][i] -
699 p[k ][j][i] - p[k ][j+1][i]) * 0.5;
700 }
701 }
702 else {
703 dpdz = (p[k+1][j][i] + p[k+1][j+1][i] -
704 p[k-1][j][i] - p[k-1][j+1][i]) * 0.25;
705 }
706
707 if (!(nvert[k][j][i] + nvert[k][j+1][i])) {
708 ucont[k][j][i].y -=
709 (dpdc * (jcsi[k][j][i].x * jeta[k][j][i].x +
710 jcsi[k][j][i].y * jeta[k][j][i].y +
711 jcsi[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i] +
712 dpde * (jeta[k][j][i].x * jeta[k][j][i].x +
713 jeta[k][j][i].y * jeta[k][j][i].y +
714 jeta[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i] +
715 dpdz * (jzet[k][j][i].x * jeta[k][j][i].x +
716 jzet[k][j][i].y * jeta[k][j][i].y +
717 jzet[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i])
718 * scale;
719 }
720 }
721 }
722 }
723
724 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && zs == 0) {
725 for (PetscInt j=lys; j<lye; j++) {
726 for (PetscInt i=lxs; i<lxe; i++) {
727
728 PetscInt k=zs;
729 PetscReal dpdc = 0.;
730 PetscReal dpde = 0.;
731
732 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i+1] + nvert[k+1][j][i+1] > 0.1) {
733 if (nvert[k][j][i-1] + nvert[k+1][j][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) {
734 dpdc = (p[k][j][i ] + p[k+1][j][i ] -
735 p[k][j][i-1] - p[k+1][j][i-1]) * 0.5;
736 }
737 }
738 else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k+1][j][i+1] > 0.1) {
739 if (nvert[k][j][i-1] + nvert[k+1][j][i-1] < 0.1) {
740 dpdc = (p[k][j][i ] + p[k+1][j][i ] -
741 p[k][j][i-1] - p[k+1][j][i-1]) * 0.5;
742 }
743 }
744 else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i-1] + nvert[k+1][j][i-1] > 0.1) {
745 if (nvert[k][j][i+1] + nvert[k+1][j][i+1] < 0.1) {
746 dpdc = (p[k][j][i+1] + p[k+1][j][i+1] -
747 p[k][j][i ] - p[k+1][j][i ]) * 0.5;
748 }
749 }
750 else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k+1][j][i-1] > 0.1) {
751 if (nvert[k][j][i+1] + nvert[k+1][j][i+1] < 0.1) {
752 dpdc = (p[k][j][i+1] + p[k+1][j][i+1] -
753 p[k][j][i ] - p[k+1][j][i ]) * 0.5;
754 }
755 }
756 else {
757 dpdc = (p[k][j][i+1] + p[k+1][j][i+1] -
758 p[k][j][i-1] - p[k+1][j][i-1]) * 0.25;
759 }
760
761 if ((j == my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j+1][i] + nvert[k+1][j+1][i] > 0.1) {
762 if (nvert[k][j-1][i] + nvert[k+1][j-1][i] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) {
763 dpde = (p[k][j ][i] + p[k+1][j ][i] -
764 p[k][j-1][i] - p[k+1][j-1][i]) * 0.5;
765 }
766 }
767 else if ((j == my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i] + nvert[k+1][j+1][i] > 0.1) {
768 if (nvert[k][j-1][i] + nvert[k+1][j-1][i] < 0.1) {
769 dpde = (p[k][j ][i] + p[k+1][j ][i] -
770 p[k][j-1][i] - p[k+1][j-1][i]) * 0.5;
771 }
772 }
773 else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j-1][i] + nvert[k+1][j-1][i] > 0.1) {
774 if (nvert[k][j+1][i] + nvert[k+1][j+1][i] < 0.1) {
775 dpde = (p[k][j+1][i] + p[k+1][j+1][i] -
776 p[k][j ][i] - p[k+1][j ][i]) * 0.5;
777 }
778 }
779 else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k+1][j-1][i] > 0.1) {
780 if (nvert[k][j+1][i] + nvert[k+1][j+1][i] < 0.1) {
781 dpde = (p[k][j+1][i] + p[k+1][j+1][i] -
782 p[k][j ][i] - p[k+1][j ][i]) * 0.5;
783 }
784 }
785 else {
786 dpde = (p[k][j+1][i] + p[k+1][j+1][i] -
787 p[k][j-1][i] - p[k+1][j-1][i]) * 0.25;
788 }
789
790 PetscReal dpdz = p[k+1][j][i] - p[k][j][i];
791
792 if (!(nvert[k][j][i] + nvert[k+1][j][i])) {
793
794 ucont[k][j][i].z -=
795 (dpdc * (kcsi[k][j][i].x * kzet[k][j][i].x +
796 kcsi[k][j][i].y * kzet[k][j][i].y +
797 kcsi[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i] +
798 dpde * (keta[k][j][i].x * kzet[k][j][i].x +
799 keta[k][j][i].y * kzet[k][j][i].y +
800 keta[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i] +
801 dpdz * (kzet[k][j][i].x * kzet[k][j][i].x +
802 kzet[k][j][i].y * kzet[k][j][i].y +
803 kzet[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i])
804 * scale;
805
806 }
807 }
808 }
809 }
810
811 // Corrects Flux Profile for Driven Flows if applicable.
813
814 //================================================================================
815 // Section 3: Finalization and Cleanup
816 //================================================================================
817
818 // --- Restore access to all PETSc vector arrays ---
819 DMDAVecRestoreArray(fda, user->Ucont, &ucont);
820 // DMDAVecRestoreArray(fda, user->lCsi, &csi); DMDAVecRestoreArray(fda, user->lEta, &eta); DMDAVecRestoreArray(fda, user->lZet, &zet);
821 //DMDAVecRestoreArray(da, user->lAj, &aj);
822 DMDAVecRestoreArray(fda, user->lICsi, &icsi); DMDAVecRestoreArray(fda, user->lIEta, &ieta); DMDAVecRestoreArray(fda, user->lIZet, &izet);
823 DMDAVecRestoreArray(fda, user->lJCsi, &jcsi); DMDAVecRestoreArray(fda, user->lJEta, &jeta); DMDAVecRestoreArray(fda, user->lJZet, &jzet);
824 DMDAVecRestoreArray(fda, user->lKCsi, &kcsi); DMDAVecRestoreArray(fda, user->lKEta, &keta); DMDAVecRestoreArray(fda, user->lKZet, &kzet);
825 DMDAVecRestoreArray(da, user->lIAj, &iaj); DMDAVecRestoreArray(da, user->lJAj, &jaj); DMDAVecRestoreArray(da, user->lKAj, &kaj);
826 DMDAVecRestoreArray(da, user->lP, &p);
827 DMDAVecRestoreArray(da, user->lNvert, &nvert);
828
829 // --- Update ghost cells for the newly corrected velocity field ---
830 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Updating ghost cells for corrected velocity.\n");
831 DMGlobalToLocalBegin(fda, user->Ucont, INSERT_VALUES, user->lUcont);
832 DMGlobalToLocalEnd(fda, user->Ucont, INSERT_VALUES, user->lUcont);
833
834 // --- Convert velocity to Cartesian and update ghost nodes ---
835 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Converting velocity to Cartesian and finalizing ghost nodes.\n");
836 Contra2Cart(user);
837 UpdateLocalGhosts(user,"Ucat");
839 //GhostNodeVelocity(user);
840
841 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Exiting Projection step.\n");
843 PetscFunctionReturn(0);
844}
PetscErrorCode RefreshBoundaryGhostCells(UserCtx *user)
(Public) Orchestrates the "light" refresh of all boundary ghost cells after the projection step.
#define LOG_LOOP_ALLOW_EXACT(scope, level, var, val, fmt,...)
Logs a custom message if a variable equals a specific value.
Definition logging.h:334
PetscErrorCode CorrectChannelFluxProfile(UserCtx *user)
Internal helper implementation: CorrectChannelFluxProfile().
Definition poisson.c:107
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
Definition setup.c:2247
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1361
@ PERIODIC
Definition variables.h:260
Vec lIEta
Definition variables.h:860
Vec lIZet
Definition variables.h:860
Vec lIAj
Definition variables.h:860
Vec lKEta
Definition variables.h:862
PetscReal dt
Definition variables.h:658
Vec lJCsi
Definition variables.h:861
Vec Ucont
Definition variables.h:837
Vec lPhi
Definition variables.h:837
Vec lKZet
Definition variables.h:862
Vec lJEta
Definition variables.h:861
Vec lKCsi
Definition variables.h:862
Vec lJZet
Definition variables.h:861
Vec lICsi
Definition variables.h:860
BCType mathematical_type
Definition variables.h:336
Vec lJAj
Definition variables.h:861
Vec lKAj
Definition variables.h:862
#define COEF_TIME_ACCURACY
Coefficient controlling the temporal accuracy scheme (e.g., 1.5 for 2nd Order Backward Difference).
Definition variables.h:57
Here is the call graph for this function:
Here is the caller graph for this function:

◆ UpdatePressure()

PetscErrorCode UpdatePressure ( UserCtx user)

Implementation of UpdatePressure().

Updates the pressure field P with the pressure correction Phi computed by the Poisson solver.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
UpdatePressure()

Definition at line 854 of file poisson.c.

855{
856 PetscFunctionBeginUser;
858 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Entering UpdatePressure.\n");
859
860 //================================================================================
861 // Section 1: Initialization and Data Acquisition
862 //================================================================================
863 DM da = user->da;
864 DMDALocalInfo info = user->info;
865
866 // Local grid extents for the main update loop
867 PetscInt xs = info.xs, xe = info.xs + info.xm;
868 PetscInt ys = info.ys, ye = info.ys + info.ym;
869 PetscInt zs = info.zs, ze = info.zs + info.zm;
870 PetscInt mx = info.mx, my = info.my, mz = info.mz;
871
872 PetscInt i,j,k;
873
874 // --- Get direct pointer access to PETSc vector data for performance ---
875 PetscReal ***p, ***phi;
876 DMDAVecGetArray(da, user->P, &p);
877 DMDAVecGetArray(da, user->Phi, &phi);
878
879 //================================================================================
880 // Section 2: Core Pressure Update
881 //================================================================================
882 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Performing core pressure update (P_new = P_old + Phi).\n");
883 for (PetscInt k = zs; k < ze; k++) {
884 for (PetscInt j = ys; j < ye; j++) {
885 for (PetscInt i = xs; i < xe; i++) {
886 // This is the fundamental pressure update in a projection method.
887 p[k][j][i] += phi[k][j][i];
888 }
889 }
890 }
891
892 // Restore arrays now that the core computation is done.
893 DMDAVecRestoreArray(da, user->Phi, &phi);
894 DMDAVecRestoreArray(da, user->P, &p);
895
896
897 //================================================================================
898 // Section 3: Handle Periodic Boundary Condition Synchronization
899 //================================================================================
900 // This block is executed only if at least one boundary is periodic.
901 // The original code contained many redundant Get/Restore and update calls.
902 // This refactored version performs the same effective logic but in a single,
903 // efficient pass, which is numerically equivalent and much cleaner.
907 {
908 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Synchronizing ghost cells for periodic boundaries.\n");
909
910 // First, update the local vectors (including ghost regions) with the new global data.
911 DMGlobalToLocalBegin(da, user->P, INSERT_VALUES, user->lP);
912 DMGlobalToLocalEnd(da, user->P, INSERT_VALUES, user->lP);
913 DMGlobalToLocalBegin(da, user->Phi, INSERT_VALUES, user->lPhi);
914 DMGlobalToLocalEnd(da, user->Phi, INSERT_VALUES, user->lPhi);
915
916 // Get pointers to all necessary local and global arrays ONCE.
917 PetscReal ***lp, ***lphi;
918 DMDAVecGetArray(da, user->lP, &lp);
919 DMDAVecGetArray(da, user->lPhi, &lphi);
920 DMDAVecGetArray(da, user->P, &p);
921 DMDAVecGetArray(da, user->Phi, &phi);
922
923 // --- X-Direction Periodic Update ---
925 // Update left boundary physical cells from right boundary ghost cells
926 if (xs == 0) {
927 PetscInt i = 0;
928 for (k = zs; k < ze; k++) {
929 for (j = ys; j < ye; j++) {
930 // Note: Accessing lp[...][i-2] reads from the ghost cell region.
931 p[k][j][i] = lp[k][j][i - 2];
932 phi[k][j][i] = lphi[k][j][i - 2];
933 }
934 }
935 }
936 // Update right boundary physical cells from left boundary ghost cells
937 if (xe == mx) {
938 PetscInt i = mx - 1;
939 for (k = zs; k < ze; k++) {
940 for (j = ys; j < ye; j++) {
941 p[k][j][i] = lp[k][j][i + 2];
942 phi[k][j][i] = lphi[k][j][i + 2];
943 }
944 }
945 }
946 }
947
948 // --- Y-Direction Periodic Update ---
950 // Update bottom boundary
951 if (ys == 0) {
952 PetscInt j = 0;
953 for (k = zs; k < ze; k++) {
954 for (i = xs; i < xe; i++) {
955 p[k][j][i] = lp[k][j - 2][i];
956 phi[k][j][i] = lphi[k][j - 2][i];
957 }
958 }
959 }
960 // Update top boundary
961 if (ye == my) {
962 PetscInt j = my - 1;
963 for (k = zs; k < ze; k++) {
964 for (i = xs; i < xe; i++) {
965 p[k][j][i] = lp[k][j + 2][i];
966 phi[k][j][i] = lphi[k][j + 2][i];
967 }
968 }
969 }
970 }
971
972 // --- Z-Direction Periodic Update ---
974 // Update front boundary
975 if (zs == 0) {
976 PetscInt k = 0;
977 for (j = ys; j < ye; j++) {
978 for (i = xs; i < xe; i++) {
979 p[k][j][i] = lp[k - 2][j][i];
980 phi[k][j][i] = lphi[k - 2][j][i];
981 }
982 }
983 }
984 // Update back boundary
985 if (ze == mz) {
986 PetscInt k = mz - 1;
987 for (j = ys; j < ye; j++) {
988 for (i = xs; i < xe; i++) {
989 p[k][j][i] = lp[k + 2][j][i];
990 phi[k][j][i] = lphi[k + 2][j][i];
991 }
992 }
993 }
994 }
995
996 // Restore all arrays ONCE.
997 DMDAVecRestoreArray(da, user->lP, &lp);
998 DMDAVecRestoreArray(da, user->lPhi, &lphi);
999 DMDAVecRestoreArray(da, user->P, &p);
1000 DMDAVecRestoreArray(da, user->Phi, &phi);
1001
1002 // After manually updating the physical boundary cells, we must call
1003 // DMGlobalToLocal again to ensure all processes have the updated ghost
1004 // values for the *next* function that needs them.
1005 DMGlobalToLocalBegin(da, user->P, INSERT_VALUES, user->lP);
1006 DMGlobalToLocalEnd(da, user->P, INSERT_VALUES, user->lP);
1007 DMGlobalToLocalBegin(da, user->Phi, INSERT_VALUES, user->lPhi);
1008 DMGlobalToLocalEnd(da, user->Phi, INSERT_VALUES, user->lPhi);
1009 }
1010
1011 //================================================================================
1012 // Section 4: Final Cleanup (pointers already restored)
1013 //================================================================================
1014
1015 UpdateLocalGhosts(user,"P");
1016 UpdateLocalGhosts(user,"Phi");
1017
1018 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Exiting UpdatePressure.\n");
1020 PetscFunctionReturn(0);
1021}
Vec Phi
Definition variables.h:837
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PoissonNullSpaceFunction()

PetscErrorCode PoissonNullSpaceFunction ( MatNullSpace  nullsp,
Vec  X,
void *  ctx 
)

Implementation of PoissonNullSpaceFunction().

The callback function for PETSc's MatNullSpace object.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
PoissonNullSpaceFunction()

Definition at line 1031 of file poisson.c.

1032{
1033 PetscErrorCode ierr;
1034 UserCtx *user = (UserCtx*)ctx;
1035 (void)nullsp;
1036
1037 DM da = user->da;
1038
1039 DMDALocalInfo info = user->info;
1040 PetscInt xs = info.xs, xe = info.xs + info.xm;
1041 PetscInt ys = info.ys, ye = info.ys + info.ym;
1042 PetscInt zs = info.zs, ze = info.zs + info.zm;
1043 PetscInt mx = info.mx, my = info.my, mz = info.mz;
1044 PetscInt lxs, lxe, lys, lye, lzs, lze;
1045
1046 PetscReal ***x, ***nvert;
1047 PetscInt i, j, k;
1048
1049/* /\* First remove a constant from the Vec field X *\/ */
1050
1051
1052 /* Then apply boundary conditions */
1053 DMDAVecGetArray(da, X, &x);
1054 DMDAVecGetArray(da, user->lNvert, &nvert);
1055
1056 lxs = xs; lxe = xe;
1057 lys = ys; lye = ye;
1058 lzs = zs; lze = ze;
1059
1060 if (xs==0) lxs = xs+1;
1061 if (ys==0) lys = ys+1;
1062 if (zs==0) lzs = zs+1;
1063
1064 if (xe==mx) lxe = xe-1;
1065 if (ye==my) lye = ye-1;
1066 if (ze==mz) lze = ze-1;
1067
1068 PetscReal lsum, sum;
1069 PetscReal lnum, num;
1070
1071 if (user->multinullspace) PetscPrintf(PETSC_COMM_WORLD, "MultiNullSpace!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
1072 if (!user->multinullspace) {
1073 lsum = 0;
1074 lnum = 0;
1075 for (k=lzs; k<lze; k++) {
1076 for (j=lys; j<lye; j++) {
1077 for (i=lxs; i<lxe; i++) {
1078 if (nvert[k][j][i] < 0.1) {
1079 lsum += x[k][j][i];
1080 lnum ++;
1081 }
1082 }
1083 }
1084 }
1085
1086 ierr = MPI_Allreduce(&lsum,&sum,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
1087 ierr = MPI_Allreduce(&lnum,&num,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
1088 /* PetscGlobalSum(&lsum, &sum, PETSC_COMM_WORLD); */
1089/* PetscGlobalSum(&lnum, &num, PETSC_COMM_WORLD); */
1090 sum = sum / (-1.0 * num);
1091
1092 for (k=lzs; k<lze; k++) {
1093 for (j=lys; j<lye; j++) {
1094 for (i=lxs; i<lxe; i++) {
1095 if (nvert[k][j][i] < 0.1) {
1096 x[k][j][i] +=sum;
1097 }
1098 }
1099 }
1100 }
1101 }
1102 else {
1103 lsum = 0;
1104 lnum = 0;
1105 for (j=lys; j<lye; j++) {
1106 for (i=lxs; i<lxe; i++) {
1107 for (k=lzs; k<lze; k++) {
1108 if (k<user->KSKE[2*(j*mx+i)] && nvert[k][j][i]<0.1) {
1109 lsum += x[k][j][i];
1110 lnum ++;
1111 }
1112 }
1113 }
1114 }
1115 ierr = MPI_Allreduce(&lsum,&sum,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
1116 ierr = MPI_Allreduce(&lnum,&num,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
1117 /* PetscGlobalSum(&lsum, &sum, PETSC_COMM_WORLD); */
1118/* PetscGlobalSum(&lnum, &num, PETSC_COMM_WORLD); */
1119 sum /= -num;
1120 for (j=lys; j<lye; j++) {
1121 for (i=lxs; i<lxe; i++) {
1122 for (k=lzs; k<lze; k++) {
1123 if (k<user->KSKE[2*(j*mx+i)] && nvert[k][j][i]<0.1) {
1124 x[k][j][i] += sum;
1125 }
1126 }
1127 }
1128 }
1129
1130 lsum = 0;
1131 lnum = 0;
1132 for (j=lys; j<lye; j++) {
1133 for (i=lxs; i<lxe; i++) {
1134 for (k=lzs; k<lze; k++) {
1135 if (k>=user->KSKE[2*(j*mx+i)] && nvert[k][j][i]<0.1) {
1136 lsum += x[k][j][i];
1137 lnum ++;
1138 }
1139 }
1140 }
1141 }
1142 ierr = MPI_Allreduce(&lsum,&sum,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
1143 ierr = MPI_Allreduce(&lnum,&num,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
1144 /* PetscGlobalSum(&lsum, &sum, PETSC_COMM_WORLD); */
1145/* PetscGlobalSum(&lnum, &num, PETSC_COMM_WORLD); */
1146 sum /= -num;
1147 for (j=lys; j<lye; j++) {
1148 for (i=lxs; i<lxe; i++) {
1149 for (k=lzs; k<lze; k++) {
1150 if (k>=user->KSKE[2*(j*mx+i)] && nvert[k][j][i]<0.1) {
1151 x[k][j][i] += sum;
1152 }
1153 }
1154 }
1155 }
1156
1157 } //if multinullspace
1158 if (zs == 0) {
1159 k = 0;
1160 for (j=ys; j<ye; j++) {
1161 for (i=xs; i<xe; i++) {
1162 x[k][j][i] = 0.;
1163 }
1164 }
1165 }
1166
1167 if (ze == mz) {
1168 k = mz-1;
1169 for (j=ys; j<ye; j++) {
1170 for (i=xs; i<xe; i++) {
1171 x[k][j][i] = 0.;
1172 }
1173 }
1174 }
1175
1176 if (ys == 0) {
1177 j = 0;
1178 for (k=zs; k<ze; k++) {
1179 for (i=xs; i<xe; i++) {
1180 x[k][j][i] = 0.;
1181 }
1182 }
1183 }
1184
1185 if (ye == my) {
1186 j = my-1;
1187 for (k=zs; k<ze; k++) {
1188 for (i=xs; i<xe; i++) {
1189 x[k][j][i] = 0.;
1190 }
1191 }
1192 }
1193
1194 if (xs == 0) {
1195 i = 0;
1196 for (k=zs; k<ze; k++) {
1197 for (j=ys; j<ye; j++) {
1198 x[k][j][i] = 0.;
1199 }
1200 }
1201 }
1202
1203 if (xe == mx) {
1204 i = mx-1;
1205 for (k=zs; k<ze; k++) {
1206 for (j=ys; j<ye; j++) {
1207 x[k][j][i] = 0.;
1208 }
1209 }
1210 }
1211
1212 for (k=zs; k<ze; k++) {
1213 for (j=ys; j<ye; j++) {
1214 for (i=xs; i<xe; i++) {
1215 if (nvert[k][j][i] > 0.1)
1216 x[k][j][i] = 0.;
1217 }
1218 }
1219 }
1220 DMDAVecRestoreArray(da, X, &x);
1221 DMDAVecRestoreArray(da, user->lNvert, &nvert);
1222
1223 return 0;
1224}
PetscInt * KSKE
Definition variables.h:850
PetscBool multinullspace
Definition variables.h:851
User-defined context containing data specific to a single computational grid level.
Definition variables.h:811
Here is the caller graph for this function:

◆ MyInterpolation()

PetscErrorCode MyInterpolation ( Mat  A,
Vec  X,
Vec  F 
)

Implementation of MyInterpolation().

The callback function for the multigrid interpolation operator (MatShell).

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
MyInterpolation()

Definition at line 1233 of file poisson.c.

1234{
1235 UserCtx *user;
1236
1237 MatShellGetContext(A, (void**)&user);
1238
1239
1240
1241 DM da = user->da;
1242
1243 DM da_c = *user->da_c;
1244
1245 DMDALocalInfo info = user->info;
1246 PetscInt xs = info.xs, xe = info.xs + info.xm;
1247 PetscInt ys = info.ys, ye = info.ys + info.ym;
1248 PetscInt zs = info.zs, ze = info.zs + info.zm;
1249 PetscInt mx = info.mx, my = info.my, mz = info.mz;
1250 PetscInt lxs, lxe, lys, lye, lzs, lze;
1251
1252 PetscReal ***f, ***x, ***nvert, ***nvert_c;
1253 PetscInt i, j, k, ic, jc, kc, ia, ja, ka;
1254
1255 lxs = xs; lxe = xe;
1256 lys = ys; lye = ye;
1257 lzs = zs; lze = ze;
1258
1259 if (xs==0) lxs = xs+1;
1260 if (ys==0) lys = ys+1;
1261 if (zs==0) lzs = zs+1;
1262
1263 if (xe==mx) lxe = xe-1;
1264 if (ye==my) lye = ye-1;
1265 if (ze==mz) lze = ze-1;
1266
1267
1268 DMDAVecGetArray(da, F, &f);
1269
1270
1271 Vec lX;
1272 DMCreateLocalVector(da_c, &lX);
1273
1274 DMGlobalToLocalBegin(da_c, X, INSERT_VALUES, lX);
1275 DMGlobalToLocalEnd(da_c, X, INSERT_VALUES, lX);
1276 DMDAVecGetArray(da_c, lX, &x);
1277
1278 DMDAVecGetArray(da, user->lNvert, &nvert);
1279 DMDAVecGetArray(da_c, *(user->lNvert_c), &nvert_c);
1280 for (k=lzs; k<lze; k++) {
1281 for (j=lys; j<lye; j++) {
1282 for (i=lxs; i<lxe; i++) {
1283
1284 GridInterpolation(i, j, k, ic, jc, kc, ia, ja, ka, user);
1285
1286 f[k][j][i] = (x[kc ][jc ][ic ] * 9 +
1287 x[kc ][jc+ja][ic ] * 3 +
1288 x[kc ][jc ][ic+ia] * 3 +
1289 x[kc ][jc+ja][ic+ia]) * 3./64. +
1290 (x[kc+ka][jc ][ic ] * 9 +
1291 x[kc+ka][jc+ja][ic ] * 3 +
1292 x[kc+ka][jc ][ic+ia] * 3 +
1293 x[kc+ka][jc+ja][ic+ia]) /64.;
1294 }
1295 }
1296 }
1297
1298 for (k=zs; k<ze; k++) {
1299 for (j=ys; j<ye; j++) {
1300 for (i=xs; i<xe; i++) {
1301
1302 if (i==0) {
1303 f[k][j][i] = 0.;//-f[k][j][i+1];
1304 }
1305 else if (i==mx-1) {
1306 f[k][j][i] = 0.;//-f[k][j][i-1];
1307 }
1308 else if (j==0) {
1309 f[k][j][i] = 0.;//-f[k][j+1][i];
1310 }
1311 else if (j==my-1) {
1312 f[k][j][i] = 0.;//-f[k][j-1][i];
1313 }
1314 else if (k==0) {
1315 f[k][j][i] = 0.;//-f[k+1][j][i];
1316 }
1317 else if (k==mz-1) {
1318 f[k][j][i] = 0.;//-f[k-1][j][i];
1319 }
1320 if (nvert[k][j][i] > 0.1) f[k][j][i] = 0.;
1321
1322 }
1323 }
1324 }
1325
1326 DMDAVecRestoreArray(da, user->lNvert, &nvert);
1327 DMDAVecRestoreArray(da_c, *(user->lNvert_c), &nvert_c);
1328
1329 DMDAVecRestoreArray(da_c, lX, &x);
1330
1331 VecDestroy(&lX);
1332 DMDAVecRestoreArray(da, F, &f);
1333
1334
1335
1336 return 0;
1337
1338}
#define GridInterpolation(i, j, k, ic, jc, kc, ia, ja, ka, user)
Definition poisson.c:5
DM * da_c
Definition variables.h:876
Vec * lNvert_c
Definition variables.h:877
Here is the caller graph for this function:

◆ RestrictResidual_SolidAware()

static PetscErrorCode RestrictResidual_SolidAware ( Mat  A,
Vec  X,
Vec  F 
)
static

Internal helper implementation: RestrictResidual_SolidAware().

Local to this translation unit.

Definition at line 1344 of file poisson.c.

1345{
1346 UserCtx *user;
1347 MatShellGetContext(A, (void**)&user);
1348
1349 DM da = user->da;
1350 DM da_f = *user->da_f;
1351
1352 DMDALocalInfo info;
1353 DMDAGetLocalInfo(da, &info);
1354 PetscInt xs = info.xs, xe = info.xs + info.xm;
1355 PetscInt ys = info.ys, ye = info.ys + info.ym;
1356 PetscInt zs = info.zs, ze = info.zs + info.zm;
1357 PetscInt mx = info.mx, my = info.my, mz = info.mz;
1358
1359 PetscReal ***f, ***x, ***nvert;
1360 PetscInt i, j, k, ih, jh, kh, ia, ja, ka;
1361
1362 DMDAVecGetArray(da, F, &f);
1363
1364 Vec lX;
1365 DMCreateLocalVector(da_f, &lX);
1366 DMGlobalToLocalBegin(da_f, X, INSERT_VALUES, lX);
1367 DMGlobalToLocalEnd(da_f, X, INSERT_VALUES, lX);
1368 DMDAVecGetArray(da_f, lX, &x);
1369
1370 DMDAVecGetArray(da, user->lNvert, &nvert);
1371
1372 PetscReal ***nvert_f;
1373 DMDAVecGetArray(da_f, user->user_f->lNvert, &nvert_f);
1374
1375 if ((user->isc)) ia = 0;
1376 else ia = 1;
1377
1378 if ((user->jsc)) ja = 0;
1379 else ja = 1;
1380
1381 if ((user->ksc)) ka = 0;
1382 else ka = 1;
1383
1384 for (k=zs; k<ze; k++) {
1385 for (j=ys; j<ye; j++) {
1386 for (i=xs; i<xe; i++) {
1387 // --- CORRECTED LOGIC ---
1388 // First, check if the current point is a boundary point.
1389 // If it is, it does not contribute to the coarse grid residual.
1390 if (i==0 || i==mx-1 || j==0 || j==my-1 || k==0 || k==mz-1 || nvert[k][j][i] > 0.1) {
1391 f[k][j][i] = 0.0;
1392 }
1393 // Only if it's a true interior fluid point, perform the restriction.
1394 else {
1395 GridRestriction(i, j, k, &ih, &jh, &kh, user);
1396 f[k][j][i] = 0.125 *
1397 (x[kh ][jh ][ih ] * PetscMax(0., 1 - nvert_f[kh ][jh ][ih ]) +
1398 x[kh ][jh ][ih-ia] * PetscMax(0., 1 - nvert_f[kh ][jh ][ih-ia]) +
1399 x[kh ][jh-ja][ih ] * PetscMax(0., 1 - nvert_f[kh ][jh-ja][ih ]) +
1400 x[kh-ka][jh ][ih ] * PetscMax(0., 1 - nvert_f[kh-ka][jh ][ih ]) +
1401 x[kh ][jh-ja][ih-ia] * PetscMax(0., 1 - nvert_f[kh ][jh-ja][ih-ia]) +
1402 x[kh-ka][jh-ja][ih ] * PetscMax(0., 1 - nvert_f[kh-ka][jh-ja][ih ]) +
1403 x[kh-ka][jh ][ih-ia] * PetscMax(0., 1 - nvert_f[kh-ka][jh ][ih-ia]) +
1404 x[kh-ka][jh-ja][ih-ia] * PetscMax(0., 1 - nvert_f[kh-ka][jh-ja][ih-ia]));
1405 }
1406 }
1407 }
1408 }
1409
1410 DMDAVecRestoreArray(da_f, user->user_f->lNvert, &nvert_f);
1411 DMDAVecRestoreArray(da_f, lX, &x);
1412 VecDestroy(&lX);
1413 DMDAVecRestoreArray(da, F, &f);
1414 DMDAVecRestoreArray(da, user->lNvert, &nvert);
1415
1416 return 0;
1417}
static PetscErrorCode GridRestriction(PetscInt i, PetscInt j, PetscInt k, PetscInt *ih, PetscInt *jh, PetscInt *kh, UserCtx *user)
Internal helper implementation: GridRestriction().
Definition poisson.c:68
UserCtx * user_f
Definition variables.h:875
DM * da_f
Definition variables.h:876
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MyRestriction()

PetscErrorCode MyRestriction ( Mat  A,
Vec  X,
Vec  F 
)

Implementation of MyRestriction().

The callback function for the multigrid restriction operator (MatShell).

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
MyRestriction()

Definition at line 1426 of file poisson.c.

1427{
1428 UserCtx *user;
1429
1430 MatShellGetContext(A, (void**)&user);
1431
1432
1433 DM da = user->da;
1434
1435 DM da_f = *user->da_f;
1436
1437 DMDALocalInfo info;
1438 DMDAGetLocalInfo(da, &info);
1439 PetscInt xs = info.xs, xe = info.xs + info.xm;
1440 PetscInt ys = info.ys, ye = info.ys + info.ym;
1441 PetscInt zs = info.zs, ze = info.zs + info.zm;
1442 PetscInt mx = info.mx, my = info.my, mz = info.mz;
1443 // PetscInt lxs, lxe, lys, lye, lzs, lze;
1444
1445 PetscReal ***f, ***x, ***nvert;
1446 PetscInt i, j, k, ih, jh, kh, ia, ja, ka;
1447
1448 DMDAVecGetArray(da, F, &f);
1449
1450 Vec lX;
1451
1452 DMCreateLocalVector(da_f, &lX);
1453 DMGlobalToLocalBegin(da_f, X, INSERT_VALUES, lX);
1454 DMGlobalToLocalEnd(da_f, X, INSERT_VALUES, lX);
1455 DMDAVecGetArray(da_f, lX, &x);
1456
1457 DMDAVecGetArray(da, user->lNvert, &nvert);
1458
1459 PetscReal ***nvert_f;
1460 DMDAVecGetArray(da_f, user->user_f->lNvert, &nvert_f);
1461
1462 if ((user->isc)) ia = 0;
1463 else ia = 1;
1464
1465 if ((user->jsc)) ja = 0;
1466 else ja = 1;
1467
1468 if ((user->ksc)) ka = 0;
1469 else ka = 1;
1470
1471 for (k=zs; k<ze; k++) {
1472 for (j=ys; j<ye; j++) {
1473 for (i=xs; i<xe; i++) {
1474 if (k==0) {
1475 f[k][j][i] = 0.;
1476 }
1477 else if (k==mz-1) {
1478 f[k][j][i] = 0.;
1479 }
1480 else if (j==0) {
1481 f[k][j][i] = 0.;
1482 }
1483 else if (j==my-1) {
1484 f[k][j][i] = 0.;
1485 }
1486 else if (i==0) {
1487 f[k][j][i] = 0.;
1488 }
1489 else if (i==mx-1) {
1490 f[k][j][i] = 0.;
1491 }
1492 else {
1493 GridRestriction(i, j, k, &ih, &jh, &kh, user);
1494 f[k][j][i] = 0.125 *
1495 (x[kh ][jh ][ih ] * PetscMax(0., 1 - nvert_f[kh ][jh ][ih ]) +
1496 x[kh ][jh ][ih-ia] * PetscMax(0., 1 - nvert_f[kh ][jh ][ih-ia]) +
1497 x[kh ][jh-ja][ih ] * PetscMax(0., 1 - nvert_f[kh ][jh-ja][ih ]) +
1498 x[kh-ka][jh ][ih ] * PetscMax(0., 1 - nvert_f[kh-ka][jh ][ih ]) +
1499 x[kh ][jh-ja][ih-ia] * PetscMax(0., 1 - nvert_f[kh ][jh-ja][ih-ia]) +
1500 x[kh-ka][jh-ja][ih ] * PetscMax(0., 1 - nvert_f[kh-ka][jh-ja][ih ]) +
1501 x[kh-ka][jh ][ih-ia] * PetscMax(0., 1 - nvert_f[kh-ka][jh ][ih-ia]) +
1502 x[kh-ka][jh-ja][ih-ia] * PetscMax(0., 1 - nvert_f[kh-ka][jh-ja][ih-ia]));
1503
1504
1505
1506 if (nvert[k][j][i] > 0.1) f[k][j][i] = 0.;
1507 }
1508 }
1509 }
1510 }
1511
1512
1513 DMDAVecRestoreArray(da_f, user->user_f->lNvert, &nvert_f);
1514
1515 DMDAVecRestoreArray(da_f, lX, &x);
1516 VecDestroy(&lX);
1517
1518 DMDAVecRestoreArray(da, F, &f);
1519 DMDAVecRestoreArray(da, user->lNvert, &nvert);
1520
1521
1522 return 0;
1523}
Here is the call graph for this function:

◆ PoissonLHSNew()

PetscErrorCode PoissonLHSNew ( UserCtx user)

Internal helper implementation: PoissonLHSNew().

Assembles the Left-Hand-Side (LHS) matrix (Laplacian operator) for the Poisson equation on a single grid level.

Local to this translation unit.

Definition at line 1532 of file poisson.c.

1533{
1534 PetscFunctionBeginUser;
1536 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Entering PoissonLHSNew to assemble Laplacian matrix.\n");
1537 PetscErrorCode ierr;
1538 //================================================================================
1539 // Section 1: Initialization and Data Acquisition
1540 //================================================================================
1541
1542
1543 // --- Get simulation and grid context ---
1544 DM da = user->da, fda = user->fda;
1545 DMDALocalInfo info = user->info;
1546 PetscInt IM = user->IM, JM = user->JM, KM = user->KM;
1547 PetscInt i,j,k;
1548
1549 // --- Grid dimensions ---
1550 PetscInt mx = info.mx, my = info.my, mz = info.mz;
1551 PetscInt xs = info.xs, xe = info.xs + info.xm;
1552 PetscInt ys = info.ys, ye = info.ys + info.ym;
1553 PetscInt zs = info.zs, ze = info.zs + info.zm;
1554 PetscInt gxs = info.gxs, gxe = gxs + info.gxm;
1555 PetscInt gys = info.gys, gye = gys + info.gym;
1556 PetscInt gzs = info.gzs, gze = gzs + info.gzm;
1557
1558 // --- Define constants for clarity ---
1559 const PetscReal IBM_FLUID_THRESHOLD = 0.1;
1560
1561 // --- Allocate the LHS matrix A on the first call ---
1562 if (!user->assignedA) {
1563 LOG_ALLOW(GLOBAL, LOG_INFO, "First call: Creating LHS matrix 'A' with 19-point stencil preallocation.\n");
1564 PetscInt N = mx * my * mz; // Total size
1565 PetscInt M; // Local size
1566 VecGetLocalSize(user->Phi, &M);
1567 // Create a sparse AIJ matrix, preallocating for 19 non-zeros per row (d=diagonal, o=off-diagonal)
1568 MatCreateAIJ(PETSC_COMM_WORLD, M, M, N, N, 19, PETSC_NULLPTR, 19, PETSC_NULLPTR, &(user->A));
1569 user->assignedA = PETSC_TRUE;
1570 }
1571
1572 // Zero out matrix entries from the previous solve
1573 MatZeroEntries(user->A);
1574
1575 // --- Get direct pointer access to grid metric data ---
1576 Cmpnts ***csi, ***eta, ***zet, ***icsi, ***ieta, ***izet, ***jcsi, ***jeta, ***jzet, ***kcsi, ***keta, ***kzet;
1577 PetscReal ***aj, ***iaj, ***jaj, ***kaj, ***nvert;
1578 DMDAVecGetArray(fda, user->lCsi, &csi); DMDAVecGetArray(fda, user->lEta, &eta); DMDAVecGetArray(fda, user->lZet, &zet);
1579 DMDAVecGetArray(fda, user->lICsi, &icsi); DMDAVecGetArray(fda, user->lIEta, &ieta); DMDAVecGetArray(fda, user->lIZet, &izet);
1580 DMDAVecGetArray(fda, user->lJCsi, &jcsi); DMDAVecGetArray(fda, user->lJEta, &jeta); DMDAVecGetArray(fda, user->lJZet, &jzet);
1581 DMDAVecGetArray(fda, user->lKCsi, &kcsi); DMDAVecGetArray(fda, user->lKEta, &keta); DMDAVecGetArray(fda, user->lKZet, &kzet);
1582 DMDAVecGetArray(da, user->lAj, &aj); DMDAVecGetArray(da, user->lIAj, &iaj); DMDAVecGetArray(da, user->lJAj, &jaj); DMDAVecGetArray(da, user->lKAj, &kaj);
1583 DMDAVecGetArray(da, user->lNvert, &nvert);
1584
1585 // --- Create temporary vectors for the metric tensor components G_ij ---
1586 Vec G11, G12, G13, G21, G22, G23, G31, G32, G33;
1587 PetscReal ***g11, ***g12, ***g13, ***g21, ***g22, ***g23, ***g31, ***g32, ***g33;
1588 VecDuplicate(user->lAj, &G11); VecDuplicate(user->lAj, &G12); VecDuplicate(user->lAj, &G13);
1589 VecDuplicate(user->lAj, &G21); VecDuplicate(user->lAj, &G22); VecDuplicate(user->lAj, &G23);
1590 VecDuplicate(user->lAj, &G31); VecDuplicate(user->lAj, &G32); VecDuplicate(user->lAj, &G33);
1591 DMDAVecGetArray(da, G11, &g11); DMDAVecGetArray(da, G12, &g12); DMDAVecGetArray(da, G13, &g13);
1592 DMDAVecGetArray(da, G21, &g21); DMDAVecGetArray(da, G22, &g22); DMDAVecGetArray(da, G23, &g23);
1593 DMDAVecGetArray(da, G31, &g31); DMDAVecGetArray(da, G32, &g32); DMDAVecGetArray(da, G33, &g33);
1594
1595 //================================================================================
1596 // Section 2: Pre-compute Metric Tensor Coefficients (g_ij)
1597 //================================================================================
1598 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Pre-computing metric tensor components (g_ij).\n");
1599 for (k = gzs; k < gze; k++) {
1600 for (j = gys; j < gye; j++) {
1601 for (i = gxs; i < gxe; i++) {
1602 // These coefficients represent the dot products of the grid's contravariant base vectors,
1603 // scaled by face area. They are the core of the Laplacian operator on a curvilinear grid.
1604 if(i>-1 && j>-1 && k>-1 && i<IM+1 && j<JM+1 && k<KM+1){
1605 g11[k][j][i] = (icsi[k][j][i].x * icsi[k][j][i].x + icsi[k][j][i].y * icsi[k][j][i].y + icsi[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i];
1606 g12[k][j][i] = (ieta[k][j][i].x * icsi[k][j][i].x + ieta[k][j][i].y * icsi[k][j][i].y + ieta[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i];
1607 g13[k][j][i] = (izet[k][j][i].x * icsi[k][j][i].x + izet[k][j][i].y * icsi[k][j][i].y + izet[k][j][i].z * icsi[k][j][i].z) * iaj[k][j][i];
1608 g21[k][j][i] = (jcsi[k][j][i].x * jeta[k][j][i].x + jcsi[k][j][i].y * jeta[k][j][i].y + jcsi[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i];
1609 g22[k][j][i] = (jeta[k][j][i].x * jeta[k][j][i].x + jeta[k][j][i].y * jeta[k][j][i].y + jeta[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i];
1610 g23[k][j][i] = (jzet[k][j][i].x * jeta[k][j][i].x + jzet[k][j][i].y * jeta[k][j][i].y + jzet[k][j][i].z * jeta[k][j][i].z) * jaj[k][j][i];
1611 g31[k][j][i] = (kcsi[k][j][i].x * kzet[k][j][i].x + kcsi[k][j][i].y * kzet[k][j][i].y + kcsi[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i];
1612 g32[k][j][i] = (keta[k][j][i].x * kzet[k][j][i].x + keta[k][j][i].y * kzet[k][j][i].y + keta[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i];
1613 g33[k][j][i] = (kzet[k][j][i].x * kzet[k][j][i].x + kzet[k][j][i].y * kzet[k][j][i].y + kzet[k][j][i].z * kzet[k][j][i].z) * kaj[k][j][i];
1614 }
1615 }
1616 }
1617 }
1618
1619 //================================================================================
1620 // Section 3: Assemble the LHS Matrix A
1621 //================================================================================
1622 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Assembling the LHS matrix A using a 19-point stencil.\n");
1623
1624 // --- Define domain boundaries for stencil logic, accounting for periodic BCs ---
1625 PetscInt x_str, x_end, y_str, y_end, z_str, z_end;
1626 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC) { x_end = mx - 1; x_str = 0; }
1627 else { x_end = mx - 2; x_str = 1; }
1628 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC) { y_end = my - 1; y_str = 0; }
1629 else { y_end = my - 2; y_str = 1; }
1630 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC) { z_end = mz - 1; z_str = 0; }
1631 else { z_end = mz - 2; z_str = 1; }
1632
1633 // --- Main assembly loop over all local grid points ---
1634 for (k = zs; k < ze; k++) {
1635 for (j = ys; j < ye; j++) {
1636 for (i = xs; i < xe; i++) {
1637 PetscScalar vol[19]; // Holds the 19 stencil coefficient values for the current row
1638 PetscInt idx[19]; // Holds the 19 global column indices for the current row
1639 PetscInt row = Gidx(i, j, k, user); // Global index for the current row
1640
1641 // --- Handle Domain Boundary and Immersed Solid Points ---
1642 // For these points, we don't solve the Poisson equation. We set an identity
1643 // row (A_ii = 1) to effectively fix the pressure value (usually to 0).
1644 if (i == 0 || i == mx - 1 || j == 0 || j == my - 1 || k == 0 || k == mz - 1 || nvert[k][j][i] > IBM_FLUID_THRESHOLD) {
1645 vol[CP] = 1.0;
1646 idx[CP] = row;
1647 MatSetValues(user->A, 1, &row, 1, &idx[CP], &vol[CP], INSERT_VALUES);
1648 }
1649 // --- Handle Fluid Points ---
1650 else {
1651 for (PetscInt m = 0; m < 19; m++) {
1652 vol[m] = 0.0;
1653 }
1654
1655 /************************************************************************
1656 * EAST FACE CONTRIBUTION (between i and i+1)
1657 ************************************************************************/
1658 if (nvert[k][j][i + 1] < IBM_FLUID_THRESHOLD && i != x_end) { // East neighbor is fluid
1659 // Primary derivative term: d/d_csi (g11 * dP/d_csi)
1660 vol[CP] -= g11[k][j][i];
1661 vol[EP] += g11[k][j][i];
1662
1663 // Cross-derivative term: d/d_csi (g12 * dP/d_eta).
1664 // This requires an average of dP/d_eta. If a neighbor is solid, the stencil
1665 // dynamically switches to a one-sided difference to avoid using solid points.
1666 if ((j == my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) || nvert[k][j+1][i] + nvert[k][j+1][i+1] > 0.1) {
1667 if (nvert[k][j-1][i] + nvert[k][j-1][i+1] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) {
1668 vol[CP] += g12[k][j][i] * 0.5; vol[EP] += g12[k][j][i] * 0.5;
1669 vol[SP] -= g12[k][j][i] * 0.5; vol[SE] -= g12[k][j][i] * 0.5;
1670 }
1671 }
1672 else if ((j == my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i] + nvert[k][j+1][i+1] > 0.1) {
1673 if (nvert[k][j-1][i] + nvert[k][j-1][i+1] < 0.1) {
1674 vol[CP] += g12[k][j][i] * 0.5; vol[EP] += g12[k][j][i] * 0.5;
1675 vol[SP] -= g12[k][j][i] * 0.5; vol[SE] -= g12[k][j][i] * 0.5;
1676 }
1677 }
1678 else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) || nvert[k][j-1][i] + nvert[k][j-1][i+1] > 0.1) {
1679 if (nvert[k][j+1][i] + nvert[k][j+1][i+1] < 0.1) {
1680 vol[NP] += g12[k][j][i] * 0.5; vol[NE] += g12[k][j][i] * 0.5;
1681 vol[CP] -= g12[k][j][i] * 0.5; vol[EP] -= g12[k][j][i] * 0.5;
1682 }
1683 }
1684 else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k][j-1][i+1] > 0.1) {
1685 if (nvert[k][j+1][i] + nvert[k][j+1][i+1] < 0.1) {
1686 vol[NP] += g12[k][j][i] * 0.5; vol[NE] += g12[k][j][i] * 0.5;
1687 vol[CP] -= g12[k][j][i] * 0.5; vol[EP] -= g12[k][j][i] * 0.5;
1688 }
1689 }
1690 else { // Centered difference
1691 vol[NP] += g12[k][j][i] * 0.25; vol[NE] += g12[k][j][i] * 0.25;
1692 vol[SP] -= g12[k][j][i] * 0.25; vol[SE] -= g12[k][j][i] * 0.25;
1693 }
1694
1695 // Cross-derivative term: d/d_csi (g13 * dP/d_zet)
1696 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) || nvert[k+1][j][i] + nvert[k+1][j][i+1] > 0.1) {
1697 if (nvert[k-1][j][i] + nvert[k-1][j][i+1] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) {
1698 vol[CP] += g13[k][j][i] * 0.5; vol[EP] += g13[k][j][i] * 0.5;
1699 vol[BP] -= g13[k][j][i] * 0.5; vol[BE] -= g13[k][j][i] * 0.5;
1700 }
1701 }
1702 else if ((k == mz-2 || k==1) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j][i+1] > 0.1) {
1703 if (nvert[k-1][j][i] + nvert[k-1][j][i+1] < 0.1) {
1704 vol[CP] += g13[k][j][i] * 0.5; vol[EP] += g13[k][j][i] * 0.5;
1705 vol[BP] -= g13[k][j][i] * 0.5; vol[BE] -= g13[k][j][i] * 0.5;
1706 }
1707 }
1708 else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) || nvert[k-1][j][i] + nvert[k-1][j][i+1] > 0.1) {
1709 if (nvert[k+1][j][i] + nvert[k+1][j][i+1] < 0.1) {
1710 vol[TP] += g13[k][j][i] * 0.5; vol[TE] += g13[k][j][i] * 0.5;
1711 vol[CP] -= g13[k][j][i] * 0.5; vol[EP] -= g13[k][j][i] * 0.5;
1712 }
1713 }
1714 else if ((k == 1 || k==mz-2) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j][i+1] > 0.1) {
1715 if (nvert[k+1][j][i] + nvert[k+1][j][i+1] < 0.1) {
1716 vol[TP] += g13[k][j][i] * 0.5; vol[TE] += g13[k][j][i] * 0.5;
1717 vol[CP] -= g13[k][j][i] * 0.5; vol[EP] -= g13[k][j][i] * 0.5;
1718 }
1719 }
1720 else { // Centered difference
1721 vol[TP] += g13[k][j][i] * 0.25; vol[TE] += g13[k][j][i] * 0.25;
1722 vol[BP] -= g13[k][j][i] * 0.25; vol[BE] -= g13[k][j][i] * 0.25;
1723 }
1724 }
1725
1726 /************************************************************************
1727 * WEST FACE CONTRIBUTION (between i-1 and i)
1728 ************************************************************************/
1729 if (nvert[k][j][i-1] < IBM_FLUID_THRESHOLD && i != x_str) {
1730 vol[CP] -= g11[k][j][i-1];
1731 vol[WP] += g11[k][j][i-1];
1732
1733 if ((j == my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) || nvert[k][j+1][i] + nvert[k][j+1][i-1] > 0.1) {
1734 if (nvert[k][j-1][i] + nvert[k][j-1][i-1] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) {
1735 vol[CP] -= g12[k][j][i-1] * 0.5; vol[WP] -= g12[k][j][i-1] * 0.5;
1736 vol[SP] += g12[k][j][i-1] * 0.5; vol[SW] += g12[k][j][i-1] * 0.5;
1737 }
1738 }
1739 else if ((j == my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i] + nvert[k][j+1][i-1] > 0.1) {
1740 if (nvert[k][j-1][i] + nvert[k][j-1][i-1] < 0.1) {
1741 vol[CP] -= g12[k][j][i-1] * 0.5; vol[WP] -= g12[k][j][i-1] * 0.5;
1742 vol[SP] += g12[k][j][i-1] * 0.5; vol[SW] += g12[k][j][i-1] * 0.5;
1743 }
1744 }
1745 else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j-1][i] + nvert[k][j-1][i-1] > 0.1) {
1746 if (nvert[k][j+1][i] + nvert[k][j+1][i-1] < 0.1) {
1747 vol[NP] -= g12[k][j][i-1] * 0.5; vol[NW] -= g12[k][j][i-1] * 0.5;
1748 vol[CP] += g12[k][j][i-1] * 0.5; vol[WP] += g12[k][j][i-1] * 0.5;
1749 }
1750 }
1751 else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k][j-1][i-1] > 0.1) {
1752 if (nvert[k][j+1][i] + nvert[k][j+1][i-1] < 0.1) {
1753 vol[NP] -= g12[k][j][i-1] * 0.5; vol[NW] -= g12[k][j][i-1] * 0.5;
1754 vol[CP] += g12[k][j][i-1] * 0.5; vol[WP] += g12[k][j][i-1] * 0.5;
1755 }
1756 }
1757 else {
1758 vol[NP] -= g12[k][j][i-1] * 0.25; vol[NW] -= g12[k][j][i-1] * 0.25;
1759 vol[SP] += g12[k][j][i-1] * 0.25; vol[SW] += g12[k][j][i-1] * 0.25;
1760 }
1761
1762 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) || nvert[k+1][j][i] + nvert[k+1][j][i-1] > 0.1) {
1763 if (nvert[k-1][j][i] + nvert[k-1][j][i-1] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) {
1764 vol[CP] -= g13[k][j][i-1] * 0.5; vol[WP] -= g13[k][j][i-1] * 0.5;
1765 vol[BP] += g13[k][j][i-1] * 0.5; vol[BW] += g13[k][j][i-1] * 0.5;
1766 }
1767 }
1768 else if ((k == mz-2 || k==1) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j][i-1] > 0.1) {
1769 if (nvert[k-1][j][i] + nvert[k-1][j][i-1] < 0.1) {
1770 vol[CP] -= g13[k][j][i-1] * 0.5; vol[WP] -= g13[k][j][i-1] * 0.5;
1771 vol[BP] += g13[k][j][i-1] * 0.5; vol[BW] += g13[k][j][i-1] * 0.5;
1772 }
1773 }
1774 else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) || nvert[k-1][j][i] + nvert[k-1][j][i-1] > 0.1) {
1775 if (nvert[k+1][j][i] + nvert[k+1][j][i-1] < 0.1) {
1776 vol[TP] -= g13[k][j][i-1] * 0.5; vol[TW] -= g13[k][j][i-1] * 0.5;
1777 vol[CP] += g13[k][j][i-1] * 0.5; vol[WP] += g13[k][j][i-1] * 0.5;
1778 }
1779 }
1780 else if ((k == 1 || k==mz-2) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j][i-1] > 0.1) {
1781 if (nvert[k+1][j][i] + nvert[k+1][j][i-1] < 0.1) {
1782 vol[TP] -= g13[k][j][i-1] * 0.5; vol[TW] -= g13[k][j][i-1] * 0.5;
1783 vol[CP] += g13[k][j][i-1] * 0.5; vol[WP] += g13[k][j][i-1] * 0.5;
1784 }
1785 }
1786 else {
1787 vol[TP] -= g13[k][j][i-1] * 0.25; vol[TW] -= g13[k][j][i-1] * 0.25;
1788 vol[BP] += g13[k][j][i-1] * 0.25; vol[BW] += g13[k][j][i-1] * 0.25;
1789 }
1790 }
1791
1792 /************************************************************************
1793 * NORTH FACE CONTRIBUTION (between j and j+1)
1794 ************************************************************************/
1795 if (nvert[k][j+1][i] < IBM_FLUID_THRESHOLD && j != y_end) {
1796 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i+1] + nvert[k][j+1][i+1] > 0.1) {
1797 if (nvert[k][j][i-1] + nvert[k][j+1][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) {
1798 vol[CP] += g21[k][j][i] * 0.5; vol[NP] += g21[k][j][i] * 0.5;
1799 vol[WP] -= g21[k][j][i] * 0.5; vol[NW] -= g21[k][j][i] * 0.5;
1800 }
1801 }
1802 else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k][j+1][i+1] > 0.1) {
1803 if (nvert[k][j][i-1] + nvert[k][j+1][i-1] < 0.1) {
1804 vol[CP] += g21[k][j][i] * 0.5; vol[NP] += g21[k][j][i] * 0.5;
1805 vol[WP] -= g21[k][j][i] * 0.5; vol[NW] -= g21[k][j][i] * 0.5;
1806 }
1807 }
1808 else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) || nvert[k][j][i-1] + nvert[k][j+1][i-1] > 0.1) {
1809 if (nvert[k][j][i+1] + nvert[k][j+1][i+1] < 0.1) {
1810 vol[EP] += g21[k][j][i] * 0.5; vol[NE] += g21[k][j][i] * 0.5;
1811 vol[CP] -= g21[k][j][i] * 0.5; vol[NP] -= g21[k][j][i] * 0.5;
1812 }
1813 }
1814 else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k][j+1][i-1] > 0.1) {
1815 if (nvert[k][j][i+1] + nvert[k][j+1][i+1] < 0.1) {
1816 vol[EP] += g21[k][j][i] * 0.5; vol[NE] += g21[k][j][i] * 0.5;
1817 vol[CP] -= g21[k][j][i] * 0.5; vol[NP] -= g21[k][j][i] * 0.5;
1818 }
1819 }
1820 else {
1821 vol[EP] += g21[k][j][i] * 0.25; vol[NE] += g21[k][j][i] * 0.25;
1822 vol[WP] -= g21[k][j][i] * 0.25; vol[NW] -= g21[k][j][i] * 0.25;
1823 }
1824
1825 vol[CP] -= g22[k][j][i];
1826 vol[NP] += g22[k][j][i];
1827
1828 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k+1][j][i] + nvert[k+1][j+1][i] > 0.1) {
1829 if (nvert[k-1][j][i] + nvert[k-1][j+1][i] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) {
1830 vol[CP] += g23[k][j][i] * 0.5; vol[NP] += g23[k][j][i] * 0.5;
1831 vol[BP] -= g23[k][j][i] * 0.5; vol[BN] -= g23[k][j][i] * 0.5;
1832 }
1833 }
1834 else if ((k == mz-2 || k==1 ) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j+1][i] > 0.1) {
1835 if (nvert[k-1][j][i] + nvert[k-1][j+1][i] < 0.1) {
1836 vol[CP] += g23[k][j][i] * 0.5; vol[NP] += g23[k][j][i] * 0.5;
1837 vol[BP] -= g23[k][j][i] * 0.5; vol[BN] -= g23[k][j][i] * 0.5;
1838 }
1839 }
1840 else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k-1][j][i] + nvert[k-1][j+1][i] > 0.1) {
1841 if (nvert[k+1][j][i] + nvert[k+1][j+1][i] < 0.1) {
1842 vol[TP] += g23[k][j][i] * 0.5; vol[TN] += g23[k][j][i] * 0.5;
1843 vol[CP] -= g23[k][j][i] * 0.5; vol[NP] -= g23[k][j][i] * 0.5;
1844 }
1845 }
1846 else if ((k == 1 || k==mz-2 ) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j+1][i] > 0.1) {
1847 if (nvert[k+1][j][i] + nvert[k+1][j+1][i] < 0.1) {
1848 vol[TP] += g23[k][j][i] * 0.5; vol[TN] += g23[k][j][i] * 0.5;
1849 vol[CP] -= g23[k][j][i] * 0.5; vol[NP] -= g23[k][j][i] * 0.5;
1850 }
1851 }
1852 else {
1853 vol[TP] += g23[k][j][i] * 0.25; vol[TN] += g23[k][j][i] * 0.25;
1854 vol[BP] -= g23[k][j][i] * 0.25; vol[BN] -= g23[k][j][i] * 0.25;
1855 }
1856 }
1857
1858 /************************************************************************
1859 * SOUTH FACE CONTRIBUTION (between j-1 and j)
1860 ************************************************************************/
1861 if (nvert[k][j-1][i] < IBM_FLUID_THRESHOLD && j != y_str) {
1862 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) || nvert[k][j][i+1] + nvert[k][j-1][i+1] > 0.1) {
1863 if (nvert[k][j][i-1] + nvert[k][j-1][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) {
1864 vol[CP] -= g21[k][j-1][i] * 0.5; vol[SP] -= g21[k][j-1][i] * 0.5;
1865 vol[WP] += g21[k][j-1][i] * 0.5; vol[SW] += g21[k][j-1][i] * 0.5;
1866 }
1867 }
1868 else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k][j-1][i+1] > 0.1) {
1869 if (nvert[k][j][i-1] + nvert[k][j-1][i-1] < 0.1) {
1870 vol[CP] -= g21[k][j-1][i] * 0.5; vol[SP] -= g21[k][j-1][i] * 0.5;
1871 vol[WP] += g21[k][j-1][i] * 0.5; vol[SW] += g21[k][j-1][i] * 0.5;
1872 }
1873 }
1874 else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i-1] + nvert[k][j-1][i-1] > 0.1) {
1875 if (nvert[k][j][i+1] + nvert[k][j-1][i+1] < 0.1) {
1876 vol[EP] -= g21[k][j-1][i] * 0.5; vol[SE] -= g21[k][j-1][i] * 0.5;
1877 vol[CP] += g21[k][j-1][i] * 0.5; vol[SP] += g21[k][j-1][i] * 0.5;
1878 }
1879 }
1880 else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k][j-1][i-1] > 0.1) {
1881 if (nvert[k][j][i+1] + nvert[k][j-1][i+1] < 0.1) {
1882 vol[EP] -= g21[k][j-1][i] * 0.5; vol[SE] -= g21[k][j-1][i] * 0.5;
1883 vol[CP] += g21[k][j-1][i] * 0.5; vol[SP] += g21[k][j-1][i] * 0.5;
1884 }
1885 }
1886 else {
1887 vol[EP] -= g21[k][j-1][i] * 0.25; vol[SE] -= g21[k][j-1][i] * 0.25;
1888 vol[WP] += g21[k][j-1][i] * 0.25; vol[SW] += g21[k][j-1][i] * 0.25;
1889 }
1890
1891 vol[CP] -= g22[k][j-1][i];
1892 vol[SP] += g22[k][j-1][i];
1893
1894 if ((k == mz-2 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k+1][j][i] + nvert[k+1][j-1][i] > 0.1) {
1895 if (nvert[k-1][j][i] + nvert[k-1][j-1][i] < 0.1 && (k!=1 || (k==1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC))) {
1896 vol[CP] -= g23[k][j-1][i] * 0.5; vol[SP] -= g23[k][j-1][i] * 0.5;
1897 vol[BP] += g23[k][j-1][i] * 0.5; vol[BS] += g23[k][j-1][i] * 0.5;
1898 }
1899 }
1900 else if ((k == mz-2 || k==1) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k+1][j][i] + nvert[k+1][j-1][i] > 0.1) {
1901 if (nvert[k-1][j][i] + nvert[k-1][j-1][i] < 0.1 ) {
1902 vol[CP] -= g23[k][j-1][i] * 0.5; vol[SP] -= g23[k][j-1][i] * 0.5;
1903 vol[BP] += g23[k][j-1][i] * 0.5; vol[BS] += g23[k][j-1][i] * 0.5;
1904 }
1905 }
1906 else if ((k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC)|| nvert[k-1][j][i] + nvert[k-1][j-1][i] > 0.1) {
1907 if (nvert[k+1][j][i] + nvert[k+1][j-1][i] < 0.1) {
1908 vol[TP] -= g23[k][j-1][i] * 0.5; vol[TS] -= g23[k][j-1][i] * 0.5;
1909 vol[CP] += g23[k][j-1][i] * 0.5; vol[SP] += g23[k][j-1][i] * 0.5;
1910 }
1911 }
1912 else if ((k == 1 || k==mz-2) && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && nvert[k-1][j][i] + nvert[k-1][j-1][i] > 0.1) {
1913 if (nvert[k+1][j][i] + nvert[k+1][j-1][i] < 0.1) {
1914 vol[TP] -= g23[k][j-1][i] * 0.5; vol[TS] -= g23[k][j-1][i] * 0.5;
1915 vol[CP] += g23[k][j-1][i] * 0.5; vol[SP] += g23[k][j-1][i] * 0.5;
1916 }
1917 }
1918 else {
1919 vol[TP] -= g23[k][j-1][i] * 0.25; vol[TS] -= g23[k][j-1][i] * 0.25;
1920 vol[BP] += g23[k][j-1][i] * 0.25; vol[BS] += g23[k][j-1][i] * 0.25;
1921 }
1922 }
1923
1924 /************************************************************************
1925 * TOP FACE CONTRIBUTION (between k and k+1)
1926 ************************************************************************/
1927 if (nvert[k+1][j][i] < IBM_FLUID_THRESHOLD && k != z_end) {
1928 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i+1] + nvert[k+1][j][i+1] > 0.1) {
1929 if (nvert[k][j][i-1] + nvert[k+1][j][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) {
1930 vol[CP] += g31[k][j][i] * 0.5; vol[TP] += g31[k][j][i] * 0.5;
1931 vol[WP] -= g31[k][j][i] * 0.5; vol[TW] -= g31[k][j][i] * 0.5;
1932 }
1933 }
1934 else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k+1][j][i+1] > 0.1) {
1935 if (nvert[k][j][i-1] + nvert[k+1][j][i-1] < 0.1) {
1936 vol[CP] += g31[k][j][i] * 0.5; vol[TP] += g31[k][j][i] * 0.5;
1937 vol[WP] -= g31[k][j][i] * 0.5; vol[TW] -= g31[k][j][i] * 0.5;
1938 }
1939 }
1940 else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i-1] + nvert[k+1][j][i-1] > 0.1) {
1941 if (nvert[k][j][i+1] + nvert[k+1][j][i+1] < 0.1) {
1942 vol[EP] += g31[k][j][i] * 0.5; vol[TE] += g31[k][j][i] * 0.5;
1943 vol[CP] -= g31[k][j][i] * 0.5; vol[TP] -= g31[k][j][i] * 0.5;
1944 }
1945 }
1946 else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k+1][j][i-1] > 0.1) {
1947 if (nvert[k][j][i+1] + nvert[k+1][j][i+1] < 0.1) {
1948 vol[EP] += g31[k][j][i] * 0.5; vol[TE] += g31[k][j][i] * 0.5;
1949 vol[CP] -= g31[k][j][i] * 0.5; vol[TP] -= g31[k][j][i] * 0.5;
1950 }
1951 }
1952 else {
1953 vol[EP] += g31[k][j][i] * 0.25; vol[TE] += g31[k][j][i] * 0.25;
1954 vol[WP] -= g31[k][j][i] * 0.25; vol[TW] -= g31[k][j][i] * 0.25;
1955 }
1956
1957 if ((j == my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j+1][i] + nvert[k+1][j+1][i] > 0.1) {
1958 if (nvert[k][j-1][i] + nvert[k+1][j-1][i] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) {
1959 vol[CP] += g32[k][j][i] * 0.5; vol[TP] += g32[k][j][i] * 0.5;
1960 vol[SP] -= g32[k][j][i] * 0.5; vol[TS] -= g32[k][j][i] * 0.5;
1961 }
1962 }
1963 else if ((j == my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i] + nvert[k+1][j+1][i] > 0.1) {
1964 if (nvert[k][j-1][i] + nvert[k+1][j-1][i] < 0.1) {
1965 vol[CP] += g32[k][j][i] * 0.5; vol[TP] += g32[k][j][i] * 0.5;
1966 vol[SP] -= g32[k][j][i] * 0.5; vol[TS] -= g32[k][j][i] * 0.5;
1967 }
1968 }
1969 else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j-1][i] + nvert[k+1][j-1][i] > 0.1) {
1970 if (nvert[k][j+1][i] + nvert[k+1][j+1][i] < 0.1) {
1971 vol[NP] += g32[k][j][i] * 0.5; vol[TN] += g32[k][j][i] * 0.5;
1972 vol[CP] -= g32[k][j][i] * 0.5; vol[TP] -= g32[k][j][i] * 0.5;
1973 }
1974 }
1975 else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k+1][j-1][i] > 0.1) {
1976 if (nvert[k][j+1][i] + nvert[k+1][j+1][i] < 0.1) {
1977 vol[NP] += g32[k][j][i] * 0.5; vol[TN] += g32[k][j][i] * 0.5;
1978 vol[CP] -= g32[k][j][i] * 0.5; vol[TP] -= g32[k][j][i] * 0.5;
1979 }
1980 }
1981 else {
1982 vol[NP] += g32[k][j][i] * 0.25; vol[TN] += g32[k][j][i] * 0.25;
1983 vol[SP] -= g32[k][j][i] * 0.25; vol[TS] -= g32[k][j][i] * 0.25;
1984 }
1985
1986 vol[CP] -= g33[k][j][i];
1987 vol[TP] += g33[k][j][i];
1988 }
1989
1990 /************************************************************************
1991 * BOTTOM FACE CONTRIBUTION (between k-1 and k)
1992 ************************************************************************/
1993 if (nvert[k-1][j][i] < IBM_FLUID_THRESHOLD && k != z_str) {
1994 if ((i == mx-2 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i+1] + nvert[k-1][j][i+1] > 0.1) {
1995 if (nvert[k][j][i-1] + nvert[k-1][j][i-1] < 0.1 && (i!=1 || (i==1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC))) {
1996 vol[CP] -= g31[k-1][j][i] * 0.5; vol[BP] -= g31[k-1][j][i] * 0.5;
1997 vol[WP] += g31[k-1][j][i] * 0.5; vol[BW] += g31[k-1][j][i] * 0.5;
1998 }
1999 }
2000 else if ((i == mx-2 || i==1) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i+1] + nvert[k-1][j][i+1] > 0.1) {
2001 if (nvert[k][j][i-1] + nvert[k-1][j][i-1] < 0.1) {
2002 vol[CP] -= g31[k-1][j][i] * 0.5; vol[BP] -= g31[k-1][j][i] * 0.5;
2003 vol[WP] += g31[k-1][j][i] * 0.5; vol[BW] += g31[k-1][j][i] * 0.5;
2004 }
2005 }
2006 else if ((i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC)|| nvert[k][j][i-1] + nvert[k-1][j][i-1] > 0.1) {
2007 if (nvert[k][j][i+1] + nvert[k-1][j][i+1] < 0.1) {
2008 vol[EP] -= g31[k-1][j][i] * 0.5; vol[BE] -= g31[k-1][j][i] * 0.5;
2009 vol[CP] += g31[k-1][j][i] * 0.5; vol[BP] += g31[k-1][j][i] * 0.5;
2010 }
2011 }
2012 else if ((i == 1 || i==mx-2) && user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && nvert[k][j][i-1] + nvert[k-1][j][i-1] > 0.1) {
2013 if (nvert[k][j][i+1] + nvert[k-1][j][i+1] < 0.1) {
2014 vol[EP] -= g31[k-1][j][i] * 0.5; vol[BE] -= g31[k-1][j][i] * 0.5;
2015 vol[CP] += g31[k-1][j][i] * 0.5; vol[BP] += g31[k-1][j][i] * 0.5;
2016 }
2017 }
2018 else {
2019 vol[EP] -= g31[k-1][j][i] * 0.25; vol[BE] -= g31[k-1][j][i] * 0.25;
2020 vol[WP] += g31[k-1][j][i] * 0.25; vol[BW] += g31[k-1][j][i] * 0.25;
2021 }
2022
2023 if ((j == my-2 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j+1][i] + nvert[k-1][j+1][i] > 0.1) {
2024 if (nvert[k][j-1][i] + nvert[k-1][j-1][i] < 0.1 && (j!=1 || (j==1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC))) {
2025 vol[CP] -= g32[k-1][j][i] * 0.5; vol[BP] -= g32[k-1][j][i] * 0.5;
2026 vol[SP] += g32[k-1][j][i] * 0.5; vol[BS] += g32[k-1][j][i] * 0.5;
2027 }
2028 }
2029 else if ((j == my-2 || j==1) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j+1][i] + nvert[k-1][j+1][i] > 0.1) {
2030 if (nvert[k][j-1][i] + nvert[k-1][j-1][i] < 0.1) {
2031 vol[CP] -= g32[k-1][j][i] * 0.5; vol[BP] -= g32[k-1][j][i] * 0.5;
2032 vol[SP] += g32[k-1][j][i] * 0.5; vol[BS] += g32[k-1][j][i] * 0.5;
2033 }
2034 }
2035 else if ((j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC)|| nvert[k][j-1][i] + nvert[k-1][j-1][i] > 0.1) {
2036 if (nvert[k][j+1][i] + nvert[k-1][j+1][i] < 0.1) {
2037 vol[NP] -= g32[k-1][j][i] * 0.5; vol[BN] -= g32[k-1][j][i] * 0.5;
2038 vol[CP] += g32[k-1][j][i] * 0.5; vol[BP] += g32[k-1][j][i] * 0.5;
2039 }
2040 }
2041 else if ((j == 1 || j==my-2) && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && nvert[k][j-1][i] + nvert[k-1][j-1][i] > 0.1) {
2042 if (nvert[k][j+1][i] + nvert[k-1][j+1][i] < 0.1) {
2043 vol[NP] -= g32[k-1][j][i] * 0.5; vol[BN] -= g32[k-1][j][i] * 0.5;
2044 vol[CP] += g32[k-1][j][i] * 0.5; vol[BP] += g32[k-1][j][i] * 0.5;
2045 }
2046 }
2047 else {
2048 vol[NP] -= g32[k-1][j][i] * 0.25; vol[BN] -= g32[k-1][j][i] * 0.25;
2049 vol[SP] += g32[k-1][j][i] * 0.25; vol[BS] += g32[k-1][j][i] * 0.25;
2050 }
2051
2052 vol[CP] -= g33[k-1][j][i];
2053 vol[BP] += g33[k-1][j][i];
2054 }
2055
2056 // --- Final scaling and insertion into the matrix ---
2057
2058 // Scale all stencil coefficients by the negative cell volume (-aj).
2059 for (PetscInt m = 0; m < 19; m++) {
2060 vol[m] *= -aj[k][j][i];
2061 }
2062
2063 // Set the global column indices for the 19 stencil points, handling periodic BCs.
2064 idx[CP] = Gidx(i, j, k, user);
2065 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==mx-2) idx[EP] = Gidx(1, j, k, user); else idx[EP] = Gidx(i+1, j, k, user);
2066 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==1) idx[WP] = Gidx(mx-2, j, k, user); else idx[WP] = Gidx(i-1, j, k, user);
2067 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==my-2) idx[NP] = Gidx(i, 1, k, user); else idx[NP] = Gidx(i, j+1, k, user);
2068 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==1) idx[SP] = Gidx(i, my-2, k, user); else idx[SP] = Gidx(i, j-1, k, user);
2069 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==mz-2) idx[TP] = Gidx(i, j, 1, user); else idx[TP] = Gidx(i, j, k+1, user);
2070 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==1) idx[BP] = Gidx(i, j, mz-2, user); else idx[BP] = Gidx(i, j, k-1, user);
2071 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && i==mx-2 && j==my-2) idx[NE] = Gidx(1, 1, k, user); else if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==mx-2) idx[NE] = Gidx(1, j+1, k, user); else if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==my-2) idx[NE] = Gidx(i+1, 1, k, user); else idx[NE] = Gidx(i+1, j+1, k, user);
2072 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && i==mx-2 && j==1) idx[SE] = Gidx(1, my-2, k, user); else if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==mx-2) idx[SE] = Gidx(1, j-1, k, user); else if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==1) idx[SE] = Gidx(i+1, my-2, k, user); else idx[SE] = Gidx(i+1, j-1, k, user);
2073 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && i==1 && j==my-2) idx[NW] = Gidx(mx-2, 1, k, user); else if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==1) idx[NW] = Gidx(mx-2, j+1, k, user); else if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==my-2) idx[NW] = Gidx(i-1, 1, k, user); else idx[NW] = Gidx(i-1, j+1, k, user);
2074 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && i==1 && j==1) idx[SW] = Gidx(mx-2, my-2, k, user); else if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==1) idx[SW] = Gidx(mx-2, j-1, k, user); else if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==1) idx[SW] = Gidx(i-1, my-2, k, user); else idx[SW] = Gidx(i-1, j-1, k, user);
2075 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && j==my-2 && k==mz-2) idx[TN] = Gidx(i, 1, 1, user); else if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==my-2) idx[TN] = Gidx(i, 1, k+1, user); else if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==mz-2) idx[TN] = Gidx(i, j+1, 1, user); else idx[TN] = Gidx(i, j+1, k+1, user);
2076 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && j==my-2 && k==1) idx[BN] = Gidx(i, 1, mz-2, user); else if(user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==my-2) idx[BN] = Gidx(i, 1, k-1, user); else if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==1) idx[BN] = Gidx(i, j+1, mz-2, user); else idx[BN] = Gidx(i, j+1, k-1, user);
2077 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && j==1 && k==mz-2) idx[TS] = Gidx(i, my-2, 1, user); else if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==1) idx[TS] = Gidx(i, my-2, k+1, user); else if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==mz-2) idx[TS] = Gidx(i, j-1, 1, user); else idx[TS] = Gidx(i, j-1, k+1, user);
2078 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && j==1 && k==1) idx[BS] = Gidx(i, my-2, mz-2, user); else if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && j==1) idx[BS] = Gidx(i, my-2, k-1, user); else if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==1) idx[BS] = Gidx(i, j-1, mz-2, user); else idx[BS] = Gidx(i, j-1, k-1, user);
2079 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && i==mx-2 && k==mz-2) idx[TE] = Gidx(1, j, 1, user); else if(user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==mx-2) idx[TE] = Gidx(1, j, k+1, user); else if(user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==mz-2) idx[TE] = Gidx(i+1, j, 1, user); else idx[TE] = Gidx(i+1, j, k+1, user);
2080 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && i==mx-2 && k==1) idx[BE] = Gidx(1, j, mz-2, user); else if(user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==mx-2) idx[BE] = Gidx(1, j, k-1, user); else if(user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==1) idx[BE] = Gidx(i+1, j, mz-2, user); else idx[BE] = Gidx(i+1, j, k-1, user);
2081 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && i==1 && k==mz-2) idx[TW] = Gidx(mx-2, j, 1, user); else if(user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==1) idx[TW] = Gidx(mx-2, j, k+1, user); else if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==mz-2) idx[TW] = Gidx(i-1, j, 1, user); else idx[TW] = Gidx(i-1, j, k+1, user);
2082 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && i==1 && k==1) idx[BW] = Gidx(mx-2, j, mz-2, user); else if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && i==1) idx[BW] = Gidx(mx-2, j, k-1, user); else if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && k==1) idx[BW] = Gidx(i-1, j, mz-2, user); else idx[BW] = Gidx(i-1, j, k-1, user);
2083
2084 // Insert the computed row into the matrix A.
2085 MatSetValues(user->A, 1, &row, 19, idx, vol, INSERT_VALUES);
2086 }
2087 }
2088 }
2089 }
2090
2091 //================================================================================
2092 // Section 4: Finalize Matrix and Cleanup
2093 //================================================================================
2094
2095 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Finalizing matrix assembly.\n");
2096 MatAssemblyBegin(user->A, MAT_FINAL_ASSEMBLY);
2097 MatAssemblyEnd(user->A, MAT_FINAL_ASSEMBLY);
2098
2099 PetscReal max_A;
2100
2101 ierr = MatNorm(user->A,NORM_INFINITY,&max_A);CHKERRQ(ierr);
2102
2103 LOG_ALLOW(GLOBAL,LOG_DEBUG," Max value in A matrix for level %d = %le.\n",user->thislevel,max_A);
2104
2105 // if (get_log_level() >= LOG_DEBUG) {
2106 // ierr = MatView(user->A,PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
2107 // }
2108
2109 // --- Restore access to all PETSc vectors and destroy temporary ones ---
2110 DMDAVecRestoreArray(da, G11, &g11); DMDAVecRestoreArray(da, G12, &g12); DMDAVecRestoreArray(da, G13, &g13);
2111 DMDAVecRestoreArray(da, G21, &g21); DMDAVecRestoreArray(da, G22, &g22); DMDAVecRestoreArray(da, G23, &g23);
2112 DMDAVecRestoreArray(da, G31, &g31); DMDAVecRestoreArray(da, G32, &g32); DMDAVecRestoreArray(da, G33, &g33);
2113
2114 VecDestroy(&G11); VecDestroy(&G12); VecDestroy(&G13);
2115 VecDestroy(&G21); VecDestroy(&G22); VecDestroy(&G23);
2116 VecDestroy(&G31); VecDestroy(&G32); VecDestroy(&G33);
2117
2118 DMDAVecRestoreArray(fda, user->lCsi, &csi); DMDAVecRestoreArray(fda, user->lEta, &eta); DMDAVecRestoreArray(fda, user->lZet, &zet);
2119 DMDAVecRestoreArray(fda, user->lICsi, &icsi); DMDAVecRestoreArray(fda, user->lIEta, &ieta); DMDAVecRestoreArray(fda, user->lIZet, &izet);
2120 DMDAVecRestoreArray(fda, user->lJCsi, &jcsi); DMDAVecRestoreArray(fda, user->lJEta, &jeta); DMDAVecRestoreArray(fda, user->lJZet, &jzet);
2121 DMDAVecRestoreArray(fda, user->lKCsi, &kcsi); DMDAVecRestoreArray(fda, user->lKEta, &keta); DMDAVecRestoreArray(fda, user->lKZet, &kzet);
2122 DMDAVecRestoreArray(da, user->lAj, &aj); DMDAVecRestoreArray(da, user->lIAj, &iaj); DMDAVecRestoreArray(da, user->lJAj, &jaj); DMDAVecRestoreArray(da, user->lKAj, &kaj);
2123 DMDAVecRestoreArray(da, user->lNvert, &nvert);
2124
2125 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Exiting PoissonLHSNew.\n");
2127 PetscFunctionReturn(0);
2128}
#define TW
Definition poisson.c:317
#define SE
Definition poisson.c:308
#define BN
Definition poisson.c:312
#define WP
Definition poisson.c:300
static PetscInt Gidx(PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
Internal helper implementation: Gidx().
Definition poisson.c:44
#define SW
Definition poisson.c:310
#define BS
Definition poisson.c:314
#define NE
Definition poisson.c:307
#define CP
Definition poisson.c:297
#define BE
Definition poisson.c:316
#define BP
Definition poisson.c:304
#define BW
Definition poisson.c:318
#define TE
Definition poisson.c:315
#define TS
Definition poisson.c:313
#define NP
Definition poisson.c:301
#define EP
Definition poisson.c:299
#define TN
Definition poisson.c:311
#define SP
Definition poisson.c:302
#define TP
Definition poisson.c:303
#define NW
Definition poisson.c:309
PetscInt KM
Definition variables.h:820
PetscBool assignedA
Definition variables.h:854
PetscInt thislevel
Definition variables.h:874
PetscInt JM
Definition variables.h:820
Vec lAj
Definition variables.h:858
PetscInt IM
Definition variables.h:820
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PoissonRHS()

PetscErrorCode PoissonRHS ( UserCtx user,
Vec  B 
)

Implementation of PoissonRHS().

Computes the Right-Hand-Side (RHS) of the Poisson equation, which is the divergence of the intermediate velocity field.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
PoissonRHS()

Definition at line 2141 of file poisson.c.

2142{
2143 PetscErrorCode ierr;
2144 DMDALocalInfo info = user->info;
2145 PetscInt xs = info.xs, xe = info.xs + info.xm;
2146 PetscInt ys = info.ys, ye = info.ys + info.ym;
2147 PetscInt zs = info.zs, ze = info.zs + info.zm;
2148 PetscInt mx = info.mx, my = info.my, mz = info.mz;
2149
2150 PetscInt i, j, k;
2151 PetscReal ***nvert, ***aj, ***rb, dt = user->simCtx->dt;
2152 struct Components{
2153 PetscReal x;
2154 PetscReal y;
2155 PetscReal z;
2156 } *** ucont;
2157
2159
2160 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Entering PoissonRHS to compute pressure equation RHS.\n");
2161
2162 DMDAVecGetArray(user->da, B, &rb);
2163 DMDAVecGetArray(user->fda, user->lUcont, &ucont);
2164 DMDAVecGetArray(user->da, user->lNvert, &nvert);
2165 DMDAVecGetArray(user->da, user->lAj, &aj);
2166
2167
2168 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Computing RHS values for each cell.\n");
2169
2170 for (k=zs; k<ze; k++) {
2171 for (j=ys; j<ye; j++) {
2172 for (i=xs; i<xe; i++) {
2173
2174 if (i==0 || i==mx-1 || j==0 || j==my-1 || k==0 || k==mz-1) {
2175 rb[k][j][i] = 0.;
2176 }
2177 else if (nvert[k][j][i] > 0.1) {
2178 rb[k][j][i] = 0;
2179 }
2180 else {
2181 rb[k][j][i] = -(ucont[k][j][i].x - ucont[k][j][i-1].x +
2182 ucont[k][j][i].y - ucont[k][j-1][i].y +
2183 ucont[k][j][i].z - ucont[k-1][j][i].z) / dt
2184 * aj[k][j][i] / 1.0 * COEF_TIME_ACCURACY; // user->simCtx->st replaced by 1.0.
2185
2186 }
2187 }
2188 }
2189 }
2190
2191
2192 // --- Check the solvability condition for the Poisson equation ---
2193 // The global sum of the RHS (proportional to the total divergence) must be zero.
2194 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Verifying solvability condition (sum of RHS terms).\n");
2195 PetscReal lsum=0., sum=0.;
2196
2197 for (k=zs; k<ze; k++) {
2198 for (j=ys; j<ye; j++) {
2199 for (i=xs; i<xe; i++) {
2200
2201 lsum += rb[k][j][i] / aj[k][j][i]* dt/COEF_TIME_ACCURACY;
2202
2203 }
2204 }
2205 }
2206
2207 ierr = MPI_Allreduce(&lsum,&sum,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2208
2209 LOG_ALLOW(GLOBAL, LOG_INFO, "Global Sum of RHS (Divergence Check): %le\n", sum);
2210
2211 user->simCtx->summationRHS = sum;
2212
2213 DMDAVecRestoreArray(user->fda, user->lUcont, &ucont);
2214 DMDAVecRestoreArray(user->da, user->lNvert, &nvert);
2215 DMDAVecRestoreArray(user->da, user->lAj, &aj);
2216 DMDAVecRestoreArray(user->da, B, &rb);
2217
2218
2220 return 0;
2221}
PetscReal summationRHS
Definition variables.h:770
Here is the caller graph for this function:

◆ VolumeFlux_rev()

PetscErrorCode VolumeFlux_rev ( UserCtx user,
PetscReal *  ibm_Flux,
PetscReal *  ibm_Area,
PetscInt  flg 
)

Implementation of VolumeFlux_rev().

A specialized version of VolumeFlux, likely for reversed normals.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
VolumeFlux_rev()

Definition at line 2230 of file poisson.c.

2232{
2233 PetscErrorCode ierr;
2234
2235 DM da = user->da, fda = user->fda;
2236
2237 DMDALocalInfo info = user->info;
2238
2239 PetscInt xs = info.xs, xe = info.xs + info.xm;
2240 PetscInt ys = info.ys, ye = info.ys + info.ym;
2241 PetscInt zs = info.zs, ze = info.zs + info.zm;
2242 PetscInt mx = info.mx, my = info.my, mz = info.mz;
2243
2244 PetscInt i, j, k;
2245 PetscInt lxs, lys, lzs, lxe, lye, lze;
2246
2247 lxs = xs; lxe = xe;
2248 lys = ys; lye = ye;
2249 lzs = zs; lze = ze;
2250
2251 if (xs==0) lxs = xs+1;
2252 if (ys==0) lys = ys+1;
2253 if (zs==0) lzs = zs+1;
2254
2255 if (xe==mx) lxe = xe-1;
2256 if (ye==my) lye = ye-1;
2257 if (ze==mz) lze = ze-1;
2258
2259 PetscReal ***nvert, ibmval=1.5;
2260 Cmpnts ***ucor, ***csi, ***eta, ***zet;
2261 DMDAVecGetArray(fda, user->Ucont, &ucor);
2262 DMDAVecGetArray(fda, user->lCsi, &csi);
2263 DMDAVecGetArray(fda, user->lEta, &eta);
2264 DMDAVecGetArray(fda, user->lZet, &zet);
2265 DMDAVecGetArray(da, user->lNvert, &nvert);
2266
2267 PetscReal libm_Flux, libm_area;
2268 libm_Flux = 0;
2269 libm_area = 0;
2270 for (k=lzs; k<lze; k++) {
2271 for (j=lys; j<lye; j++) {
2272 for (i=lxs; i<lxe; i++) {
2273 if (nvert[k][j][i] < 0.1) {
2274 if (nvert[k][j][i+1] > ibmval-0.4 && nvert[k][j][i+1] < ibmval && i < mx-2) {
2275 libm_Flux += ucor[k][j][i].x;
2276 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2277 csi[k][j][i].y * csi[k][j][i].y +
2278 csi[k][j][i].z * csi[k][j][i].z);
2279
2280 }
2281 if (nvert[k][j+1][i] > ibmval-0.4 && nvert[k][j+1][i] < ibmval && j < my-2) {
2282 libm_Flux += ucor[k][j][i].y;
2283 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2284 eta[k][j][i].y * eta[k][j][i].y +
2285 eta[k][j][i].z * eta[k][j][i].z);
2286 }
2287 if (nvert[k+1][j][i] > ibmval-0.4 && nvert[k+1][j][i] < ibmval && k < mz-2) {
2288 libm_Flux += ucor[k][j][i].z;
2289 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2290 zet[k][j][i].y * zet[k][j][i].y +
2291 zet[k][j][i].z * zet[k][j][i].z);
2292 }
2293 }
2294
2295 if (nvert[k][j][i] > ibmval-0.4 && nvert[k][j][i] < ibmval) {
2296 if (nvert[k][j][i+1] < 0.1 && i < mx-2) {
2297 libm_Flux -= ucor[k][j][i].x;
2298 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2299 csi[k][j][i].y * csi[k][j][i].y +
2300 csi[k][j][i].z * csi[k][j][i].z);
2301
2302 }
2303 if (nvert[k][j+1][i] < 0.1 && j < my-2) {
2304 libm_Flux -= ucor[k][j][i].y;
2305 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2306 eta[k][j][i].y * eta[k][j][i].y +
2307 eta[k][j][i].z * eta[k][j][i].z);
2308 }
2309 if (nvert[k+1][j][i] < 0.1 && k < mz-2) {
2310 libm_Flux -= ucor[k][j][i].z;
2311 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2312 zet[k][j][i].y * zet[k][j][i].y +
2313 zet[k][j][i].z * zet[k][j][i].z);
2314 }
2315 }
2316
2317 }
2318 }
2319 }
2320
2321 ierr = MPI_Allreduce(&libm_Flux, ibm_Flux,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2322 ierr = MPI_Allreduce(&libm_area, ibm_Area,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2323
2324 /* PetscGlobalSum(&libm_Flux, ibm_Flux, PETSC_COMM_WORLD); */
2325/* PetscGlobalSum(&libm_area, ibm_Area, PETSC_COMM_WORLD); */
2326 PetscPrintf(PETSC_COMM_WORLD, "IBMFlux REV %le %le\n", *ibm_Flux, *ibm_Area);
2327
2328 PetscReal correction;
2329
2330 if (*ibm_Area > 1.e-15) {
2331 if (flg)
2332 correction = (*ibm_Flux + user->FluxIntpSum) / *ibm_Area;
2333 else
2334 correction = *ibm_Flux / *ibm_Area;
2335 }
2336 else {
2337 correction = 0;
2338 }
2339
2340 for (k=lzs; k<lze; k++) {
2341 for (j=lys; j<lye; j++) {
2342 for (i=lxs; i<lxe; i++) {
2343 if (nvert[k][j][i] < 0.1) {
2344 if (nvert[k][j][i+1] > ibmval-0.4 && nvert[k][j][i+1] < ibmval && i < mx-2) {
2345 ucor[k][j][i].x -= sqrt(csi[k][j][i].x * csi[k][j][i].x +
2346 csi[k][j][i].y * csi[k][j][i].y +
2347 csi[k][j][i].z * csi[k][j][i].z) *
2348 correction;
2349
2350 }
2351 if (nvert[k][j+1][i] > ibmval-0.4 && nvert[k][j+1][i] < ibmval && j < my-2) {
2352 ucor[k][j][i].y -= sqrt(eta[k][j][i].x * eta[k][j][i].x +
2353 eta[k][j][i].y * eta[k][j][i].y +
2354 eta[k][j][i].z * eta[k][j][i].z) *
2355 correction;
2356 }
2357 if (nvert[k+1][j][i] > ibmval-0.4 && nvert[k+1][j][i] < ibmval && k < mz-2) {
2358 ucor[k][j][i].z -= sqrt(zet[k][j][i].x * zet[k][j][i].x +
2359 zet[k][j][i].y * zet[k][j][i].y +
2360 zet[k][j][i].z * zet[k][j][i].z) *
2361 correction;
2362 }
2363 }
2364
2365 if (nvert[k][j][i] > ibmval-0.4 && nvert[k][j][i] < ibmval) {
2366 if (nvert[k][j][i+1] < 0.1 && i < mx-2) {
2367 ucor[k][j][i].x += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2368 csi[k][j][i].y * csi[k][j][i].y +
2369 csi[k][j][i].z * csi[k][j][i].z) *
2370 correction;
2371
2372 }
2373 if (nvert[k][j+1][i] < 0.1 && j < my-2) {
2374 ucor[k][j][i].y += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2375 eta[k][j][i].y * eta[k][j][i].y +
2376 eta[k][j][i].z * eta[k][j][i].z) *
2377 correction;
2378 }
2379 if (nvert[k+1][j][i] < 0.1 && k < mz-2) {
2380 ucor[k][j][i].z += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2381 zet[k][j][i].y * zet[k][j][i].y +
2382 zet[k][j][i].z * zet[k][j][i].z) *
2383 correction;
2384 }
2385 }
2386
2387 }
2388 }
2389 }
2390
2391
2392
2393 libm_Flux = 0;
2394 libm_area = 0;
2395 for (k=lzs; k<lze; k++) {
2396 for (j=lys; j<lye; j++) {
2397 for (i=lxs; i<lxe; i++) {
2398 if (nvert[k][j][i] < 0.1) {
2399 if (nvert[k][j][i+1] > ibmval-0.4 && nvert[k][j][i+1] < ibmval && i < mx-2) {
2400 libm_Flux += ucor[k][j][i].x;
2401 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2402 csi[k][j][i].y * csi[k][j][i].y +
2403 csi[k][j][i].z * csi[k][j][i].z);
2404
2405 }
2406 if (nvert[k][j+1][i] > ibmval-0.4 && nvert[k][j+1][i] < ibmval && j < my-2) {
2407 libm_Flux += ucor[k][j][i].y;
2408 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2409 eta[k][j][i].y * eta[k][j][i].y +
2410 eta[k][j][i].z * eta[k][j][i].z);
2411 }
2412 if (nvert[k+1][j][i] > ibmval-0.4 && nvert[k+1][j][i] < ibmval && k < mz-2) {
2413 libm_Flux += ucor[k][j][i].z;
2414 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2415 zet[k][j][i].y * zet[k][j][i].y +
2416 zet[k][j][i].z * zet[k][j][i].z);
2417 }
2418 }
2419
2420 if (nvert[k][j][i] > ibmval-0.4 && nvert[k][j][i] < ibmval) {
2421 if (nvert[k][j][i+1] < 0.1 && i < mx-2) {
2422 libm_Flux -= ucor[k][j][i].x;
2423 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2424 csi[k][j][i].y * csi[k][j][i].y +
2425 csi[k][j][i].z * csi[k][j][i].z);
2426
2427 }
2428 if (nvert[k][j+1][i] < 0.1 && j < my-2) {
2429 libm_Flux -= ucor[k][j][i].y;
2430 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2431 eta[k][j][i].y * eta[k][j][i].y +
2432 eta[k][j][i].z * eta[k][j][i].z);
2433 }
2434 if (nvert[k+1][j][i] < 0.1 && k < mz-2) {
2435 libm_Flux -= ucor[k][j][i].z;
2436 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2437 zet[k][j][i].y * zet[k][j][i].y +
2438 zet[k][j][i].z * zet[k][j][i].z);
2439 }
2440 }
2441
2442 }
2443 }
2444 }
2445
2446 ierr = MPI_Allreduce(&libm_Flux, ibm_Flux,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2447 ierr = MPI_Allreduce(&libm_area, ibm_Area,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2448
2449 /* PetscGlobalSum(&libm_Flux, ibm_Flux, PETSC_COMM_WORLD); */
2450/* PetscGlobalSum(&libm_area, ibm_Area, PETSC_COMM_WORLD); */
2451 PetscPrintf(PETSC_COMM_WORLD, "IBMFlux22 REV %le %le\n", *ibm_Flux, *ibm_Area);
2452
2453 DMDAVecRestoreArray(da, user->lNvert, &nvert);
2454 DMDAVecRestoreArray(fda, user->lCsi, &csi);
2455 DMDAVecRestoreArray(fda, user->lEta, &eta);
2456 DMDAVecRestoreArray(fda, user->lZet, &zet);
2457 DMDAVecRestoreArray(fda, user->Ucont, &ucor);
2458
2459 DMGlobalToLocalBegin(fda, user->Ucont, INSERT_VALUES, user->lUcont);
2460 DMGlobalToLocalEnd(fda, user->Ucont, INSERT_VALUES, user->lUcont);
2461 return 0;
2462}
PetscReal FluxIntpSum
Definition variables.h:834
Here is the caller graph for this function:

◆ VolumeFlux()

PetscErrorCode VolumeFlux ( UserCtx user,
PetscReal *  ibm_Flux,
PetscReal *  ibm_Area,
PetscInt  flg 
)

Implementation of VolumeFlux().

Calculates the net flux across the immersed boundary surface.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
VolumeFlux()

Definition at line 2472 of file poisson.c.

2473{
2474 PetscErrorCode ierr;
2475 // --- CONTEXT ACQUISITION BLOCK ---
2476 // Get the master simulation context from the UserCtx.
2477 SimCtx *simCtx = user->simCtx;
2478
2479 // Create local variables to mirror the legacy globals for minimal code changes.
2480 const PetscInt NumberOfBodies = simCtx->NumberOfBodies;
2481 // --- END CONTEXT ACQUISITION BLOCK ---
2482
2483 DM da = user->da, fda = user->fda;
2484
2485 DMDALocalInfo info = user->info;
2486
2487 PetscInt xs = info.xs, xe = info.xs + info.xm;
2488 PetscInt ys = info.ys, ye = info.ys + info.ym;
2489 PetscInt zs = info.zs, ze = info.zs + info.zm;
2490 PetscInt mx = info.mx, my = info.my, mz = info.mz;
2491
2492 PetscInt i, j, k,ibi;
2493 PetscInt lxs, lys, lzs, lxe, lye, lze;
2494
2495 lxs = xs; lxe = xe;
2496 lys = ys; lye = ye;
2497 lzs = zs; lze = ze;
2498
2499 if (xs==0) lxs = xs+1;
2500 if (ys==0) lys = ys+1;
2501 if (zs==0) lzs = zs+1;
2502
2503 if (xe==mx) lxe = xe-1;
2504 if (ye==my) lye = ye-1;
2505 if (ze==mz) lze = ze-1;
2506
2507 PetscReal epsilon=1.e-8;
2508 PetscReal ***nvert, ibmval=1.9999;
2509
2510 struct Components {
2511 PetscReal x;
2512 PetscReal y;
2513 PetscReal z;
2514 }***ucor, ***lucor,***csi, ***eta, ***zet;
2515
2516
2517 PetscInt xend=mx-2 ,yend=my-2,zend=mz-2;
2518
2519 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC) xend=mx-1;
2520 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC) yend=my-1;
2521 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC) zend=mz-1;
2522
2523 DMDAVecGetArray(fda, user->Ucont, &ucor);
2524 DMDAVecGetArray(fda, user->lCsi, &csi);
2525 DMDAVecGetArray(fda, user->lEta, &eta);
2526 DMDAVecGetArray(fda, user->lZet, &zet);
2527 DMDAVecGetArray(da, user->lNvert, &nvert);
2528
2529 PetscReal libm_Flux, libm_area, libm_Flux_abs=0., ibm_Flux_abs;
2530 libm_Flux = 0;
2531 libm_area = 0;
2532
2533 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Entering VolumeFlux to enforce no-penetration condition.\n");
2534
2535 //Mohsen March 2017
2536 PetscReal *lIB_Flux = NULL, *lIB_area = NULL, *IB_Flux = NULL, *IB_Area = NULL;
2537 if (NumberOfBodies > 1) {
2538
2539 lIB_Flux=(PetscReal *)calloc(NumberOfBodies,sizeof(PetscReal));
2540 lIB_area=(PetscReal *)calloc(NumberOfBodies,sizeof(PetscReal));
2541 IB_Flux=(PetscReal *)calloc(NumberOfBodies,sizeof(PetscReal));
2542 IB_Area=(PetscReal *)calloc(NumberOfBodies,sizeof(PetscReal));
2543
2544
2545 for (ibi=0; ibi<NumberOfBodies; ibi++) {
2546 lIB_Flux[ibi]=0.0;
2547 lIB_area[ibi]=0.0;
2548 IB_Flux[ibi]=0.0;
2549 IB_Area[ibi]=0.0;
2550 }
2551 }
2552
2553
2554 //================================================================================
2555 // PASS 1: Calculate Uncorrected Flux and Area
2556 // This pass measures the total fluid "leakage" across the immersed boundary.
2557 //================================================================================
2558 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Pass 1: Measuring uncorrected flux and area.\n");
2559
2560 for (k=lzs; k<lze; k++) {
2561 for (j=lys; j<lye; j++) {
2562 for (i=lxs; i<lxe; i++) {
2563 if (nvert[k][j][i] < 0.1) {
2564 if (nvert[k][j][i+1] > 0.1 && nvert[k][j][i+1] < ibmval && i < xend) {
2565
2566 if (fabs(ucor[k][j][i].x)>epsilon) {
2567 libm_Flux += ucor[k][j][i].x;
2568 if (flg==3)
2569 libm_Flux_abs += fabs(ucor[k][j][i].x)/sqrt(csi[k][j][i].x * csi[k][j][i].x +
2570 csi[k][j][i].y * csi[k][j][i].y +
2571 csi[k][j][i].z * csi[k][j][i].z);
2572 else
2573 libm_Flux_abs += fabs(ucor[k][j][i].x);
2574
2575 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2576 csi[k][j][i].y * csi[k][j][i].y +
2577 csi[k][j][i].z * csi[k][j][i].z);
2578
2579 if (NumberOfBodies > 1) {
2580
2581 ibi=(int)((nvert[k][j][i+1]-1.0)*1001);
2582 lIB_Flux[ibi] += ucor[k][j][i].x;
2583 lIB_area[ibi] += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2584 csi[k][j][i].y * csi[k][j][i].y +
2585 csi[k][j][i].z * csi[k][j][i].z);
2586 }
2587 } else
2588 ucor[k][j][i].x=0.;
2589
2590 }
2591 if (nvert[k][j+1][i] > 0.1 && nvert[k][j+1][i] < ibmval && j < yend) {
2592
2593 if (fabs(ucor[k][j][i].y)>epsilon) {
2594 libm_Flux += ucor[k][j][i].y;
2595 if (flg==3)
2596 libm_Flux_abs += fabs(ucor[k][j][i].y)/sqrt(eta[k][j][i].x * eta[k][j][i].x +
2597 eta[k][j][i].y * eta[k][j][i].y +
2598 eta[k][j][i].z * eta[k][j][i].z);
2599 else
2600 libm_Flux_abs += fabs(ucor[k][j][i].y);
2601 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2602 eta[k][j][i].y * eta[k][j][i].y +
2603 eta[k][j][i].z * eta[k][j][i].z);
2604 if (NumberOfBodies > 1) {
2605
2606 ibi=(int)((nvert[k][j+1][i]-1.0)*1001);
2607
2608 lIB_Flux[ibi] += ucor[k][j][i].y;
2609 lIB_area[ibi] += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2610 eta[k][j][i].y * eta[k][j][i].y +
2611 eta[k][j][i].z * eta[k][j][i].z);
2612 }
2613 } else
2614 ucor[k][j][i].y=0.;
2615 }
2616 if (nvert[k+1][j][i] > 0.1 && nvert[k+1][j][i] < ibmval && k < zend) {
2617
2618 if (fabs(ucor[k][j][i].z)>epsilon) {
2619 libm_Flux += ucor[k][j][i].z;
2620 if (flg==3)
2621 libm_Flux_abs += fabs(ucor[k][j][i].z)/sqrt(zet[k][j][i].x * zet[k][j][i].x +
2622 zet[k][j][i].y * zet[k][j][i].y +
2623 zet[k][j][i].z * zet[k][j][i].z);
2624 else
2625 libm_Flux_abs += fabs(ucor[k][j][i].z);
2626 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2627 zet[k][j][i].y * zet[k][j][i].y +
2628 zet[k][j][i].z * zet[k][j][i].z);
2629
2630 if (NumberOfBodies > 1) {
2631
2632 ibi=(int)((nvert[k+1][j][i]-1.0)*1001);
2633 lIB_Flux[ibi] += ucor[k][j][i].z;
2634 lIB_area[ibi] += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2635 zet[k][j][i].y * zet[k][j][i].y +
2636 zet[k][j][i].z * zet[k][j][i].z);
2637 }
2638 }else
2639 ucor[k][j][i].z=0.;
2640 }
2641 }
2642
2643 if (nvert[k][j][i] > 0.1 && nvert[k][j][i] < ibmval) {
2644
2645 if (nvert[k][j][i+1] < 0.1 && i < xend) {
2646 if (fabs(ucor[k][j][i].x)>epsilon) {
2647 libm_Flux -= ucor[k][j][i].x;
2648 if (flg==3)
2649 libm_Flux_abs += fabs(ucor[k][j][i].x)/sqrt(csi[k][j][i].x * csi[k][j][i].x +
2650 csi[k][j][i].y * csi[k][j][i].y +
2651 csi[k][j][i].z * csi[k][j][i].z);
2652 else
2653 libm_Flux_abs += fabs(ucor[k][j][i].x);
2654 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2655 csi[k][j][i].y * csi[k][j][i].y +
2656 csi[k][j][i].z * csi[k][j][i].z);
2657 if (NumberOfBodies > 1) {
2658
2659 ibi=(int)((nvert[k][j][i]-1.0)*1001);
2660 lIB_Flux[ibi] -= ucor[k][j][i].x;
2661 lIB_area[ibi] += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2662 csi[k][j][i].y * csi[k][j][i].y +
2663 csi[k][j][i].z * csi[k][j][i].z);
2664 }
2665
2666 }else
2667 ucor[k][j][i].x=0.;
2668 }
2669 if (nvert[k][j+1][i] < 0.1 && j < yend) {
2670 if (fabs(ucor[k][j][i].y)>epsilon) {
2671 libm_Flux -= ucor[k][j][i].y;
2672 if (flg==3)
2673 libm_Flux_abs += fabs(ucor[k][j][i].y)/ sqrt(eta[k][j][i].x * eta[k][j][i].x +
2674 eta[k][j][i].y * eta[k][j][i].y +
2675 eta[k][j][i].z * eta[k][j][i].z);
2676 else
2677 libm_Flux_abs += fabs(ucor[k][j][i].y);
2678 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2679 eta[k][j][i].y * eta[k][j][i].y +
2680 eta[k][j][i].z * eta[k][j][i].z);
2681 if (NumberOfBodies > 1) {
2682
2683 ibi=(int)((nvert[k][j][i]-1.0)*1001);
2684 lIB_Flux[ibi] -= ucor[k][j][i].y;
2685 lIB_area[ibi] += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2686 eta[k][j][i].y * eta[k][j][i].y +
2687 eta[k][j][i].z * eta[k][j][i].z);
2688 }
2689 }else
2690 ucor[k][j][i].y=0.;
2691 }
2692 if (nvert[k+1][j][i] < 0.1 && k < zend) {
2693 if (fabs(ucor[k][j][i].z)>epsilon) {
2694 libm_Flux -= ucor[k][j][i].z;
2695 if (flg==3)
2696 libm_Flux_abs += fabs(ucor[k][j][i].z)/sqrt(zet[k][j][i].x * zet[k][j][i].x +
2697 zet[k][j][i].y * zet[k][j][i].y +
2698 zet[k][j][i].z * zet[k][j][i].z);
2699 else
2700 libm_Flux_abs += fabs(ucor[k][j][i].z);
2701 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2702 zet[k][j][i].y * zet[k][j][i].y +
2703 zet[k][j][i].z * zet[k][j][i].z);
2704 if (NumberOfBodies > 1) {
2705
2706 ibi=(int)((nvert[k][j][i]-1.0)*1001);
2707 lIB_Flux[ibi] -= ucor[k][j][i].z;
2708 lIB_area[ibi] += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2709 zet[k][j][i].y * zet[k][j][i].y +
2710 zet[k][j][i].z * zet[k][j][i].z);
2711 }
2712 }else
2713 ucor[k][j][i].z=0.;
2714 }
2715 }
2716
2717 }
2718 }
2719 }
2720
2721 ierr = MPI_Allreduce(&libm_Flux, ibm_Flux,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2722 ierr = MPI_Allreduce(&libm_Flux_abs, &ibm_Flux_abs,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2723 ierr = MPI_Allreduce(&libm_area, ibm_Area,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2724
2725 if (NumberOfBodies > 1) {
2726 ierr = MPI_Allreduce(lIB_Flux,IB_Flux,NumberOfBodies,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
2727 ierr = MPI_Allreduce(lIB_area,IB_Area,NumberOfBodies,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRMPI(ierr);
2728 }
2729
2730 PetscReal correction;
2731
2732 PetscReal *Correction = NULL;
2733 if (NumberOfBodies > 1) {
2734 Correction=(PetscReal *)calloc(NumberOfBodies,sizeof(PetscReal));
2735 for (ibi=0; ibi<NumberOfBodies; ibi++) Correction[ibi]=0.0;
2736 }
2737
2738 if (*ibm_Area > 1.e-15) {
2739 if (flg>1)
2740 correction = (*ibm_Flux + user->FluxIntpSum)/ ibm_Flux_abs;
2741 else if (flg)
2742 correction = (*ibm_Flux + user->FluxIntpSum) / *ibm_Area;
2743 else
2744 correction = *ibm_Flux / *ibm_Area;
2745 if (NumberOfBodies > 1)
2746 for (ibi=0; ibi<NumberOfBodies; ibi++) if (IB_Area[ibi]>1.e-15) Correction[ibi] = IB_Flux[ibi] / IB_Area[ibi];
2747 }
2748 else {
2749 correction = 0;
2750 }
2751 // --- Log the uncorrected results and calculated correction ---
2752 LOG_ALLOW(GLOBAL, LOG_INFO, "IBM Uncorrected Flux: %g, Area: %g, Correction: %g\n", *ibm_Flux, *ibm_Area, correction);
2753 if (NumberOfBodies>1){
2754 for (ibi=0; ibi<NumberOfBodies; ibi++) LOG_ALLOW(GLOBAL, LOG_INFO, " [Body %d] Uncorrected Flux: %g, Area: %g, Correction: %g\n", ibi, IB_Flux[ibi], IB_Area[ibi], Correction[ibi]);
2755 }
2756
2757 //================================================================================
2758 // PASS 2: Apply Correction to Velocity Field
2759 // This pass modifies the velocity at the boundary to enforce zero net flux.
2760 //================================================================================
2761 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Pass 2: Applying velocity corrections at the boundary.\n");
2762
2763 for (k=lzs; k<lze; k++) {
2764 for (j=lys; j<lye; j++) {
2765 for (i=lxs; i<lxe; i++) {
2766 if (nvert[k][j][i] < 0.1) {
2767 if (nvert[k][j][i+1] > 0.1 && nvert[k][j][i+1] <ibmval && i < xend) {
2768 if (fabs(ucor[k][j][i].x)>epsilon){
2769 if (flg==3)
2770 ucor[k][j][i].x -=correction*fabs(ucor[k][j][i].x)/
2771 sqrt(csi[k][j][i].x * csi[k][j][i].x +
2772 csi[k][j][i].y * csi[k][j][i].y +
2773 csi[k][j][i].z * csi[k][j][i].z);
2774 else if (flg==2)
2775 ucor[k][j][i].x -=correction*fabs(ucor[k][j][i].x);
2776 else if (NumberOfBodies > 1) {
2777 ibi=(int)((nvert[k][j][i+1]-1.0)*1001);
2778 ucor[k][j][i].x -= sqrt(csi[k][j][i].x * csi[k][j][i].x +
2779 csi[k][j][i].y * csi[k][j][i].y +
2780 csi[k][j][i].z * csi[k][j][i].z) *
2781 Correction[ibi];
2782 }
2783 else
2784 ucor[k][j][i].x -= sqrt(csi[k][j][i].x * csi[k][j][i].x +
2785 csi[k][j][i].y * csi[k][j][i].y +
2786 csi[k][j][i].z * csi[k][j][i].z) *
2787 correction;
2788 }
2789 }
2790 if (nvert[k][j+1][i] > 0.1 && nvert[k][j+1][i] < ibmval && j < yend) {
2791 if (fabs(ucor[k][j][i].y)>epsilon) {
2792 if (flg==3)
2793 ucor[k][j][i].y -=correction*fabs(ucor[k][j][i].y)/
2794 sqrt(eta[k][j][i].x * eta[k][j][i].x +
2795 eta[k][j][i].y * eta[k][j][i].y +
2796 eta[k][j][i].z * eta[k][j][i].z);
2797 else if (flg==2)
2798 ucor[k][j][i].y -=correction*fabs(ucor[k][j][i].y);
2799 else if (NumberOfBodies > 1) {
2800 ibi=(int)((nvert[k][j+1][i]-1.0)*1001);
2801 ucor[k][j][i].y -= sqrt(eta[k][j][i].x * eta[k][j][i].x +
2802 eta[k][j][i].y * eta[k][j][i].y +
2803 eta[k][j][i].z * eta[k][j][i].z) *
2804 Correction[ibi];
2805 }
2806 else
2807 ucor[k][j][i].y -= sqrt(eta[k][j][i].x * eta[k][j][i].x +
2808 eta[k][j][i].y * eta[k][j][i].y +
2809 eta[k][j][i].z * eta[k][j][i].z) *
2810 correction;
2811 }
2812 }
2813 if (nvert[k+1][j][i] > 0.1 && nvert[k+1][j][i] < ibmval && k < zend) {
2814 if (fabs(ucor[k][j][i].z)>epsilon) {
2815 if (flg==3)
2816 ucor[k][j][i].z -= correction*fabs(ucor[k][j][i].z)/
2817 sqrt(zet[k][j][i].x * zet[k][j][i].x +
2818 zet[k][j][i].y * zet[k][j][i].y +
2819 zet[k][j][i].z * zet[k][j][i].z);
2820 else if (flg==2)
2821 ucor[k][j][i].z -= correction*fabs(ucor[k][j][i].z);
2822 else if (NumberOfBodies > 1) {
2823 ibi=(int)((nvert[k+1][j][i]-1.0)*1001);
2824 ucor[k][j][i].z -= sqrt(zet[k][j][i].x * zet[k][j][i].x +
2825 zet[k][j][i].y * zet[k][j][i].y +
2826 zet[k][j][i].z * zet[k][j][i].z) *
2827 Correction[ibi];
2828 }
2829 else
2830 ucor[k][j][i].z -= sqrt(zet[k][j][i].x * zet[k][j][i].x +
2831 zet[k][j][i].y * zet[k][j][i].y +
2832 zet[k][j][i].z * zet[k][j][i].z) *
2833 correction;
2834 }
2835 }
2836 }
2837
2838 if (nvert[k][j][i] > 0.1 && nvert[k][j][i] < ibmval) {
2839 if (nvert[k][j][i+1] < 0.1 && i < xend) {
2840 if (fabs(ucor[k][j][i].x)>epsilon) {
2841 if (flg==3)
2842 ucor[k][j][i].x += correction*fabs(ucor[k][j][i].x)/
2843 sqrt(csi[k][j][i].x * csi[k][j][i].x +
2844 csi[k][j][i].y * csi[k][j][i].y +
2845 csi[k][j][i].z * csi[k][j][i].z);
2846 else if (flg==2)
2847 ucor[k][j][i].x += correction*fabs(ucor[k][j][i].x);
2848 else if (NumberOfBodies > 1) {
2849 ibi=(int)((nvert[k][j][i]-1.0)*1001);
2850 ucor[k][j][i].x += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2851 csi[k][j][i].y * csi[k][j][i].y +
2852 csi[k][j][i].z * csi[k][j][i].z) *
2853 Correction[ibi];
2854 }
2855 else
2856 ucor[k][j][i].x += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2857 csi[k][j][i].y * csi[k][j][i].y +
2858 csi[k][j][i].z * csi[k][j][i].z) *
2859 correction;
2860 }
2861 }
2862 if (nvert[k][j+1][i] < 0.1 && j < yend) {
2863 if (fabs(ucor[k][j][i].y)>epsilon) {
2864 if (flg==3)
2865 ucor[k][j][i].y +=correction*fabs(ucor[k][j][i].y)/
2866 sqrt(eta[k][j][i].x * eta[k][j][i].x +
2867 eta[k][j][i].y * eta[k][j][i].y +
2868 eta[k][j][i].z * eta[k][j][i].z);
2869 else if (flg==2)
2870 ucor[k][j][i].y +=correction*fabs(ucor[k][j][i].y);
2871 else if (NumberOfBodies > 1) {
2872 ibi=(int)((nvert[k][j][i]-1.0)*1001);
2873 ucor[k][j][i].y += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2874 eta[k][j][i].y * eta[k][j][i].y +
2875 eta[k][j][i].z * eta[k][j][i].z) *
2876 Correction[ibi];
2877 }
2878 else
2879 ucor[k][j][i].y += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2880 eta[k][j][i].y * eta[k][j][i].y +
2881 eta[k][j][i].z * eta[k][j][i].z) *
2882 correction;
2883 }
2884 }
2885 if (nvert[k+1][j][i] < 0.1 && k < zend) {
2886 if (fabs(ucor[k][j][i].z)>epsilon) {
2887 if (flg==3)
2888 ucor[k][j][i].z += correction*fabs(ucor[k][j][i].z)/
2889 sqrt(zet[k][j][i].x * zet[k][j][i].x +
2890 zet[k][j][i].y * zet[k][j][i].y +
2891 zet[k][j][i].z * zet[k][j][i].z);
2892 else if (flg==2)
2893 ucor[k][j][i].z += correction*fabs(ucor[k][j][i].z);
2894 else if (NumberOfBodies > 1) {
2895 ibi=(int)((nvert[k][j][i]-1.0)*1001);
2896 ucor[k][j][i].z += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2897 zet[k][j][i].y * zet[k][j][i].y +
2898 zet[k][j][i].z * zet[k][j][i].z) *
2899 Correction[ibi];
2900 }
2901 else
2902 ucor[k][j][i].z += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2903 zet[k][j][i].y * zet[k][j][i].y +
2904 zet[k][j][i].z * zet[k][j][i].z) *
2905 correction;
2906 }
2907 }
2908 }
2909
2910 }
2911 }
2912 }
2913
2914 //================================================================================
2915 // PASS 3: Verification
2916 // This optional pass recalculates the flux to confirm the correction was successful.
2917 //================================================================================
2918 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Pass 3: Verifying corrected flux.\n");
2919
2920 libm_Flux = 0;
2921 libm_area = 0;
2922 for (k=lzs; k<lze; k++) {
2923 for (j=lys; j<lye; j++) {
2924 for (i=lxs; i<lxe; i++) {
2925 if (nvert[k][j][i] < 0.1) {
2926 if (nvert[k][j][i+1] > 0.1 && nvert[k][j][i+1] < ibmval && i < xend) {
2927 libm_Flux += ucor[k][j][i].x;
2928 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2929 csi[k][j][i].y * csi[k][j][i].y +
2930 csi[k][j][i].z * csi[k][j][i].z);
2931
2932 }
2933 if (nvert[k][j+1][i] > 0.1 && nvert[k][j+1][i] < ibmval && j < yend) {
2934 libm_Flux += ucor[k][j][i].y;
2935 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2936 eta[k][j][i].y * eta[k][j][i].y +
2937 eta[k][j][i].z * eta[k][j][i].z);
2938 }
2939 if (nvert[k+1][j][i] > 0.1 && nvert[k+1][j][i] < ibmval && k < zend) {
2940 libm_Flux += ucor[k][j][i].z;
2941 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2942 zet[k][j][i].y * zet[k][j][i].y +
2943 zet[k][j][i].z * zet[k][j][i].z);
2944 }
2945 }
2946
2947 if (nvert[k][j][i] > 0.1 && nvert[k][j][i] < ibmval) {
2948 if (nvert[k][j][i+1] < 0.1 && i < xend) {
2949 libm_Flux -= ucor[k][j][i].x;
2950 libm_area += sqrt(csi[k][j][i].x * csi[k][j][i].x +
2951 csi[k][j][i].y * csi[k][j][i].y +
2952 csi[k][j][i].z * csi[k][j][i].z);
2953
2954 }
2955 if (nvert[k][j+1][i] < 0.1 && j < yend) {
2956 libm_Flux -= ucor[k][j][i].y;
2957 libm_area += sqrt(eta[k][j][i].x * eta[k][j][i].x +
2958 eta[k][j][i].y * eta[k][j][i].y +
2959 eta[k][j][i].z * eta[k][j][i].z);
2960 }
2961 if (nvert[k+1][j][i] < 0.1 && k < zend) {
2962 libm_Flux -= ucor[k][j][i].z;
2963 libm_area += sqrt(zet[k][j][i].x * zet[k][j][i].x +
2964 zet[k][j][i].y * zet[k][j][i].y +
2965 zet[k][j][i].z * zet[k][j][i].z);
2966 }
2967 }
2968
2969 }
2970 }
2971 }
2972
2973 ierr = MPI_Allreduce(&libm_Flux, ibm_Flux,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2974 ierr = MPI_Allreduce(&libm_area, ibm_Area,1,MPI_DOUBLE,MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2975
2976 /* PetscGlobalSum(&libm_Flux, ibm_Flux, PETSC_COMM_WORLD); */
2977/* PetscGlobalSum(&libm_area, ibm_Area, PETSC_COMM_WORLD); */
2978 LOG_ALLOW(GLOBAL, LOG_INFO, "IBM Corrected (Verified) Flux: %g, Area: %g\n", *ibm_Flux, *ibm_Area);
2979
2980
2982 if (xe==mx){
2983 i=mx-2;
2984 for (k=lzs; k<lze; k++) {
2985 for (j=lys; j<lye; j++) {
2986 // if(j>0 && k>0 && j<user->JM && k<user->KM){
2987 if ((nvert[k][j][i]>ibmval && nvert[k][j][i+1]<0.1) || (nvert[k][j][i]<0.1 && nvert[k][j][i+1]>ibmval)) ucor[k][j][i].x=0.0;
2988
2989 // }
2990 }
2991 }
2992 }
2993 }
2994
2996 if (ye==my){
2997 j=my-2;
2998 for (k=lzs; k<lze; k++) {
2999 for (i=lxs; i<lxe; i++) {
3000 // if(i>0 && k>0 && i<user->IM && k<user->KM){
3001 if ((nvert[k][j][i]>ibmval && nvert[k][j+1][i]<0.1) || (nvert[k][j][i]<0.1 && nvert[k][j+1][i]>ibmval)) ucor[k][j][i].y=0.0;
3002 // }
3003 }
3004 }
3005 }
3006 }
3007
3009 if (ze==mz){
3010 k=mz-2;
3011 for (j=lys; j<lye; j++) {
3012 for (i=lxs; i<lxe; i++) {
3013 // if(i>0 && j>0 && i<user->IM && j<user->JM){
3014 if ((nvert[k][j][i]>ibmval && nvert[k+1][j][i]<0.1) || (nvert[k][j][i]<0.1 && nvert[k+1][j][i]>ibmval)) ucor[k][j][i].z=0.0;
3015 // }
3016 }
3017 }
3018 }
3019 }
3020
3021
3022 DMDAVecRestoreArray(da, user->lNvert, &nvert);
3023 DMDAVecRestoreArray(fda, user->lCsi, &csi);
3024 DMDAVecRestoreArray(fda, user->lEta, &eta);
3025 DMDAVecRestoreArray(fda, user->lZet, &zet);
3026 DMDAVecRestoreArray(fda, user->Ucont, &ucor);
3027
3028 DMGlobalToLocalBegin(fda, user->Ucont, INSERT_VALUES, user->lUcont);
3029 DMGlobalToLocalEnd(fda, user->Ucont, INSERT_VALUES, user->lUcont);
3030
3031 /* periodic boundary condition update corrected flux */
3032 // Mohsen Dec 2015 (kept for transition safety; modern periodic helper path is also active)
3033 PetscBool has_periodic_ucont_seam =
3040 PetscInt periodic_seam_updates_local = 0, periodic_seam_updates_global = 0;
3041 PetscReal periodic_seam_max_delta_local = 0.0, periodic_seam_max_delta_global = 0.0;
3042
3043 if (has_periodic_ucont_seam) {
3044 LOG_ALLOW(GLOBAL, LOG_DEBUG, "VolumeFlux: entering legacy periodic Ucont seam refresh block.\n");
3045 }
3046
3047 DMDAVecGetArray(fda, user->lUcont, &lucor);
3048 DMDAVecGetArray(fda, user->Ucont, &ucor);
3049
3051 if (xs==0){
3052 i=xs;
3053 for (k=zs; k<ze; k++) {
3054 for (j=ys; j<ye; j++) {
3055 if(j>0 && k>0 && j<user->JM && k<user->KM){
3056 PetscReal old_val = ucor[k][j][i].x;
3057 PetscReal new_val = lucor[k][j][i-2].x;
3058 PetscReal delta = PetscAbsReal(new_val - old_val);
3059 ucor[k][j][i].x = new_val;
3060 if (delta > 1.0e-14) periodic_seam_updates_local++;
3061 periodic_seam_max_delta_local = PetscMax(periodic_seam_max_delta_local, delta);
3062 }
3063 }
3064 }
3065 }
3066 }
3068 if (ys==0){
3069 j=ys;
3070 for (k=zs; k<ze; k++) {
3071 for (i=xs; i<xe; i++) {
3072 if(i>0 && k>0 && i<user->IM && k<user->KM){
3073 PetscReal old_val = ucor[k][j][i].y;
3074 PetscReal new_val = lucor[k][j-2][i].y;
3075 PetscReal delta = PetscAbsReal(new_val - old_val);
3076 ucor[k][j][i].y = new_val;
3077 if (delta > 1.0e-14) periodic_seam_updates_local++;
3078 periodic_seam_max_delta_local = PetscMax(periodic_seam_max_delta_local, delta);
3079 }
3080 }
3081 }
3082 }
3083 }
3085 if (zs==0){
3086 k=zs;
3087 for (j=ys; j<ye; j++) {
3088 for (i=xs; i<xe; i++) {
3089 if(i>0 && j>0 && i<user->IM && j<user->JM){
3090 PetscReal old_val = ucor[k][j][i].z;
3091 PetscReal new_val = lucor[k-2][j][i].z;
3092 PetscReal delta = PetscAbsReal(new_val - old_val);
3093 ucor[k][j][i].z = new_val;
3094 if (delta > 1.0e-14) periodic_seam_updates_local++;
3095 periodic_seam_max_delta_local = PetscMax(periodic_seam_max_delta_local, delta);
3096 }
3097 }
3098 }
3099 }
3100 }
3101 DMDAVecRestoreArray(fda, user->lUcont, &lucor);
3102 DMDAVecRestoreArray(fda, user->Ucont, &ucor);
3103
3104 if (has_periodic_ucont_seam) {
3105 ierr = MPI_Allreduce(&periodic_seam_updates_local, &periodic_seam_updates_global, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3106 ierr = MPI_Allreduce(&periodic_seam_max_delta_local, &periodic_seam_max_delta_global, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3108 "VolumeFlux: legacy periodic Ucont seam refresh updated %d values, max |delta|=%.6e.\n",
3109 (int)periodic_seam_updates_global, periodic_seam_max_delta_global);
3110 }
3111
3112 /* DMLocalToGlobalBegin(user->fda, user->lUcont, INSERT_VALUES, user->Ucont); */
3113/* DMLocalToGlobalEnd(user->fda, user->lUcont, INSERT_VALUES, user->Ucont); */
3114 DMGlobalToLocalBegin(user->fda, user->Ucont, INSERT_VALUES, user->lUcont);
3115 DMGlobalToLocalEnd(user->fda, user->Ucont, INSERT_VALUES, user->lUcont);
3116
3117 if (NumberOfBodies > 1) {
3118 free(lIB_Flux);
3119 free(lIB_area);
3120 free(IB_Flux);
3121 free(IB_Area);
3122 free(Correction);
3123 }
3124
3125 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Exiting VolumeFlux.\n");
3126
3127 return 0;
3128}
PetscInt NumberOfBodies
Definition variables.h:703
Here is the caller graph for this function:

◆ FullyBlocked()

static PetscErrorCode FullyBlocked ( UserCtx user)
static

Internal helper implementation: FullyBlocked().

Local to this translation unit.

Definition at line 3134 of file poisson.c.

3135{
3136 PetscErrorCode ierr;
3137 DM da = user->da;
3138 Vec nNvert;
3139 DMDALocalInfo info = user->info;
3140
3141 PetscInt mx = info.mx, my = info.my, mz = info.mz;
3142
3143 PetscInt i, j, k;
3144
3145 PetscInt *KSKE = user->KSKE;
3146 PetscReal ***nvert;
3147 PetscBool *Blocked;
3148
3149 DMDACreateNaturalVector(da, &nNvert);
3150 DMDAGlobalToNaturalBegin(da, user->Nvert, INSERT_VALUES, nNvert);
3151 DMDAGlobalToNaturalEnd(da, user->Nvert, INSERT_VALUES, nNvert);
3152
3153 VecScatter ctx;
3154 Vec Zvert;
3155 VecScatterCreateToZero(nNvert, &ctx, &Zvert);
3156
3157 VecScatterBegin(ctx, nNvert, Zvert, INSERT_VALUES, SCATTER_FORWARD);
3158 VecScatterEnd(ctx, nNvert, Zvert, INSERT_VALUES, SCATTER_FORWARD);
3159
3160 VecScatterDestroy(&ctx);
3161 VecDestroy(&nNvert);
3162
3163 PetscInt rank;
3164 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRMPI(ierr);
3165
3166 if (!rank) {
3167
3168 VecGetArray3d(Zvert, mz, my, mx, 0, 0, 0, &nvert);
3169 PetscMalloc(mx*my*sizeof(PetscBool), &Blocked);
3170 for (j=1; j<my-1; j++) {
3171 for (i=1; i<mx-1; i++) {
3172 Blocked[j*mx+i] = PETSC_FALSE;
3173 for (k=0; k<mz; k++) {
3174 if (nvert[k][j][i] > 0.1) {
3175 if (!Blocked[j*mx+i]) {
3176 KSKE[2*(j*mx+i)] = k;
3177 Blocked[j*mx+i] = PETSC_TRUE;
3178 }
3179 else {
3180 KSKE[2*(j*mx+i)] = PetscMin(KSKE[2*(j*mx+i)], k);
3181 }
3182 }
3183 }
3184 }
3185 }
3186
3187
3188 user->multinullspace = PETSC_TRUE;
3189 for (j=1; j<my-1; j++) {
3190 for (i=1; i<mx-1; i++) {
3191 if (!Blocked[j*mx+i]) {
3192 user->multinullspace = PETSC_FALSE;
3193 break;
3194 }
3195 }
3196 }
3197 PetscFree(Blocked);
3198 VecRestoreArray3d(Zvert, mz, my, mx, 0, 0, 0, &nvert);
3199 ierr = MPI_Bcast(&user->multinullspace, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3200 if (user->multinullspace) {
3201 ierr = MPI_Bcast(user->KSKE, 2*mx*my, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3202
3203 }
3204 }
3205 else {
3206 ierr = MPI_Bcast(&user->multinullspace, 1, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3207 if (user->multinullspace) {
3208 ierr = MPI_Bcast(user->KSKE, 2*mx*my, MPI_INT, 0, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3209 }
3210 }
3211
3212
3213
3214 VecDestroy(&Zvert);
3215 return 0;
3216}
Vec Nvert
Definition variables.h:837
Here is the caller graph for this function:

◆ MyNvertRestriction()

static PetscErrorCode MyNvertRestriction ( UserCtx user_h,
UserCtx user_c 
)
static

Internal helper implementation: MyNvertRestriction().

Local to this translation unit.

Definition at line 3222 of file poisson.c.

3223{
3224 // DA da = user_c->da, fda = user_c->fda;
3225
3226
3227
3228 DMDALocalInfo info = user_c->info;
3229 PetscInt xs = info.xs, xe = info.xs + info.xm;
3230 PetscInt ys = info.ys, ye = info.ys + info.ym;
3231 PetscInt zs = info.zs, ze = info.zs + info.zm;
3232 PetscInt mx = info.mx, my = info.my, mz = info.mz;
3233
3234 PetscInt i,j,k;
3235 PetscInt ih, jh, kh, ia, ja, ka;
3236 PetscInt lxs, lxe, lys, lye, lzs, lze;
3237
3238 PetscReal ***nvert, ***nvert_h;
3239
3240 DMDAVecGetArray(user_h->da, user_h->lNvert, &nvert_h);
3241 DMDAVecGetArray(user_c->da, user_c->Nvert, &nvert);
3242
3243 lxs = xs; lxe = xe;
3244 lys = ys; lye = ye;
3245 lzs = zs; lze = ze;
3246
3247 if (xs==0) lxs = xs+1;
3248 if (ys==0) lys = ys+1;
3249 if (zs==0) lzs = zs+1;
3250
3251 if (xe==mx) lxe = xe-1;
3252 if (ye==my) lye = ye-1;
3253 if (ze==mz) lze = ze-1;
3254
3255 if ((user_c->isc)) ia = 0;
3256 else ia = 1;
3257
3258 if ((user_c->jsc)) ja = 0;
3259 else ja = 1;
3260
3261 if ((user_c->ksc)) ka = 0;
3262 else ka = 1;
3263
3264 VecSet(user_c->Nvert, 0.);
3265 if (user_c->thislevel > 0) {
3266 for (k=lzs; k<lze; k++) {
3267 for (j=lys; j<lye; j++) {
3268 for (i=lxs; i<lxe; i++) {
3269 GridRestriction(i, j, k, &ih, &jh, &kh, user_c);
3270 if (nvert_h[kh ][jh ][ih ] *
3271 nvert_h[kh ][jh ][ih-ia] *
3272 nvert_h[kh ][jh-ja][ih ] *
3273 nvert_h[kh-ka][jh ][ih ] *
3274 nvert_h[kh ][jh-ja][ih-ia] *
3275 nvert_h[kh-ka][jh ][ih-ia] *
3276 nvert_h[kh-ka][jh-ja][ih ] *
3277 nvert_h[kh-ka][jh-ja][ih-ia] > 0.1) {
3278 nvert[k][j][i] = PetscMax(1., nvert[k][j][i]);
3279 }
3280 }
3281 }
3282 }
3283 }
3284 else {
3285 for (k=lzs; k<lze; k++) {
3286 for (j=lys; j<lye; j++) {
3287 for (i=lxs; i<lxe; i++) {
3288 GridRestriction(i, j, k, &ih, &jh, &kh, user_c);
3289 if (nvert_h[kh ][jh ][ih ] *
3290 nvert_h[kh ][jh ][ih-ia] *
3291 nvert_h[kh ][jh-ja][ih ] *
3292 nvert_h[kh-ka][jh ][ih ] *
3293 nvert_h[kh ][jh-ja][ih-ia] *
3294 nvert_h[kh-ka][jh ][ih-ia] *
3295 nvert_h[kh-ka][jh-ja][ih ] *
3296 nvert_h[kh-ka][jh-ja][ih-ia] > 0.1) {
3297 nvert[k][j][i] = PetscMax(1., nvert[k][j][i]);
3298 }
3299 }
3300 }
3301 }
3302 }
3303 DMDAVecRestoreArray(user_h->da, user_h->lNvert, &nvert_h);
3304 DMDAVecRestoreArray(user_c->da, user_c->Nvert, &nvert);
3305
3306 DMGlobalToLocalBegin(user_c->da, user_c->Nvert, INSERT_VALUES, user_c->lNvert);
3307 DMGlobalToLocalEnd(user_c->da, user_c->Nvert, INSERT_VALUES, user_c->lNvert);
3308 //Mohsen Dec 2015
3309 DMDAVecGetArray(user_c->da, user_c->lNvert, &nvert);
3310 DMDAVecGetArray(user_c->da, user_c->Nvert, &nvert_h);
3311
3312 for (k=lzs; k<lze; k++) {
3313 for (j=lys; j<lye; j++) {
3314 for (i=lxs; i<lxe; i++) {
3315 if (nvert_h[k][j][i] < 0.1) {
3316 if (nvert[k][j][i+1] + nvert[k][j][i-1] > 1.1 &&
3317 nvert[k][j+1][i] + nvert[k][j-1][i] > 1.1 &&
3318 nvert[k+1][j][i] + nvert[k-1][j][i] > 1.1) {
3319 nvert_h[k][j][i] = 1.;
3320 }
3321 }
3322 }
3323 }
3324 }
3325
3326 DMDAVecRestoreArray(user_c->da, user_c->lNvert, &nvert);
3327 DMDAVecRestoreArray(user_c->da, user_c->Nvert, &nvert_h);
3328 DMGlobalToLocalBegin(user_c->da, user_c->Nvert, INSERT_VALUES, user_c->lNvert);
3329 DMGlobalToLocalEnd(user_c->da, user_c->Nvert, INSERT_VALUES, user_c->lNvert);
3330 /* DMLocalToGlobalBegin(user_c->da, user_c->lNvert, INSERT_VALUES, user_c->Nvert); */
3331/* DMLocalToGlobalEnd(user_c->da, user_c->lNvert, INSERT_VALUES, user_c->Nvert); */
3332 return 0;
3333}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PoissonSolver_MG()

PetscErrorCode PoissonSolver_MG ( UserMG usermg)

Implementation of PoissonSolver_MG().

Solves the pressure-Poisson equation using a geometric multigrid method.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/poisson.h.

See also
PoissonSolver_MG()

Definition at line 3344 of file poisson.c.

3345{
3346 // --- CONTEXT ACQUISITION BLOCK ---
3347 // Get the master simulation context from the first block's UserCtx on the finest level.
3348 // This provides access to all former global variables.
3349 SimCtx *simCtx = usermg->mgctx[0].user[0].simCtx;
3350
3351 // Create local variables to mirror the legacy globals for minimal code changes.
3352 const PetscInt block_number = simCtx->block_number;
3353 const PetscInt immersed = simCtx->immersed;
3354 const PetscInt MHV = simCtx->MHV;
3355 const PetscInt LV = simCtx->LV;
3356 PetscMPIInt rank = simCtx->rank;
3357 // --- END CONTEXT ACQUISITION BLOCK ---
3358
3359 PetscErrorCode ierr;
3360 PetscInt l, bi;
3361 MGCtx *mgctx = usermg->mgctx;
3362 KSP mgksp, subksp;
3363 PC mgpc, subpc;
3364 UserCtx *user;
3365
3366 PetscFunctionBeginUser; // Moved to after variable declarations
3368 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting Multigrid Poisson Solve...\n");
3369
3370 for (bi = 0; bi < block_number; bi++) {
3371
3372 // ====================================================================
3373 // SECTION: Immersed Boundary Specific Setup (Conditional)
3374 // ====================================================================
3375 if (immersed) {
3376 LOG_ALLOW(LOCAL, LOG_DEBUG, "Block %d: Performing IBM pre-solve setup (Nvert restriction, etc.).\n", bi);
3377 for (l = usermg->mglevels - 1; l > 0; l--) {
3378 mgctx[l].user[bi].multinullspace = PETSC_FALSE;
3379 MyNvertRestriction(&mgctx[l].user[bi], &mgctx[l-1].user[bi]);
3380 }
3381 // Coarsest level check for disconnected domains due to IBM
3382 l = 0;
3383 user = mgctx[l].user;
3384 ierr = PetscMalloc1(user[bi].info.mx * user[bi].info.my * 2, &user[bi].KSKE); CHKERRQ(ierr);
3385 FullyBlocked(&user[bi]);
3386 }
3387
3388
3389 l = usermg->mglevels - 1;
3390 user = mgctx[l].user;
3391
3392 // We are solving the linear system AX=B where A = Laplacian Operator Matrix; X = Unknown Phi (Pressure Correction) and B = RHS (Flux Divergence based)
3393
3394 // --- 1. Compute RHS of the Poisson Equation ---
3395 LOG_ALLOW(LOCAL, LOG_DEBUG, "Block %d: Computing Poisson RHS...\n", bi);
3396 ierr = VecDuplicate(user[bi].P, &user[bi].B); CHKERRQ(ierr);
3397
3398 PetscReal ibm_Flux, ibm_Area;
3399 PetscInt flg = immersed - 1;
3400
3401 // Calculate volume flux source terms (often from IBM)
3402 VolumeFlux(&user[bi], &ibm_Flux, &ibm_Area, flg);
3403 if (MHV || LV) {
3404 flg = ((MHV > 1 || LV) && bi == 0) ? 1 : 0;
3405 VolumeFlux_rev(&user[bi], &ibm_Flux, &ibm_Area, flg);
3406 }
3407 // Calculate the main flux divergence term B.
3408 PoissonRHS(&user[bi], user[bi].B);
3409
3410 // --- 2. Assemble LHS Matrix (Laplacian) on all MG levels ---
3411 LOG_ALLOW(LOCAL, LOG_DEBUG, "Block %d: Assembling Poisson LHS on all levels...\n", bi);
3412 for (l = usermg->mglevels - 1; l >= 0; l--) {
3413 user = mgctx[l].user;
3414 LOG_ALLOW(GLOBAL,LOG_DEBUG," Calculating LHS for Level %d.\n",l);
3415 PoissonLHSNew(&user[bi]);
3416 }
3417
3418 // --- 3. Setup PETSc KSP and PCMG (Multigrid Preconditioner) ---
3419 LOG_ALLOW(LOCAL, LOG_DEBUG, "Block %d: Configuring KSP and PCMG...\n", bi);
3420
3421 ierr = KSPCreate(PETSC_COMM_WORLD, &mgksp); CHKERRQ(ierr);
3422 ierr = KSPAppendOptionsPrefix(mgksp, "ps_"); CHKERRQ(ierr);
3423
3424 // =======================================================================
3425 DualMonitorCtx *monctx;
3426 char filen[PETSC_MAX_PATH_LEN + 128];
3427
3428 // 1. Allocate the context and set it up.
3429 ierr = PetscNew(&monctx); CHKERRQ(ierr);
3430
3431 monctx->step = simCtx->step;
3432 monctx->block_id = bi;
3433 monctx->file_handle = NULL;
3434
3435 // Only rank 0 handles the file.
3436 if (!rank) {
3437 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/Poisson_Solver_Convergence_History_Block_%d.log", simCtx->log_dir, bi); CHKERRQ(ierr);
3438 // On the very first step of a fresh run, TRUNCATE the file.
3439 // In continue mode, always APPEND to preserve existing data.
3440 if (simCtx->step == simCtx->StartStep + 1 && !simCtx->continueMode) {
3441 monctx->file_handle = fopen(filen, "w");
3442 } else { // For all subsequent steps (or continue mode), APPEND.
3443 monctx->file_handle = fopen(filen, "a");
3444 }
3445
3446 if (monctx->file_handle) {
3447 PetscFPrintf(PETSC_COMM_SELF, monctx->file_handle, "--- Convergence for Timestep %d, Block %d ---\n", (int)simCtx->step, bi);
3448 } else {
3449 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Could not open KSP monitor log file: %s", filen);
3450 }
3451 }
3452
3454
3455 ierr = KSPMonitorSet(mgksp, DualKSPMonitor, monctx, DualMonitorDestroy); CHKERRQ(ierr);
3456 // =======================================================================
3457
3458 ierr = KSPGetPC(mgksp, &mgpc); CHKERRQ(ierr);
3459 ierr = PCSetType(mgpc, PCMG); CHKERRQ(ierr);
3460
3461 ierr = PCMGSetLevels(mgpc, usermg->mglevels, PETSC_NULLPTR); CHKERRQ(ierr);
3462 ierr = PCMGSetCycleType(mgpc, PC_MG_CYCLE_V); CHKERRQ(ierr);
3463 ierr = PCMGSetType(mgpc, PC_MG_MULTIPLICATIVE); CHKERRQ(ierr);
3464
3465 // --- 4. Define Restriction and Interpolation Operators for MG ---
3466 for (l = usermg->mglevels - 1; l > 0; l--) {
3467
3468 // Get stable pointers directly from the main mgctx array.
3469 // These pointers point to memory that will persist.
3470 UserCtx *fine_user_ctx = &mgctx[l].user[bi];
3471 UserCtx *coarse_user_ctx = &mgctx[l-1].user[bi];
3472
3473 // --- Configure the context pointers ---
3474 // The coarse UserCtx needs to know about the fine grid for restriction.
3475 coarse_user_ctx->da_f = &(fine_user_ctx->da);
3476 coarse_user_ctx->user_f = fine_user_ctx;
3477
3478 // The fine UserCtx needs to know about the coarse grid for interpolation.
3479 fine_user_ctx->da_c = &(coarse_user_ctx->da);
3480 fine_user_ctx->user_c = coarse_user_ctx;
3481 fine_user_ctx->lNvert_c = &(coarse_user_ctx->lNvert);
3482
3483 // --- Get matrix dimensions ---
3484 PetscInt m_c = (coarse_user_ctx->info.xm * coarse_user_ctx->info.ym * coarse_user_ctx->info.zm);
3485 PetscInt m_f = (fine_user_ctx->info.xm * fine_user_ctx->info.ym * fine_user_ctx->info.zm);
3486 PetscInt M_c = (coarse_user_ctx->info.mx * coarse_user_ctx->info.my * coarse_user_ctx->info.mz);
3487 PetscInt M_f = (fine_user_ctx->info.mx * fine_user_ctx->info.my * fine_user_ctx->info.mz);
3488
3489 LOG_ALLOW(GLOBAL,LOG_DEBUG,"level = %d; m_c = %d; m_f = %d; M_c = %d; M_f = %d.\n",l,m_c,m_f,M_c,M_f);
3490 // --- Create the MatShell objects ---
3491 // Pass the STABLE pointer coarse_user_ctx as the context for restriction.
3492 ierr = MatCreateShell(PETSC_COMM_WORLD, m_c, m_f, M_c, M_f, (void*)coarse_user_ctx, &fine_user_ctx->MR); CHKERRQ(ierr);
3493
3494 // Pass the STABLE pointer fine_user_ctx as the context for interpolation.
3495 ierr = MatCreateShell(PETSC_COMM_WORLD, m_f, m_c, M_f, M_c, (void*)fine_user_ctx, &fine_user_ctx->MP); CHKERRQ(ierr);
3496
3497 // --- Set the operations for the MatShells ---
3498 ierr = MatShellSetOperation(fine_user_ctx->MR, MATOP_MULT, (void(*)(void))RestrictResidual_SolidAware); CHKERRQ(ierr);
3499 ierr = MatShellSetOperation(fine_user_ctx->MP, MATOP_MULT, (void(*)(void))MyInterpolation); CHKERRQ(ierr);
3500
3501 // --- Register the operators with PCMG ---
3502 ierr = PCMGSetRestriction(mgpc, l, fine_user_ctx->MR); CHKERRQ(ierr);
3503 ierr = PCMGSetInterpolation(mgpc, l, fine_user_ctx->MP); CHKERRQ(ierr);
3504
3505 }
3506
3507 // --- 5. Configure Solvers on Each MG Level ---
3508 for (l = usermg->mglevels - 1; l >= 0; l--) {
3509 user = mgctx[l].user;
3510 if (l > 0) { // Smoother for fine levels
3511 ierr = PCMGGetSmoother(mgpc, l, &subksp); CHKERRQ(ierr);
3512 } else { // Direct or iterative solver for the coarsest level
3513 ierr = PCMGGetCoarseSolve(mgpc, &subksp); CHKERRQ(ierr);
3514 ierr = KSPSetTolerances(subksp, 1.e-8, PETSC_DEFAULT, PETSC_DEFAULT, 40); CHKERRQ(ierr);
3515 }
3516
3517 ierr = KSPSetOperators(subksp, user[bi].A, user[bi].A); CHKERRQ(ierr);
3518 ierr = KSPSetFromOptions(subksp); CHKERRQ(ierr);
3519 ierr = KSPGetPC(subksp, &subpc); CHKERRQ(ierr);
3520 ierr = PCSetType(subpc, PCBJACOBI); CHKERRQ(ierr);
3521
3522 KSP *subsubksp;
3523 PC subsubpc;
3524 PetscInt nlocal;
3525
3526 // This logic is required for both the smoother and the coarse solve
3527 // since both use PCBJACOBI.
3528 ierr = KSPSetUp(subksp); CHKERRQ(ierr); // Set up KSP to allow access to sub-KSPs
3529 ierr = PCBJacobiGetSubKSP(subpc, &nlocal, NULL, &subsubksp); CHKERRQ(ierr);
3530
3531 for (PetscInt abi = 0; abi < nlocal; abi++) {
3532 ierr = KSPGetPC(subsubksp[abi], &subsubpc); CHKERRQ(ierr);
3533 // Add the critical shift amount
3534 ierr = PCFactorSetShiftAmount(subsubpc, 1.e-10); CHKERRQ(ierr);
3535 }
3536
3537 ierr = MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, PETSC_NULLPTR, &user[bi].nullsp); CHKERRQ(ierr);
3538 ierr = MatNullSpaceSetFunction(user[bi].nullsp, PoissonNullSpaceFunction, &user[bi]); CHKERRQ(ierr);
3539 ierr = MatSetNullSpace(user[bi].A, user[bi].nullsp); CHKERRQ(ierr);
3540
3541 ierr = PCMGSetResidual(mgpc, l, PCMGResidualDefault, user[bi].A); CHKERRQ(ierr);
3542 ierr = KSPSetUp(subksp); CHKERRQ(ierr);
3543
3544 if (l < usermg->mglevels - 1) {
3545 ierr = MatCreateVecs(user[bi].A, &user[bi].R, PETSC_NULLPTR); CHKERRQ(ierr);
3546 ierr = PCMGSetRhs(mgpc, l, user[bi].R); CHKERRQ(ierr);
3547 }
3548 }
3549
3550 // --- 6. Set Final KSP Operators and Solve ---
3551 l = usermg->mglevels - 1;
3552 user = mgctx[l].user;
3553
3554 LOG_ALLOW(LOCAL, LOG_DEBUG, "Block %d: Setting KSP operators and solving...\n", bi);
3555 ierr = KSPSetOperators(mgksp, user[bi].A, user[bi].A); CHKERRQ(ierr);
3556 ierr = MatSetNullSpace(user[bi].A, user[bi].nullsp); CHKERRQ(ierr);
3557 ierr = KSPSetFromOptions(mgksp); CHKERRQ(ierr);
3558 ierr = KSPSetUp(mgksp); CHKERRQ(ierr);
3559 ierr = KSPSolve(mgksp, user[bi].B, user[bi].Phi); CHKERRQ(ierr);
3560
3561 // --- 7. Cleanup for this block ---
3562 for (l = usermg->mglevels - 1; l >= 0; l--) {
3563 user = mgctx[l].user;
3564 MatNullSpaceDestroy(&user[bi].nullsp);
3565 MatDestroy(&user[bi].A);
3566 user[bi].assignedA = PETSC_FALSE;
3567 if (l > 0) {
3568 MatDestroy(&user[bi].MR);
3569 MatDestroy(&user[bi].MP);
3570 } else if (l==0 && immersed) {
3571 PetscFree(user[bi].KSKE);
3572 }
3573 if (l < usermg->mglevels - 1) {
3574 VecDestroy(&user[bi].R);
3575 }
3576 }
3577
3578 KSPDestroy(&mgksp);
3579 VecDestroy(&mgctx[usermg->mglevels-1].user[bi].B);
3580
3581 } // End of loop over blocks
3582
3583 LOG_ALLOW(GLOBAL, LOG_INFO, "Multigrid Poisson Solve complete.\n");
3585 PetscFunctionReturn(0);
3586}
PetscErrorCode DualMonitorDestroy(void **ctx)
Destroys the DualMonitorCtx.
Definition logging.c:808
PetscBool log_to_console
Definition logging.h:57
PetscInt step
Definition logging.h:59
PetscErrorCode DualKSPMonitor(KSP ksp, PetscInt it, PetscReal rnorm, void *ctx)
A custom KSP monitor that logs to a file and optionally to the console.
Definition logging.c:847
FILE * file_handle
Definition logging.h:56
PetscInt block_id
Definition logging.h:60
Context for a dual-purpose KSP monitor.
Definition logging.h:55
PetscErrorCode PoissonNullSpaceFunction(MatNullSpace nullsp, Vec X, void *ctx)
Implementation of PoissonNullSpaceFunction().
Definition poisson.c:1031
PetscErrorCode PoissonLHSNew(UserCtx *user)
Internal helper implementation: PoissonLHSNew().
Definition poisson.c:1532
PetscErrorCode VolumeFlux_rev(UserCtx *user, PetscReal *ibm_Flux, PetscReal *ibm_Area, PetscInt flg)
Implementation of VolumeFlux_rev().
Definition poisson.c:2230
static PetscErrorCode RestrictResidual_SolidAware(Mat A, Vec X, Vec F)
Internal helper implementation: RestrictResidual_SolidAware().
Definition poisson.c:1344
PetscErrorCode VolumeFlux(UserCtx *user, PetscReal *ibm_Flux, PetscReal *ibm_Area, PetscInt flg)
Implementation of VolumeFlux().
Definition poisson.c:2472
PetscErrorCode PoissonRHS(UserCtx *user, Vec B)
Implementation of PoissonRHS().
Definition poisson.c:2141
PetscErrorCode MyInterpolation(Mat A, Vec X, Vec F)
Implementation of MyInterpolation().
Definition poisson.c:1233
static PetscErrorCode FullyBlocked(UserCtx *user)
Internal helper implementation: FullyBlocked().
Definition poisson.c:3134
static PetscErrorCode MyNvertRestriction(UserCtx *user_h, UserCtx *user_c)
Internal helper implementation: MyNvertRestriction().
Definition poisson.c:3222
PetscInt MHV
Definition variables.h:679
PetscBool continueMode
Definition variables.h:660
UserCtx * user
Definition variables.h:528
PetscInt LV
Definition variables.h:679
PetscInt block_number
Definition variables.h:712
PetscInt StartStep
Definition variables.h:653
UserCtx * user_c
Definition variables.h:875
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:668
PetscInt mglevels
Definition variables.h:535
PetscInt step
Definition variables.h:651
PetscBool ps_ksp_pic_monitor_true_residual
Definition variables.h:695
MGCtx * mgctx
Definition variables.h:538
PetscInt immersed
Definition variables.h:673
Context for Multigrid operations.
Definition variables.h:527
Here is the call graph for this function:
Here is the caller graph for this function: