PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Metric.h File Reference
#include <petsc.h>
#include "variables.h"
#include "logging.h"
#include <stdlib.h>
#include "io.h"
#include "setup.h"
Include dependency graph for Metric.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

PetscErrorCode MetricLogicalToPhysical (UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, PetscReal xi, PetscReal eta, PetscReal zta, Cmpnts *Xp)
 Public wrapper: map (cell index, ξ,η,ζ) to (x,y,z).
 
PetscErrorCode MetricGetCellVertices (UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, Cmpnts V[8])
 Extract the eight vertex coordinates of the hexahedral cell (i,j,k).
 
PetscErrorCode MetricJacobian (UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, PetscReal xi, PetscReal eta, PetscReal zta, PetscReal J[3][3], PetscReal *detJ)
 Compute Jacobian matrix and its determinant at (xi,eta,zta).
 
PetscErrorCode MetricVelocityContravariant (const PetscReal J[3][3], PetscReal detJ, const PetscReal u[3], PetscReal uc[3])
 Convert physical velocity (u,v,w) to contravariant components (u^xi, u^eta, u^zta).
 
PetscErrorCode CalculateFaceNormalAndArea (Cmpnts csi, Cmpnts eta, Cmpnts zet, double ni[3], double nj[3], double nk[3], double *Ai, double *Aj, double *Ak)
 Computes the unit normal vectors and areas of the three faces of a computational cell.
 
PetscErrorCode InvertCovariantMetricTensor (double covariantTensor[3][3], double contravariantTensor[3][3])
 Inverts the 3x3 covariant metric tensor to obtain the contravariant metric tensor.
 
PetscErrorCode ComputeCellCharacteristicLengthScale (PetscReal ajc, Cmpnts csi, Cmpnts eta, Cmpnts zet, double *dx, double *dy, double *dz)
 Computes characteristic length scales (dx, dy, dz) for a curvilinear cell.
 
PetscErrorCode ApplyPeriodicCorrectionsToCellCentersAndSpacing (UserCtx *user)
 Applies periodic boundary corrections to cell centers (Cent) and grid spacing (GridSpace).
 
PetscErrorCode ApplyPeriodicCorrectionsToKFaceCenter (UserCtx *user)
 Applies periodic boundary corrections to i-face centers (Centx).
 
PetscErrorCode ApplyPeriodicCorrectionsToJFaceCenter (UserCtx *user)
 Applies periodic boundary corrections to j-face centers (Centy).
 
PetscErrorCode ComputeFaceMetrics (UserCtx *user)
 Computes the primary face metric components (Csi, Eta, Zet), including boundary extrapolation, and stores them in the corresponding global Vec members of the UserCtx structure (user->Csi, user->Eta, user->Zet).
 
PetscErrorCode ComputeCellCenteredJacobianInverse (UserCtx *user)
 Calculates the cell-centered inverse Jacobian determinant (1/J) for INTERIOR cells and stores it in user->Aj.
 
PetscErrorCode CheckAndFixGridOrientation (UserCtx *user)
 Ensure a right-handed metric basis (Csi, Eta, Zet) and a positive Jacobian (Aj) over the whole domain.
 
PetscErrorCode ComputeCellCentersAndSpacing (UserCtx *user)
 Computes the physical location of cell centers and the spacing between them.
 
PetscErrorCode ComputeIFaceMetrics (UserCtx *user)
 Computes metrics centered on constant-i faces (i-faces).
 
PetscErrorCode ComputeJFaceMetrics (UserCtx *user)
 Computes metrics centered on constant-j faces (j-faces).
 
PetscErrorCode ComputeKFaceMetrics (UserCtx *user)
 Computes metrics centered on constant-k faces (k-faces).
 
PetscErrorCode ComputeMetricsDivergence (UserCtx *user)
 Performs a diagnostic check on the divergence of the face area metric vectors.
 
PetscErrorCode ComputeMetricNorms (UserCtx *user)
 Computes the max-min values of the grid metrics.
 
PetscErrorCode CalculateAllGridMetrics (SimCtx *simCtx)
 Orchestrates the calculation of all grid metrics.
 

Function Documentation

◆ MetricLogicalToPhysical()

PetscErrorCode MetricLogicalToPhysical ( UserCtx user,
const Cmpnts ***  X,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscReal  xi,
PetscReal  eta,
PetscReal  zta,
Cmpnts Xp 
)

Public wrapper: map (cell index, ξ,η,ζ) to (x,y,z).

Definition at line 77 of file Metric.c.

82{
83 PetscErrorCode ierr;
84 Cmpnts V[8];
85 PetscFunctionBeginUser;
86
88
89 ierr = MetricGetCellVertices(user,X,i,j,k,V); CHKERRQ(ierr);
90 TrilinearBlend(V,xi,eta,zta,Xp);
91
93
94 PetscFunctionReturn(0);
95}
static void TrilinearBlend(const Cmpnts V[8], PetscReal xi, PetscReal eta, PetscReal zta, Cmpnts *Xp)
Map logical coordinates to physical space using trilinear basis.
Definition Metric.c:54
PetscErrorCode MetricGetCellVertices(UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, Cmpnts V[8])
Extract the eight vertex coordinates of the hexahedral cell (i,j,k).
Definition Metric.c:27
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:746
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:737
A 3D point or vector with PetscScalar components.
Definition variables.h:100
Here is the call graph for this function:
Here is the caller graph for this function:

◆ MetricGetCellVertices()

PetscErrorCode MetricGetCellVertices ( UserCtx user,
const Cmpnts ***  X,
PetscInt  i,
PetscInt  j,
PetscInt  k,
Cmpnts  V[8] 
)

Extract the eight vertex coordinates of the hexahedral cell (i,j,k).

Vertices are returned in the standard trilinear ordering: bit 0 → x-corner, bit 1 → y-corner, bit 2 → z-corner. (000 = origin of the cell, 111 = far corner.)

Definition at line 27 of file Metric.c.

31{
32 PetscFunctionBeginUser;
33 for (PetscInt c = 0; c < 8; ++c) {
34 PetscInt ii = i + ((c & 1) ? 1 : 0);
35 PetscInt jj = j + ((c & 2) ? 1 : 0);
36 PetscInt kk = k + ((c & 4) ? 1 : 0);
37 LOG_LOOP_ALLOW(GLOBAL, LOG_VERBOSE,i+j+k,10," ii: %d,jj:%d,kk:%d - Retrieved.\n",ii,jj,kk);
38 V[c] = X[kk][jj][ii];
39 }
40 PetscFunctionReturn(0);
41}
#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt,...)
Logs a message inside a loop, but only every interval iterations.
Definition logging.h:312
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:34
Here is the caller graph for this function:

◆ MetricJacobian()

PetscErrorCode MetricJacobian ( UserCtx user,
const Cmpnts ***  X,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscReal  xi,
PetscReal  eta,
PetscReal  zta,
PetscReal  J[3][3],
PetscReal *  detJ 
)

Compute Jacobian matrix and its determinant at (xi,eta,zta).

   J = [ x_ξ  x_η  x_ζ ]
       [ y_ξ  y_η  y_ζ ]
       [ z_ξ  z_η  z_ζ ]

This is handy for converting physical velocities (u,v,w) into contravariant components and for volume weighting.

Definition at line 110 of file Metric.c.

115{
116 PetscErrorCode ierr;
117 Cmpnts V[8];
118 PetscFunctionBeginUser;
119
121
122 ierr = MetricGetCellVertices(user,X,i,j,k,V); CHKERRQ(ierr);
123
124 /* derivatives of trilinear shape functions */
125 PetscReal dN_dXi[8], dN_dEta[8], dN_dZta[8];
126 for (PetscInt c=0;c<8;++c) {
127 PetscReal sx = (c & 1) ? 1.0 : -1.0;
128 PetscReal sy = (c & 2) ? 1.0 : -1.0;
129 PetscReal sz = (c & 4) ? 1.0 : -1.0;
130 dN_dXi [c] = 0.125 * sx * ( (c&2?eta:1-eta) ) * ( (c&4?zta:1-zta) );
131 dN_dEta[c] = 0.125 * sy * ( (c&1?xi :1-xi ) ) * ( (c&4?zta:1-zta) );
132 dN_dZta[c] = 0.125 * sz * ( (c&1?xi :1-xi ) ) * ( (c&2?eta:1-eta) );
133 }
134
135 /* assemble Jacobian */
136 PetscReal x_xi=0,y_xi=0,z_xi=0,
137 x_eta=0,y_eta=0,z_eta=0,
138 x_zta=0,y_zta=0,z_zta=0;
139 for (PetscInt c=0;c<8;++c) {
140 x_xi += dN_dXi [c]*V[c].x; y_xi += dN_dXi [c]*V[c].y; z_xi += dN_dXi [c]*V[c].z;
141 x_eta += dN_dEta[c]*V[c].x; y_eta += dN_dEta[c]*V[c].y; z_eta += dN_dEta[c]*V[c].z;
142 x_zta += dN_dZta[c]*V[c].x; y_zta += dN_dZta[c]*V[c].y; z_zta += dN_dZta[c]*V[c].z;
143 }
144
145 J[0][0]=x_xi; J[0][1]=x_eta; J[0][2]=x_zta;
146 J[1][0]=y_xi; J[1][1]=y_eta; J[1][2]=y_zta;
147 J[2][0]=z_xi; J[2][1]=z_eta; J[2][2]=z_zta;
148
149 if (detJ) {
150 *detJ = x_xi*(y_eta*z_zta - y_zta*z_eta)
151 - x_eta*(y_xi*z_zta - y_zta*z_xi)
152 + x_zta*(y_xi*z_eta - y_eta*z_xi);
153 }
154
156
157 PetscFunctionReturn(0);
158}
Here is the call graph for this function:

◆ MetricVelocityContravariant()

PetscErrorCode MetricVelocityContravariant ( const PetscReal  J[3][3],
PetscReal  detJ,
const PetscReal  u[3],
PetscReal  uc[3] 
)

Convert physical velocity (u,v,w) to contravariant components (u^xi, u^eta, u^zta).

Definition at line 167 of file Metric.c.

169{
170 PetscFunctionBeginUser;
171
173
174 /* contravariant basis vectors (row of adjugate(J)) divided by detJ */
175 PetscReal gxi[3] = { J[1][1]*J[2][2]-J[1][2]*J[2][1],
176 -J[0][1]*J[2][2]+J[0][2]*J[2][1],
177 J[0][1]*J[1][2]-J[0][2]*J[1][1] };
178 PetscReal geta[3] = { -J[1][0]*J[2][2]+J[1][2]*J[2][0],
179 J[0][0]*J[2][2]-J[0][2]*J[2][0],
180 -J[0][0]*J[1][2]+J[0][2]*J[1][0] };
181 PetscReal gzta[3] = { J[1][0]*J[2][1]-J[1][1]*J[2][0],
182 -J[0][0]*J[2][1]+J[0][1]*J[2][0],
183 J[0][0]*J[1][1]-J[0][1]*J[1][0] };
184
185 PetscReal invDet = 1.0 / detJ;
186 for (int d=0; d<3; ++d) { gxi[d] *= invDet; geta[d] *= invDet; gzta[d] *= invDet; }
187
188 uc[0] = gxi [0]*u[0] + gxi [1]*u[1] + gxi [2]*u[2];
189 uc[1] = geta[0]*u[0] + geta[1]*u[1] + geta[2]*u[2];
190 uc[2] = gzta[0]*u[0] + gzta[1]*u[1] + gzta[2]*u[2];
191
193
194 PetscFunctionReturn(0);
195}

◆ CalculateFaceNormalAndArea()

PetscErrorCode CalculateFaceNormalAndArea ( Cmpnts  csi,
Cmpnts  eta,
Cmpnts  zet,
double  ni[3],
double  nj[3],
double  nk[3],
double *  Ai,
double *  Aj,
double *  Ak 
)

Computes the unit normal vectors and areas of the three faces of a computational cell.

Given the metric vectors (csi, eta, zet), this function calculates the geometric properties of the cell faces aligned with the i, j, and k directions.

Parameters
csi,eta,zetThe metric vectors at the cell center.
niOutput: A 3-element array for the unit normal vector of the i-face.
njOutput: A 3-element array for the unit normal vector of the j-face.
nkOutput: A 3-element array for the unit normal vector of the k-face.
AiOutput: Pointer to store the area of the i-face.
AjOutput: Pointer to store the area of the j-face.
AkOutput: Pointer to store the area of the k-face.
Returns
PetscErrorCode 0 on success.

Definition at line 257 of file Metric.c.

258{
259 PetscFunctionBeginUser;
261 double g[3][3];
262 double G[3][3];
263
264 g[0][0]=csi.x, g[0][1]=csi.y, g[0][2]=csi.z;
265 g[1][0]=eta.x, g[1][1]=eta.y, g[1][2]=eta.z;
266 g[2][0]=zet.x, g[2][1]=zet.y, g[2][2]=zet.z;
267
269 double xcsi=G[0][0], ycsi=G[1][0], zcsi=G[2][0];
270 double xeta=G[0][1], yeta=G[1][1], zeta=G[2][1];
271 double xzet=G[0][2], yzet=G[1][2], zzet=G[2][2];
272
273 double nx_i = xcsi, ny_i = ycsi, nz_i = zcsi;
274 double nx_j = xeta, ny_j = yeta, nz_j = zeta;
275 double nx_k = xzet, ny_k = yzet, nz_k = zzet;
276
277 double sum_i=sqrt(nx_i*nx_i+ny_i*ny_i+nz_i*nz_i);
278 double sum_j=sqrt(nx_j*nx_j+ny_j*ny_j+nz_j*nz_j);
279 double sum_k=sqrt(nx_k*nx_k+ny_k*ny_k+nz_k*nz_k);
280
281 *Ai = sqrt( g[0][0]*g[0][0] + g[0][1]*g[0][1] + g[0][2]*g[0][2] ); // area
282 *Aj = sqrt( g[1][0]*g[1][0] + g[1][1]*g[1][1] + g[1][2]*g[1][2] );
283 *Ak =sqrt( g[2][0]*g[2][0] + g[2][1]*g[2][1] + g[2][2]*g[2][2] );
284
285 nx_i /= sum_i, ny_i /= sum_i, nz_i /= sum_i;
286 nx_j /= sum_j, ny_j /= sum_j, nz_j /= sum_j;
287 nx_k /= sum_k, ny_k /= sum_k, nz_k /= sum_k;
288
289 ni[0] = nx_i, ni[1] = ny_i, ni[2] = nz_i;
290 nj[0] = nx_j, nj[1] = ny_j, nj[2] = nz_j;
291 nk[0] = nx_k, nk[1] = ny_k, nk[2] = nz_k;
292
294 PetscFunctionReturn(0);
295}
PetscErrorCode InvertCovariantMetricTensor(double covariantTensor[3][3], double contravariantTensor[3][3])
Inverts the 3x3 covariant metric tensor to obtain the contravariant metric tensor.
Definition Metric.c:212
PetscScalar x
Definition variables.h:101
PetscScalar z
Definition variables.h:101
PetscScalar y
Definition variables.h:101
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InvertCovariantMetricTensor()

PetscErrorCode InvertCovariantMetricTensor ( double  covariantTensor[3][3],
double  contravariantTensor[3][3] 
)

Inverts the 3x3 covariant metric tensor to obtain the contravariant metric tensor.

In curvilinear coordinates, the input matrix g contains the dot products of the covariant basis vectors (e.g., g_ij = e_i . e_j). Its inverse, G, is the contravariant metric tensor, which is essential for transforming vectors and tensors between coordinate systems.

Parameters
covariantTensorInput: A 3x3 matrix representing the covariant metric tensor.
contravariantTensorOutput: A 3x3 matrix where the inverted result is stored.
Returns
PetscErrorCode 0 on success.

Definition at line 212 of file Metric.c.

213{
214 PetscFunctionBeginUser;
215
216 const double a11=covariantTensor[0][0], a12=covariantTensor[0][1], a13=covariantTensor[0][2];
217 const double a21=covariantTensor[1][0], a22=covariantTensor[1][1], a23=covariantTensor[1][2];
218 const double a31=covariantTensor[2][0], a32=covariantTensor[2][1], a33=covariantTensor[2][2];
219
220 double det = a11*(a33*a22-a32*a23) - a21*(a33*a12-a32*a13) + a31*(a23*a12-a22*a13);
221
222 if (fabs(det) < 1.0e-12) {
223 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Matrix is singular, determinant is near zero.");
224 }
225
226 contravariantTensor[0][0] = (a33*a22-a32*a23)/det;
227 contravariantTensor[0][1] = -(a33*a12-a32*a13)/det;
228 contravariantTensor[0][2] = (a23*a12-a22*a13)/det;
229 contravariantTensor[1][0] = -(a33*a21-a31*a23)/det;
230 contravariantTensor[1][1] = (a33*a11-a31*a13)/det;
231 contravariantTensor[1][2] = -(a23*a11-a21*a13)/det;
232 contravariantTensor[2][0] = (a32*a21-a31*a22)/det;
233 contravariantTensor[2][1] = -(a32*a11-a31*a12)/det;
234 contravariantTensor[2][2] = (a22*a11-a21*a12)/det;
235
236 PetscFunctionReturn(0);
237}
Here is the caller graph for this function:

◆ ComputeCellCharacteristicLengthScale()

PetscErrorCode ComputeCellCharacteristicLengthScale ( PetscReal  ajc,
Cmpnts  csi,
Cmpnts  eta,
Cmpnts  zet,
double *  dx,
double *  dy,
double *  dz 
)

Computes characteristic length scales (dx, dy, dz) for a curvilinear cell.

For a non-uniform, non-orthogonal cell, there is no single "dx". This function computes an effective length scale in each Cartesian direction based on the cell volume and the areas of its faces.

Parameters
ajcThe Jacobian of the grid transformation (1 / cell volume).
csi,eta,zetThe metric vectors at the cell center.
dxOutput: Pointer to store the characteristic length in the x-direction.
dyOutput: Pointer to store the characteristic length in the y-direction.
dzOutput: Pointer to store the characteristic length in the z-direction.
Returns
PetscErrorCode 0 on success.

Definition at line 313 of file Metric.c.

314{
315 PetscFunctionBeginUser;
317 double ni[3], nj[3], nk[3];
318 double Li, Lj, Lk;
319 double Ai, Aj, Ak;
320 double vol = 1./ajc;
321
322 CalculateFaceNormalAndArea(csi, eta, zet, ni, nj, nk, &Ai, &Aj, &Ak);
323 Li = vol / Ai;
324 Lj = vol / Aj;
325 Lk = vol / Ak;
326
327 // Length scale vector = di * ni_vector + dj * nj_vector + dk * nk_vector
328 *dx = fabs( Li * ni[0] + Lj * nj[0] + Lk * nk[0] );
329 *dy = fabs( Li * ni[1] + Lj * nj[1] + Lk * nk[1] );
330 *dz = fabs( Li * ni[2] + Lj * nj[2] + Lk * nk[2] );
331
333 PetscFunctionReturn(0);
334}
PetscErrorCode CalculateFaceNormalAndArea(Cmpnts csi, Cmpnts eta, Cmpnts zet, double ni[3], double nj[3], double nk[3], double *Ai, double *Aj, double *Ak)
Computes the unit normal vectors and areas of the three faces of a computational cell.
Definition Metric.c:257
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ApplyPeriodicCorrectionsToCellCentersAndSpacing()

PetscErrorCode ApplyPeriodicCorrectionsToCellCentersAndSpacing ( UserCtx user)

Applies periodic boundary corrections to cell centers (Cent) and grid spacing (GridSpace).

This function handles the special logic needed when periodic boundaries are present. For coarse grids (cgrid), it directly copies from ghost regions. For fine grids, it calculates the boundary values using the GridSpace information.

Parameters
userThe UserCtx containing grid and field data.
Returns
PetscErrorCode 0 on success.

Definition at line 452 of file Metric.c.

453{
454 PetscErrorCode ierr;
455 DMDALocalInfo info = user->info;
456 PetscInt xs = info.xs, xe = info.xs + info.xm;
457 PetscInt ys = info.ys, ye = info.ys + info.ym;
458 PetscInt zs = info.zs, ze = info.zs + info.zm;
459 PetscInt mx = info.mx, my = info.my, mz = info.mz;
460 Cmpnts ***cent, ***lcent, ***gs;
461 PetscReal delta;
462
463 PetscFunctionBeginUser;
465
466 // Check if any periodic boundaries exist
467 PetscBool has_periodic = PETSC_FALSE;
468 for (int i = 0; i < 6; i++) {
469 if (user->boundary_faces[i].mathematical_type == PERIODIC) {
470 has_periodic = PETSC_TRUE;
471 break;
472 }
473 }
474
475 if (!has_periodic) {
476 LOG_ALLOW(LOCAL, LOG_TRACE, "No periodic boundaries; skipping corrections for Cent/GridSpace.\n");
478 PetscFunctionReturn(0);
479 }
480
481 LOG_ALLOW(LOCAL, LOG_DEBUG, "Applying periodic corrections to Cent and GridSpace.\n");
482
483 // Must update ghosts first before applying corrections
484 ierr = UpdateLocalGhosts(user, "Cent"); CHKERRQ(ierr);
485 ierr = UpdateLocalGhosts(user, "GridSpace"); CHKERRQ(ierr);
486
487 // --- X-direction periodic corrections ---
490
491 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
492 ierr = DMDAVecGetArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
493 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
494
495 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && xs == 0) {
496 if (user->cgrid) {
497 for (PetscInt k=zs; k<ze; k++) {
498 for (PetscInt j=ys; j<ye; j++) {
499 cent[k][j][0] = lcent[k][j][-2];
500 }
501 }
502 } else {
503 for (PetscInt k=zs; k<ze; k++) {
504 for (PetscInt j=ys; j<ye; j++) {
505 delta = (gs[k][j][1].x + gs[k][j][-2].x) / 2.0;
506 cent[k][j][0].x = cent[k][j][1].x - delta;
507 cent[k][j][0].y = cent[k][j][1].y;
508 cent[k][j][0].z = cent[k][j][1].z;
509 }
510 }
511 }
512 }
513
514 if (user->boundary_faces[BC_FACE_POS_X].mathematical_type == PERIODIC && xe == mx) {
515 if (user->cgrid) {
516 for (PetscInt k=zs; k<ze; k++) {
517 for (PetscInt j=ys; j<ye; j++) {
518 cent[k][j][mx-1] = lcent[k][j][mx+1];
519 }
520 }
521 } else {
522 for (PetscInt k=zs; k<ze; k++) {
523 for (PetscInt j=ys; j<ye; j++) {
524 delta = (gs[k][j][mx-2].x + gs[k][j][mx+1].x) / 2.0;
525 cent[k][j][mx-1].x = cent[k][j][mx-2].x + delta;
526 cent[k][j][mx-1].y = cent[k][j][mx-2].y;
527 cent[k][j][mx-1].z = cent[k][j][mx-2].z;
528 }
529 }
530 }
531 }
532
533 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
534 ierr = DMDAVecRestoreArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
535 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
536 }
537 // --- Y-direction periodic corrections ---
540
541 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
542 ierr = DMDAVecGetArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
543 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
544
545 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && ys == 0) {
546 if (user->cgrid) {
547 for (PetscInt k=zs; k<ze; k++) {
548 for (PetscInt i=xs; i<xe; i++) {
549 cent[k][0][i] = lcent[k][-2][i];
550 }
551 }
552 } else {
553 for (PetscInt k=zs; k<ze; k++) {
554 for (PetscInt i=xs; i<xe; i++) {
555 delta = (gs[k][1][i].y + gs[k][-2][i].y) / 2.0;
556 cent[k][0][i].x = cent[k][1][i].x;
557 cent[k][0][i].y = cent[k][1][i].y - delta;
558 cent[k][0][i].z = cent[k][1][i].z;
559 }
560 }
561 }
562 }
563
564 if (user->boundary_faces[BC_FACE_POS_Y].mathematical_type == PERIODIC && ye == my) {
565 if (user->cgrid) {
566 for (PetscInt k=zs; k<ze; k++) {
567 for (PetscInt i=xs; i<xe; i++) {
568 cent[k][my-1][i] = lcent[k][my+1][i];
569 }
570 }
571 } else {
572 for (PetscInt k=zs; k<ze; k++) {
573 for (PetscInt i=xs; i<xe; i++) {
574 delta = (gs[k][my-2][i].y + gs[k][my+1][i].y) / 2.0;
575 cent[k][my-1][i].x = cent[k][my-2][i].x;
576 cent[k][my-1][i].y = cent[k][my-2][i].y + delta;
577 cent[k][my-1][i].z = cent[k][my-2][i].z;
578 }
579 }
580 }
581 }
582
583 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
584 ierr = DMDAVecRestoreArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
585 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
586
587 }
588
589 // --- Z-direction periodic corrections ---
592
593 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
594 ierr = DMDAVecGetArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
595 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
596
597 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && zs == 0) {
598 if (user->cgrid) {
599 for (PetscInt j=ys; j<ye; j++) {
600 for (PetscInt i=xs; i<xe; i++) {
601 cent[0][j][i] = lcent[-2][j][i];
602 }
603 }
604 } else {
605 for (PetscInt j=ys; j<ye; j++) {
606 for (PetscInt i=xs; i<xe; i++) {
607 delta = (gs[1][j][i].z + gs[-2][j][i].z) / 2.0;
608 cent[0][j][i].x = cent[1][j][i].x;
609 cent[0][j][i].y = cent[1][j][i].y;
610 cent[0][j][i].z = cent[1][j][i].z - delta;
611 }
612 }
613 }
614 }
615
616 if (user->boundary_faces[BC_FACE_POS_Z].mathematical_type == PERIODIC && ze == mz) {
617 if (user->cgrid) {
618 for (PetscInt j=ys; j<ye; j++) {
619 for (PetscInt i=xs; i<xe; i++) {
620 cent[mz-1][j][i] = lcent[mz+1][j][i];
621 }
622 }
623 } else {
624 for (PetscInt j=ys; j<ye; j++) {
625 for (PetscInt i=xs; i<xe; i++) {
626 delta = (gs[mz-2][j][i].z + gs[mz+1][j][i].z) / 2.0;
627 cent[mz-1][j][i].x = cent[mz-2][j][i].x;
628 cent[mz-1][j][i].y = cent[mz-2][j][i].y;
629 cent[mz-1][j][i].z = cent[mz-2][j][i].z + delta;
630 }
631 }
632 }
633 }
634
635 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
636 ierr = DMDAVecRestoreArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
637 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
638
639 }
640
642 PetscFunctionReturn(0);
643}
#define LOCAL
Logging scope definitions for controlling message output.
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:200
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:33
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1157
Vec lCent
Definition variables.h:776
@ PERIODIC
Definition variables.h:219
PetscInt cgrid
Definition variables.h:743
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:746
Vec lGridSpace
Definition variables.h:776
DMDALocalInfo info
Definition variables.h:735
Vec Cent
Definition variables.h:776
BCType mathematical_type
Definition variables.h:295
@ BC_FACE_NEG_X
Definition variables.h:204
@ BC_FACE_POS_Z
Definition variables.h:206
@ BC_FACE_POS_Y
Definition variables.h:205
@ BC_FACE_NEG_Z
Definition variables.h:206
@ BC_FACE_POS_X
Definition variables.h:204
@ BC_FACE_NEG_Y
Definition variables.h:205
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ApplyPeriodicCorrectionsToKFaceCenter()

PetscErrorCode ApplyPeriodicCorrectionsToKFaceCenter ( UserCtx user)

Applies periodic boundary corrections to i-face centers (Centx).

Applies periodic boundary corrections to k-face centers (Centz).

Only X-direction periodicity affects Centx. This function must be called after Centx has been initially computed but before it's used for metric calculations.

Parameters
userThe UserCtx containing grid and field data.
Returns
PetscErrorCode 0 on success.

Only Z-direction periodicity affects Centz. This function must be called after Centz has been initially computed but before it's used for metric calculations.

Parameters
userThe UserCtx containing grid and field data.
Returns
PetscErrorCode 0 on success.

Applies periodic boundary corrections to i-face centers (Centx).

Only Z-direction periodicity affects Centz. This function must be called after Centz has been initially computed but before it's used for metric calculations.

Parameters
userThe UserCtx containing grid and field data.
Returns
PetscErrorCode 0 on success.

Definition at line 828 of file Metric.c.

829{
830 PetscErrorCode ierr;
831 DMDALocalInfo info = user->info;
832 PetscInt zs = info.zs, ze = info.zs + info.zm;
833 PetscInt mz = info.mz;
834 PetscInt gxs = info.gxs, gxe = info.gxs + info.gxm;
835 PetscInt gys = info.gys, gye = info.gys + info.gym;
836 PetscInt gzs = info.gzs, gze = info.gzs + info.gzm;
837 Cmpnts ***centz, ***gs;
838
839 PetscFunctionBeginUser;
841
842 // Check if Z-periodic boundaries exist
845 LOG_ALLOW(LOCAL, LOG_TRACE, "No Z-periodic boundaries; skipping Centz corrections.\n");
847 PetscFunctionReturn(0);
848 }
849
850 LOG_ALLOW(LOCAL, LOG_DEBUG, "Applying Z-periodic corrections to Centz.\n");
851
852 ierr = DMDAVecGetArray(user->fda, user->Centz, &centz); CHKERRQ(ierr);
853 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
854
855 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && zs == 0) {
856 if (user->cgrid) {
857 for (PetscInt j=gys+1; j<gye; j++) {
858 for (PetscInt i=gxs+1; i<gxe; i++) {
859 centz[-1][j][i].x = centz[-3][j][i].x;
860 centz[-1][j][i].y = centz[-3][j][i].y;
861 centz[-1][j][i].z = centz[-3][j][i].z;
862 }
863 }
864 } else {
865 for (PetscInt j=gys+1; j<gye; j++) {
866 for (PetscInt i=gxs+1; i<gxe; i++) {
867 centz[-1][j][i].x = centz[0][j][i].x;
868 centz[-1][j][i].y = centz[0][j][i].y;
869 centz[-1][j][i].z = centz[0][j][i].z - gs[-2][j][i].z;
870 }
871 }
872 }
873 }
874
875 if (user->boundary_faces[BC_FACE_POS_Z].mathematical_type == PERIODIC && ze == mz) {
876 if (user->cgrid) {
877 for (PetscInt j=gys+1; j<gye; j++) {
878 for (PetscInt i=gxs+1; i<gxe; i++) {
879 centz[mz-1][j][i].x = centz[mz+1][j][i].x;
880 centz[mz-1][j][i].y = centz[mz+1][j][i].y;
881 centz[mz-1][j][i].z = centz[mz+1][j][i].z;
882 }
883 }
884 } else {
885 for (PetscInt j=gys+1; j<gye; j++) {
886 for (PetscInt i=gxs+1; i<gxe; i++) {
887 centz[mz-1][j][i].x = centz[mz-2][j][i].x;
888 centz[mz-1][j][i].y = centz[mz-2][j][i].y;
889 centz[mz-1][j][i].z = centz[mz-2][j][i].z + gs[mz+1][j][i].z;
890 }
891 }
892 }
893 }
894
895 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
896 ierr = DMDAVecRestoreArray(user->fda, user->Centz, &centz); CHKERRQ(ierr);
897
899 PetscFunctionReturn(0);
900}
Vec Centz
Definition variables.h:777
Here is the caller graph for this function:

◆ ApplyPeriodicCorrectionsToJFaceCenter()

PetscErrorCode ApplyPeriodicCorrectionsToJFaceCenter ( UserCtx user)

Applies periodic boundary corrections to j-face centers (Centy).

Only Y-direction periodicity affects Centy. This function must be called after Centy has been initially computed but before it's used for metric calculations.

Parameters
userThe UserCtx containing grid and field data.
Returns
PetscErrorCode 0 on success.

Definition at line 742 of file Metric.c.

743{
744 PetscErrorCode ierr;
745 DMDALocalInfo info = user->info;
746 PetscInt ys = info.ys, ye = info.ys + info.ym;
747 PetscInt my = info.my;
748 PetscInt gxs = info.gxs, gxe = info.gxs + info.gxm;
749 PetscInt gys = info.gys, gye = info.gys + info.gym;
750 PetscInt gzs = info.gzs, gze = info.gzs + info.gzm;
751 Cmpnts ***centy, ***gs;
752
753 PetscFunctionBeginUser;
755
756 // Check if Y-periodic boundaries exist
759 LOG_ALLOW(LOCAL, LOG_TRACE, "No Y-periodic boundaries; skipping Centy corrections.\n");
761 PetscFunctionReturn(0);
762 }
763
764 LOG_ALLOW(LOCAL, LOG_DEBUG, "Applying Y-periodic corrections to Centy.\n");
765
766 ierr = DMDAVecGetArray(user->fda, user->Centy, &centy); CHKERRQ(ierr);
767 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
768
769 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && ys == 0) {
770 if (user->cgrid) {
771 for (PetscInt k=gzs+1; k<gze; k++) {
772 for (PetscInt i=gxs+1; i<gxe; i++) {
773 centy[k][-1][i].x = centy[k][-3][i].x;
774 centy[k][-1][i].y = centy[k][-3][i].y;
775 centy[k][-1][i].z = centy[k][-3][i].z;
776 }
777 }
778 } else {
779 for (PetscInt k=gzs+1; k<gze; k++) {
780 for (PetscInt i=gxs+1; i<gxe; i++) {
781 centy[k][-1][i].x = centy[k][0][i].x;
782 centy[k][-1][i].y = centy[k][0][i].y - gs[k][-2][i].y;
783 centy[k][-1][i].z = centy[k][0][i].z;
784 }
785 }
786 }
787 }
788
789 if (user->boundary_faces[BC_FACE_POS_Y].mathematical_type == PERIODIC && ye == my) {
790 if (user->cgrid) {
791 for (PetscInt k=gzs+1; k<gze; k++) {
792 for (PetscInt i=gxs+1; i<gxe; i++) {
793 centy[k][my-1][i].x = centy[k][my+1][i].x;
794 centy[k][my-1][i].y = centy[k][my+1][i].y;
795 centy[k][my-1][i].z = centy[k][my+1][i].z;
796 }
797 }
798 } else {
799 for (PetscInt k=gzs+1; k<gze; k++) {
800 for (PetscInt i=gxs+1; i<gxe; i++) {
801 centy[k][my-1][i].x = centy[k][my-2][i].x;
802 centy[k][my-1][i].y = centy[k][my-2][i].y + gs[k][my+1][i].y;
803 centy[k][my-1][i].z = centy[k][my-2][i].z;
804 }
805 }
806 }
807 }
808
809 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
810 ierr = DMDAVecRestoreArray(user->fda, user->Centy, &centy); CHKERRQ(ierr);
811
813 PetscFunctionReturn(0);
814}
Vec Centy
Definition variables.h:777
Here is the caller graph for this function:

◆ ComputeFaceMetrics()

PetscErrorCode ComputeFaceMetrics ( UserCtx user)

Computes the primary face metric components (Csi, Eta, Zet), including boundary extrapolation, and stores them in the corresponding global Vec members of the UserCtx structure (user->Csi, user->Eta, user->Zet).

This is a self-contained routine that performs the following steps:

  1. Obtains local ghosted nodal coordinates using DMGetCoordinatesLocal.
  2. Calculates metrics for INTERIOR faces where finite difference stencils are valid.
  3. EXTRAPOLATES metrics for faces on the physical domain boundaries by copying from the nearest computed interior face.
  4. Assembles the global user->Csi, user->Eta, user->Zet Vecs.
  5. Updates the local ghosted user->lCsi, user->lEta, user->lZet Vecs.
Parameters
[in,out]userPointer to the UserCtx structure.
Returns
PetscErrorCode 0 on success.
Note
  • This function is a complete "compute and make ready" unit for Csi, Eta, and Zet.
  • It's recommended to call VecZeroEntries on user->Csi, Eta, Zet before this if they might contain old data.

    This is a self-contained routine that performs the following steps:

    1. Obtains local ghosted nodal coordinates using DMGetCoordinatesLocal.
    2. Calculates metrics for INTERIOR faces where finite difference stencils are valid.
    3. EXTRAPOLATES metrics for faces on the physical domain boundaries by copying from the nearest computed interior face.
    4. Assembles the global user->Csi, user->Eta, user->Zet Vecs.
    5. Updates the local ghosted user->lCsi, user->lEta, user->lZet Vecs.

This function calculates the face area vectors, which are fundamental to the finite volume method on a curvilinear grid. The process is performed in two main stages to ensure robustness and correctness across the entire domain, including physical boundaries.

Stage 1: Interior Face Calculation The core of the function uses centered finite-difference stencils on the nodal coordinates (coor) to compute the metric terms. For example, csi at a node (k,j,i) is calculated using a 2x2 stencil of nodes in the J-K plane.

Crucially, these stencils are only valid for interior nodes/faces where all required neighboring nodes exist. The loops are intentionally constructed (e.g., i_loop_start = 1) to skip the calculation directly on the domain's physical boundaries (e.g., at i=0, j=0, etc.), as the stencil would require out-of-bounds data.

Stage 2: Boundary Face Extrapolation After the interior metrics are computed, the values for the faces lying on the physical boundaries of the domain are populated. This is done via zero-order extrapolation, which simply means copying the values from the nearest valid interior face layer.

For example, on a rank owning the global i=0 boundary, zet_arr[k][j][0] is explicitly set to be equal to zet_arr[k][j][1]. Similarly, on a rank owning the i=mx-1 boundary, zet_arr[k][j][mx-1] is set to zet_arr[k][j][mx-2].

This two-stage approach ensures that every node in the physical domain, including the boundaries, has a valid metric value associated with it.

The function concludes by assembling the global PETSc vectors and updating the local ghosted versions, making the computed metrics ready for use by the solver.

Parameters
[in,out]userPointer to the UserCtx structure.
Returns
PetscErrorCode 0 on success.
Note
  • This function is a complete "compute and make ready" unit for Csi, Eta, and Zet.
  • It's recommended to call VecZeroEntries on user->Csi, Eta, Zet before this if they might contain old data.
  • Csi,Eta,Zeta are face centered quantities which represent the surface area in magnitude and the direction of positive computational coordinate increase in direction.

Definition at line 956 of file Metric.c.

957{
958 PetscErrorCode ierr;
959 DMDALocalInfo info;
960 Cmpnts ***csi_arr, ***eta_arr, ***zet_arr;
961 Cmpnts ***nodal_coords_arr;
962 Vec localCoords_from_dm;
963
964 PetscFunctionBeginUser;
965
967
968 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting calculation and update for Csi, Eta, Zet.\n");
969
970 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
971
972 // --- 1. Get Nodal Physical Coordinates (Local Ghosted Array directly) ---
973 ierr = DMGetCoordinatesLocal(user->da, &localCoords_from_dm); CHKERRQ(ierr);
974 if (!localCoords_from_dm) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocal failed to return a coordinate vector. \n");
975 ierr = DMDAVecGetArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
976
977 // --- 2. Get arrays for output global Vecs from UserCtx ---
978 ierr = DMDAVecGetArray(user->fda, user->Csi, &csi_arr); CHKERRQ(ierr);
979 ierr = DMDAVecGetArray(user->fda, user->Eta, &eta_arr); CHKERRQ(ierr);
980 ierr = DMDAVecGetArray(user->fda, user->Zet, &zet_arr); CHKERRQ(ierr);
981
982 // Define owned node ranges (global indices)
983 PetscInt xs = info.xs, xe = info.xs + info.xm;
984 PetscInt ys = info.ys, ye = info.ys + info.ym;
985 PetscInt zs = info.zs, ze = info.zs + info.zm;
986
987 // Global domain dimensions (total number of nodes)
988 PetscInt mx = info.mx;
989 PetscInt my = info.my;
990 PetscInt mz = info.mz;
991
992 // --- 3. Calculate Csi, Eta, Zet for INTERIOR Stencils ---
993 // Start loops from 1 if at global boundary 0 to ensure k_node-1 etc. are valid.
994 PetscInt k_loop_start = (zs == 0) ? zs + 1 : zs;
995 PetscInt j_loop_start = (ys == 0) ? ys + 1 : ys;
996 PetscInt i_loop_start = (xs == 0) ? xs + 1 : xs;
997
998 // These represent the surface area of the curvilinear cell face and the normal rotated such that the direction of increasing coordinate is maintained.
999 // The metric vectors (Csi, Eta, Zet) are defined to point in the direction of their corresponding increasing computational coordinate.
1000
1001 // Calculate Csi
1002 for (PetscInt k_node = k_loop_start; k_node < ze; ++k_node) {
1003 for (PetscInt j_node = j_loop_start; j_node < ye; ++j_node) {
1004 for (PetscInt i_node = xs; i_node < xe; ++i_node) {
1005
1006 PetscReal dx_deta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node-1][j_node][i_node].x - nodal_coords_arr[k_node][j_node-1][i_node].x - nodal_coords_arr[k_node-1][j_node-1][i_node].x);
1007 PetscReal dy_deta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node-1][j_node][i_node].y - nodal_coords_arr[k_node][j_node-1][i_node].y - nodal_coords_arr[k_node-1][j_node-1][i_node].y);
1008 PetscReal dz_deta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node-1][j_node][i_node].z - nodal_coords_arr[k_node][j_node-1][i_node].z - nodal_coords_arr[k_node-1][j_node-1][i_node].z);
1009 PetscReal dx_dzeta = 0.5 * (nodal_coords_arr[k_node][j_node-1][i_node].x + nodal_coords_arr[k_node][j_node][i_node].x - nodal_coords_arr[k_node-1][j_node-1][i_node].x - nodal_coords_arr[k_node-1][j_node][i_node].x);
1010 PetscReal dy_dzeta = 0.5 * (nodal_coords_arr[k_node][j_node-1][i_node].y + nodal_coords_arr[k_node][j_node][i_node].y - nodal_coords_arr[k_node-1][j_node-1][i_node].y - nodal_coords_arr[k_node-1][j_node][i_node].y);
1011 PetscReal dz_dzeta = 0.5 * (nodal_coords_arr[k_node][j_node-1][i_node].z + nodal_coords_arr[k_node][j_node][i_node].z - nodal_coords_arr[k_node-1][j_node-1][i_node].z - nodal_coords_arr[k_node-1][j_node][i_node].z);
1012
1013 csi_arr[k_node][j_node][i_node].x = dy_deta * dz_dzeta - dz_deta * dy_dzeta;
1014 csi_arr[k_node][j_node][i_node].y = dz_deta * dx_dzeta - dx_deta * dz_dzeta;
1015 csi_arr[k_node][j_node][i_node].z = dx_deta * dy_dzeta - dy_deta * dx_dzeta;
1016 }
1017 }
1018 }
1019
1020 // Calculate Eta
1021 for (PetscInt k_node = k_loop_start; k_node < ze; ++k_node) {
1022 for (PetscInt j_node = ys; j_node < ye; ++j_node) {
1023 for (PetscInt i_node = i_loop_start; i_node < xe; ++i_node) {
1024
1025 PetscReal dx_dxi = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node-1][j_node][i_node].x - nodal_coords_arr[k_node][j_node][i_node-1].x - nodal_coords_arr[k_node-1][j_node][i_node-1].x);
1026 PetscReal dy_dxi = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node-1][j_node][i_node].y - nodal_coords_arr[k_node][j_node][i_node-1].y - nodal_coords_arr[k_node-1][j_node][i_node-1].y);
1027 PetscReal dz_dxi = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node-1][j_node][i_node].z - nodal_coords_arr[k_node][j_node][i_node-1].z - nodal_coords_arr[k_node-1][j_node][i_node-1].z);
1028 PetscReal dx_dzeta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node][j_node][i_node-1].x - nodal_coords_arr[k_node-1][j_node][i_node].x - nodal_coords_arr[k_node-1][j_node][i_node-1].x);
1029 PetscReal dy_dzeta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node][j_node][i_node-1].y - nodal_coords_arr[k_node-1][j_node][i_node].y - nodal_coords_arr[k_node-1][j_node][i_node-1].y);
1030 PetscReal dz_dzeta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node][j_node][i_node-1].z - nodal_coords_arr[k_node-1][j_node][i_node].z - nodal_coords_arr[k_node-1][j_node][i_node-1].z);
1031
1032 eta_arr[k_node][j_node][i_node].x = dy_dzeta * dz_dxi - dz_dzeta * dy_dxi;
1033 eta_arr[k_node][j_node][i_node].y = dz_dzeta * dx_dxi - dx_dzeta * dz_dxi;
1034 eta_arr[k_node][j_node][i_node].z = dx_dzeta * dy_dxi - dy_dzeta * dx_dxi;
1035 }
1036 }
1037 }
1038
1039 // Calculate Zet
1040 for (PetscInt k_node = zs; k_node < ze; ++k_node) {
1041 for (PetscInt j_node = j_loop_start; j_node < ye; ++j_node) {
1042 for (PetscInt i_node = i_loop_start; i_node < xe; ++i_node) {
1043
1044 PetscReal dx_dxi = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node][j_node-1][i_node].x - nodal_coords_arr[k_node][j_node][i_node-1].x - nodal_coords_arr[k_node][j_node-1][i_node-1].x);
1045 PetscReal dy_dxi = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node][j_node-1][i_node].y - nodal_coords_arr[k_node][j_node][i_node-1].y - nodal_coords_arr[k_node][j_node-1][i_node-1].y);
1046 PetscReal dz_dxi = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node][j_node-1][i_node].z - nodal_coords_arr[k_node][j_node][i_node-1].z - nodal_coords_arr[k_node][j_node-1][i_node-1].z);
1047 PetscReal dx_deta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node][j_node][i_node-1].x - nodal_coords_arr[k_node][j_node-1][i_node].x - nodal_coords_arr[k_node][j_node-1][i_node-1].x);
1048 PetscReal dy_deta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node][j_node][i_node-1].y - nodal_coords_arr[k_node][j_node-1][i_node].y - nodal_coords_arr[k_node][j_node-1][i_node-1].y);
1049 PetscReal dz_deta = 0.5 * (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node][j_node][i_node-1].z - nodal_coords_arr[k_node][j_node-1][i_node].z - nodal_coords_arr[k_node][j_node-1][i_node-1].z);
1050
1051 zet_arr[k_node][j_node][i_node].x = dy_dxi * dz_deta - dz_dxi * dy_deta;
1052 zet_arr[k_node][j_node][i_node].y = dz_dxi * dx_deta - dx_dxi * dz_deta;
1053 zet_arr[k_node][j_node][i_node].z = dx_dxi * dy_deta - dy_dxi * dx_deta;
1054 }
1055 }
1056 }
1057
1058 // --- 4. Boundary Extrapolation ---
1059 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Extrapolating boundary values for Csi, Eta, Zet.\n");
1060 PetscInt i_bnd, j_bnd, k_bnd;
1061
1062 if (xs == 0) { // If this rank owns the global i=0 boundary
1063 i_bnd = 0;
1064 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1065 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1066 if (i_bnd + 1 < mx) {
1067 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd][j_bnd][i_bnd+1];
1068 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd][i_bnd+1];
1069 }
1070 }
1071 }
1072 }
1073 if (xe == mx) { // If this rank owns the global i=mx-1 boundary
1074 i_bnd = mx - 1;
1075 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1076 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1077 if (i_bnd - 1 >= 0) {
1078 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd][j_bnd][i_bnd-1];
1079 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd][i_bnd-1];
1080 }
1081 }
1082 }
1083 }
1084 if (ys == 0) {
1085 j_bnd = 0;
1086 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1087 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1088 if (j_bnd + 1 < my) {
1089 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd][j_bnd+1][i_bnd];
1090 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd+1][i_bnd];
1091 }
1092 }
1093 }
1094 }
1095 if (ye == my) {
1096 j_bnd = my - 1;
1097 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1098 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1099 if (j_bnd - 1 >= 0) {
1100 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd][j_bnd-1][i_bnd];
1101 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd-1][i_bnd];
1102 }
1103 }
1104 }
1105 }
1106 if (zs == 0) {
1107 k_bnd = 0;
1108 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1109 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1110 if (k_bnd + 1 < mz) {
1111 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd+1][j_bnd][i_bnd];
1112 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd+1][j_bnd][i_bnd];
1113 }
1114 }
1115 }
1116 }
1117 if (ze == mz) {
1118 k_bnd = mz - 1;
1119 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1120 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1121 if (k_bnd - 1 >= 0) {
1122 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd-1][j_bnd][i_bnd];
1123 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd-1][j_bnd][i_bnd];
1124 }
1125 }
1126 }
1127 }
1128
1129 if (info.xs==0 && info.ys==0 && info.zs==0) {
1130 PetscReal dot = zet_arr[0][0][0].z; /* dot with global +z */
1131 LOG_ALLOW(GLOBAL,LOG_DEBUG,"Zet(k=0)·ez = %.3f (should be >0 for right-handed grid)\n", dot);
1132 }
1133
1134 // --- 5. Restore all arrays ---
1135 ierr = DMDAVecRestoreArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
1136 ierr = DMDAVecRestoreArray(user->fda, user->Csi, &csi_arr); CHKERRQ(ierr);
1137 ierr = DMDAVecRestoreArray(user->fda, user->Eta, &eta_arr); CHKERRQ(ierr);
1138 ierr = DMDAVecRestoreArray(user->fda, user->Zet, &zet_arr); CHKERRQ(ierr);
1139
1140 // --- 6. Assemble Global Vectors ---
1141 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Assembling global Csi, Eta, Zet.\n");
1142 ierr = VecAssemblyBegin(user->Csi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Csi); CHKERRQ(ierr);
1143 ierr = VecAssemblyBegin(user->Eta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Eta); CHKERRQ(ierr);
1144 ierr = VecAssemblyBegin(user->Zet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Zet); CHKERRQ(ierr);
1145
1146 // --- 7. Update Local Ghosted Versions ---
1147 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Updating local lCsi, lEta, lZet.\n");
1148 ierr = UpdateLocalGhosts(user, "Csi"); CHKERRQ(ierr);
1149 ierr = UpdateLocalGhosts(user, "Eta"); CHKERRQ(ierr);
1150 ierr = UpdateLocalGhosts(user, "Zet"); CHKERRQ(ierr);
1151
1152 LOG_ALLOW(GLOBAL, LOG_INFO, "Completed calculation, extrapolation, and update for Csi, Eta, Zet.\n");
1153
1155
1156 PetscFunctionReturn(0);
1157}
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
Vec Zet
Definition variables.h:776
Vec Csi
Definition variables.h:776
Vec Eta
Definition variables.h:776
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeCellCenteredJacobianInverse()

PetscErrorCode ComputeCellCenteredJacobianInverse ( UserCtx user)

Calculates the cell-centered inverse Jacobian determinant (1/J) for INTERIOR cells and stores it in user->Aj.

This version includes boundary extrapolation.

Nodal coordinates are obtained internally. Refer to previous Doxygen comments for details on physical locations and storage convention (aj_arr[k_n][j_n][i_n] for cell C(i_n-1,j_n-1,k_n-1)).

Parameters
[in,out]userPointer to the UserCtx structure.
Returns
PetscErrorCode 0 on success.

Calculates the cell-centered inverse Jacobian determinant (1/J) for INTERIOR cells and stores it in user->Aj.

Parameters
[in,out]userPointer to the UserCtx structure.
Returns
PetscErrorCode 0 on success.

Definition at line 1171 of file Metric.c.

1172{
1173 PetscErrorCode ierr;
1174 DMDALocalInfo info;
1175 PetscScalar ***aj_arr;
1176 Cmpnts ***nodal_coords_arr;
1177 Vec localCoords_from_dm;
1178
1179 PetscFunctionBeginUser;
1180 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting calculation, extrapolation, and update for Aj.\n");
1181
1182 // --- 1. Get Nodal Coordinates and Output Array ---
1183 ierr = DMGetCoordinatesLocal(user->da, &localCoords_from_dm); CHKERRQ(ierr);
1184 ierr = DMDAVecGetArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
1185 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1186 ierr = DMDAVecGetArray(user->da, user->Aj, &aj_arr); CHKERRQ(ierr);
1187
1188 // Define owned node ranges (global indices)
1189 PetscInt xs = info.xs, xe = info.xs + info.xm;
1190 PetscInt ys = info.ys, ye = info.ys + info.ym;
1191 PetscInt zs = info.zs, ze = info.zs + info.zm;
1192
1193 // Global domain dimensions (total number of nodes)
1194 PetscInt mx = info.mx;
1195 PetscInt my = info.my;
1196 PetscInt mz = info.mz;
1197
1198 // --- 2. Calculate Aj for INTERIOR Stencils ---
1199
1200 PetscInt k_start_node = (zs == 0) ? zs + 1 : zs;
1201 PetscInt j_start_node = (ys == 0) ? ys + 1 : ys;
1202 PetscInt i_start_node = (xs == 0) ? xs + 1 : xs;
1203
1204 PetscInt k_end_node = (ze == mz) ? ze - 1 : ze;
1205 PetscInt j_end_node = (ye == my) ? ye - 1 : ye;
1206 PetscInt i_end_node = (xe == mx) ? xe - 1 : xe;
1207
1208 for (PetscInt k_node = k_start_node; k_node < k_end_node; ++k_node) {
1209 for (PetscInt j_node = j_start_node; j_node < j_end_node; ++j_node) {
1210 for (PetscInt i_node = i_start_node; i_node < i_end_node; ++i_node) {
1211
1212 PetscReal dx_dxi = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node][j_node-1][i_node].x + nodal_coords_arr[k_node-1][j_node][i_node].x + nodal_coords_arr[k_node-1][j_node-1][i_node].x) - (nodal_coords_arr[k_node][j_node][i_node-1].x + nodal_coords_arr[k_node][j_node-1][i_node-1].x + nodal_coords_arr[k_node-1][j_node][i_node-1].x + nodal_coords_arr[k_node-1][j_node-1][i_node-1].x) );
1213
1214 PetscReal dy_dxi = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node][j_node-1][i_node].y + nodal_coords_arr[k_node-1][j_node][i_node].y + nodal_coords_arr[k_node-1][j_node-1][i_node].y) - (nodal_coords_arr[k_node][j_node][i_node-1].y + nodal_coords_arr[k_node][j_node-1][i_node-1].y + nodal_coords_arr[k_node-1][j_node][i_node-1].y + nodal_coords_arr[k_node-1][j_node-1][i_node-1].y) );
1215
1216 PetscReal dz_dxi = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node][j_node-1][i_node].z + nodal_coords_arr[k_node-1][j_node][i_node].z + nodal_coords_arr[k_node-1][j_node-1][i_node].z) - (nodal_coords_arr[k_node][j_node][i_node-1].z + nodal_coords_arr[k_node][j_node-1][i_node-1].z + nodal_coords_arr[k_node-1][j_node][i_node-1].z + nodal_coords_arr[k_node-1][j_node-1][i_node-1].z) );
1217
1218 PetscReal dx_deta = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node][j_node][i_node-1].x + nodal_coords_arr[k_node-1][j_node][i_node].x + nodal_coords_arr[k_node-1][j_node][i_node-1].x) - (nodal_coords_arr[k_node][j_node-1][i_node].x + nodal_coords_arr[k_node][j_node-1][i_node-1].x + nodal_coords_arr[k_node-1][j_node-1][i_node].x + nodal_coords_arr[k_node-1][j_node-1][i_node-1].x) );
1219
1220 PetscReal dy_deta = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node][j_node][i_node-1].y + nodal_coords_arr[k_node-1][j_node][i_node].y + nodal_coords_arr[k_node-1][j_node][i_node-1].y) - (nodal_coords_arr[k_node][j_node-1][i_node].y + nodal_coords_arr[k_node][j_node-1][i_node-1].y + nodal_coords_arr[k_node-1][j_node-1][i_node].y + nodal_coords_arr[k_node-1][j_node-1][i_node-1].y) );
1221
1222 PetscReal dz_deta = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node][j_node][i_node-1].z + nodal_coords_arr[k_node-1][j_node][i_node].z + nodal_coords_arr[k_node-1][j_node][i_node-1].z) - (nodal_coords_arr[k_node][j_node-1][i_node].z + nodal_coords_arr[k_node][j_node-1][i_node-1].z + nodal_coords_arr[k_node-1][j_node-1][i_node].z + nodal_coords_arr[k_node-1][j_node-1][i_node-1].z) );
1223
1224 PetscReal dx_dzeta = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].x + nodal_coords_arr[k_node][j_node-1][i_node].x + nodal_coords_arr[k_node][j_node][i_node-1].x + nodal_coords_arr[k_node][j_node-1][i_node-1].x) - (nodal_coords_arr[k_node-1][j_node][i_node].x + nodal_coords_arr[k_node-1][j_node-1][i_node].x + nodal_coords_arr[k_node-1][j_node][i_node-1].x + nodal_coords_arr[k_node-1][j_node-1][i_node-1].x) );
1225
1226 PetscReal dy_dzeta = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].y + nodal_coords_arr[k_node][j_node-1][i_node].y + nodal_coords_arr[k_node][j_node][i_node-1].y + nodal_coords_arr[k_node][j_node-1][i_node-1].y) - (nodal_coords_arr[k_node-1][j_node][i_node].y + nodal_coords_arr[k_node-1][j_node-1][i_node].y + nodal_coords_arr[k_node-1][j_node][i_node-1].y + nodal_coords_arr[k_node-1][j_node-1][i_node-1].y) );
1227
1228 PetscReal dz_dzeta = 0.25 * ( (nodal_coords_arr[k_node][j_node][i_node].z + nodal_coords_arr[k_node][j_node-1][i_node].z + nodal_coords_arr[k_node][j_node][i_node-1].z + nodal_coords_arr[k_node][j_node-1][i_node-1].z) - (nodal_coords_arr[k_node-1][j_node][i_node].z + nodal_coords_arr[k_node-1][j_node-1][i_node].z + nodal_coords_arr[k_node-1][j_node][i_node-1].z + nodal_coords_arr[k_node-1][j_node-1][i_node-1].z) );
1229
1230 PetscReal jacobian_det = dx_dxi * (dy_deta * dz_dzeta - dz_deta * dy_dzeta) - dy_dxi * (dx_deta * dz_dzeta - dz_deta * dx_dzeta) + dz_dxi * (dx_deta * dy_dzeta - dy_deta * dx_dzeta);
1231 if (PetscAbsReal(jacobian_det) < 1.0e-18) { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FLOP_COUNT, "Jacobian is near zero..."); }
1232 aj_arr[k_node][j_node][i_node] = 1.0 / jacobian_det;
1233 }
1234 }
1235 }
1236
1237 // --- 4. Boundary Extrapolation for Aj ---
1238 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Extrapolating boundary values for Aj. \n");
1239 PetscInt i_bnd, j_bnd, k_bnd;
1240
1241 if (xs == 0) {
1242 i_bnd = 0;
1243 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1244 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1245 if (i_bnd + 1 < mx) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd][i_bnd+1];
1246 }
1247 }
1248 }
1249 if (xe == mx) {
1250 i_bnd = mx - 1;
1251 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1252 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1253 if (i_bnd - 1 >= 0) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd][i_bnd-1];
1254 }
1255 }
1256 }
1257 // (Similar extrapolation blocks for Y and Z boundaries for aj_arr)
1258 if (ys == 0) {
1259 j_bnd = 0;
1260 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1261 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1262 if (j_bnd + 1 < my) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd+1][i_bnd];
1263 }
1264 }
1265 }
1266 if (ye == my) {
1267 j_bnd = my - 1;
1268 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
1269 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1270 if (j_bnd - 1 >= 0) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd-1][i_bnd];
1271 }
1272 }
1273 }
1274 if (zs == 0) {
1275 k_bnd = 0;
1276 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1277 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1278 if (k_bnd + 1 < mz) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd+1][j_bnd][i_bnd];
1279 }
1280 }
1281 }
1282 if (ze == mz) {
1283 k_bnd = mz - 1;
1284 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
1285 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
1286 if (k_bnd - 1 >= 0) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd-1][j_bnd][i_bnd];
1287 }
1288 }
1289 }
1290
1291 // --- 5. Restore arrays ---
1292 ierr = DMDAVecRestoreArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
1293 ierr = DMDAVecRestoreArray(user->da, user->Aj, &aj_arr); CHKERRQ(ierr);
1294
1295 // --- 6. Assemble Global Vector ---
1296 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Assembling global Aj.\n");
1297 ierr = VecAssemblyBegin(user->Aj); CHKERRQ(ierr);
1298 ierr = VecAssemblyEnd(user->Aj); CHKERRQ(ierr);
1299
1300 // --- 7. Update Local Ghosted Version ---
1301 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Updating local lAj.\n");
1302 ierr = UpdateLocalGhosts(user, "Aj"); CHKERRQ(ierr);
1303
1304 LOG_ALLOW(GLOBAL, LOG_INFO, "Completed calculation, extrapolation, and update for Aj.\n");
1305 PetscFunctionReturn(0);
1306}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CheckAndFixGridOrientation()

PetscErrorCode CheckAndFixGridOrientation ( UserCtx user)

Ensure a right-handed metric basis (Csi, Eta, Zet) and a positive Jacobian (Aj) over the whole domain.

The metric-generation kernels are completely algebraic, so they will happily deliver a left-handed basis if the mesh file enumerates nodes in the opposite ζ-direction.
This routine makes the orientation explicit and—if needed—repairs it once per run:

Step Action
1 Compute global Aj_min, Aj_max.
2 Mixed signs (Aj_min < 0 && Aj_max > 0) → abort: the mesh is topologically inconsistent.
3 All negative (Aj_max < 0) → flip
Csi, Eta, Zet, Aj & update local ghosts.
4 Store user->orientation = ±1 so BC / IC routines can apply sign-aware logic if they care about inlet direction.
Parameters
[in,out]userFully initialised UserCtx that already contains
Csi, Eta, Zet, Aj, their local ghosts, and valid distributed DMs.
Returns
0 on success or a PETSc error code on failure.
Note
Call immediately after ComputeCellCenteredJacobianInverse() and before any routine that differentiates or applies BCs.
Author
<your name>

The metric-generation kernels are completely algebraic, so they will happily deliver a left-handed basis if the mesh file enumerates nodes in the opposite ζ-direction.
This routine makes the orientation explicit and—if needed—repairs it once per run:

Step Action
1 Compute global Aj_min, Aj_max.
2 Mixed signs (Aj_min < 0 && Aj_max > 0) → abort: the mesh is topologically inconsistent.
3 All negative (Aj_max < 0) → flip
Csi, Eta, Zet, Aj & update local ghosts.
4 Store user->orientation = ±1 so BC / IC routines can apply sign-aware logic if they care about inlet direction.
Parameters
[in,out]userFully initialised UserCtx that already contains
Csi, Eta, Zet, Aj, their local ghosts, and valid distributed DMs.
Returns
0 on success or a PETSc error code on failure.
Note
Call immediately after ComputeCellCenteredJacobianInverse() and before any routine that differentiates or applies BCs.
Author
vishal kandala

Definition at line 368 of file Metric.c.

369{
370 PetscErrorCode ierr;
371 PetscReal aj_min, aj_max;
372 PetscMPIInt rank;
373
374 PetscFunctionBeginUser;
375
377
378 /* ---------------- step 1: global extrema of Aj ---------------- */
379 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
380
381 ierr = VecMin(user->Aj, NULL, &aj_min); CHKERRQ(ierr); /* already global */
382 ierr = VecMax(user->Aj, NULL, &aj_max); CHKERRQ(ierr);
383
385 "[orientation] Global Aj range: [%.3e , %.3e]\n",
386 (double)aj_min, (double)aj_max);
387
388 /* ---------------- step 2: detect malformed mesh ---------------- */
389 if (aj_min < 0.0 && aj_max > 0.0)
390 SETERRABORT(PETSC_COMM_WORLD, PETSC_ERR_USER,
391 "Mixed Jacobian signs detected – grid is topologically inconsistent.");
392
393 /* Default: grid is right-handed unless proven otherwise */
394 PetscInt orientation = +1;
395
396 /* ---------------- step 3: repair left-handed mesh -------------- */
397 if (aj_max < 0.0) { /* entire domain has Aj < 0 */
398 orientation = -1;
399
400 if (!rank)
402 "[orientation] Detected left-handed grid – flipping metric vectors\n");
403
404 /* Flip sign of *all* metric vectors and Aj */
405 ierr = VecScale(user->Csi, -1.0); CHKERRQ(ierr);
406 ierr = VecScale(user->Eta, -1.0); CHKERRQ(ierr);
407 ierr = VecScale(user->Zet, -1.0); CHKERRQ(ierr);
408 ierr = VecScale(user->Aj , -1.0); CHKERRQ(ierr);
409
410 /* Local ghost regions now stale – refresh */
411 ierr = UpdateLocalGhosts(user, "Csi"); CHKERRQ(ierr);
412 ierr = UpdateLocalGhosts(user, "Eta"); CHKERRQ(ierr);
413 ierr = UpdateLocalGhosts(user, "Zet"); CHKERRQ(ierr);
414 ierr = UpdateLocalGhosts(user, "Aj"); CHKERRQ(ierr);
415
416 /* Sanity print: Aj must be > 0 now */
417 ierr = VecMin(user->Aj, NULL, &aj_min); CHKERRQ(ierr);
418 ierr = VecMax(user->Aj, NULL, &aj_max); CHKERRQ(ierr);
419
420 if (aj_min <= 0.0)
421 SETERRABORT(PETSC_COMM_WORLD, PETSC_ERR_USER,
422 "Failed to flip grid orientation – Aj still non-positive.");
423 else if (aj_min && aj_max > 0.0)
424 orientation = +1;
425 }
426
427 /* ---------------- step 4: store result in UserCtx -------------- */
428 user->GridOrientation = orientation;
429
430 if (!rank)
432 "[orientation] Grid confirmed %s-handed after flip (orientation=%+d)\n",
433 (orientation>0) ? "right" : "left", orientation);
434
436
437 PetscFunctionReturn(0);
438}
PetscInt GridOrientation
Definition variables.h:741
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeCellCentersAndSpacing()

PetscErrorCode ComputeCellCentersAndSpacing ( UserCtx user)

Computes the physical location of cell centers and the spacing between them.

This function calculates two key geometric properties from the nodal coordinates:

  1. Cent: A vector field storing the (x,y,z) coordinates of the center of each grid cell.
  2. GridSpace: A vector field storing the physical distance between adjacent cell centers in the i, j, and k computational directions.

It is a direct adaptation of the corresponding logic from the legacy FormMetrics.

Parameters
userThe UserCtx for a specific grid level. The function populates user->Cent and user->GridSpace.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

This function calculates two key geometric properties from the nodal coordinates:

  1. Cent: A vector field storing the (x,y,z) coordinates of the center of each grid cell.
  2. GridSpace: A vector field storing the physical distance between adjacent cell centers in the i, j, and k computational directions.

It is a direct adaptation of the corresponding logic from the legacy FormMetrics.

Parameters
userThe UserCtx for a specific grid level. The function populates user->Cent and user->GridSpace.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.
Note
Grid Spacing represents the vector connecting two adjacent grid cell faces. It is a vector whose magnitude gives the distance between two faces and direction is from one face center to the other.

Definition at line 1326 of file Metric.c.

1327{
1328 PetscErrorCode ierr;
1329 DMDALocalInfo info;
1330 Vec lCoords;
1331 const Cmpnts ***coor;
1332 Cmpnts ***cent, ***gs;
1333 PetscReal xcp, ycp, zcp, xcm, ycm, zcm;
1334 PetscInt xs,ys,zs,xe,ye,ze,mx,my,mz;
1335
1336 PetscFunctionBeginUser;
1337
1339
1340 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Computing cell centers and spacing for level %d block %d...\n", user->simCtx->rank, user->thislevel, user->_this);
1341
1342 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1343 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1344 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1345
1346 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
1347 ierr = DMDAVecGetArray(user->fda, user->GridSpace, &gs); CHKERRQ(ierr);
1348
1349 xs = info.xs; xe = info.xs + info.xm;
1350 ys = info.ys; ye = info.ys + info.ym;
1351 zs = info.zs; ze = info.zs + info.zm;
1352 mx = info.mx; my = info.my; mz = info.mz;
1353
1354 PetscInt k_start_node = (zs == 0) ? zs + 1 : zs;
1355 PetscInt j_start_node = (ys == 0) ? ys + 1 : ys;
1356 PetscInt i_start_node = (xs == 0) ? xs + 1 : xs;
1357
1358 PetscInt k_end_node = (ze == mz) ? ze - 1 : ze;
1359 PetscInt j_end_node = (ye == my) ? ye - 1 : ye;
1360 PetscInt i_end_node = (xe == mx) ? xe - 1 : xe;
1361
1362 // Loop over the interior OWNED cells (stencil requires i-1, j-1, k-1)
1363 for (PetscInt k=k_start_node; k<k_end_node; k++) {
1364 for (PetscInt j=j_start_node; j<j_end_node; j++) {
1365 for (PetscInt i=i_start_node; i<i_end_node; i++) {
1366 // Calculate cell center as the average of its 8 corner nodes
1367 cent[k][j][i].x = 0.125 * (coor[k][j][i].x + coor[k][j-1][i].x + coor[k-1][j][i].x + coor[k-1][j-1][i].x + coor[k][j][i-1].x + coor[k][j-1][i-1].x + coor[k-1][j][i-1].x + coor[k-1][j-1][i-1].x);
1368 cent[k][j][i].y = 0.125 * (coor[k][j][i].y + coor[k][j-1][i].y + coor[k-1][j][i].y + coor[k-1][j-1][i].y + coor[k][j][i-1].y + coor[k][j-1][i-1].y + coor[k-1][j][i-1].y + coor[k-1][j-1][i-1].y);
1369 cent[k][j][i].z = 0.125 * (coor[k][j][i].z + coor[k][j-1][i].z + coor[k-1][j][i].z + coor[k-1][j-1][i].z + coor[k][j][i-1].z + coor[k][j-1][i-1].z + coor[k-1][j][i-1].z + coor[k-1][j-1][i-1].z);
1370
1371 // Calculate Grid Spacing in i-direction (distance between i-face centers)
1372 xcp = 0.25 * (coor[k][j][i].x + coor[k][j-1][i].x + coor[k-1][j-1][i].x + coor[k-1][j][i].x);
1373 ycp = 0.25 * (coor[k][j][i].y + coor[k][j-1][i].y + coor[k-1][j-1][i].y + coor[k-1][j][i].y);
1374 zcp = 0.25 * (coor[k][j][i].z + coor[k][j-1][i].z + coor[k-1][j-1][i].z + coor[k-1][j][i].z);
1375 xcm = 0.25 * (coor[k][j][i-1].x + coor[k][j-1][i-1].x + coor[k-1][j-1][i-1].x + coor[k-1][j][i-1].x);
1376 ycm = 0.25 * (coor[k][j][i-1].y + coor[k][j-1][i-1].y + coor[k-1][j-1][i-1].y + coor[k-1][j][i-1].y);
1377 zcm = 0.25 * (coor[k][j][i-1].z + coor[k][j-1][i-1].z + coor[k-1][j-1][i-1].z + coor[k-1][j][i-1].z);
1378 gs[k][j][i].x = PetscSqrtReal(PetscSqr(xcp-xcm) + PetscSqr(ycp-ycm) + PetscSqr(zcp-zcm));
1379
1380 // Calculate Grid Spacing in j-direction (distance between j-face centers)
1381 xcp = 0.25 * (coor[k][j][i].x + coor[k][j][i-1].x + coor[k-1][j][i].x + coor[k-1][j][i-1].x);
1382 ycp = 0.25 * (coor[k][j][i].y + coor[k][j][i-1].y + coor[k-1][j][i].y + coor[k-1][j][i-1].y);
1383 zcp = 0.25 * (coor[k][j][i].z + coor[k][j][i-1].z + coor[k-1][j][i].z + coor[k-1][j][i-1].z);
1384 xcm = 0.25 * (coor[k][j-1][i].x + coor[k][j-1][i-1].x + coor[k-1][j-1][i].x + coor[k-1][j-1][i-1].x);
1385 ycm = 0.25 * (coor[k][j-1][i].y + coor[k][j-1][i-1].y + coor[k-1][j-1][i].y + coor[k-1][j-1][i-1].y);
1386 zcm = 0.25 * (coor[k][j-1][i].z + coor[k][j-1][i-1].z + coor[k-1][j-1][i].z + coor[k-1][j-1][i-1].z);
1387 gs[k][j][i].y = PetscSqrtReal(PetscSqr(xcp-xcm) + PetscSqr(ycp-ycm) + PetscSqr(zcp-zcm));
1388
1389 // Calculate Grid Spacing in k-direction (distance between k-face centers)
1390 xcp = 0.25 * (coor[k][j][i].x + coor[k][j][i-1].x + coor[k][j-1][i].x + coor[k][j-1][i-1].x);
1391 ycp = 0.25 * (coor[k][j][i].y + coor[k][j][i-1].y + coor[k][j-1][i].y + coor[k][j-1][i-1].y);
1392 zcp = 0.25 * (coor[k][j][i].z + coor[k][j][i-1].z + coor[k][j-1][i].z + coor[k][j-1][i-1].z);
1393 xcm = 0.25 * (coor[k-1][j][i].x + coor[k-1][j][i-1].x + coor[k-1][j-1][i].x + coor[k-1][j-1][i-1].x);
1394 ycm = 0.25 * (coor[k-1][j][i].y + coor[k-1][j][i-1].y + coor[k-1][j-1][i].y + coor[k-1][j-1][i-1].y);
1395 zcm = 0.25 * (coor[k-1][j][i].z + coor[k-1][j-1][i-1].z + coor[k-1][j-1][i].z + coor[k-1][j-1][i-1].z);
1396 gs[k][j][i].z = PetscSqrtReal(PetscSqr(xcp-xcm) + PetscSqr(ycp-ycm) + PetscSqr(zcp-zcm));
1397 }
1398 }
1399 }
1400
1401 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1402 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
1403 ierr = DMDAVecRestoreArray(user->fda, user->GridSpace, &gs); CHKERRQ(ierr);
1404
1405 // Assemble and update ghost regions for the new data
1406 ierr = VecAssemblyBegin(user->Cent); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Cent); CHKERRQ(ierr);
1407 ierr = VecAssemblyBegin(user->GridSpace); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->GridSpace); CHKERRQ(ierr);
1408 ierr = UpdateLocalGhosts(user, "Cent"); CHKERRQ(ierr);
1409 ierr = UpdateLocalGhosts(user, "GridSpace"); CHKERRQ(ierr);
1410
1411 ierr = ApplyPeriodicCorrectionsToCellCentersAndSpacing(user); CHKERRQ(ierr);
1412
1413 // Final assembly and ghost update after corrections
1414 ierr = VecAssemblyBegin(user->Cent); CHKERRQ(ierr);
1415 ierr = VecAssemblyEnd(user->Cent); CHKERRQ(ierr);
1416 ierr = UpdateLocalGhosts(user, "Cent"); CHKERRQ(ierr);
1417
1419
1420 PetscFunctionReturn(0);
1421}
PetscErrorCode ApplyPeriodicCorrectionsToCellCentersAndSpacing(UserCtx *user)
Applies periodic boundary corrections to cell centers (Cent) and grid spacing (GridSpace).
Definition Metric.c:452
Vec GridSpace
Definition variables.h:776
PetscMPIInt rank
Definition variables.h:588
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:731
PetscInt _this
Definition variables.h:741
PetscInt thislevel
Definition variables.h:792
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeIFaceMetrics()

PetscErrorCode ComputeIFaceMetrics ( UserCtx user)

Computes metrics centered on constant-i faces (i-faces).

This function calculates the metric terms (ICsi, IEta, IZet) and the inverse Jacobian (IAj) located at the center of each i-face. The stencils use i-face-centered coordinates (Centx) which must be computed first. The logic is a direct adaptation of the legacy FormMetrics function.

Parameters
userThe UserCtx for a specific grid level. Populates user->ICsi, etc.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

This function calculates the metric terms (ICsi, IEta, IZet) and the inverse Jacobian (IAj) located at the geometric center of each constant-i face. This is a critical step for staggered-grid finite difference schemes.

The process is a direct and faithful refactoring of the corresponding logic from the legacy FormMetrics function:

  1. It first calculates the physical (x,y,z) coordinates of the center of each i-face and stores them in the user->Centx vector.
  2. It then uses a boundary-aware, second-order finite difference stencil on the Centx field to compute the derivatives (e.g., d(x)/d(csi)).
    • Central differences are used in the grid interior.
    • One-sided differences are used at the physical domain boundaries.
  3. Finally, these derivatives are used to compute the final metric terms and the inverse Jacobian, which are stored in their respective Vec objects.
Parameters
userThe UserCtx for a specific grid level. This function populates the user->ICsi, user->IEta, user->IZet, and user->IAj vectors.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.
Note
Icsi,Ieta,Izet represent the computational coordinate gradients scaled by local volume inverse ((Iaj)

Definition at line 1450 of file Metric.c.

1451{
1452 PetscErrorCode ierr;
1453 DMDALocalInfo info;
1454 Vec lCoords;
1455 const Cmpnts ***coor;
1456 Cmpnts ***centx; //***gs;
1457 const Cmpnts ***centx_const;
1458 Cmpnts ***icsi, ***ieta, ***izet;
1459 PetscScalar ***iaj;
1460 PetscReal dxdc, dydc, dzdc, dxde, dyde, dzde, dxdz, dydz, dzdz;
1461
1462 PetscFunctionBeginUser;
1463
1465
1466 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Computing i-face metrics for level %d block %d...\n", user->simCtx->rank, user->thislevel, user->_this);
1467
1468 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1469 PetscInt xs = info.xs, xe = info.xs + info.xm, mx = info.mx;
1470 PetscInt ys = info.ys, ye = info.ys + info.ym, my = info.my;
1471 PetscInt zs = info.zs, ze = info.zs + info.zm, mz = info.mz;
1472 PetscInt gxs = info.gxs, gxe = info.gxs + info.gxm;
1473 PetscInt gys = info.gys, gye = info.gys + info.gym;
1474 PetscInt gzs = info.gzs, gze = info.gzs + info.gzm;
1475
1476 PetscInt lxs = xs; PetscInt lxe = xe;
1477 PetscInt lys = ys; PetscInt lye = ye;
1478 PetscInt lzs = zs; PetscInt lze = ze;
1479
1480 if (xs==0) lxs = xs+1;
1481 if (ys==0) lys = ys+1;
1482 if (zs==0) lzs = zs+1;
1483
1484 if (xe==mx) lxe=xe-1;
1485 if (ye==my) lye=ye-1;
1486 if (ze==mz) lze=ze-1;
1487
1488 // --- Part 1: Calculate the location of i-face centers (Centx) ---
1489 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1490 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1491 ierr = DMDAVecGetArray(user->fda, user->Centx, &centx); CHKERRQ(ierr);
1492 // ierr = DMDAVecGetArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1493
1494 //LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Calculating i-face centers (Centx) with i[%d,%d], j[%d,%d], k[%d,%d] ...\n", user->simCtx->rank,gxs,gxe,gys,gye,gzs,gze);
1495
1496 // Loop over the ghosted region to calculate all local face centers
1497 // To ensure we don't mistakenly calculate unused/dummy elements along non-dominant directions.
1498 PetscInt j_end = (ye == mx)? my - 1:gye;
1499 PetscInt k_end = (ze == mz)? mz - 1:gze;
1500
1501 for (PetscInt k = gzs + 1; k < k_end; k++) {
1502 for (PetscInt j = gys + 1; j < j_end; j++) {
1503 for (PetscInt i = gxs; i < gxe; i++) {
1504 //----- DEBUG ------
1505 //LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Calculating i-face center at (k=%d, j=%d, i=%d)\n", user->simCtx->rank, k, j, i);
1506 //LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Using corner nodes: (%f,%f,%f), (%f,%f,%f), (%f,%f,%f), (%f,%f,%f)\n", user->simCtx->rank,
1507 // coor[k][j][i].x, coor[k][j][i].y, coor[k][j][i].z,
1508 // coor[k-1][j][i].x, coor[k-1][j][i].y, coor[k-1][j][i].z,
1509 // coor[k][j-1][i].x, coor[k][j-1][i].y, coor[k][j-1][i].z,
1510 // coor[k-1][j-1][i].x, coor[k-1][j-1][i].y, coor[k-1][j-1][i].z);
1511
1512 centx[k][j][i].x = 0.25 * (coor[k][j][i].x + coor[k-1][j][i].x + coor[k][j-1][i].x + coor[k-1][j-1][i].x);
1513 centx[k][j][i].y = 0.25 * (coor[k][j][i].y + coor[k-1][j][i].y + coor[k][j-1][i].y + coor[k-1][j-1][i].y);
1514 centx[k][j][i].z = 0.25 * (coor[k][j][i].z + coor[k-1][j][i].z + coor[k][j-1][i].z + coor[k-1][j-1][i].z);
1515
1516 //LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Calculated i-face center: (%f,%f,%f)\n", user->simCtx->rank, centx[k][j][i].x, centx[k][j][i].y, centx[k][j][i].z);
1517 }
1518 }
1519 }
1520
1521 //LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: i-face center coordinates calculated. \n", user->simCtx->rank);
1522 /*
1523 if(xs==0){
1524 for(PetscInt k=gzs+1;k < gze; k++){
1525 for(PetscInt j=gys+1;j < gye; j++){
1526 PetscInt i=0;
1527 centx[k][j][i-1].x=centx[k][j][i].x-gs[k][j][i-2].x;
1528 centx[k][j][i-1].y=centx[k][j][i].y;
1529 centx[k][j][i-1].z=centx[k][j][i].z;
1530 }
1531 }
1532 }
1533 if (xe==mx){
1534 for(PetscInt k=gzs+1; k<gze; k++) {
1535 for (PetscInt j=gys+1; j<gye;j++) {
1536 PetscInt i=mx-1;
1537 centx[k][j][i].x=centx[k][j][i-1].x+gs[k][j][i+2].x;
1538 centx[k][j][i].y=centx[k][j][i-1].y;
1539 centx[k][j][i].z=centx[k][j][i-1].z;
1540 }
1541 }
1542 }
1543 */
1544
1545 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1546 ierr = DMDAVecRestoreArray(user->fda, user->Centx, &centx); CHKERRQ(ierr);
1547
1548 // ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1549
1550 // For periodic BCs, exchange ghosts between processes
1553 ierr = DMLocalToLocalBegin(user->fda, user->Centx, INSERT_VALUES, user->Centx); CHKERRQ(ierr);
1554 ierr = DMLocalToLocalEnd(user->fda, user->Centx, INSERT_VALUES, user->Centx); CHKERRQ(ierr);
1555 }
1556
1557 ierr = ApplyPeriodicCorrectionsToIFaceCenter(user); CHKERRQ(ierr);
1558
1559 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: i-face centers (Centx) calculated and ghosts updated.\n", user->simCtx->rank);
1560
1561 // --- Part 2: Calculate metrics using face-centered coordinates ---
1562 ierr = DMDAVecGetArrayRead(user->fda, user->Centx, &centx_const); CHKERRQ(ierr);
1563 ierr = DMDAVecGetArray(user->fda, user->ICsi, &icsi); CHKERRQ(ierr);
1564 ierr = DMDAVecGetArray(user->fda, user->IEta, &ieta); CHKERRQ(ierr);
1565 ierr = DMDAVecGetArray(user->fda, user->IZet, &izet); CHKERRQ(ierr);
1566 ierr = DMDAVecGetArray(user->da, user->IAj, &iaj); CHKERRQ(ierr);
1567
1568 // Loop over the OWNED region where we will store the final metrics
1569 for (PetscInt k=lzs; k<lze; k++) {
1570 for (PetscInt j=lys; j<lye; j++) {
1571 for (PetscInt i=xs; i<lxe; i++) {
1572
1573 // --- Stencil Logic for d/dcsi (derivative in i-direction) ---
1575 // Forward difference at the domain's min-i boundary
1576 dxdc = centx_const[k][j][i+1].x - centx_const[k][j][i].x;
1577 dydc = centx_const[k][j][i+1].y - centx_const[k][j][i].y;
1578 dzdc = centx_const[k][j][i+1].z - centx_const[k][j][i].z;
1579 } else if (i == mx - 2 && user->boundary_faces[BC_FACE_POS_X].mathematical_type != PERIODIC) {
1580 // Backward difference at the domain's max-i boundary
1581 dxdc = centx_const[k][j][i].x - centx_const[k][j][i-1].x;
1582 dydc = centx_const[k][j][i].y - centx_const[k][j][i-1].y;
1583 dzdc = centx_const[k][j][i].z - centx_const[k][j][i-1].z;
1584 } else { // Central difference in the interior (or if PERIODIC BCs)
1585 dxdc = 0.5 * (centx_const[k][j][i+1].x - centx_const[k][j][i-1].x);
1586 dydc = 0.5 * (centx_const[k][j][i+1].y - centx_const[k][j][i-1].y);
1587 dzdc = 0.5 * (centx_const[k][j][i+1].z - centx_const[k][j][i-1].z);
1588 }
1589
1590 // --- Stencil Logic for d/deta (derivative in j-direction) ---
1591 if (j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) {
1592 // Forward difference
1593 dxde = centx_const[k][j+1][i].x - centx_const[k][j][i].x;
1594 dyde = centx_const[k][j+1][i].y - centx_const[k][j][i].y;
1595 dzde = centx_const[k][j+1][i].z - centx_const[k][j][i].z;
1596 } else if (j == my - 2 && user->boundary_faces[BC_FACE_POS_Y].mathematical_type != PERIODIC) {
1597 // Backward difference
1598 dxde = centx_const[k][j][i].x - centx_const[k][j-1][i].x;
1599 dyde = centx_const[k][j][i].y - centx_const[k][j-1][i].y;
1600 dzde = centx_const[k][j][i].z - centx_const[k][j-1][i].z;
1601 } else { // Central difference (interior or PERIODIC)
1602 dxde = 0.5 * (centx_const[k][j+1][i].x - centx_const[k][j-1][i].x);
1603 dyde = 0.5 * (centx_const[k][j+1][i].y - centx_const[k][j-1][i].y);
1604 dzde = 0.5 * (centx_const[k][j+1][i].z - centx_const[k][j-1][i].z);
1605 }
1606
1607 // --- Stencil Logic for d/dzeta (derivative in k-direction) ---
1608 if (k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) {
1609 // Forward difference
1610 dxdz = centx_const[k+1][j][i].x - centx_const[k][j][i].x;
1611 dydz = centx_const[k+1][j][i].y - centx_const[k][j][i].y;
1612 dzdz = centx_const[k+1][j][i].z - centx_const[k][j][i].z;
1613 } else if (k == mz - 2 && user->boundary_faces[BC_FACE_POS_Z].mathematical_type != PERIODIC) {
1614 // Backward difference
1615 dxdz = centx_const[k][j][i].x - centx_const[k-1][j][i].x;
1616 dydz = centx_const[k][j][i].y - centx_const[k-1][j][i].y;
1617 dzdz = centx_const[k][j][i].z - centx_const[k-1][j][i].z;
1618 } else { // Central difference (Interior + PERIODIC)
1619 dxdz = 0.5 * (centx_const[k+1][j][i].x - centx_const[k-1][j][i].x);
1620 dydz = 0.5 * (centx_const[k+1][j][i].y - centx_const[k-1][j][i].y);
1621 dzdz = 0.5 * (centx_const[k+1][j][i].z - centx_const[k-1][j][i].z);
1622 }
1623
1624 // --- Metric calculations (identical to legacy FormMetrics) ---
1625 icsi[k][j][i].x = dyde * dzdz - dzde * dydz;
1626 icsi[k][j][i].y = -dxde * dzdz + dzde * dxdz;
1627 icsi[k][j][i].z = dxde * dydz - dyde * dxdz;
1628
1629 ieta[k][j][i].x = dydz * dzdc - dzdz * dydc;
1630 ieta[k][j][i].y = -dxdz * dzdc + dzdz * dxdc;
1631 ieta[k][j][i].z = dxdz * dydc - dydz * dxdc;
1632
1633 izet[k][j][i].x = dydc * dzde - dzdc * dyde;
1634 izet[k][j][i].y = -dxdc * dzde + dzdc * dxde;
1635 izet[k][j][i].z = dxdc * dyde - dydc * dxde;
1636
1637 iaj[k][j][i] = dxdc * icsi[k][j][i].x + dydc * icsi[k][j][i].y + dzdc * icsi[k][j][i].z;
1638 if (PetscAbsScalar(iaj[k][j][i]) > 1e-12) {
1639 iaj[k][j][i] = 1.0 / iaj[k][j][i];
1640 }
1641 }
1642 }
1643 }
1644
1645 ierr = DMDAVecRestoreArrayRead(user->fda, user->Centx, &centx_const); CHKERRQ(ierr);
1646 ierr = DMDAVecRestoreArray(user->fda, user->ICsi, &icsi); CHKERRQ(ierr);
1647 ierr = DMDAVecRestoreArray(user->fda, user->IEta, &ieta); CHKERRQ(ierr);
1648 ierr = DMDAVecRestoreArray(user->fda, user->IZet, &izet); CHKERRQ(ierr);
1649 ierr = DMDAVecRestoreArray(user->da, user->IAj, &iaj); CHKERRQ(ierr);
1650
1651 // --- Part 3: Assemble global vectors and update local ghosts ---
1652 ierr = VecAssemblyBegin(user->ICsi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->ICsi); CHKERRQ(ierr);
1653 ierr = VecAssemblyBegin(user->IEta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->IEta); CHKERRQ(ierr);
1654 ierr = VecAssemblyBegin(user->IZet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->IZet); CHKERRQ(ierr);
1655 ierr = VecAssemblyBegin(user->IAj); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->IAj); CHKERRQ(ierr);
1656
1657 ierr = UpdateLocalGhosts(user, "ICsi"); CHKERRQ(ierr);
1658 ierr = UpdateLocalGhosts(user, "IEta"); CHKERRQ(ierr);
1659 ierr = UpdateLocalGhosts(user, "IZet"); CHKERRQ(ierr);
1660 ierr = UpdateLocalGhosts(user, "IAj"); CHKERRQ(ierr);
1661
1663
1664 PetscFunctionReturn(0);
1665}
PetscErrorCode ApplyPeriodicCorrectionsToIFaceCenter(UserCtx *user)
Applies periodic boundary corrections to i-face centers (Centx).
Definition Metric.c:656
Vec IZet
Definition variables.h:778
Vec IEta
Definition variables.h:778
Vec Centx
Definition variables.h:777
Vec ICsi
Definition variables.h:778
Vec IAj
Definition variables.h:778
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeJFaceMetrics()

PetscErrorCode ComputeJFaceMetrics ( UserCtx user)

Computes metrics centered on constant-j faces (j-faces).

This function calculates the metric terms (JCsi, JEta, JZet) and the inverse Jacobian (JAj) located at the geometric center of each constant-j face. This is a critical step for staggered-grid finite difference schemes.

The process is a direct and faithful refactoring of the corresponding logic from the legacy FormMetrics function:

  1. It first calculates the physical (x,y,z) coordinates of the center of each i-face and stores them in the user->Centy vector.
  2. It then uses a boundary-aware, second-order finite difference stencil on the Centy field to compute the derivatives (e.g., d(x)/d(csi)).
    • Central differences are used in the grid interior.
    • One-sided differences are used at the physical domain boundaries.
  3. Finally, these derivatives are used to compute the final metric terms and the inverse Jacobian, which are stored in their respective Vec objects.
Parameters
userThe UserCtx for a specific grid level. This function populates the user->JCsi, user->JEta, user->JZet, and user->JAj vectors.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

This function calculates the metric terms (JCsi, JEta, JZet) and the inverse Jacobian (JAj) located at the geometric center of each constant-j face. This is a critical step for staggered-grid finite difference schemes.

The process is a direct and faithful refactoring of the corresponding logic from the legacy FormMetrics function:

  1. It first calculates the physical (x,y,z) coordinates of the center of each i-face and stores them in the user->Centy vector.
  2. It then uses a boundary-aware, second-order finite difference stencil on the Centy field to compute the derivatives (e.g., d(x)/d(csi)).
    • Central differences are used in the grid interior.
    • One-sided differences are used at the physical domain boundaries.
  3. Finally, these derivatives are used to compute the final metric terms and the inverse Jacobian, which are stored in their respective Vec objects.
Parameters
userThe UserCtx for a specific grid level. This function populates the user->JCsi, user->JEta, user->JZet, and user->JAj vectors.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.
Note
Jcsi,Jeta,Jzet represent the computational coordinate gradients scaled by local volume inverse ((Jaj)

Definition at line 1692 of file Metric.c.

1693{
1694 PetscErrorCode ierr;
1695 DMDALocalInfo info;
1696 Vec lCoords;
1697 const Cmpnts ***coor;
1698 Cmpnts ***centy; //***gs;
1699 const Cmpnts ***centy_const;
1700 Cmpnts ***jcsi, ***jeta, ***jzet;
1701 PetscScalar ***jaj;
1702 PetscReal dxdc, dydc, dzdc, dxde, dyde, dzde, dxdz, dydz, dzdz;
1703
1704 PetscFunctionBeginUser;
1705
1707
1708 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Computing j-face metrics for level %d block %d...\n", user->simCtx->rank, user->thislevel, user->_this);
1709
1710 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1711 PetscInt xs = info.xs, xe = info.xs + info.xm, mx = info.mx;
1712 PetscInt ys = info.ys, ye = info.ys + info.ym, my = info.my;
1713 PetscInt zs = info.zs, ze = info.zs + info.zm, mz = info.mz;
1714 PetscInt gxs = info.gxs, gxe = info.gxs + info.gxm;
1715 PetscInt gys = info.gys, gye = info.gys + info.gym;
1716 PetscInt gzs = info.gzs, gze = info.gzs + info.gzm;
1717
1718 PetscInt lxs = xs; PetscInt lxe = xe;
1719 PetscInt lys = ys; PetscInt lye = ye;
1720 PetscInt lzs = zs; PetscInt lze = ze;
1721
1722 if (xs==0) lxs = xs+1;
1723 if (ys==0) lys = ys+1;
1724 if (zs==0) lzs = zs+1;
1725
1726 if (xe==mx) lxe=xe-1;
1727 if (ye==my) lye=ye-1;
1728 if (ze==mz) lze=ze-1;
1729
1730 // --- Part 1: Calculate the location of i-face centers (Centx) ---
1731 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1732 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1733 ierr = DMDAVecGetArray(user->fda, user->Centy, &centy); CHKERRQ(ierr);
1734 // ierr = DMDAVecGetArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1735
1736 // Loop over the ghosted region to calculate all local face centers
1737 // To ensure we don't mistakenly calculate unused/dummy elements along non-dominant directions.
1738 PetscInt k_end = (ze == mz)? mz - 1:gze;
1739 PetscInt i_end = (xe == mx)? mx - 1:gxe;
1740
1741 for (PetscInt k = gzs + 1; k < k_end; k++) {
1742 for (PetscInt j = gys; j < gye; j++) {
1743 for (PetscInt i = gxs + 1; i < i_end; i++) {
1744 centy[k][j][i].x = 0.25 * (coor[k][j][i].x + coor[k-1][j][i].x + coor[k][j][i-1].x + coor[k-1][j][i-1].x);
1745 centy[k][j][i].y = 0.25 * (coor[k][j][i].y + coor[k-1][j][i].y + coor[k][j][i-1].y + coor[k-1][j][i-1].y);
1746 centy[k][j][i].z = 0.25 * (coor[k][j][i].z + coor[k-1][j][i].z + coor[k][j][i-1].z + coor[k-1][j][i-1].z);
1747 }
1748 }
1749 }
1750
1751 /*
1752 if(ys==0){
1753 for(PetscInt k=gzs+1;k < gze; k++){
1754 for(PetscInt i=gxs+1;j < gxe; i++){
1755 PetscInt j=0;
1756 centy[k][j-1][i].x=centy[k][j][i].x;
1757 centy[k][j-1][i].y=centy[k][j][i].y-gs[k][j-2][i].y;
1758 centy[k][j-1][i].z=centy[k][j][i].z;
1759 }
1760 }
1761 }
1762 if (ye==my){
1763 for(PetscInt k=gzs+1; k<gze; k++) {
1764 for (PetscInt i=gxs+1; j<gxe;i++) {
1765 PetscInt j=my-1;
1766 centy[k][j][i].x=centy[k][j-1][i].x
1767 centy[k][j][i].y=centy[k][j-1][i].y+gs[k][j+2][i].y;
1768 centy[k][j][i].z=centy[k][j-1][i].z;
1769 }
1770 }
1771 }
1772 */
1773
1774 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1775 ierr = DMDAVecRestoreArray(user->fda, user->Centy, &centy); CHKERRQ(ierr);
1776 // ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1777
1778 // For periodic BCs, exchange ghosts between processes
1781 ierr = DMLocalToLocalBegin(user->fda, user->Centy, INSERT_VALUES, user->Centy); CHKERRQ(ierr);
1782 ierr = DMLocalToLocalEnd(user->fda, user->Centy, INSERT_VALUES, user->Centy); CHKERRQ(ierr);
1783 }
1784
1785 ierr = ApplyPeriodicCorrectionsToJFaceCenter(user); CHKERRQ(ierr);
1786
1787 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: j-face centers (Centx) calculated and ghosts updated.\n", user->simCtx->rank);
1788
1789 // --- Part 2: Calculate metrics using face-centered coordinates ---
1790 ierr = DMDAVecGetArrayRead(user->fda, user->Centy, &centy_const); CHKERRQ(ierr);
1791 ierr = DMDAVecGetArray(user->fda, user->JCsi, &jcsi); CHKERRQ(ierr);
1792 ierr = DMDAVecGetArray(user->fda, user->JEta, &jeta); CHKERRQ(ierr);
1793 ierr = DMDAVecGetArray(user->fda, user->JZet, &jzet); CHKERRQ(ierr);
1794 ierr = DMDAVecGetArray(user->da, user->JAj, &jaj); CHKERRQ(ierr);
1795
1796 // Loop over the OWNED region where we will store the final metrics
1797 for (PetscInt k=lzs; k<lze; k++) {
1798 for (PetscInt j=ys; j<lye; j++) {
1799 for (PetscInt i=lxs; i<lxe; i++) {
1800
1801 // --- Stencil Logic for d/dcsi (derivative in i-direction) ---
1802 if (i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) {
1803 // Forward difference at the domain's min-i boundary
1804 dxdc = centy_const[k][j][i+1].x - centy_const[k][j][i].x;
1805 dydc = centy_const[k][j][i+1].y - centy_const[k][j][i].y;
1806 dzdc = centy_const[k][j][i+1].z - centy_const[k][j][i].z;
1807 } else if (i == mx - 2 && user->boundary_faces[BC_FACE_POS_X].mathematical_type != PERIODIC) {
1808 // Backward difference at the domain's max-i boundary
1809 dxdc = centy_const[k][j][i].x - centy_const[k][j][i-1].x;
1810 dydc = centy_const[k][j][i].y - centy_const[k][j][i-1].y;
1811 dzdc = centy_const[k][j][i].z - centy_const[k][j][i-1].z;
1812 } else { // Central difference in the interior or PERIODIC
1813 dxdc = 0.5 * (centy_const[k][j][i+1].x - centy_const[k][j][i-1].x);
1814 dydc = 0.5 * (centy_const[k][j][i+1].y - centy_const[k][j][i-1].y);
1815 dzdc = 0.5 * (centy_const[k][j][i+1].z - centy_const[k][j][i-1].z);
1816 }
1817
1818 // --- Stencil Logic for d/deta (derivative in j-direction) ---
1819 if (j == 0 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) {
1820 // Forward difference
1821 dxde = centy_const[k][j+1][i].x - centy_const[k][j][i].x;
1822 dyde = centy_const[k][j+1][i].y - centy_const[k][j][i].y;
1823 dzde = centy_const[k][j+1][i].z - centy_const[k][j][i].z;
1824 } else if (j == my - 2 && user->boundary_faces[BC_FACE_POS_Y].mathematical_type != PERIODIC) {
1825 // Backward difference
1826 dxde = centy_const[k][j][i].x - centy_const[k][j-1][i].x;
1827 dyde = centy_const[k][j][i].y - centy_const[k][j-1][i].y;
1828 dzde = centy_const[k][j][i].z - centy_const[k][j-1][i].z;
1829 } else { // Central difference (interior or PERIODIC)
1830 dxde = 0.5 * (centy_const[k][j+1][i].x - centy_const[k][j-1][i].x);
1831 dyde = 0.5 * (centy_const[k][j+1][i].y - centy_const[k][j-1][i].y);
1832 dzde = 0.5 * (centy_const[k][j+1][i].z - centy_const[k][j-1][i].z);
1833 }
1834
1835 // --- Stencil Logic for d/dzeta (derivative in k-direction) ---
1836 if (k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) {
1837 // Forward difference
1838 dxdz = centy_const[k+1][j][i].x - centy_const[k][j][i].x;
1839 dydz = centy_const[k+1][j][i].y - centy_const[k][j][i].y;
1840 dzdz = centy_const[k+1][j][i].z - centy_const[k][j][i].z;
1841 } else if (k == mz - 2 && user->boundary_faces[BC_FACE_POS_Z].mathematical_type != PERIODIC) {
1842 // Backward difference
1843 dxdz = centy_const[k][j][i].x - centy_const[k-1][j][i].x;
1844 dydz = centy_const[k][j][i].y - centy_const[k-1][j][i].y;
1845 dzdz = centy_const[k][j][i].z - centy_const[k-1][j][i].z;
1846 } else { // Central difference (Interior or PERIODIC)
1847 dxdz = 0.5 * (centy_const[k+1][j][i].x - centy_const[k-1][j][i].x);
1848 dydz = 0.5 * (centy_const[k+1][j][i].y - centy_const[k-1][j][i].y);
1849 dzdz = 0.5 * (centy_const[k+1][j][i].z - centy_const[k-1][j][i].z);
1850 }
1851
1852 // --- Metric calculations (identical to legacy FormMetrics) ---
1853 jcsi[k][j][i].x = dyde * dzdz - dzde * dydz;
1854 jcsi[k][j][i].y = -dxde * dzdz + dzde * dxdz;
1855 jcsi[k][j][i].z = dxde * dydz - dyde * dxdz;
1856
1857 jeta[k][j][i].x = dydz * dzdc - dzdz * dydc;
1858 jeta[k][j][i].y = -dxdz * dzdc + dzdz * dxdc;
1859 jeta[k][j][i].z = dxdz * dydc - dydz * dxdc;
1860
1861 jzet[k][j][i].x = dydc * dzde - dzdc * dyde;
1862 jzet[k][j][i].y = -dxdc * dzde + dzdc * dxde;
1863 jzet[k][j][i].z = dxdc * dyde - dydc * dxde;
1864
1865 jaj[k][j][i] = dxdc * jcsi[k][j][i].x + dydc * jcsi[k][j][i].y + dzdc * jcsi[k][j][i].z;
1866 if (PetscAbsScalar(jaj[k][j][i]) > 1e-12) {
1867 jaj[k][j][i] = 1.0 / jaj[k][j][i];
1868 }
1869 }
1870 }
1871 }
1872
1873 ierr = DMDAVecRestoreArrayRead(user->fda, user->Centy, &centy_const); CHKERRQ(ierr);
1874 ierr = DMDAVecRestoreArray(user->fda, user->JCsi, &jcsi); CHKERRQ(ierr);
1875 ierr = DMDAVecRestoreArray(user->fda, user->JEta, &jeta); CHKERRQ(ierr);
1876 ierr = DMDAVecRestoreArray(user->fda, user->JZet, &jzet); CHKERRQ(ierr);
1877 ierr = DMDAVecRestoreArray(user->da, user->JAj, &jaj); CHKERRQ(ierr);
1878
1879 // --- Part 3: Assemble global vectors and update local ghosts ---
1880 ierr = VecAssemblyBegin(user->JCsi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JCsi); CHKERRQ(ierr);
1881 ierr = VecAssemblyBegin(user->JEta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JEta); CHKERRQ(ierr);
1882 ierr = VecAssemblyBegin(user->JZet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JZet); CHKERRQ(ierr);
1883 ierr = VecAssemblyBegin(user->JAj); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JAj); CHKERRQ(ierr);
1884
1885 ierr = UpdateLocalGhosts(user, "JCsi"); CHKERRQ(ierr);
1886 ierr = UpdateLocalGhosts(user, "JEta"); CHKERRQ(ierr);
1887 ierr = UpdateLocalGhosts(user, "JZet"); CHKERRQ(ierr);
1888 ierr = UpdateLocalGhosts(user, "JAj"); CHKERRQ(ierr);
1889
1891
1892 PetscFunctionReturn(0);
1893}
PetscErrorCode ApplyPeriodicCorrectionsToJFaceCenter(UserCtx *user)
Applies periodic boundary corrections to j-face centers (Centy).
Definition Metric.c:742
Vec JCsi
Definition variables.h:779
Vec JEta
Definition variables.h:779
Vec JZet
Definition variables.h:779
Vec JAj
Definition variables.h:779
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeKFaceMetrics()

PetscErrorCode ComputeKFaceMetrics ( UserCtx user)

Computes metrics centered on constant-k faces (k-faces).

This function calculates the metric terms (KCsi, KEta, KZet) and the inverse Jacobian (KAj) located at the geometric center of each constant-j face. This is a critical step for staggered-grid finite difference schemes.

The process is a direct and faithful refactoring of the corresponding logic from the legacy FormMetrics function:

  1. It first calculates the physical (x,y,z) coordinates of the center of each i-face and stores them in the user->Centz vector.
  2. It then uses a boundary-aware, second-order finite difference stencil on the Centz field to compute the derivatives (e.g., d(x)/d(csi)).
    • Central differences are used in the grid interior.
    • One-sided differences are used at the physical domain boundaries.
  3. Finally, these derivatives are used to compute the final metric terms and the inverse Jacobian, which are stored in their respective Vec objects.
Parameters
userThe UserCtx for a specific grid level. This function populates the user->KCsi, user->KEta, user->KZet, and user->KAj vectors.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

This function calculates the metric terms (KCsi, KEta, KZet) and the inverse Jacobian (KAj) located at the geometric center of each constant-k face. This is a critical step for staggered-grid finite difference schemes.

The process is a direct and faithful refactoring of the corresponding logic from the legacy FormMetrics function:

  1. It first calculates the physical (x,y,z) coordinates of the center of each i-face and stores them in the user->Centz vector.
  2. It then uses a boundary-aware, second-order finite difference stencil on the Centz field to compute the derivatives (e.g., d(x)/d(csi)).
    • Central differences are used in the grid interior.
    • One-sided differences are used at the physical domain boundaries.
  3. Finally, these derivatives are used to compute the final metric terms and the inverse Jacobian, which are stored in their respective Vec objects.
Parameters
userThe UserCtx for a specific grid level. This function populates the user->KCsi, user->KEta, user->KZet, and user->KAj vectors.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.
Note
Kcsi,Keta,Kzet represent the computational coordinate gradients scaled by local volume inverse ((Kaj)

Definition at line 1920 of file Metric.c.

1921{
1922 PetscErrorCode ierr;
1923 DMDALocalInfo info;
1924 Vec lCoords;
1925 const Cmpnts ***coor;
1926 Cmpnts ***centz; //***gs;
1927 const Cmpnts ***centz_const;
1928 Cmpnts ***kcsi, ***keta, ***kzet;
1929 PetscScalar ***kaj;
1930 PetscReal dxdc, dydc, dzdc, dxde, dyde, dzde, dxdz, dydz, dzdz;
1931
1932 PetscFunctionBeginUser;
1933
1935
1936 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Computing k-face metrics for level %d block %d...\n", user->simCtx->rank, user->thislevel, user->_this);
1937
1938 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1939 PetscInt xs = info.xs, xe = info.xs + info.xm, mx = info.mx;
1940 PetscInt ys = info.ys, ye = info.ys + info.ym, my = info.my;
1941 PetscInt zs = info.zs, ze = info.zs + info.zm, mz = info.mz;
1942 PetscInt gxs = info.gxs, gxe = info.gxs + info.gxm;
1943 PetscInt gys = info.gys, gye = info.gys + info.gym;
1944 PetscInt gzs = info.gzs, gze = info.gzs + info.gzm;
1945
1946 PetscInt lxs = xs; PetscInt lxe = xe;
1947 PetscInt lys = ys; PetscInt lye = ye;
1948 PetscInt lzs = zs; PetscInt lze = ze;
1949
1950 if (xs==0) lxs = xs+1;
1951 if (ys==0) lys = ys+1;
1952 if (zs==0) lzs = zs+1;
1953
1954 if (xe==mx) lxe=xe-1;
1955 if (ye==my) lye=ye-1;
1956 if (ze==mz) lze=ze-1;
1957
1958 // --- Part 1: Calculate the location of i-face centers (Centx) ---
1959 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1960 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1961 ierr = DMDAVecGetArray(user->fda, user->Centz, &centz); CHKERRQ(ierr);
1962 // ierr = DMDAVecGetArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1963
1964 // Loop over the ghosted region to calculate all local face centers
1965 // To ensure we don't mistakenly calculate unused/dummy elements along non-dominant directions.
1966 PetscInt i_end = (xe == mx)? mx - 1:gxe;
1967 PetscInt j_end = (ye == my)? my - 1:gye;
1968 for (PetscInt k = gzs; k < gze; k++) {
1969 for (PetscInt j = gys; j < gye; j++) {
1970 for (PetscInt i = gxs + 1; i < gxe; i++) {
1971 centz[k][j][i].x = 0.25 * (coor[k][j][i].x + coor[k][j-1][i].x + coor[k][j][i-1].x + coor[k][j-1][i-1].x);
1972 centz[k][j][i].y = 0.25 * (coor[k][j][i].y + coor[k][j-1][i].y + coor[k][j][i-1].y + coor[k][j-1][i-1].y);
1973 centz[k][j][i].z = 0.25 * (coor[k][j][i].z + coor[k][j-1][i].z + coor[k][j][i-1].z + coor[k][j-1][i-1].z);
1974 }
1975 }
1976 }
1977
1978 /*
1979 if(zs==0){
1980 for(PetscInt j=gys+1;j < gye; j++){
1981 for(PetscInt i=gxs+1;j < gxe; i++){
1982 PetscInt k=0;
1983 centz[k-1][j][i].x=centz[k][j][i].x;
1984 centz[k-1][j][i].y=centz[k][j][i].y;
1985 centz[k-1][j][i].z=centz[k][j][i].z-gs[k-2][j][i].z;
1986 }
1987 }
1988 }
1989 if (ze==mz){
1990 for(PetscInt j=gys+1; j<gye; j++) {
1991 for (PetscInt i=gxs+1; j<gxe;i++) {
1992 PetscInt k=mz-1;
1993 centy[k][j][i].x=centy[k-1][j][i].x
1994 centy[k][j][i].y=centy[k-1][j][i].y;
1995 centz[k][j][i].z=centz[k-1][j][i].z+gs[k+2][j][1].z;
1996 }
1997 }
1998 }
1999 */
2000
2001 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
2002 ierr = DMDAVecRestoreArray(user->fda, user->Centz, &centz); CHKERRQ(ierr);
2003 // ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
2004
2005 // For periodic BCs, exchange ghosts between processes
2008 ierr = DMLocalToLocalBegin(user->fda, user->Centz, INSERT_VALUES, user->Centz); CHKERRQ(ierr);
2009 ierr = DMLocalToLocalEnd(user->fda, user->Centz, INSERT_VALUES, user->Centz); CHKERRQ(ierr);
2010 }
2011
2012 ierr = ApplyPeriodicCorrectionsToKFaceCenter(user); CHKERRQ(ierr);
2013
2014 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: k-face centers (Centx) calculated and ghosts updated.\n", user->simCtx->rank);
2015
2016 // --- Part 2: Calculate metrics using face-centered coordinates ---
2017 ierr = DMDAVecGetArrayRead(user->fda, user->Centz, &centz_const); CHKERRQ(ierr);
2018 ierr = DMDAVecGetArray(user->fda, user->KCsi, &kcsi); CHKERRQ(ierr);
2019 ierr = DMDAVecGetArray(user->fda, user->KEta, &keta); CHKERRQ(ierr);
2020 ierr = DMDAVecGetArray(user->fda, user->KZet, &kzet); CHKERRQ(ierr);
2021 ierr = DMDAVecGetArray(user->da, user->KAj, &kaj); CHKERRQ(ierr);
2022
2023 // Loop over the OWNED region where we will store the final metrics
2024 for (PetscInt k=zs; k<lze; k++) {
2025 for (PetscInt j=lys; j<lye; j++) {
2026 for (PetscInt i=lxs; i<lxe; i++) {
2027
2028 // --- Stencil Logic for d/dcsi (derivative in i-direction) ---
2029 if (i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) {
2030 // Forward difference at the domain's min-i boundary
2031 dxdc = centz_const[k][j][i+1].x - centz_const[k][j][i].x;
2032 dydc = centz_const[k][j][i+1].y - centz_const[k][j][i].y;
2033 dzdc = centz_const[k][j][i+1].z - centz_const[k][j][i].z;
2034 } else if (i == mx - 2 && user->boundary_faces[BC_FACE_POS_X].mathematical_type != PERIODIC) {
2035 // Backward difference at the domain's max-i boundary
2036 dxdc = centz_const[k][j][i].x - centz_const[k][j][i-1].x;
2037 dydc = centz_const[k][j][i].y - centz_const[k][j][i-1].y;
2038 dzdc = centz_const[k][j][i].z - centz_const[k][j][i-1].z;
2039 } else { // Central difference in the interior (or PERIODIC)
2040 dxdc = 0.5 * (centz_const[k][j][i+1].x - centz_const[k][j][i-1].x);
2041 dydc = 0.5 * (centz_const[k][j][i+1].y - centz_const[k][j][i-1].y);
2042 dzdc = 0.5 * (centz_const[k][j][i+1].z - centz_const[k][j][i-1].z);
2043 }
2044
2045 // --- Stencil Logic for d/deta (derivative in j-direction) ---
2046 if (j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) {
2047 // Forward difference
2048 dxde = centz_const[k][j+1][i].x - centz_const[k][j][i].x;
2049 dyde = centz_const[k][j+1][i].y - centz_const[k][j][i].y;
2050 dzde = centz_const[k][j+1][i].z - centz_const[k][j][i].z;
2051 } else if (j == my - 2 && user->boundary_faces[BC_FACE_POS_Y].mathematical_type != PERIODIC) {
2052 // Backward difference
2053 dxde = centz_const[k][j][i].x - centz_const[k][j-1][i].x;
2054 dyde = centz_const[k][j][i].y - centz_const[k][j-1][i].y;
2055 dzde = centz_const[k][j][i].z - centz_const[k][j-1][i].z;
2056 } else { // Central difference (interior or PERIODIC)
2057 dxde = 0.5 * (centz_const[k][j+1][i].x - centz_const[k][j-1][i].x);
2058 dyde = 0.5 * (centz_const[k][j+1][i].y - centz_const[k][j-1][i].y);
2059 dzde = 0.5 * (centz_const[k][j+1][i].z - centz_const[k][j-1][i].z);
2060 }
2061
2062 // --- Stencil Logic for d/dzeta (derivative in k-direction) ---
2063 if (k == 0 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) {
2064 // Forward difference
2065 dxdz = centz_const[k+1][j][i].x - centz_const[k][j][i].x;
2066 dydz = centz_const[k+1][j][i].y - centz_const[k][j][i].y;
2067 dzdz = centz_const[k+1][j][i].z - centz_const[k][j][i].z;
2068 } else if (k == mz - 2 && user->boundary_faces[BC_FACE_POS_Z].mathematical_type != PERIODIC) {
2069 // Backward difference
2070 dxdz = centz_const[k][j][i].x - centz_const[k-1][j][i].x;
2071 dydz = centz_const[k][j][i].y - centz_const[k-1][j][i].y;
2072 dzdz = centz_const[k][j][i].z - centz_const[k-1][j][i].z;
2073 } else { // Central difference (Interior or PERIODIC)
2074 dxdz = 0.5 * (centz_const[k+1][j][i].x - centz_const[k-1][j][i].x);
2075 dydz = 0.5 * (centz_const[k+1][j][i].y - centz_const[k-1][j][i].y);
2076 dzdz = 0.5 * (centz_const[k+1][j][i].z - centz_const[k-1][j][i].z);
2077 }
2078
2079 // --- Metric calculations (identical to legacy FormMetrics) ---
2080 kcsi[k][j][i].x = dyde * dzdz - dzde * dydz;
2081 kcsi[k][j][i].y = -dxde * dzdz + dzde * dxdz;
2082 kcsi[k][j][i].z = dxde * dydz - dyde * dxdz;
2083
2084 keta[k][j][i].x = dydz * dzdc - dzdz * dydc;
2085 keta[k][j][i].y = -dxdz * dzdc + dzdz * dxdc;
2086 keta[k][j][i].z = dxdz * dydc - dydz * dxdc;
2087
2088 kzet[k][j][i].x = dydc * dzde - dzdc * dyde;
2089 kzet[k][j][i].y = -dxdc * dzde + dzdc * dxde;
2090 kzet[k][j][i].z = dxdc * dyde - dydc * dxde;
2091
2092 kaj[k][j][i] = dxdc * kcsi[k][j][i].x + dydc * kcsi[k][j][i].y + dzdc * kcsi[k][j][i].z;
2093 if (PetscAbsScalar(kaj[k][j][i]) > 1e-12) {
2094 kaj[k][j][i] = 1.0 / kaj[k][j][i];
2095 }
2096 }
2097 }
2098 }
2099
2100 ierr = DMDAVecRestoreArrayRead(user->fda, user->Centz, &centz_const); CHKERRQ(ierr);
2101 ierr = DMDAVecRestoreArray(user->fda, user->KCsi, &kcsi); CHKERRQ(ierr);
2102 ierr = DMDAVecRestoreArray(user->fda, user->KEta, &keta); CHKERRQ(ierr);
2103 ierr = DMDAVecRestoreArray(user->fda, user->KZet, &kzet); CHKERRQ(ierr);
2104 ierr = DMDAVecRestoreArray(user->da, user->KAj, &kaj); CHKERRQ(ierr);
2105
2106 // --- Part 3: Assemble global vectors and update local ghosts ---
2107 ierr = VecAssemblyBegin(user->KCsi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KCsi); CHKERRQ(ierr);
2108 ierr = VecAssemblyBegin(user->KEta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KEta); CHKERRQ(ierr);
2109 ierr = VecAssemblyBegin(user->KZet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KZet); CHKERRQ(ierr);
2110 ierr = VecAssemblyBegin(user->KAj); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KAj); CHKERRQ(ierr);
2111
2112 ierr = UpdateLocalGhosts(user, "KCsi"); CHKERRQ(ierr);
2113 ierr = UpdateLocalGhosts(user, "KEta"); CHKERRQ(ierr);
2114 ierr = UpdateLocalGhosts(user, "KZet"); CHKERRQ(ierr);
2115 ierr = UpdateLocalGhosts(user, "KAj"); CHKERRQ(ierr);
2116
2118
2119 PetscFunctionReturn(0);
2120}
PetscErrorCode ApplyPeriodicCorrectionsToKFaceCenter(UserCtx *user)
Applies periodic boundary corrections to k-face centers (Centz).
Definition Metric.c:828
Vec KAj
Definition variables.h:780
Vec KEta
Definition variables.h:780
Vec KZet
Definition variables.h:780
Vec KCsi
Definition variables.h:780
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeMetricsDivergence()

PetscErrorCode ComputeMetricsDivergence ( UserCtx user)

Performs a diagnostic check on the divergence of the face area metric vectors.

For a closed cell, the sum of the face area vectors should be zero (Gauss's divergence theorem). This function computes a measure of this divergence and reports the maximum value over the domain. A small value indicates a well-formed grid. This is a direct adaptation of the legacy function.

Parameters
userThe UserCtx for a specific grid level (typically the finest).
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Performs a diagnostic check on the divergence of the face area metric vectors.

This function serves as a diagnostic tool to assess the quality of the grid metrics. It calculates the divergence of the face metrics (Csi, Eta, Zet) and scales it by the inverse of the cell Jacobian. The maximum divergence value is then located, and its grid coordinates are printed to the console, helping to pinpoint areas of potential grid quality issues.

Parameters
userThe UserCtx, containing all necessary grid data.
Returns
PetscErrorCode

Definition at line 2152 of file Metric.c.

2153{
2154 DM da = user->da, fda = user->fda;
2155 DMDALocalInfo info = user->info;
2156 PetscInt xs = info.xs, xe = info.xs + info.xm;
2157 PetscInt ys = info.ys, ye = info.ys + info.ym;
2158 PetscInt zs = info.zs, ze = info.zs + info.zm;
2159 PetscInt mx = info.mx, my = info.my, mz = info.mz;
2160 PetscInt lxs, lys, lzs, lxe, lye, lze;
2161 PetscInt i, j, k;
2162 Vec Div;
2163 PetscReal ***div, ***aj;
2164 Cmpnts ***csi, ***eta, ***zet;
2165 PetscReal maxdiv;
2166
2167 PetscFunctionBeginUser;
2168
2170
2171 lxs = xs; lxe = xe;
2172 lys = ys; lye = ye;
2173 lzs = zs; lze = ze;
2174
2175 if (xs == 0) lxs = xs + 1;
2176 if (ys == 0) lys = ys + 1;
2177 if (zs == 0) lzs = zs + 1;
2178
2179 if (xe == mx) lxe = xe - 1;
2180 if (ye == my) lye = ye - 1;
2181 if (ze == mz) lze = ze - 1;
2182
2183 DMDAVecGetArray(fda, user->lCsi, &csi);
2184 DMDAVecGetArray(fda, user->lEta, &eta);
2185 DMDAVecGetArray(fda, user->lZet, &zet);
2186 DMDAVecGetArray(da, user->lAj, &aj);
2187
2188 VecDuplicate(user->P, &Div);
2189 VecSet(Div, 0.);
2190 DMDAVecGetArray(da, Div, &div);
2191
2192 for (k = lzs; k < lze; k++) {
2193 for (j = lys; j < lye; j++) {
2194 for (i = lxs; i < lxe; i++) {
2195 PetscReal divergence = (csi[k][j][i].x - csi[k][j][i-1].x +
2196 eta[k][j][i].x - eta[k][j-1][i].x +
2197 zet[k][j][i].x - zet[k-1][j][i].x +
2198 csi[k][j][i].y - csi[k][j][i-1].y +
2199 eta[k][j][i].y - eta[k][j-1][i].y +
2200 zet[k][j][i].y - zet[k-1][j][i].y +
2201 csi[k][j][i].z - csi[k][j][i-1].z +
2202 eta[k][j][i].z - eta[k][j-1][i].z +
2203 zet[k][j][i].z - zet[k-1][j][i].z) * aj[k][j][i];
2204 div[k][j][i] = fabs(divergence);
2205 }
2206 }
2207 }
2208
2209 DMDAVecRestoreArray(da, Div, &div);
2210
2211 PetscReal MaxFlatIndex;
2212 VecMax(Div, &MaxFlatIndex, &maxdiv);
2213 LOG_ALLOW(GLOBAL,LOG_INFO,"The Maximum Metric Divergence is %e at flat index %d.\n",maxdiv,MaxFlatIndex);
2214
2215 for (k=zs; k<ze; k++) {
2216 for (j=ys; j<ye; j++) {
2217 for (i=xs; i<xe; i++) {
2218 if (Gidx(i,j,k,user) == MaxFlatIndex) {
2219 LOG_ALLOW(GLOBAL,LOG_INFO,"The Maximum Metric Divergence(%e) is at location [%d][%d][%d]. \n", maxdiv,(int)k,(int)j,(int)i);
2220 }
2221 }
2222 }
2223 }
2224
2225
2226 DMDAVecRestoreArray(fda, user->lCsi, &csi);
2227 DMDAVecRestoreArray(fda, user->lEta, &eta);
2228 DMDAVecRestoreArray(fda, user->lZet, &zet);
2229 DMDAVecRestoreArray(da, user->lAj, &aj);
2230 VecDestroy(&Div);
2231
2232
2234
2235 PetscFunctionReturn(0);
2236}
static PetscInt Gidx(PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
Definition Metric.c:2122
Vec lZet
Definition variables.h:776
Vec lCsi
Definition variables.h:776
Vec lAj
Definition variables.h:776
Vec lEta
Definition variables.h:776
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ComputeMetricNorms()

PetscErrorCode ComputeMetricNorms ( UserCtx user)

Computes the max-min values of the grid metrics.

This function serves as a diagnostic tool to assess the quality of the grid metrics. It calculates the bounds of the face metrics (Csi, Eta, Zet).

Parameters
userThe UserCtx, containing all necessary grid data.
Returns
PetscErrorCode

Definition at line 2249 of file Metric.c.

2250{
2251
2252 DMDALocalInfo info = user->info;
2253 PetscInt xs = info.xs, xe = info.xs + info.xm;
2254 PetscInt ys = info.ys, ye = info.ys + info.ym;
2255 PetscInt zs = info.zs, ze = info.zs + info.zm;
2256 PetscInt i, j, k;
2257
2258 PetscFunctionBeginUser;
2259
2261
2262 PetscReal CsiMax, EtaMax, ZetMax;
2263 PetscReal ICsiMax, IEtaMax, IZetMax;
2264 PetscReal JCsiMax, JEtaMax, JZetMax;
2265 PetscReal KCsiMax, KEtaMax, KZetMax;
2266 PetscReal AjMax, IAjMax, JAjMax, KAjMax;
2267
2268 PetscInt CsiMaxArg, EtaMaxArg, ZetMaxArg;
2269 PetscInt ICsiMaxArg, IEtaMaxArg, IZetMaxArg;
2270 PetscInt JCsiMaxArg, JEtaMaxArg, JZetMaxArg;
2271 PetscInt KCsiMaxArg, KEtaMaxArg, KZetMaxArg;
2272 PetscInt AjMaxArg, IAjMaxArg, JAjMaxArg, KAjMaxArg;
2273
2274 // Max Values
2275 VecMax(user->lCsi,&CsiMaxArg,&CsiMax);
2276 VecMax(user->lEta,&EtaMaxArg,&EtaMax);
2277 VecMax(user->lZet,&ZetMaxArg,&ZetMax);
2278
2279 VecMax(user->lICsi,&ICsiMaxArg,&ICsiMax);
2280 VecMax(user->lIEta,&IEtaMaxArg,&IEtaMax);
2281 VecMax(user->lIZet,&IZetMaxArg,&IZetMax);
2282
2283 VecMax(user->lJCsi,&JCsiMaxArg,&JCsiMax);
2284 VecMax(user->lJEta,&JEtaMaxArg,&JEtaMax);
2285 VecMax(user->lJZet,&JZetMaxArg,&JZetMax);
2286
2287 VecMax(user->lKCsi,&KCsiMaxArg,&KCsiMax);
2288 VecMax(user->lKEta,&KEtaMaxArg,&KEtaMax);
2289 VecMax(user->lKZet,&KZetMaxArg,&KZetMax);
2290
2291 VecMax(user->lAj,&AjMaxArg,&AjMax);
2292 VecMax(user->lIAj,&IAjMaxArg,&IAjMax);
2293 VecMax(user->lJAj,&JAjMaxArg,&JAjMax);
2294 VecMax(user->lKAj,&KAjMaxArg,&KAjMax);
2295
2296 VecMax(user->lAj,&AjMaxArg,&AjMax);
2297 VecMax(user->lIAj,&IAjMaxArg,&IAjMax);
2298 VecMax(user->lJAj,&JAjMaxArg,&JAjMax);
2299 VecMax(user->lKAj,&KAjMaxArg,&KAjMax);
2300
2301 LOG_ALLOW(GLOBAL,LOG_INFO," Metric Norms for MG level %d .\n",user->thislevel);
2302
2303 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: CsiMax = %le, EtaMax = %le, ZetMax = %le.\n",CsiMax,EtaMax,ZetMax);
2304 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: ICsiMax = %le, IEtaMax = %le, IZetMax = %le.\n",ICsiMax,IEtaMax,IZetMax);
2305 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: JCsiMax = %le, JEtaMax = %le, JZetMax = %le.\n",JCsiMax,JEtaMax,JZetMax);
2306 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: KCsiMax = %le, KEtaMax = %le, KZetMax = %le.\n",KCsiMax,KEtaMax,KZetMax);
2307 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Volumes(Inverse) are: Aj = %le, IAj = %le, JAj = %le, KAj = %le.\n",AjMax,IAjMax,JAjMax,KAjMax);
2308
2309 for (k=zs; k<ze; k++) {
2310 for (j=ys; j<ye; j++) {
2311 for (i=xs; i<xe; i++) {
2312 if (Gidx(i,j,k,user) == CsiMaxArg) {
2313 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Csi = %le is at [%d][%d][%d] \n", CsiMax,k,j,i);
2314 }
2315 if (Gidx(i,j,k,user) == EtaMaxArg) {
2316 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Eta = %le is at [%d][%d][%d] \n", EtaMax,k,j,i);
2317 }
2318 if (Gidx(i,j,k,user) == ZetMaxArg) {
2319 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Zet = %le is at [%d][%d][%d] \n", ZetMax,k,j,i);
2320 }
2321 if (Gidx(i,j,k,user) == ICsiMaxArg) {
2322 LOG_ALLOW(GLOBAL,LOG_INFO,"Max ICsi = %le is at [%d][%d][%d] \n", ICsiMax,k,j,i);
2323 }
2324 if (Gidx(i,j,k,user) == IEtaMaxArg) {
2325 LOG_ALLOW(GLOBAL,LOG_INFO,"Max IEta = %le is at [%d][%d][%d] \n", IEtaMax,k,j,i);
2326 }
2327 if (Gidx(i,j,k,user) == IZetMaxArg) {
2328 LOG_ALLOW(GLOBAL,LOG_INFO,"Max IZet = %le is at [%d][%d][%d] \n", IZetMax,k,j,i);
2329 }
2330 if (Gidx(i,j,k,user) == JCsiMaxArg) {
2331 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JCsi = %le is at [%d][%d][%d] \n", JCsiMax,k,j,i);
2332 }
2333 if (Gidx(i,j,k,user) == JEtaMaxArg) {
2334 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JEta = %le is at [%d][%d][%d] \n", JEtaMax,k,j,i);
2335 }
2336 if (Gidx(i,j,k,user) == JZetMaxArg) {
2337 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JZet = %le is at [%d][%d][%d] \n", JZetMax,k,j,i);
2338 }
2339 if (Gidx(i,j,k,user) == KCsiMaxArg) {
2340 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KCsi = %le is at [%d][%d][%d] \n", KCsiMax,k,j,i);
2341 }
2342 if (Gidx(i,j,k,user) == KEtaMaxArg) {
2343 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KEta = %le is at [%d][%d][%d] \n", KEtaMax,k,j,i);
2344 }
2345 if (Gidx(i,j,k,user) == KZetMaxArg) {
2346 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KZet = %le is at [%d][%d][%d] \n", KZetMax,k,j,i);
2347 }
2348 if (Gidx(i,j,k,user) == AjMaxArg) {
2349 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Aj = %le is at [%d][%d][%d] \n", AjMax,k,j,i);
2350 }
2351 if (Gidx(i,j,k,user) == IAjMaxArg) {
2352 LOG_ALLOW(GLOBAL,LOG_INFO,"Max IAj = %le is at [%d][%d][%d] \n", IAjMax,k,j,i);
2353 }
2354 if (Gidx(i,j,k,user) == JAjMaxArg) {
2355 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JAj = %le is at [%d][%d][%d] \n", JAjMax,k,j,i);
2356 }
2357 if (Gidx(i,j,k,user) == KAjMaxArg) {
2358 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KAj = %le is at [%d][%d][%d] \n", KAjMax,k,j,i);
2359 }
2360 }
2361 }
2362 }
2363
2364 /*
2365 VecView(user->lCsi,PETSC_VIEWER_STDOUT_WORLD);
2366 VecView(user->lEta,PETSC_VIEWER_STDOUT_WORLD);
2367 VecView(user->lZet,PETSC_VIEWER_STDOUT_WORLD);
2368 */
2369
2371
2372 PetscFunctionReturn(0);
2373}
Vec lIEta
Definition variables.h:778
Vec lIZet
Definition variables.h:778
Vec lIAj
Definition variables.h:778
Vec lKEta
Definition variables.h:780
Vec lJCsi
Definition variables.h:779
Vec lKZet
Definition variables.h:780
Vec lJEta
Definition variables.h:779
Vec lKCsi
Definition variables.h:780
Vec lJZet
Definition variables.h:779
Vec lICsi
Definition variables.h:778
Vec lJAj
Definition variables.h:779
Vec lKAj
Definition variables.h:780
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CalculateAllGridMetrics()

PetscErrorCode CalculateAllGridMetrics ( SimCtx simCtx)

Orchestrates the calculation of all grid metrics.

This function iterates through every UserCtx in the multigrid and multi-block hierarchy. For each context, it calls a series of modern, modular helper functions to compute the face metrics (Csi, Eta, Zet), the cell-centered inverse Jacobian (Aj), and to validate the grid's orientation.

Parameters
simCtxThe master SimCtx, containing the configured UserCtx hierarchy.
Returns
PetscErrorCode

Definition at line 2388 of file Metric.c.

2389{
2390 PetscErrorCode ierr;
2391 UserMG *usermg = &simCtx->usermg;
2392 MGCtx *mgctx = usermg->mgctx;
2393 PetscInt nblk = simCtx->block_number;
2394
2395 PetscFunctionBeginUser;
2396
2398
2399 LOG_ALLOW(GLOBAL, LOG_INFO, "Calculating grid metrics for all levels and blocks...\n");
2400
2401 // Loop through all levels and all blocks
2402 for (PetscInt level = usermg->mglevels -1 ; level >=0; level--) {
2403 for (PetscInt bi = 0; bi < nblk; bi++) {
2404 UserCtx *user = &mgctx[level].user[bi];
2405 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Rank %d: Calculating metrics for level %d, block %d\n", simCtx->rank, level, bi);
2406
2407 // Call the modern, modular helper functions for each UserCtx.
2408 // These functions are self-contained and operate on the data within the provided context.
2409 ierr = ComputeFaceMetrics(user); CHKERRQ(ierr);
2410 ierr = ComputeCellCenteredJacobianInverse(user); CHKERRQ(ierr);
2411 ierr = CheckAndFixGridOrientation(user); CHKERRQ(ierr);
2412 ierr = ComputeCellCentersAndSpacing(user); CHKERRQ(ierr);
2413 ierr = ComputeIFaceMetrics(user); CHKERRQ(ierr);
2414 ierr = ComputeJFaceMetrics(user); CHKERRQ(ierr);
2415 ierr = ComputeKFaceMetrics(user); CHKERRQ(ierr);
2416
2417 // Apply Periodic Boundary Condition Adjustments if necessary
2418 ierr = ApplyMetricsPeriodicBCs(user); CHKERRQ(ierr);
2419 // Diagnostics
2420 ierr = ComputeMetricNorms(user);
2421 if (level == usermg->mglevels - 1) {
2422 ierr = ComputeMetricsDivergence(user); CHKERRQ(ierr);
2423 }
2424 }
2425 }
2426
2427 LOG_ALLOW(GLOBAL, LOG_INFO, "Grid metrics calculation complete.\n");
2428
2430
2431 PetscFunctionReturn(0);
2432}
PetscErrorCode ApplyMetricsPeriodicBCs(UserCtx *user)
(Orchestrator) Updates all metric-related fields in the local ghost cell regions for periodic boundar...
PetscErrorCode ComputeMetricNorms(UserCtx *user)
Computes the max-min values of the grid metrics.
Definition Metric.c:2249
PetscErrorCode CheckAndFixGridOrientation(UserCtx *user)
Ensure a right-handed metric basis (Csi, Eta, Zet) and a positive Jacobian (Aj) over the whole domain...
Definition Metric.c:368
PetscErrorCode ComputeCellCentersAndSpacing(UserCtx *user)
Computes the physical location of cell centers and the spacing between them.
Definition Metric.c:1326
PetscErrorCode ComputeJFaceMetrics(UserCtx *user)
Computes metrics centered on constant-j faces (j-faces).
Definition Metric.c:1692
PetscErrorCode ComputeMetricsDivergence(UserCtx *user)
Computes the divergence of the grid metrics and identifies the maximum value.
Definition Metric.c:2152
PetscErrorCode ComputeFaceMetrics(UserCtx *user)
Computes the primary face metric components (Csi, Eta, Zet), including boundary extrapolation,...
Definition Metric.c:956
PetscErrorCode ComputeCellCenteredJacobianInverse(UserCtx *user)
Calculates the cell-centered inverse Jacobian determinant (1/J), including boundary extrapolation,...
Definition Metric.c:1171
PetscErrorCode ComputeKFaceMetrics(UserCtx *user)
Computes metrics centered on constant-k faces (k-faces).
Definition Metric.c:1920
PetscErrorCode ComputeIFaceMetrics(UserCtx *user)
Computes metrics centered on constant-i faces (i-faces).
Definition Metric.c:1450
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
----— DEBUG ---------------------------------------— #define LOG_ALLOW(scope, level,...
Definition logging.h:267
UserCtx * user
Definition variables.h:474
PetscInt block_number
Definition variables.h:649
UserMG usermg
Definition variables.h:698
PetscInt mglevels
Definition variables.h:481
MGCtx * mgctx
Definition variables.h:484
Context for Multigrid operations.
Definition variables.h:473
User-defined context containing data specific to a single computational grid level.
Definition variables.h:728
User-level context for managing the entire multigrid hierarchy.
Definition variables.h:480
Here is the call graph for this function:
Here is the caller graph for this function: