PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Functions
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)
 Maps a logical point inside one hexahedral cell to physical space.
 
PetscErrorCode MetricGetCellVertices (UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, Cmpnts V[8])
 Collects the eight node coordinates of one logical hexahedral cell.
 
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)
 Evaluates the trilinear mapping Jacobian and its determinant in one cell.
 
PetscErrorCode MetricVelocityContravariant (const PetscReal J[3][3], PetscReal detJ, const PetscReal u[3], PetscReal uc[3])
 Converts a Cartesian velocity vector to contravariant logical components.
 
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)
 Builds translated periodic images for cell centers and grid spacing.
 
PetscErrorCode ApplyPeriodicCorrectionsToIFaceCenter (UserCtx *user)
 Builds translated periodic images for i-face centers (Centx).
 
PetscErrorCode ApplyPeriodicCorrectionsToJFaceCenter (UserCtx *user)
 Builds translated periodic images for j-face centers (Centy).
 
PetscErrorCode ApplyPeriodicCorrectionsToKFaceCenter (UserCtx *user)
 Builds translated periodic images for k-face centers (Centz).
 
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)
 Verify and, when consistently inverted, repair the 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 
)

Maps a logical point inside one hexahedral cell to physical space.

Uses trilinear interpolation of the eight cell vertices. Logical coordinates are measured from the cell's lower logical corner and normally lie in [0, 1].

Parameters
userGrid context used for cell indexing.
XGhosted node-coordinate array for the block.
iCell index in the xi direction.
jCell index in the eta direction.
kCell index in the zeta direction.
xiLocal xi coordinate within the cell.
etaLocal eta coordinate within the cell.
ztaLocal zeta coordinate within the cell.
[out]XpPhysical Cartesian position evaluated at the logical point.
Returns
PetscErrorCode 0 on success.

Maps a logical point inside one hexahedral cell to physical space.

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

See also
MetricLogicalToPhysical()

Definition at line 76 of file Metric.c.

81{
82 PetscErrorCode ierr;
83 Cmpnts V[8];
84 PetscFunctionBeginUser;
85
87
88 ierr = MetricGetCellVertices(user,X,i,j,k,V); CHKERRQ(ierr);
89 TrilinearBlend(V,xi,eta,zta,Xp);
90
92
93 PetscFunctionReturn(0);
94}
static void TrilinearBlend(const Cmpnts V[8], PetscReal xi, PetscReal eta, PetscReal zta, Cmpnts *Xp)
Blend eight corner values at the supplied trilinear reference coordinates.
Definition Metric.c:50
PetscErrorCode MetricGetCellVertices(UserCtx *user, const Cmpnts ***X, PetscInt i, PetscInt j, PetscInt k, Cmpnts V[8])
Implementation of MetricGetCellVertices().
Definition Metric.c:26
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:859
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:850
A 3D point or vector with PetscScalar components.
Definition variables.h:102
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] 
)

Collects the eight node coordinates of one logical hexahedral cell.

Vertex ordering matches the trilinear metric kernels in this module.

Parameters
userGrid context used for cell indexing.
XGhosted node-coordinate array for the block.
iCell index in the xi direction.
jCell index in the eta direction.
kCell index in the zeta direction.
[out]VEight physical vertex coordinates in metric-kernel order.
Returns
PetscErrorCode 0 on success.

Collects the eight node coordinates of one logical hexahedral cell.

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

See also
MetricGetCellVertices()

Definition at line 26 of file Metric.c.

30{
31 (void)user;
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:298
#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 
)

Evaluates the trilinear mapping Jacobian and its determinant in one cell.

The returned matrix is \(\partial(x,y,z)/\partial(\xi,\eta,\zeta)\); callers use its determinant to reject degenerate or inverted cells.

Parameters
userGrid context used for cell indexing.
XGhosted node-coordinate array for the block.
iCell index in the xi direction.
jCell index in the eta direction.
kCell index in the zeta direction.
xiLocal xi coordinate within the cell.
etaLocal eta coordinate within the cell.
ztaLocal zeta coordinate within the cell.
[out]JMapping Jacobian in row-major Cartesian/logical form.
[out]detJDeterminant of J.
Returns
PetscErrorCode 0 on success.

Evaluates the trilinear mapping Jacobian and its determinant in one cell.

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

See also
MetricJacobian()

Definition at line 105 of file Metric.c.

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

Converts a Cartesian velocity vector to contravariant logical components.

Uses the inverse of the physical-to-logical Jacobian; detJ must describe the same mapping as J and must be nonzero.

Parameters
JMapping Jacobian at the evaluation point.
detJDeterminant of J.
uCartesian velocity components.
[out]ucContravariant xi/eta/zeta velocity components.
Returns
PetscErrorCode 0 on success.

Converts a Cartesian velocity vector to contravariant logical components.

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

See also
MetricVelocityContravariant()

Definition at line 165 of file Metric.c.

167{
168 PetscFunctionBeginUser;
169
171
172 /* contravariant basis vectors (row of adjugate(J)) divided by detJ */
173 PetscReal gxi[3] = { J[1][1]*J[2][2]-J[1][2]*J[2][1],
174 -J[0][1]*J[2][2]+J[0][2]*J[2][1],
175 J[0][1]*J[1][2]-J[0][2]*J[1][1] };
176 PetscReal geta[3] = { -J[1][0]*J[2][2]+J[1][2]*J[2][0],
177 J[0][0]*J[2][2]-J[0][2]*J[2][0],
178 -J[0][0]*J[1][2]+J[0][2]*J[1][0] };
179 PetscReal gzta[3] = { J[1][0]*J[2][1]-J[1][1]*J[2][0],
180 -J[0][0]*J[2][1]+J[0][1]*J[2][0],
181 J[0][0]*J[1][1]-J[0][1]*J[1][0] };
182
183 PetscReal invDet = 1.0 / detJ;
184 for (int d=0; d<3; ++d) { gxi[d] *= invDet; geta[d] *= invDet; gzta[d] *= invDet; }
185
186 uc[0] = gxi [0]*u[0] + gxi [1]*u[1] + gxi [2]*u[2];
187 uc[1] = geta[0]*u[0] + geta[1]*u[1] + geta[2]*u[2];
188 uc[2] = gzta[0]*u[0] + gzta[1]*u[1] + gzta[2]*u[2];
189
191
192 PetscFunctionReturn(0);
193}
Here is the caller graph for this function:

◆ 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
csiCovariant xi metric vector.
etaCovariant eta metric vector.
zetCovariant zeta metric vector.
[out]niUnit normal of the xi-normal face.
[out]njUnit normal of the eta-normal face.
[out]nkUnit normal of the zeta-normal face.
[out]AiArea of the xi-normal face.
[out]AjArea of the eta-normal face.
[out]AkArea of the zeta-normal face.
Returns
PetscErrorCode 0 on success.

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

Local to this translation unit.

Definition at line 236 of file Metric.c.

237{
238 PetscFunctionBeginUser;
240 double g[3][3];
241 double G[3][3];
242
243 g[0][0]=csi.x, g[0][1]=csi.y, g[0][2]=csi.z;
244 g[1][0]=eta.x, g[1][1]=eta.y, g[1][2]=eta.z;
245 g[2][0]=zet.x, g[2][1]=zet.y, g[2][2]=zet.z;
246
248 double xcsi=G[0][0], ycsi=G[1][0], zcsi=G[2][0];
249 double xeta=G[0][1], yeta=G[1][1], zeta=G[2][1];
250 double xzet=G[0][2], yzet=G[1][2], zzet=G[2][2];
251
252 double nx_i = xcsi, ny_i = ycsi, nz_i = zcsi;
253 double nx_j = xeta, ny_j = yeta, nz_j = zeta;
254 double nx_k = xzet, ny_k = yzet, nz_k = zzet;
255
256 double sum_i=sqrt(nx_i*nx_i+ny_i*ny_i+nz_i*nz_i);
257 double sum_j=sqrt(nx_j*nx_j+ny_j*ny_j+nz_j*nz_j);
258 double sum_k=sqrt(nx_k*nx_k+ny_k*ny_k+nz_k*nz_k);
259
260 *Ai = sqrt( g[0][0]*g[0][0] + g[0][1]*g[0][1] + g[0][2]*g[0][2] ); // area
261 *Aj = sqrt( g[1][0]*g[1][0] + g[1][1]*g[1][1] + g[1][2]*g[1][2] );
262 *Ak =sqrt( g[2][0]*g[2][0] + g[2][1]*g[2][1] + g[2][2]*g[2][2] );
263
264 nx_i /= sum_i, ny_i /= sum_i, nz_i /= sum_i;
265 nx_j /= sum_j, ny_j /= sum_j, nz_j /= sum_j;
266 nx_k /= sum_k, ny_k /= sum_k, nz_k /= sum_k;
267
268 ni[0] = nx_i, ni[1] = ny_i, ni[2] = nz_i;
269 nj[0] = nx_j, nj[1] = ny_j, nj[2] = nz_j;
270 nk[0] = nx_k, nk[1] = ny_k, nk[2] = nz_k;
271
273 PetscFunctionReturn(0);
274}
PetscErrorCode InvertCovariantMetricTensor(double covariantTensor[3][3], double contravariantTensor[3][3])
Internal helper implementation: InvertCovariantMetricTensor().
Definition Metric.c:202
PetscScalar x
Definition variables.h:103
PetscScalar z
Definition variables.h:103
PetscScalar y
Definition variables.h:103
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.
[out]contravariantTensorInverse metric tensor written in place.
Returns
PetscErrorCode 0 on success.

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

Local to this translation unit.

Definition at line 202 of file Metric.c.

203{
204 PetscFunctionBeginUser;
205
206 const double a11=covariantTensor[0][0], a12=covariantTensor[0][1], a13=covariantTensor[0][2];
207 const double a21=covariantTensor[1][0], a22=covariantTensor[1][1], a23=covariantTensor[1][2];
208 const double a31=covariantTensor[2][0], a32=covariantTensor[2][1], a33=covariantTensor[2][2];
209
210 double det = a11*(a33*a22-a32*a23) - a21*(a33*a12-a32*a13) + a31*(a23*a12-a22*a13);
211
212 if (fabs(det) < 1.0e-12) {
213 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_MAT_LU_ZRPVT, "Matrix is singular, determinant is near zero.");
214 }
215
216 contravariantTensor[0][0] = (a33*a22-a32*a23)/det;
217 contravariantTensor[0][1] = -(a33*a12-a32*a13)/det;
218 contravariantTensor[0][2] = (a23*a12-a22*a13)/det;
219 contravariantTensor[1][0] = -(a33*a21-a31*a23)/det;
220 contravariantTensor[1][1] = (a33*a11-a31*a13)/det;
221 contravariantTensor[1][2] = -(a23*a11-a21*a13)/det;
222 contravariantTensor[2][0] = (a32*a21-a31*a22)/det;
223 contravariantTensor[2][1] = -(a32*a11-a31*a12)/det;
224 contravariantTensor[2][2] = (a22*a11-a21*a12)/det;
225
226 PetscFunctionReturn(0);
227}
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
ajcCell Jacobian/volume metric at the cell center.
csiCovariant xi metric vector.
etaCovariant eta metric vector.
zetCovariant zeta metric vector.
[out]dxEffective physical length associated with xi variation.
[out]dyEffective physical length associated with eta variation.
[out]dzEffective physical length associated with zeta variation.
Returns
PetscErrorCode 0 on success.

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

Local to this translation unit.

Definition at line 282 of file Metric.c.

283{
284 PetscFunctionBeginUser;
286 double ni[3], nj[3], nk[3];
287 double Li, Lj, Lk;
288 double Ai, Aj, Ak;
289 double vol = 1./ajc;
290
291 CalculateFaceNormalAndArea(csi, eta, zet, ni, nj, nk, &Ai, &Aj, &Ak);
292 Li = vol / Ai;
293 Lj = vol / Aj;
294 Lk = vol / Ak;
295
296 // Length scale vector = di * ni_vector + dj * nj_vector + dk * nk_vector
297 *dx = fabs( Li * ni[0] + Lj * nj[0] + Lk * nk[0] );
298 *dy = fabs( Li * ni[1] + Lj * nj[1] + Lk * nk[1] );
299 *dz = fabs( Li * ni[2] + Lj * nj[2] + Lk * nk[2] );
300
302 PetscFunctionReturn(0);
303}
PetscErrorCode CalculateFaceNormalAndArea(Cmpnts csi, Cmpnts eta, Cmpnts zet, double ni[3], double nj[3], double nk[3], double *Ai, double *Aj, double *Ak)
Internal helper implementation: CalculateFaceNormalAndArea().
Definition Metric.c:236
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ApplyPeriodicCorrectionsToCellCentersAndSpacing()

PetscErrorCode ApplyPeriodicCorrectionsToCellCentersAndSpacing ( UserCtx user)

Builds translated periodic images for cell centers and grid spacing.

PETSc wraps field indices but does not translate coordinates. This routine applies the validated per-axis geometric translation to wrapped center coordinates and refreshes the associated local grid spacing.

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

Builds translated periodic images for cell centers and grid spacing.

Local to this translation unit.

Definition at line 391 of file Metric.c.

392{
393 PetscErrorCode ierr;
394 DMDALocalInfo info = user->info;
395 PetscInt xs = info.xs, xe = info.xs + info.xm;
396 PetscInt ys = info.ys, ye = info.ys + info.ym;
397 PetscInt zs = info.zs, ze = info.zs + info.zm;
398 PetscInt mx = info.mx, my = info.my, mz = info.mz;
399 Cmpnts ***cent, ***lcent, ***gs;
400 PetscReal delta;
401
402 PetscFunctionBeginUser;
404
405 // Check if any periodic boundaries exist
406 PetscBool has_periodic = PETSC_FALSE;
407 for (int i = 0; i < 6; i++) {
408 if (user->boundary_faces[i].mathematical_type == PERIODIC) {
409 has_periodic = PETSC_TRUE;
410 break;
411 }
412 }
413
414 if (!has_periodic) {
415 LOG_ALLOW(LOCAL, LOG_TRACE, "No periodic boundaries; skipping corrections for Cent/GridSpace.\n");
417 PetscFunctionReturn(0);
418 }
419
420 LOG_ALLOW(LOCAL, LOG_DEBUG, "Applying periodic corrections to Cent and GridSpace.\n");
421
422 // Must update ghosts first before applying corrections
423 ierr = UpdateLocalGhosts(user, FIELD_ID_CENT); CHKERRQ(ierr);
424 ierr = UpdateLocalGhosts(user, FIELD_ID_GRID_SPACE); CHKERRQ(ierr);
425
426 // --- X-direction periodic corrections ---
429
430 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
431 ierr = DMDAVecGetArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
432 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
433
434 if (user->boundary_faces[BC_FACE_NEG_X].mathematical_type == PERIODIC && xs == 0) {
435 if (user->cgrid) {
436 for (PetscInt k=zs; k<ze; k++) {
437 for (PetscInt j=ys; j<ye; j++) {
438 cent[k][j][0] = lcent[k][j][-2];
439 }
440 }
441 } else {
442 for (PetscInt k=zs; k<ze; k++) {
443 for (PetscInt j=ys; j<ye; j++) {
444 delta = (gs[k][j][1].x + gs[k][j][-2].x) / 2.0;
445 cent[k][j][0].x = cent[k][j][1].x - delta;
446 cent[k][j][0].y = cent[k][j][1].y;
447 cent[k][j][0].z = cent[k][j][1].z;
448 }
449 }
450 }
451 }
452
453 if (user->boundary_faces[BC_FACE_POS_X].mathematical_type == PERIODIC && xe == mx) {
454 if (user->cgrid) {
455 for (PetscInt k=zs; k<ze; k++) {
456 for (PetscInt j=ys; j<ye; j++) {
457 cent[k][j][mx-1] = lcent[k][j][mx+1];
458 }
459 }
460 } else {
461 for (PetscInt k=zs; k<ze; k++) {
462 for (PetscInt j=ys; j<ye; j++) {
463 delta = (gs[k][j][mx-2].x + gs[k][j][mx+1].x) / 2.0;
464 cent[k][j][mx-1].x = cent[k][j][mx-2].x + delta;
465 cent[k][j][mx-1].y = cent[k][j][mx-2].y;
466 cent[k][j][mx-1].z = cent[k][j][mx-2].z;
467 }
468 }
469 }
470 }
471
472 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
473 ierr = DMDAVecRestoreArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
474 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
475 }
476 // --- Y-direction periodic corrections ---
479
480 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
481 ierr = DMDAVecGetArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
482 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
483
484 if (user->boundary_faces[BC_FACE_NEG_Y].mathematical_type == PERIODIC && ys == 0) {
485 if (user->cgrid) {
486 for (PetscInt k=zs; k<ze; k++) {
487 for (PetscInt i=xs; i<xe; i++) {
488 cent[k][0][i] = lcent[k][-2][i];
489 }
490 }
491 } else {
492 for (PetscInt k=zs; k<ze; k++) {
493 for (PetscInt i=xs; i<xe; i++) {
494 delta = (gs[k][1][i].y + gs[k][-2][i].y) / 2.0;
495 cent[k][0][i].x = cent[k][1][i].x;
496 cent[k][0][i].y = cent[k][1][i].y - delta;
497 cent[k][0][i].z = cent[k][1][i].z;
498 }
499 }
500 }
501 }
502
503 if (user->boundary_faces[BC_FACE_POS_Y].mathematical_type == PERIODIC && ye == my) {
504 if (user->cgrid) {
505 for (PetscInt k=zs; k<ze; k++) {
506 for (PetscInt i=xs; i<xe; i++) {
507 cent[k][my-1][i] = lcent[k][my+1][i];
508 }
509 }
510 } else {
511 for (PetscInt k=zs; k<ze; k++) {
512 for (PetscInt i=xs; i<xe; i++) {
513 delta = (gs[k][my-2][i].y + gs[k][my+1][i].y) / 2.0;
514 cent[k][my-1][i].x = cent[k][my-2][i].x;
515 cent[k][my-1][i].y = cent[k][my-2][i].y + delta;
516 cent[k][my-1][i].z = cent[k][my-2][i].z;
517 }
518 }
519 }
520 }
521
522 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
523 ierr = DMDAVecRestoreArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
524 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
525
526 }
527
528 // --- Z-direction periodic corrections ---
531
532 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
533 ierr = DMDAVecGetArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
534 ierr = DMDAVecGetArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
535
536 if (user->boundary_faces[BC_FACE_NEG_Z].mathematical_type == PERIODIC && zs == 0) {
537 if (user->cgrid) {
538 for (PetscInt j=ys; j<ye; j++) {
539 for (PetscInt i=xs; i<xe; i++) {
540 cent[0][j][i] = lcent[-2][j][i];
541 }
542 }
543 } else {
544 for (PetscInt j=ys; j<ye; j++) {
545 for (PetscInt i=xs; i<xe; i++) {
546 delta = (gs[1][j][i].z + gs[-2][j][i].z) / 2.0;
547 cent[0][j][i].x = cent[1][j][i].x;
548 cent[0][j][i].y = cent[1][j][i].y;
549 cent[0][j][i].z = cent[1][j][i].z - delta;
550 }
551 }
552 }
553 }
554
555 if (user->boundary_faces[BC_FACE_POS_Z].mathematical_type == PERIODIC && ze == mz) {
556 if (user->cgrid) {
557 for (PetscInt j=ys; j<ye; j++) {
558 for (PetscInt i=xs; i<xe; i++) {
559 cent[mz-1][j][i] = lcent[mz+1][j][i];
560 }
561 }
562 } else {
563 for (PetscInt j=ys; j<ye; j++) {
564 for (PetscInt i=xs; i<xe; i++) {
565 delta = (gs[mz-2][j][i].z + gs[mz+1][j][i].z) / 2.0;
566 cent[mz-1][j][i].x = cent[mz-2][j][i].x;
567 cent[mz-1][j][i].y = cent[mz-2][j][i].y;
568 cent[mz-1][j][i].z = cent[mz-2][j][i].z + delta;
569 }
570 }
571 }
572 }
573
574 ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace, &gs); CHKERRQ(ierr);
575 ierr = DMDAVecRestoreArray(user->fda, user->lCent, &lcent); CHKERRQ(ierr);
576 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
577
578 }
579
581 PetscFunctionReturn(0);
582}
@ FIELD_ID_GRID_SPACE
@ FIELD_ID_CENT
#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, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1838
Vec lCent
Definition variables.h:974
@ PERIODIC
Definition variables.h:292
PetscInt cgrid
Definition variables.h:926
BoundaryFaceConfig boundary_faces[6]
Definition variables.h:931
Vec lGridSpace
Definition variables.h:974
DMDALocalInfo info
Definition variables.h:918
Vec Cent
Definition variables.h:974
BCType mathematical_type
Definition variables.h:368
@ BC_FACE_NEG_X
Definition variables.h:262
@ BC_FACE_POS_Z
Definition variables.h:264
@ BC_FACE_POS_Y
Definition variables.h:263
@ BC_FACE_NEG_Z
Definition variables.h:264
@ BC_FACE_POS_X
Definition variables.h:262
@ BC_FACE_NEG_Y
Definition variables.h:263
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ApplyPeriodicCorrectionsToIFaceCenter()

PetscErrorCode ApplyPeriodicCorrectionsToIFaceCenter ( UserCtx user)

Builds translated periodic images for i-face centers (Centx).

Every active periodic axis can affect the ghost images of Centx. This must be called after Centx is computed and before it is used for metric calculations.

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

Builds translated periodic images for i-face centers (Centx).

Local to this translation unit.

Definition at line 590 of file Metric.c.

591{
592 const FieldId fields[] = {FIELD_ID_CENTX};
593
594 PetscFunctionBeginUser;
595 PetscCall(SynchronizePeriodicFaceFields(user, 'i', 1, fields));
596 PetscFunctionReturn(0);
597}
PetscErrorCode SynchronizePeriodicFaceFields(UserCtx *user, char face_direction, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent fields belonging to one face family.
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_CENTX
Here is the call graph for this function:

◆ ApplyPeriodicCorrectionsToJFaceCenter()

PetscErrorCode ApplyPeriodicCorrectionsToJFaceCenter ( UserCtx user)

Builds translated periodic images for j-face centers (Centy).

Every active periodic axis can affect the ghost images of Centy. This must be called after Centy is computed and before it is used for metric calculations.

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

Builds translated periodic images for j-face centers (Centy).

Local to this translation unit.

Definition at line 606 of file Metric.c.

607{
608 const FieldId fields[] = {FIELD_ID_CENTY};
609
610 PetscFunctionBeginUser;
611 PetscCall(SynchronizePeriodicFaceFields(user, 'j', 1, fields));
612 PetscFunctionReturn(0);
613}
@ FIELD_ID_CENTY
Here is the call graph for this function:

◆ ApplyPeriodicCorrectionsToKFaceCenter()

PetscErrorCode ApplyPeriodicCorrectionsToKFaceCenter ( UserCtx user)

Builds translated periodic images for k-face centers (Centz).

Every active periodic axis can affect the ghost images of Centz. This must be called after Centz is computed and before it is used for metric calculations.

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

Builds translated periodic images for k-face centers (Centz).

Local to this translation unit.

Definition at line 622 of file Metric.c.

623{
624 const FieldId fields[] = {FIELD_ID_CENTZ};
625
626 PetscFunctionBeginUser;
627 PetscCall(SynchronizePeriodicFaceFields(user, 'k', 1, fields));
628 PetscFunctionReturn(0);
629}
@ FIELD_ID_CENTZ
Here is the call 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.

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).

Local to this translation unit.

Definition at line 637 of file Metric.c.

638{
639 PetscErrorCode ierr;
640 DMDALocalInfo info;
641 Cmpnts ***csi_arr, ***eta_arr, ***zet_arr;
642 Cmpnts ***nodal_coords_arr;
643 Vec localCoords_from_dm;
644
645 PetscFunctionBeginUser;
646
648
649 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting calculation and update for Csi, Eta, Zet.\n");
650
651 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
652
653 // --- 1. Get Nodal Physical Coordinates (Local Ghosted Array directly) ---
654 ierr = DMGetCoordinatesLocal(user->da, &localCoords_from_dm); CHKERRQ(ierr);
655 if (!localCoords_from_dm) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocal failed to return a coordinate vector. \n");
656 ierr = DMDAVecGetArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
657
658 // --- 2. Get arrays for output global Vecs from UserCtx ---
659 ierr = DMDAVecGetArray(user->fda, user->Csi, &csi_arr); CHKERRQ(ierr);
660 ierr = DMDAVecGetArray(user->fda, user->Eta, &eta_arr); CHKERRQ(ierr);
661 ierr = DMDAVecGetArray(user->fda, user->Zet, &zet_arr); CHKERRQ(ierr);
662
663 // Define owned node ranges (global indices)
664 PetscInt xs = info.xs, xe = info.xs + info.xm;
665 PetscInt ys = info.ys, ye = info.ys + info.ym;
666 PetscInt zs = info.zs, ze = info.zs + info.zm;
667
668 // Global domain dimensions (total number of nodes)
669 PetscInt mx = info.mx;
670 PetscInt my = info.my;
671 PetscInt mz = info.mz;
672
673 // --- 3. Calculate Csi, Eta, Zet for INTERIOR Stencils ---
674 // Start loops from 1 if at global boundary 0 to ensure k_node-1 etc. are valid.
675 PetscInt k_loop_start = (zs == 0) ? zs + 1 : zs;
676 PetscInt j_loop_start = (ys == 0) ? ys + 1 : ys;
677 PetscInt i_loop_start = (xs == 0) ? xs + 1 : xs;
678
679 // These represent the surface area of the curvilinear cell face and the normal rotated such that the direction of increasing coordinate is maintained.
680 // The metric vectors (Csi, Eta, Zet) are defined to point in the direction of their corresponding increasing computational coordinate.
681
682 // Calculate Csi
683 for (PetscInt k_node = k_loop_start; k_node < ze; ++k_node) {
684 for (PetscInt j_node = j_loop_start; j_node < ye; ++j_node) {
685 for (PetscInt i_node = xs; i_node < xe; ++i_node) {
686
687 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);
688 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);
689 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);
690 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);
691 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);
692 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);
693
694 csi_arr[k_node][j_node][i_node].x = dy_deta * dz_dzeta - dz_deta * dy_dzeta;
695 csi_arr[k_node][j_node][i_node].y = dz_deta * dx_dzeta - dx_deta * dz_dzeta;
696 csi_arr[k_node][j_node][i_node].z = dx_deta * dy_dzeta - dy_deta * dx_dzeta;
697 }
698 }
699 }
700
701 // Calculate Eta
702 for (PetscInt k_node = k_loop_start; k_node < ze; ++k_node) {
703 for (PetscInt j_node = ys; j_node < ye; ++j_node) {
704 for (PetscInt i_node = i_loop_start; i_node < xe; ++i_node) {
705
706 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);
707 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);
708 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);
709 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);
710 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);
711 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);
712
713 eta_arr[k_node][j_node][i_node].x = dy_dzeta * dz_dxi - dz_dzeta * dy_dxi;
714 eta_arr[k_node][j_node][i_node].y = dz_dzeta * dx_dxi - dx_dzeta * dz_dxi;
715 eta_arr[k_node][j_node][i_node].z = dx_dzeta * dy_dxi - dy_dzeta * dx_dxi;
716 }
717 }
718 }
719
720 // Calculate Zet
721 for (PetscInt k_node = zs; k_node < ze; ++k_node) {
722 for (PetscInt j_node = j_loop_start; j_node < ye; ++j_node) {
723 for (PetscInt i_node = i_loop_start; i_node < xe; ++i_node) {
724
725 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);
726 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);
727 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);
728 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);
729 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);
730 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);
731
732 zet_arr[k_node][j_node][i_node].x = dy_dxi * dz_deta - dz_dxi * dy_deta;
733 zet_arr[k_node][j_node][i_node].y = dz_dxi * dx_deta - dx_dxi * dz_deta;
734 zet_arr[k_node][j_node][i_node].z = dx_dxi * dy_deta - dy_dxi * dx_deta;
735 }
736 }
737 }
738
739 // --- 4. Boundary Extrapolation ---
740 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Extrapolating boundary values for Csi, Eta, Zet.\n");
741 PetscInt i_bnd, j_bnd, k_bnd;
742
743 if (xs == 0) { // If this rank owns the global i=0 boundary
744 i_bnd = 0;
745 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
746 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
747 if (i_bnd + 1 < mx) {
748 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd][j_bnd][i_bnd+1];
749 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd][i_bnd+1];
750 }
751 }
752 }
753 }
754 if (xe == mx) { // If this rank owns the global i=mx-1 boundary
755 i_bnd = mx - 1;
756 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
757 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
758 if (i_bnd - 1 >= 0) {
759 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd][j_bnd][i_bnd-1];
760 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd][i_bnd-1];
761 }
762 }
763 }
764 }
765 if (ys == 0) {
766 j_bnd = 0;
767 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
768 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
769 if (j_bnd + 1 < my) {
770 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd][j_bnd+1][i_bnd];
771 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd+1][i_bnd];
772 }
773 }
774 }
775 }
776 if (ye == my) {
777 j_bnd = my - 1;
778 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
779 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
780 if (j_bnd - 1 >= 0) {
781 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd][j_bnd-1][i_bnd];
782 zet_arr[k_bnd][j_bnd][i_bnd] = zet_arr[k_bnd][j_bnd-1][i_bnd];
783 }
784 }
785 }
786 }
787 if (zs == 0) {
788 k_bnd = 0;
789 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
790 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
791 if (k_bnd + 1 < mz) {
792 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd+1][j_bnd][i_bnd];
793 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd+1][j_bnd][i_bnd];
794 }
795 }
796 }
797 }
798 if (ze == mz) {
799 k_bnd = mz - 1;
800 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
801 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
802 if (k_bnd - 1 >= 0) {
803 csi_arr[k_bnd][j_bnd][i_bnd] = csi_arr[k_bnd-1][j_bnd][i_bnd];
804 eta_arr[k_bnd][j_bnd][i_bnd] = eta_arr[k_bnd-1][j_bnd][i_bnd];
805 }
806 }
807 }
808 }
809
810 if (info.xs==0 && info.ys==0 && info.zs==0) {
811 PetscReal dot = zet_arr[0][0][0].z; /* dot with global +z */
812 LOG_ALLOW(GLOBAL,LOG_DEBUG,"Zet(k=0)·ez = %.3f (should be >0 for right-handed grid)\n", dot);
813 }
814
815 // --- 5. Restore all arrays ---
816 ierr = DMDAVecRestoreArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
817 ierr = DMDAVecRestoreArray(user->fda, user->Csi, &csi_arr); CHKERRQ(ierr);
818 ierr = DMDAVecRestoreArray(user->fda, user->Eta, &eta_arr); CHKERRQ(ierr);
819 ierr = DMDAVecRestoreArray(user->fda, user->Zet, &zet_arr); CHKERRQ(ierr);
820
821 // --- 6. Assemble Global Vectors ---
822 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Assembling global Csi, Eta, Zet.\n");
823 ierr = VecAssemblyBegin(user->Csi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Csi); CHKERRQ(ierr);
824 ierr = VecAssemblyBegin(user->Eta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Eta); CHKERRQ(ierr);
825 ierr = VecAssemblyBegin(user->Zet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Zet); CHKERRQ(ierr);
826
827 // --- 7. Update Local Ghosted Versions ---
828 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Updating local lCsi, lEta, lZet.\n");
829 ierr = UpdateLocalGhosts(user, FIELD_ID_CSI); CHKERRQ(ierr);
830 ierr = UpdateLocalGhosts(user, FIELD_ID_ETA); CHKERRQ(ierr);
831 ierr = UpdateLocalGhosts(user, FIELD_ID_ZET); CHKERRQ(ierr);
832
833 LOG_ALLOW(GLOBAL, LOG_INFO, "Completed calculation, extrapolation, and update for Csi, Eta, Zet.\n");
834
836
837 PetscFunctionReturn(0);
838}
@ FIELD_ID_CSI
@ FIELD_ID_ETA
@ FIELD_ID_ZET
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
Vec Zet
Definition variables.h:974
Vec Csi
Definition variables.h:974
Vec Eta
Definition variables.h:974
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.

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

See also
ComputeCellCenteredJacobianInverse()

Definition at line 849 of file Metric.c.

850{
851 PetscErrorCode ierr;
852 DMDALocalInfo info;
853 PetscScalar ***aj_arr;
854 Cmpnts ***nodal_coords_arr;
855 Vec localCoords_from_dm;
856
857 PetscFunctionBeginUser;
858 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting calculation, extrapolation, and update for Aj.\n");
859
860 // --- 1. Get Nodal Coordinates and Output Array ---
861 ierr = DMGetCoordinatesLocal(user->da, &localCoords_from_dm); CHKERRQ(ierr);
862 ierr = DMDAVecGetArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
863 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
864 ierr = DMDAVecGetArray(user->da, user->Aj, &aj_arr); CHKERRQ(ierr);
865
866 // Define owned node ranges (global indices)
867 PetscInt xs = info.xs, xe = info.xs + info.xm;
868 PetscInt ys = info.ys, ye = info.ys + info.ym;
869 PetscInt zs = info.zs, ze = info.zs + info.zm;
870
871 // Global domain dimensions (total number of nodes)
872 PetscInt mx = info.mx;
873 PetscInt my = info.my;
874 PetscInt mz = info.mz;
875
876 // --- 2. Calculate Aj for INTERIOR Stencils ---
877
878 PetscInt k_start_node = (zs == 0) ? zs + 1 : zs;
879 PetscInt j_start_node = (ys == 0) ? ys + 1 : ys;
880 PetscInt i_start_node = (xs == 0) ? xs + 1 : xs;
881
882 PetscInt k_end_node = (ze == mz) ? ze - 1 : ze;
883 PetscInt j_end_node = (ye == my) ? ye - 1 : ye;
884 PetscInt i_end_node = (xe == mx) ? xe - 1 : xe;
885
886 for (PetscInt k_node = k_start_node; k_node < k_end_node; ++k_node) {
887 for (PetscInt j_node = j_start_node; j_node < j_end_node; ++j_node) {
888 for (PetscInt i_node = i_start_node; i_node < i_end_node; ++i_node) {
889
890 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) );
891
892 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) );
893
894 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) );
895
896 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) );
897
898 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) );
899
900 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) );
901
902 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) );
903
904 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) );
905
906 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) );
907
908 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);
909 if (PetscAbsReal(jacobian_det) < 1.0e-18) { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FLOP_COUNT, "Jacobian is near zero..."); }
910 aj_arr[k_node][j_node][i_node] = 1.0 / jacobian_det;
911 }
912 }
913 }
914
915 // --- 4. Boundary Extrapolation for Aj ---
916 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Extrapolating boundary values for Aj. \n");
917 PetscInt i_bnd, j_bnd, k_bnd;
918
919 if (xs == 0) {
920 i_bnd = 0;
921 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
922 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
923 if (i_bnd + 1 < mx) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd][i_bnd+1];
924 }
925 }
926 }
927 if (xe == mx) {
928 i_bnd = mx - 1;
929 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
930 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
931 if (i_bnd - 1 >= 0) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd][i_bnd-1];
932 }
933 }
934 }
935 // (Similar extrapolation blocks for Y and Z boundaries for aj_arr)
936 if (ys == 0) {
937 j_bnd = 0;
938 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
939 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
940 if (j_bnd + 1 < my) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd+1][i_bnd];
941 }
942 }
943 }
944 if (ye == my) {
945 j_bnd = my - 1;
946 for (k_bnd = zs; k_bnd < ze; ++k_bnd) {
947 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
948 if (j_bnd - 1 >= 0) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd][j_bnd-1][i_bnd];
949 }
950 }
951 }
952 if (zs == 0) {
953 k_bnd = 0;
954 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
955 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
956 if (k_bnd + 1 < mz) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd+1][j_bnd][i_bnd];
957 }
958 }
959 }
960 if (ze == mz) {
961 k_bnd = mz - 1;
962 for (j_bnd = ys; j_bnd < ye; ++j_bnd) {
963 for (i_bnd = xs; i_bnd < xe; ++i_bnd) {
964 if (k_bnd - 1 >= 0) aj_arr[k_bnd][j_bnd][i_bnd] = aj_arr[k_bnd-1][j_bnd][i_bnd];
965 }
966 }
967 }
968
969 // --- 5. Restore arrays ---
970 ierr = DMDAVecRestoreArrayRead(user->fda, localCoords_from_dm, &nodal_coords_arr); CHKERRQ(ierr);
971 ierr = DMDAVecRestoreArray(user->da, user->Aj, &aj_arr); CHKERRQ(ierr);
972
973 // --- 6. Assemble Global Vector ---
974 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Assembling global Aj.\n");
975 ierr = VecAssemblyBegin(user->Aj); CHKERRQ(ierr);
976 ierr = VecAssemblyEnd(user->Aj); CHKERRQ(ierr);
977
978 // --- 7. Update Local Ghosted Version ---
979 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Updating local lAj.\n");
980 ierr = UpdateLocalGhosts(user, FIELD_ID_AJ); CHKERRQ(ierr);
981
982 LOG_ALLOW(GLOBAL, LOG_INFO, "Completed calculation, extrapolation, and update for Aj.\n");
983 PetscFunctionReturn(0);
984}
@ FIELD_ID_AJ
Here is the call graph for this function:
Here is the caller graph for this function:

◆ CheckAndFixGridOrientation()

PetscErrorCode CheckAndFixGridOrientation ( UserCtx user)

Verify and, when consistently inverted, repair the 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 metadata intentionally omitted in API docs.

Verify and, when consistently inverted, repair the right-handed metric basis (Csi, Eta, Zet) and a positive Jacobian (Aj) over the whole domain.

Local to this translation unit.

Definition at line 313 of file Metric.c.

314{
315 PetscErrorCode ierr;
316 PetscReal aj_min, aj_max;
317 PetscMPIInt rank;
318
319 PetscFunctionBeginUser;
320
322
323 /* ---------------- step 1: global extrema of Aj ---------------- */
324 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
325
326 ierr = VecMin(user->Aj, NULL, &aj_min); CHKERRQ(ierr); /* already global */
327 ierr = VecMax(user->Aj, NULL, &aj_max); CHKERRQ(ierr);
328
330 "[orientation] Global Aj range: [%.3e , %.3e]\n",
331 (double)aj_min, (double)aj_max);
332
333 /* ---------------- step 2: detect malformed mesh ---------------- */
334 if (aj_min < 0.0 && aj_max > 0.0)
335 SETERRABORT(PETSC_COMM_WORLD, PETSC_ERR_USER,
336 "Mixed Jacobian signs detected – grid is topologically inconsistent.");
337
338 /* Default: grid is right-handed unless proven otherwise */
339 PetscInt orientation = +1;
340
341 /* ---------------- step 3: repair left-handed mesh -------------- */
342 if (aj_max < 0.0) { /* entire domain has Aj < 0 */
343 orientation = -1;
344
345 if (!rank)
347 "[orientation] Detected left-handed grid – flipping metric vectors\n");
348
349 /* Flip sign of *all* metric vectors and Aj */
350 ierr = VecScale(user->Csi, -1.0); CHKERRQ(ierr);
351 ierr = VecScale(user->Eta, -1.0); CHKERRQ(ierr);
352 ierr = VecScale(user->Zet, -1.0); CHKERRQ(ierr);
353 ierr = VecScale(user->Aj , -1.0); CHKERRQ(ierr);
354
355 /* Local ghost regions now stale – refresh */
356 ierr = UpdateLocalGhosts(user, FIELD_ID_CSI); CHKERRQ(ierr);
357 ierr = UpdateLocalGhosts(user, FIELD_ID_ETA); CHKERRQ(ierr);
358 ierr = UpdateLocalGhosts(user, FIELD_ID_ZET); CHKERRQ(ierr);
359 ierr = UpdateLocalGhosts(user, FIELD_ID_AJ); CHKERRQ(ierr);
360
361 /* Sanity print: Aj must be > 0 now */
362 ierr = VecMin(user->Aj, NULL, &aj_min); CHKERRQ(ierr);
363 ierr = VecMax(user->Aj, NULL, &aj_max); CHKERRQ(ierr);
364
365 if (aj_min <= 0.0)
366 SETERRABORT(PETSC_COMM_WORLD, PETSC_ERR_USER,
367 "Failed to flip grid orientation – Aj still non-positive.");
368 else if (aj_min && aj_max > 0.0)
369 orientation = +1;
370 }
371
372 /* ---------------- step 4: store result in UserCtx -------------- */
373 user->GridOrientation = orientation;
374
375 if (!rank)
377 "[orientation] Grid confirmed %s-handed after flip (orientation=%+d)\n",
378 (orientation>0) ? "right" : "left", orientation);
379
381
382 PetscFunctionReturn(0);
383}
PetscInt GridOrientation
Definition variables.h:924
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.

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

Local to this translation unit.

Definition at line 993 of file Metric.c.

994{
995 PetscErrorCode ierr;
996 DMDALocalInfo info;
997 Vec lCoords;
998 const Cmpnts ***coor;
999 Cmpnts ***cent, ***gs;
1000 PetscReal xcp, ycp, zcp, xcm, ycm, zcm;
1001 PetscInt xs,ys,zs,xe,ye,ze,mx,my,mz;
1002
1003 PetscFunctionBeginUser;
1004
1006
1007 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);
1008
1009 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1010 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1011 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1012
1013 ierr = DMDAVecGetArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
1014 ierr = DMDAVecGetArray(user->fda, user->GridSpace, &gs); CHKERRQ(ierr);
1015
1016 xs = info.xs; xe = info.xs + info.xm;
1017 ys = info.ys; ye = info.ys + info.ym;
1018 zs = info.zs; ze = info.zs + info.zm;
1019 mx = info.mx; my = info.my; mz = info.mz;
1020
1021 PetscInt k_start_node = (zs == 0) ? zs + 1 : zs;
1022 PetscInt j_start_node = (ys == 0) ? ys + 1 : ys;
1023 PetscInt i_start_node = (xs == 0) ? xs + 1 : xs;
1024
1025 PetscInt k_end_node = (ze == mz) ? ze - 1 : ze;
1026 PetscInt j_end_node = (ye == my) ? ye - 1 : ye;
1027 PetscInt i_end_node = (xe == mx) ? xe - 1 : xe;
1028
1029 // Loop over the interior OWNED cells (stencil requires i-1, j-1, k-1)
1030 for (PetscInt k=k_start_node; k<k_end_node; k++) {
1031 for (PetscInt j=j_start_node; j<j_end_node; j++) {
1032 for (PetscInt i=i_start_node; i<i_end_node; i++) {
1033 // Calculate cell center as the average of its 8 corner nodes
1034 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);
1035 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);
1036 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);
1037
1038 // Calculate Grid Spacing in i-direction (distance between i-face centers)
1039 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);
1040 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);
1041 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);
1042 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);
1043 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);
1044 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);
1045 gs[k][j][i].x = PetscSqrtReal(PetscSqr(xcp-xcm) + PetscSqr(ycp-ycm) + PetscSqr(zcp-zcm));
1046
1047 // Calculate Grid Spacing in j-direction (distance between j-face centers)
1048 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);
1049 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);
1050 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);
1051 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);
1052 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);
1053 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);
1054 gs[k][j][i].y = PetscSqrtReal(PetscSqr(xcp-xcm) + PetscSqr(ycp-ycm) + PetscSqr(zcp-zcm));
1055
1056 // Calculate Grid Spacing in k-direction (distance between k-face centers)
1057 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);
1058 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);
1059 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);
1060 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);
1061 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);
1062 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);
1063 gs[k][j][i].z = PetscSqrtReal(PetscSqr(xcp-xcm) + PetscSqr(ycp-ycm) + PetscSqr(zcp-zcm));
1064 }
1065 }
1066 }
1067
1068 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1069 ierr = DMDAVecRestoreArray(user->fda, user->Cent, &cent); CHKERRQ(ierr);
1070 ierr = DMDAVecRestoreArray(user->fda, user->GridSpace, &gs); CHKERRQ(ierr);
1071
1072 // Assemble and update ghost regions for the new data
1073 ierr = VecAssemblyBegin(user->Cent); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->Cent); CHKERRQ(ierr);
1074 ierr = VecAssemblyBegin(user->GridSpace); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->GridSpace); CHKERRQ(ierr);
1075 ierr = UpdateLocalGhosts(user, FIELD_ID_CENT); CHKERRQ(ierr);
1076 ierr = UpdateLocalGhosts(user, FIELD_ID_GRID_SPACE); CHKERRQ(ierr);
1077
1078 ierr = ApplyPeriodicCorrectionsToCellCentersAndSpacing(user); CHKERRQ(ierr);
1079
1080 // Final assembly and ghost update after corrections
1081 ierr = VecAssemblyBegin(user->Cent); CHKERRQ(ierr);
1082 ierr = VecAssemblyEnd(user->Cent); CHKERRQ(ierr);
1083 ierr = UpdateLocalGhosts(user, FIELD_ID_CENT); CHKERRQ(ierr);
1084
1086
1087 PetscFunctionReturn(0);
1088}
PetscErrorCode ApplyPeriodicCorrectionsToCellCentersAndSpacing(UserCtx *user)
Internal helper implementation: ApplyPeriodicCorrectionsToCellCentersAndSpacing().
Definition Metric.c:391
Vec GridSpace
Definition variables.h:974
PetscMPIInt rank
Definition variables.h:698
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:909
PetscInt _this
Definition variables.h:924
PetscInt thislevel
Definition variables.h:988
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.

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

Local to this translation unit.

Definition at line 1096 of file Metric.c.

1097{
1098 PetscErrorCode ierr;
1099 DMDALocalInfo info;
1100 Vec lCoords;
1101 const Cmpnts ***coor;
1102 Cmpnts ***centx; //***gs;
1103 const Cmpnts ***centx_const;
1104 Cmpnts ***icsi, ***ieta, ***izet;
1105 PetscScalar ***iaj;
1106 PetscReal dxdc, dydc, dzdc, dxde, dyde, dzde, dxdz, dydz, dzdz;
1107
1108 PetscFunctionBeginUser;
1109
1111
1112 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Computing i-face metrics for level %d block %d...\n", user->simCtx->rank, user->thislevel, user->_this);
1113
1114 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1115 PetscInt xs = info.xs, xe = info.xs + info.xm, mx = info.mx;
1116 PetscInt ys = info.ys, ye = info.ys + info.ym, my = info.my;
1117 PetscInt zs = info.zs, ze = info.zs + info.zm, mz = info.mz;
1118 PetscInt lxe = xe;
1119 PetscInt lys = ys; PetscInt lye = ye;
1120 PetscInt lzs = zs; PetscInt lze = ze;
1121
1122 if (ys==0) lys = ys+1;
1123 if (zs==0) lzs = zs+1;
1124
1125 if (xe==mx) lxe=xe-1;
1126 if (ye==my) lye=ye-1;
1127 if (ze==mz) lze=ze-1;
1128
1129 // --- Part 1: Calculate the location of i-face centers (Centx) ---
1130 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1131 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1132 ierr = DMDAVecGetArray(user->fda, user->Centx, &centx); CHKERRQ(ierr);
1133 // ierr = DMDAVecGetArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1134
1135 //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);
1136
1137 // Populate only owned physical face centers. Periodic endpoint and ghost
1138 // coordinates are established by the canonical face-field synchronizer.
1139 for (PetscInt k = PetscMax(zs, 1); k < PetscMin(ze, mz - 1); k++) {
1140 for (PetscInt j = PetscMax(ys, 1); j < PetscMin(ye, my - 1); j++) {
1141 for (PetscInt i = xs; i < PetscMin(xe, mx - 1); i++) {
1142 //----- DEBUG ------
1143 //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);
1144 //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,
1145 // coor[k][j][i].x, coor[k][j][i].y, coor[k][j][i].z,
1146 // coor[k-1][j][i].x, coor[k-1][j][i].y, coor[k-1][j][i].z,
1147 // coor[k][j-1][i].x, coor[k][j-1][i].y, coor[k][j-1][i].z,
1148 // coor[k-1][j-1][i].x, coor[k-1][j-1][i].y, coor[k-1][j-1][i].z);
1149
1150 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);
1151 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);
1152 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);
1153
1154 //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);
1155 }
1156 }
1157 }
1158
1159 //LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: i-face center coordinates calculated. \n", user->simCtx->rank);
1160 /*
1161 if(xs==0){
1162 for(PetscInt k=gzs+1;k < gze; k++){
1163 for(PetscInt j=gys+1;j < gye; j++){
1164 PetscInt i=0;
1165 centx[k][j][i-1].x=centx[k][j][i].x-gs[k][j][i-2].x;
1166 centx[k][j][i-1].y=centx[k][j][i].y;
1167 centx[k][j][i-1].z=centx[k][j][i].z;
1168 }
1169 }
1170 }
1171 if (xe==mx){
1172 for(PetscInt k=gzs+1; k<gze; k++) {
1173 for (PetscInt j=gys+1; j<gye;j++) {
1174 PetscInt i=mx-1;
1175 centx[k][j][i].x=centx[k][j][i-1].x+gs[k][j][i+2].x;
1176 centx[k][j][i].y=centx[k][j][i-1].y;
1177 centx[k][j][i].z=centx[k][j][i-1].z;
1178 }
1179 }
1180 }
1181 */
1182
1183 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1184 ierr = DMDAVecRestoreArray(user->fda, user->Centx, &centx); CHKERRQ(ierr);
1185
1186 // ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1187
1188 {
1189 const FieldId face_centers[] = {FIELD_ID_CENTX};
1190 ierr = SynchronizePeriodicFaceFields(user, 'i', 1, face_centers); CHKERRQ(ierr);
1191 }
1192
1193 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: i-face centers (Centx) calculated and ghosts updated.\n", user->simCtx->rank);
1194
1195 // --- Part 2: Calculate metrics using face-centered coordinates ---
1196 ierr = DMDAVecGetArrayRead(user->fda, user->lCentx, &centx_const); CHKERRQ(ierr);
1197 ierr = DMDAVecGetArray(user->fda, user->ICsi, &icsi); CHKERRQ(ierr);
1198 ierr = DMDAVecGetArray(user->fda, user->IEta, &ieta); CHKERRQ(ierr);
1199 ierr = DMDAVecGetArray(user->fda, user->IZet, &izet); CHKERRQ(ierr);
1200 ierr = DMDAVecGetArray(user->da, user->IAj, &iaj); CHKERRQ(ierr);
1201
1202 // Loop over the OWNED region where we will store the final metrics
1203 for (PetscInt k=lzs; k<lze; k++) {
1204 for (PetscInt j=lys; j<lye; j++) {
1205 for (PetscInt i=xs; i<lxe; i++) {
1206
1207 // --- Stencil Logic for d/dcsi (derivative in i-direction) ---
1209 // Forward difference at the domain's min-i boundary
1210 dxdc = centx_const[k][j][i+1].x - centx_const[k][j][i].x;
1211 dydc = centx_const[k][j][i+1].y - centx_const[k][j][i].y;
1212 dzdc = centx_const[k][j][i+1].z - centx_const[k][j][i].z;
1213 } else if (i == mx - 2 && user->boundary_faces[BC_FACE_POS_X].mathematical_type != PERIODIC) {
1214 // Backward difference at the domain's max-i boundary
1215 dxdc = centx_const[k][j][i].x - centx_const[k][j][i-1].x;
1216 dydc = centx_const[k][j][i].y - centx_const[k][j][i-1].y;
1217 dzdc = centx_const[k][j][i].z - centx_const[k][j][i-1].z;
1218 } else { // Central difference in the interior (or if PERIODIC BCs)
1219 dxdc = 0.5 * (centx_const[k][j][i+1].x - centx_const[k][j][i-1].x);
1220 dydc = 0.5 * (centx_const[k][j][i+1].y - centx_const[k][j][i-1].y);
1221 dzdc = 0.5 * (centx_const[k][j][i+1].z - centx_const[k][j][i-1].z);
1222 }
1223
1224 // --- Stencil Logic for d/deta (derivative in j-direction) ---
1225 if (j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) {
1226 // Forward difference
1227 dxde = centx_const[k][j+1][i].x - centx_const[k][j][i].x;
1228 dyde = centx_const[k][j+1][i].y - centx_const[k][j][i].y;
1229 dzde = centx_const[k][j+1][i].z - centx_const[k][j][i].z;
1230 } else if (j == my - 2 && user->boundary_faces[BC_FACE_POS_Y].mathematical_type != PERIODIC) {
1231 // Backward difference
1232 dxde = centx_const[k][j][i].x - centx_const[k][j-1][i].x;
1233 dyde = centx_const[k][j][i].y - centx_const[k][j-1][i].y;
1234 dzde = centx_const[k][j][i].z - centx_const[k][j-1][i].z;
1235 } else { // Central difference (interior or PERIODIC)
1236 dxde = 0.5 * (centx_const[k][j+1][i].x - centx_const[k][j-1][i].x);
1237 dyde = 0.5 * (centx_const[k][j+1][i].y - centx_const[k][j-1][i].y);
1238 dzde = 0.5 * (centx_const[k][j+1][i].z - centx_const[k][j-1][i].z);
1239 }
1240
1241 // --- Stencil Logic for d/dzeta (derivative in k-direction) ---
1242 if (k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) {
1243 // Forward difference
1244 dxdz = centx_const[k+1][j][i].x - centx_const[k][j][i].x;
1245 dydz = centx_const[k+1][j][i].y - centx_const[k][j][i].y;
1246 dzdz = centx_const[k+1][j][i].z - centx_const[k][j][i].z;
1247 } else if (k == mz - 2 && user->boundary_faces[BC_FACE_POS_Z].mathematical_type != PERIODIC) {
1248 // Backward difference
1249 dxdz = centx_const[k][j][i].x - centx_const[k-1][j][i].x;
1250 dydz = centx_const[k][j][i].y - centx_const[k-1][j][i].y;
1251 dzdz = centx_const[k][j][i].z - centx_const[k-1][j][i].z;
1252 } else { // Central difference (Interior + PERIODIC)
1253 dxdz = 0.5 * (centx_const[k+1][j][i].x - centx_const[k-1][j][i].x);
1254 dydz = 0.5 * (centx_const[k+1][j][i].y - centx_const[k-1][j][i].y);
1255 dzdz = 0.5 * (centx_const[k+1][j][i].z - centx_const[k-1][j][i].z);
1256 }
1257
1258 // --- Metric calculations (identical to legacy FormMetrics) ---
1259 icsi[k][j][i].x = dyde * dzdz - dzde * dydz;
1260 icsi[k][j][i].y = -dxde * dzdz + dzde * dxdz;
1261 icsi[k][j][i].z = dxde * dydz - dyde * dxdz;
1262
1263 ieta[k][j][i].x = dydz * dzdc - dzdz * dydc;
1264 ieta[k][j][i].y = -dxdz * dzdc + dzdz * dxdc;
1265 ieta[k][j][i].z = dxdz * dydc - dydz * dxdc;
1266
1267 izet[k][j][i].x = dydc * dzde - dzdc * dyde;
1268 izet[k][j][i].y = -dxdc * dzde + dzdc * dxde;
1269 izet[k][j][i].z = dxdc * dyde - dydc * dxde;
1270
1271 iaj[k][j][i] = dxdc * icsi[k][j][i].x + dydc * icsi[k][j][i].y + dzdc * icsi[k][j][i].z;
1272 if (PetscAbsScalar(iaj[k][j][i]) > 1e-12) {
1273 iaj[k][j][i] = 1.0 / iaj[k][j][i];
1274 }
1275 }
1276 }
1277 }
1278
1279 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCentx, &centx_const); CHKERRQ(ierr);
1280 ierr = DMDAVecRestoreArray(user->fda, user->ICsi, &icsi); CHKERRQ(ierr);
1281 ierr = DMDAVecRestoreArray(user->fda, user->IEta, &ieta); CHKERRQ(ierr);
1282 ierr = DMDAVecRestoreArray(user->fda, user->IZet, &izet); CHKERRQ(ierr);
1283 ierr = DMDAVecRestoreArray(user->da, user->IAj, &iaj); CHKERRQ(ierr);
1284
1285 // --- Part 3: Assemble global vectors and update local ghosts ---
1286 ierr = VecAssemblyBegin(user->ICsi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->ICsi); CHKERRQ(ierr);
1287 ierr = VecAssemblyBegin(user->IEta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->IEta); CHKERRQ(ierr);
1288 ierr = VecAssemblyBegin(user->IZet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->IZet); CHKERRQ(ierr);
1289 ierr = VecAssemblyBegin(user->IAj); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->IAj); CHKERRQ(ierr);
1290
1291 ierr = UpdateLocalGhosts(user, FIELD_ID_ICSI); CHKERRQ(ierr);
1292 ierr = UpdateLocalGhosts(user, FIELD_ID_IETA); CHKERRQ(ierr);
1293 ierr = UpdateLocalGhosts(user, FIELD_ID_IZET); CHKERRQ(ierr);
1294 ierr = UpdateLocalGhosts(user, FIELD_ID_IAJ); CHKERRQ(ierr);
1295
1297
1298 PetscFunctionReturn(0);
1299}
@ FIELD_ID_IAJ
@ FIELD_ID_IETA
@ FIELD_ID_ICSI
@ FIELD_ID_IZET
Vec IZet
Definition variables.h:977
Vec IEta
Definition variables.h:977
Vec Centx
Definition variables.h:975
Vec ICsi
Definition variables.h:977
Vec IAj
Definition variables.h:977
Vec lCentx
Definition variables.h:976
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.

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

Local to this translation unit.

Definition at line 1307 of file Metric.c.

1308{
1309 PetscErrorCode ierr;
1310 DMDALocalInfo info;
1311 Vec lCoords;
1312 const Cmpnts ***coor;
1313 Cmpnts ***centy; //***gs;
1314 const Cmpnts ***centy_const;
1315 Cmpnts ***jcsi, ***jeta, ***jzet;
1316 PetscScalar ***jaj;
1317 PetscReal dxdc, dydc, dzdc, dxde, dyde, dzde, dxdz, dydz, dzdz;
1318
1319 PetscFunctionBeginUser;
1320
1322
1323 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Computing j-face metrics for level %d block %d...\n", user->simCtx->rank, user->thislevel, user->_this);
1324
1325 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1326 PetscInt xs = info.xs, xe = info.xs + info.xm, mx = info.mx;
1327 PetscInt ys = info.ys, ye = info.ys + info.ym, my = info.my;
1328 PetscInt zs = info.zs, ze = info.zs + info.zm, mz = info.mz;
1329 PetscInt lxs = xs; PetscInt lxe = xe;
1330 PetscInt lye = ye;
1331 PetscInt lzs = zs; PetscInt lze = ze;
1332
1333 if (xs==0) lxs = xs+1;
1334 if (zs==0) lzs = zs+1;
1335
1336 if (xe==mx) lxe=xe-1;
1337 if (ye==my) lye=ye-1;
1338 if (ze==mz) lze=ze-1;
1339
1340 // --- Part 1: Calculate the location of i-face centers (Centx) ---
1341 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1342 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1343 ierr = DMDAVecGetArray(user->fda, user->Centy, &centy); CHKERRQ(ierr);
1344 // ierr = DMDAVecGetArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1345
1346 for (PetscInt k = PetscMax(zs, 1); k < PetscMin(ze, mz - 1); k++) {
1347 for (PetscInt j = ys; j < PetscMin(ye, my - 1); j++) {
1348 for (PetscInt i = PetscMax(xs, 1); i < PetscMin(xe, mx - 1); i++) {
1349 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);
1350 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);
1351 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);
1352 }
1353 }
1354 }
1355
1356 /*
1357 if(ys==0){
1358 for(PetscInt k=gzs+1;k < gze; k++){
1359 for(PetscInt i=gxs+1;j < gxe; i++){
1360 PetscInt j=0;
1361 centy[k][j-1][i].x=centy[k][j][i].x;
1362 centy[k][j-1][i].y=centy[k][j][i].y-gs[k][j-2][i].y;
1363 centy[k][j-1][i].z=centy[k][j][i].z;
1364 }
1365 }
1366 }
1367 if (ye==my){
1368 for(PetscInt k=gzs+1; k<gze; k++) {
1369 for (PetscInt i=gxs+1; j<gxe;i++) {
1370 PetscInt j=my-1;
1371 centy[k][j][i].x=centy[k][j-1][i].x
1372 centy[k][j][i].y=centy[k][j-1][i].y+gs[k][j+2][i].y;
1373 centy[k][j][i].z=centy[k][j-1][i].z;
1374 }
1375 }
1376 }
1377 */
1378
1379 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1380 ierr = DMDAVecRestoreArray(user->fda, user->Centy, &centy); CHKERRQ(ierr);
1381 // ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1382
1383 {
1384 const FieldId face_centers[] = {FIELD_ID_CENTY};
1385 ierr = SynchronizePeriodicFaceFields(user, 'j', 1, face_centers); CHKERRQ(ierr);
1386 }
1387
1388 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: j-face centers (Centx) calculated and ghosts updated.\n", user->simCtx->rank);
1389
1390 // --- Part 2: Calculate metrics using face-centered coordinates ---
1391 ierr = DMDAVecGetArrayRead(user->fda, user->lCenty, &centy_const); CHKERRQ(ierr);
1392 ierr = DMDAVecGetArray(user->fda, user->JCsi, &jcsi); CHKERRQ(ierr);
1393 ierr = DMDAVecGetArray(user->fda, user->JEta, &jeta); CHKERRQ(ierr);
1394 ierr = DMDAVecGetArray(user->fda, user->JZet, &jzet); CHKERRQ(ierr);
1395 ierr = DMDAVecGetArray(user->da, user->JAj, &jaj); CHKERRQ(ierr);
1396
1397 // Loop over the OWNED region where we will store the final metrics
1398 for (PetscInt k=lzs; k<lze; k++) {
1399 for (PetscInt j=ys; j<lye; j++) {
1400 for (PetscInt i=lxs; i<lxe; i++) {
1401
1402 // --- Stencil Logic for d/dcsi (derivative in i-direction) ---
1403 if (i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) {
1404 // Forward difference at the domain's min-i boundary
1405 dxdc = centy_const[k][j][i+1].x - centy_const[k][j][i].x;
1406 dydc = centy_const[k][j][i+1].y - centy_const[k][j][i].y;
1407 dzdc = centy_const[k][j][i+1].z - centy_const[k][j][i].z;
1408 } else if (i == mx - 2 && user->boundary_faces[BC_FACE_POS_X].mathematical_type != PERIODIC) {
1409 // Backward difference at the domain's max-i boundary
1410 dxdc = centy_const[k][j][i].x - centy_const[k][j][i-1].x;
1411 dydc = centy_const[k][j][i].y - centy_const[k][j][i-1].y;
1412 dzdc = centy_const[k][j][i].z - centy_const[k][j][i-1].z;
1413 } else { // Central difference in the interior or PERIODIC
1414 dxdc = 0.5 * (centy_const[k][j][i+1].x - centy_const[k][j][i-1].x);
1415 dydc = 0.5 * (centy_const[k][j][i+1].y - centy_const[k][j][i-1].y);
1416 dzdc = 0.5 * (centy_const[k][j][i+1].z - centy_const[k][j][i-1].z);
1417 }
1418
1419 // --- Stencil Logic for d/deta (derivative in j-direction) ---
1420 if (j == 0 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) {
1421 // Forward difference
1422 dxde = centy_const[k][j+1][i].x - centy_const[k][j][i].x;
1423 dyde = centy_const[k][j+1][i].y - centy_const[k][j][i].y;
1424 dzde = centy_const[k][j+1][i].z - centy_const[k][j][i].z;
1425 } else if (j == my - 2 && user->boundary_faces[BC_FACE_POS_Y].mathematical_type != PERIODIC) {
1426 // Backward difference
1427 dxde = centy_const[k][j][i].x - centy_const[k][j-1][i].x;
1428 dyde = centy_const[k][j][i].y - centy_const[k][j-1][i].y;
1429 dzde = centy_const[k][j][i].z - centy_const[k][j-1][i].z;
1430 } else { // Central difference (interior or PERIODIC)
1431 dxde = 0.5 * (centy_const[k][j+1][i].x - centy_const[k][j-1][i].x);
1432 dyde = 0.5 * (centy_const[k][j+1][i].y - centy_const[k][j-1][i].y);
1433 dzde = 0.5 * (centy_const[k][j+1][i].z - centy_const[k][j-1][i].z);
1434 }
1435
1436 // --- Stencil Logic for d/dzeta (derivative in k-direction) ---
1437 if (k == 1 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) {
1438 // Forward difference
1439 dxdz = centy_const[k+1][j][i].x - centy_const[k][j][i].x;
1440 dydz = centy_const[k+1][j][i].y - centy_const[k][j][i].y;
1441 dzdz = centy_const[k+1][j][i].z - centy_const[k][j][i].z;
1442 } else if (k == mz - 2 && user->boundary_faces[BC_FACE_POS_Z].mathematical_type != PERIODIC) {
1443 // Backward difference
1444 dxdz = centy_const[k][j][i].x - centy_const[k-1][j][i].x;
1445 dydz = centy_const[k][j][i].y - centy_const[k-1][j][i].y;
1446 dzdz = centy_const[k][j][i].z - centy_const[k-1][j][i].z;
1447 } else { // Central difference (Interior or PERIODIC)
1448 dxdz = 0.5 * (centy_const[k+1][j][i].x - centy_const[k-1][j][i].x);
1449 dydz = 0.5 * (centy_const[k+1][j][i].y - centy_const[k-1][j][i].y);
1450 dzdz = 0.5 * (centy_const[k+1][j][i].z - centy_const[k-1][j][i].z);
1451 }
1452
1453 // --- Metric calculations (identical to legacy FormMetrics) ---
1454 jcsi[k][j][i].x = dyde * dzdz - dzde * dydz;
1455 jcsi[k][j][i].y = -dxde * dzdz + dzde * dxdz;
1456 jcsi[k][j][i].z = dxde * dydz - dyde * dxdz;
1457
1458 jeta[k][j][i].x = dydz * dzdc - dzdz * dydc;
1459 jeta[k][j][i].y = -dxdz * dzdc + dzdz * dxdc;
1460 jeta[k][j][i].z = dxdz * dydc - dydz * dxdc;
1461
1462 jzet[k][j][i].x = dydc * dzde - dzdc * dyde;
1463 jzet[k][j][i].y = -dxdc * dzde + dzdc * dxde;
1464 jzet[k][j][i].z = dxdc * dyde - dydc * dxde;
1465
1466 jaj[k][j][i] = dxdc * jcsi[k][j][i].x + dydc * jcsi[k][j][i].y + dzdc * jcsi[k][j][i].z;
1467 if (PetscAbsScalar(jaj[k][j][i]) > 1e-12) {
1468 jaj[k][j][i] = 1.0 / jaj[k][j][i];
1469 }
1470 }
1471 }
1472 }
1473
1474 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCenty, &centy_const); CHKERRQ(ierr);
1475 ierr = DMDAVecRestoreArray(user->fda, user->JCsi, &jcsi); CHKERRQ(ierr);
1476 ierr = DMDAVecRestoreArray(user->fda, user->JEta, &jeta); CHKERRQ(ierr);
1477 ierr = DMDAVecRestoreArray(user->fda, user->JZet, &jzet); CHKERRQ(ierr);
1478 ierr = DMDAVecRestoreArray(user->da, user->JAj, &jaj); CHKERRQ(ierr);
1479
1480 // --- Part 3: Assemble global vectors and update local ghosts ---
1481 ierr = VecAssemblyBegin(user->JCsi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JCsi); CHKERRQ(ierr);
1482 ierr = VecAssemblyBegin(user->JEta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JEta); CHKERRQ(ierr);
1483 ierr = VecAssemblyBegin(user->JZet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JZet); CHKERRQ(ierr);
1484 ierr = VecAssemblyBegin(user->JAj); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->JAj); CHKERRQ(ierr);
1485
1486 ierr = UpdateLocalGhosts(user, FIELD_ID_JCSI); CHKERRQ(ierr);
1487 ierr = UpdateLocalGhosts(user, FIELD_ID_JETA); CHKERRQ(ierr);
1488 ierr = UpdateLocalGhosts(user, FIELD_ID_JZET); CHKERRQ(ierr);
1489 ierr = UpdateLocalGhosts(user, FIELD_ID_JAJ); CHKERRQ(ierr);
1490
1492
1493 PetscFunctionReturn(0);
1494}
@ FIELD_ID_JETA
@ FIELD_ID_JAJ
@ FIELD_ID_JCSI
@ FIELD_ID_JZET
Vec JCsi
Definition variables.h:978
Vec JEta
Definition variables.h:978
Vec JZet
Definition variables.h:978
Vec lCenty
Definition variables.h:976
Vec JAj
Definition variables.h:978
Vec Centy
Definition variables.h:975
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.

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

Local to this translation unit.

Definition at line 1502 of file Metric.c.

1503{
1504 PetscErrorCode ierr;
1505 DMDALocalInfo info;
1506 Vec lCoords;
1507 const Cmpnts ***coor;
1508 Cmpnts ***centz; //***gs;
1509 const Cmpnts ***centz_const;
1510 Cmpnts ***kcsi, ***keta, ***kzet;
1511 PetscScalar ***kaj;
1512 PetscReal dxdc, dydc, dzdc, dxde, dyde, dzde, dxdz, dydz, dzdz;
1513
1514 PetscFunctionBeginUser;
1515
1517
1518 LOG_ALLOW(LOCAL, LOG_INFO, "Rank %d: Computing k-face metrics for level %d block %d...\n", user->simCtx->rank, user->thislevel, user->_this);
1519
1520 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
1521 PetscInt xs = info.xs, xe = info.xs + info.xm, mx = info.mx;
1522 PetscInt ys = info.ys, ye = info.ys + info.ym, my = info.my;
1523 PetscInt zs = info.zs, ze = info.zs + info.zm, mz = info.mz;
1524 PetscInt lxs = xs; PetscInt lxe = xe;
1525 PetscInt lys = ys; PetscInt lye = ye;
1526 PetscInt lze = ze;
1527
1528 if (xs==0) lxs = xs+1;
1529 if (ys==0) lys = ys+1;
1530
1531 if (xe==mx) lxe=xe-1;
1532 if (ye==my) lye=ye-1;
1533 if (ze==mz) lze=ze-1;
1534
1535 // --- Part 1: Calculate the location of i-face centers (Centx) ---
1536 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
1537 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1538 ierr = DMDAVecGetArray(user->fda, user->Centz, &centz); CHKERRQ(ierr);
1539 // ierr = DMDAVecGetArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1540
1541 for (PetscInt k = zs; k < PetscMin(ze, mz - 1); k++) {
1542 for (PetscInt j = PetscMax(ys, 1); j < PetscMin(ye, my - 1); j++) {
1543 for (PetscInt i = PetscMax(xs, 1); i < PetscMin(xe, mx - 1); i++) {
1544 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);
1545 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);
1546 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);
1547 }
1548 }
1549 }
1550
1551 /*
1552 if(zs==0){
1553 for(PetscInt j=gys+1;j < gye; j++){
1554 for(PetscInt i=gxs+1;j < gxe; i++){
1555 PetscInt k=0;
1556 centz[k-1][j][i].x=centz[k][j][i].x;
1557 centz[k-1][j][i].y=centz[k][j][i].y;
1558 centz[k-1][j][i].z=centz[k][j][i].z-gs[k-2][j][i].z;
1559 }
1560 }
1561 }
1562 if (ze==mz){
1563 for(PetscInt j=gys+1; j<gye; j++) {
1564 for (PetscInt i=gxs+1; j<gxe;i++) {
1565 PetscInt k=mz-1;
1566 centy[k][j][i].x=centy[k-1][j][i].x
1567 centy[k][j][i].y=centy[k-1][j][i].y;
1568 centz[k][j][i].z=centz[k-1][j][i].z+gs[k+2][j][1].z;
1569 }
1570 }
1571 }
1572 */
1573
1574 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor); CHKERRQ(ierr);
1575 ierr = DMDAVecRestoreArray(user->fda, user->Centz, &centz); CHKERRQ(ierr);
1576 // ierr = DMDAVecRestoreArray(user->fda, user->lGridSpace,&gs); CHKERRQ(ierr);
1577
1578 {
1579 const FieldId face_centers[] = {FIELD_ID_CENTZ};
1580 ierr = SynchronizePeriodicFaceFields(user, 'k', 1, face_centers); CHKERRQ(ierr);
1581 }
1582
1583 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: k-face centers (Centx) calculated and ghosts updated.\n", user->simCtx->rank);
1584
1585 // --- Part 2: Calculate metrics using face-centered coordinates ---
1586 ierr = DMDAVecGetArrayRead(user->fda, user->lCentz, &centz_const); CHKERRQ(ierr);
1587 ierr = DMDAVecGetArray(user->fda, user->KCsi, &kcsi); CHKERRQ(ierr);
1588 ierr = DMDAVecGetArray(user->fda, user->KEta, &keta); CHKERRQ(ierr);
1589 ierr = DMDAVecGetArray(user->fda, user->KZet, &kzet); CHKERRQ(ierr);
1590 ierr = DMDAVecGetArray(user->da, user->KAj, &kaj); CHKERRQ(ierr);
1591
1592 // Loop over the OWNED region where we will store the final metrics
1593 for (PetscInt k=zs; k<lze; k++) {
1594 for (PetscInt j=lys; j<lye; j++) {
1595 for (PetscInt i=lxs; i<lxe; i++) {
1596
1597 // --- Stencil Logic for d/dcsi (derivative in i-direction) ---
1598 if (i == 1 && user->boundary_faces[BC_FACE_NEG_X].mathematical_type != PERIODIC) {
1599 // Forward difference at the domain's min-i boundary
1600 dxdc = centz_const[k][j][i+1].x - centz_const[k][j][i].x;
1601 dydc = centz_const[k][j][i+1].y - centz_const[k][j][i].y;
1602 dzdc = centz_const[k][j][i+1].z - centz_const[k][j][i].z;
1603 } else if (i == mx - 2 && user->boundary_faces[BC_FACE_POS_X].mathematical_type != PERIODIC) {
1604 // Backward difference at the domain's max-i boundary
1605 dxdc = centz_const[k][j][i].x - centz_const[k][j][i-1].x;
1606 dydc = centz_const[k][j][i].y - centz_const[k][j][i-1].y;
1607 dzdc = centz_const[k][j][i].z - centz_const[k][j][i-1].z;
1608 } else { // Central difference in the interior (or PERIODIC)
1609 dxdc = 0.5 * (centz_const[k][j][i+1].x - centz_const[k][j][i-1].x);
1610 dydc = 0.5 * (centz_const[k][j][i+1].y - centz_const[k][j][i-1].y);
1611 dzdc = 0.5 * (centz_const[k][j][i+1].z - centz_const[k][j][i-1].z);
1612 }
1613
1614 // --- Stencil Logic for d/deta (derivative in j-direction) ---
1615 if (j == 1 && user->boundary_faces[BC_FACE_NEG_Y].mathematical_type != PERIODIC) {
1616 // Forward difference
1617 dxde = centz_const[k][j+1][i].x - centz_const[k][j][i].x;
1618 dyde = centz_const[k][j+1][i].y - centz_const[k][j][i].y;
1619 dzde = centz_const[k][j+1][i].z - centz_const[k][j][i].z;
1620 } else if (j == my - 2 && user->boundary_faces[BC_FACE_POS_Y].mathematical_type != PERIODIC) {
1621 // Backward difference
1622 dxde = centz_const[k][j][i].x - centz_const[k][j-1][i].x;
1623 dyde = centz_const[k][j][i].y - centz_const[k][j-1][i].y;
1624 dzde = centz_const[k][j][i].z - centz_const[k][j-1][i].z;
1625 } else { // Central difference (interior or PERIODIC)
1626 dxde = 0.5 * (centz_const[k][j+1][i].x - centz_const[k][j-1][i].x);
1627 dyde = 0.5 * (centz_const[k][j+1][i].y - centz_const[k][j-1][i].y);
1628 dzde = 0.5 * (centz_const[k][j+1][i].z - centz_const[k][j-1][i].z);
1629 }
1630
1631 // --- Stencil Logic for d/dzeta (derivative in k-direction) ---
1632 if (k == 0 && user->boundary_faces[BC_FACE_NEG_Z].mathematical_type != PERIODIC) {
1633 // Forward difference
1634 dxdz = centz_const[k+1][j][i].x - centz_const[k][j][i].x;
1635 dydz = centz_const[k+1][j][i].y - centz_const[k][j][i].y;
1636 dzdz = centz_const[k+1][j][i].z - centz_const[k][j][i].z;
1637 } else if (k == mz - 2 && user->boundary_faces[BC_FACE_POS_Z].mathematical_type != PERIODIC) {
1638 // Backward difference
1639 dxdz = centz_const[k][j][i].x - centz_const[k-1][j][i].x;
1640 dydz = centz_const[k][j][i].y - centz_const[k-1][j][i].y;
1641 dzdz = centz_const[k][j][i].z - centz_const[k-1][j][i].z;
1642 } else { // Central difference (Interior or PERIODIC)
1643 dxdz = 0.5 * (centz_const[k+1][j][i].x - centz_const[k-1][j][i].x);
1644 dydz = 0.5 * (centz_const[k+1][j][i].y - centz_const[k-1][j][i].y);
1645 dzdz = 0.5 * (centz_const[k+1][j][i].z - centz_const[k-1][j][i].z);
1646 }
1647
1648 // --- Metric calculations (identical to legacy FormMetrics) ---
1649 kcsi[k][j][i].x = dyde * dzdz - dzde * dydz;
1650 kcsi[k][j][i].y = -dxde * dzdz + dzde * dxdz;
1651 kcsi[k][j][i].z = dxde * dydz - dyde * dxdz;
1652
1653 keta[k][j][i].x = dydz * dzdc - dzdz * dydc;
1654 keta[k][j][i].y = -dxdz * dzdc + dzdz * dxdc;
1655 keta[k][j][i].z = dxdz * dydc - dydz * dxdc;
1656
1657 kzet[k][j][i].x = dydc * dzde - dzdc * dyde;
1658 kzet[k][j][i].y = -dxdc * dzde + dzdc * dxde;
1659 kzet[k][j][i].z = dxdc * dyde - dydc * dxde;
1660
1661 kaj[k][j][i] = dxdc * kcsi[k][j][i].x + dydc * kcsi[k][j][i].y + dzdc * kcsi[k][j][i].z;
1662 if (PetscAbsScalar(kaj[k][j][i]) > 1e-12) {
1663 kaj[k][j][i] = 1.0 / kaj[k][j][i];
1664 }
1665 }
1666 }
1667 }
1668
1669 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCentz, &centz_const); CHKERRQ(ierr);
1670 ierr = DMDAVecRestoreArray(user->fda, user->KCsi, &kcsi); CHKERRQ(ierr);
1671 ierr = DMDAVecRestoreArray(user->fda, user->KEta, &keta); CHKERRQ(ierr);
1672 ierr = DMDAVecRestoreArray(user->fda, user->KZet, &kzet); CHKERRQ(ierr);
1673 ierr = DMDAVecRestoreArray(user->da, user->KAj, &kaj); CHKERRQ(ierr);
1674
1675 // --- Part 3: Assemble global vectors and update local ghosts ---
1676 ierr = VecAssemblyBegin(user->KCsi); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KCsi); CHKERRQ(ierr);
1677 ierr = VecAssemblyBegin(user->KEta); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KEta); CHKERRQ(ierr);
1678 ierr = VecAssemblyBegin(user->KZet); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KZet); CHKERRQ(ierr);
1679 ierr = VecAssemblyBegin(user->KAj); CHKERRQ(ierr); ierr = VecAssemblyEnd(user->KAj); CHKERRQ(ierr);
1680
1681 ierr = UpdateLocalGhosts(user, FIELD_ID_KCSI); CHKERRQ(ierr);
1682 ierr = UpdateLocalGhosts(user, FIELD_ID_KETA); CHKERRQ(ierr);
1683 ierr = UpdateLocalGhosts(user, FIELD_ID_KZET); CHKERRQ(ierr);
1684 ierr = UpdateLocalGhosts(user, FIELD_ID_KAJ); CHKERRQ(ierr);
1685
1687
1688 PetscFunctionReturn(0);
1689}
@ FIELD_ID_KETA
@ FIELD_ID_KAJ
@ FIELD_ID_KZET
@ FIELD_ID_KCSI
Vec KAj
Definition variables.h:979
Vec Centz
Definition variables.h:975
Vec KEta
Definition variables.h:979
Vec KZet
Definition variables.h:979
Vec KCsi
Definition variables.h:979
Vec lCentz
Definition variables.h:976
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.

Local to this translation unit.

Definition at line 1716 of file Metric.c.

1717{
1718 DM da = user->da, fda = user->fda;
1719 DMDALocalInfo info = user->info;
1720 PetscInt xs = info.xs, xe = info.xs + info.xm;
1721 PetscInt ys = info.ys, ye = info.ys + info.ym;
1722 PetscInt zs = info.zs, ze = info.zs + info.zm;
1723 PetscInt mx = info.mx, my = info.my, mz = info.mz;
1724 PetscInt lxs, lys, lzs, lxe, lye, lze;
1725 PetscInt i, j, k;
1726 Vec Div;
1727 PetscReal ***div, ***aj;
1728 Cmpnts ***csi, ***eta, ***zet;
1729 PetscReal maxdiv;
1730
1731 PetscFunctionBeginUser;
1732
1734
1735 lxs = xs; lxe = xe;
1736 lys = ys; lye = ye;
1737 lzs = zs; lze = ze;
1738
1739 if (xs == 0) lxs = xs + 1;
1740 if (ys == 0) lys = ys + 1;
1741 if (zs == 0) lzs = zs + 1;
1742
1743 if (xe == mx) lxe = xe - 1;
1744 if (ye == my) lye = ye - 1;
1745 if (ze == mz) lze = ze - 1;
1746
1747 DMDAVecGetArray(fda, user->lCsi, &csi);
1748 DMDAVecGetArray(fda, user->lEta, &eta);
1749 DMDAVecGetArray(fda, user->lZet, &zet);
1750 DMDAVecGetArray(da, user->lAj, &aj);
1751
1752 VecDuplicate(user->P, &Div);
1753 VecSet(Div, 0.);
1754 DMDAVecGetArray(da, Div, &div);
1755
1756 for (k = lzs; k < lze; k++) {
1757 for (j = lys; j < lye; j++) {
1758 for (i = lxs; i < lxe; i++) {
1759 PetscReal divergence = (csi[k][j][i].x - csi[k][j][i-1].x +
1760 eta[k][j][i].x - eta[k][j-1][i].x +
1761 zet[k][j][i].x - zet[k-1][j][i].x +
1762 csi[k][j][i].y - csi[k][j][i-1].y +
1763 eta[k][j][i].y - eta[k][j-1][i].y +
1764 zet[k][j][i].y - zet[k-1][j][i].y +
1765 csi[k][j][i].z - csi[k][j][i-1].z +
1766 eta[k][j][i].z - eta[k][j-1][i].z +
1767 zet[k][j][i].z - zet[k-1][j][i].z) * aj[k][j][i];
1768 div[k][j][i] = fabs(divergence);
1769 }
1770 }
1771 }
1772
1773 DMDAVecRestoreArray(da, Div, &div);
1774
1775 PetscInt MaxFlatIndex = -1;
1776 VecMax(Div, &MaxFlatIndex, &maxdiv);
1777 LOG_ALLOW(GLOBAL,LOG_INFO,"The Maximum Metric Divergence is %e at flat index %" PetscInt_FMT ".\n",maxdiv,MaxFlatIndex);
1778
1779 for (k=zs; k<ze; k++) {
1780 for (j=ys; j<ye; j++) {
1781 for (i=xs; i<xe; i++) {
1782 if (Gidx(i,j,k,user) == MaxFlatIndex) {
1783 LOG_ALLOW(GLOBAL,LOG_INFO,"The Maximum Metric Divergence(%e) is at location [%d][%d][%d]. \n", maxdiv,(int)k,(int)j,(int)i);
1784 }
1785 }
1786 }
1787 }
1788
1789
1790 DMDAVecRestoreArray(fda, user->lCsi, &csi);
1791 DMDAVecRestoreArray(fda, user->lEta, &eta);
1792 DMDAVecRestoreArray(fda, user->lZet, &zet);
1793 DMDAVecRestoreArray(da, user->lAj, &aj);
1794 VecDestroy(&Div);
1795
1796
1798
1799 PetscFunctionReturn(0);
1800}
static PetscInt Gidx(PetscInt i, PetscInt j, PetscInt k, UserCtx *user)
Convert logical cell indices into the flattened global cell identifier.
Definition Metric.c:1694
Vec lZet
Definition variables.h:974
Vec lCsi
Definition variables.h:974
Vec lAj
Definition variables.h:974
Vec lEta
Definition variables.h:974
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

Computes the max-min values of the grid metrics.

Local to this translation unit.

Definition at line 1808 of file Metric.c.

1809{
1810
1811 DMDALocalInfo info = user->info;
1812 PetscInt xs = info.xs, xe = info.xs + info.xm;
1813 PetscInt ys = info.ys, ye = info.ys + info.ym;
1814 PetscInt zs = info.zs, ze = info.zs + info.zm;
1815 PetscInt i, j, k;
1816
1817 PetscFunctionBeginUser;
1818
1820
1821 PetscReal CsiMax, EtaMax, ZetMax;
1822 PetscReal ICsiMax, IEtaMax, IZetMax;
1823 PetscReal JCsiMax, JEtaMax, JZetMax;
1824 PetscReal KCsiMax, KEtaMax, KZetMax;
1825 PetscReal AjMax, IAjMax, JAjMax, KAjMax;
1826
1827 PetscInt CsiMaxArg, EtaMaxArg, ZetMaxArg;
1828 PetscInt ICsiMaxArg, IEtaMaxArg, IZetMaxArg;
1829 PetscInt JCsiMaxArg, JEtaMaxArg, JZetMaxArg;
1830 PetscInt KCsiMaxArg, KEtaMaxArg, KZetMaxArg;
1831 PetscInt AjMaxArg, IAjMaxArg, JAjMaxArg, KAjMaxArg;
1832
1833 // Max Values
1834 VecMax(user->lCsi,&CsiMaxArg,&CsiMax);
1835 VecMax(user->lEta,&EtaMaxArg,&EtaMax);
1836 VecMax(user->lZet,&ZetMaxArg,&ZetMax);
1837
1838 VecMax(user->lICsi,&ICsiMaxArg,&ICsiMax);
1839 VecMax(user->lIEta,&IEtaMaxArg,&IEtaMax);
1840 VecMax(user->lIZet,&IZetMaxArg,&IZetMax);
1841
1842 VecMax(user->lJCsi,&JCsiMaxArg,&JCsiMax);
1843 VecMax(user->lJEta,&JEtaMaxArg,&JEtaMax);
1844 VecMax(user->lJZet,&JZetMaxArg,&JZetMax);
1845
1846 VecMax(user->lKCsi,&KCsiMaxArg,&KCsiMax);
1847 VecMax(user->lKEta,&KEtaMaxArg,&KEtaMax);
1848 VecMax(user->lKZet,&KZetMaxArg,&KZetMax);
1849
1850 VecMax(user->lAj,&AjMaxArg,&AjMax);
1851 VecMax(user->lIAj,&IAjMaxArg,&IAjMax);
1852 VecMax(user->lJAj,&JAjMaxArg,&JAjMax);
1853 VecMax(user->lKAj,&KAjMaxArg,&KAjMax);
1854
1855 VecMax(user->lAj,&AjMaxArg,&AjMax);
1856 VecMax(user->lIAj,&IAjMaxArg,&IAjMax);
1857 VecMax(user->lJAj,&JAjMaxArg,&JAjMax);
1858 VecMax(user->lKAj,&KAjMaxArg,&KAjMax);
1859
1860 LOG_ALLOW(GLOBAL,LOG_INFO," Metric Norms for MG level %d .\n",user->thislevel);
1861
1862 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: CsiMax = %le, EtaMax = %le, ZetMax = %le.\n",CsiMax,EtaMax,ZetMax);
1863 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: ICsiMax = %le, IEtaMax = %le, IZetMax = %le.\n",ICsiMax,IEtaMax,IZetMax);
1864 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: JCsiMax = %le, JEtaMax = %le, JZetMax = %le.\n",JCsiMax,JEtaMax,JZetMax);
1865 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Metric Values are: KCsiMax = %le, KEtaMax = %le, KZetMax = %le.\n",KCsiMax,KEtaMax,KZetMax);
1866 LOG_ALLOW(GLOBAL,LOG_INFO,"The Max Volumes(Inverse) are: Aj = %le, IAj = %le, JAj = %le, KAj = %le.\n",AjMax,IAjMax,JAjMax,KAjMax);
1867
1868 for (k=zs; k<ze; k++) {
1869 for (j=ys; j<ye; j++) {
1870 for (i=xs; i<xe; i++) {
1871 if (Gidx(i,j,k,user) == CsiMaxArg) {
1872 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Csi = %le is at [%d][%d][%d] \n", CsiMax,k,j,i);
1873 }
1874 if (Gidx(i,j,k,user) == EtaMaxArg) {
1875 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Eta = %le is at [%d][%d][%d] \n", EtaMax,k,j,i);
1876 }
1877 if (Gidx(i,j,k,user) == ZetMaxArg) {
1878 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Zet = %le is at [%d][%d][%d] \n", ZetMax,k,j,i);
1879 }
1880 if (Gidx(i,j,k,user) == ICsiMaxArg) {
1881 LOG_ALLOW(GLOBAL,LOG_INFO,"Max ICsi = %le is at [%d][%d][%d] \n", ICsiMax,k,j,i);
1882 }
1883 if (Gidx(i,j,k,user) == IEtaMaxArg) {
1884 LOG_ALLOW(GLOBAL,LOG_INFO,"Max IEta = %le is at [%d][%d][%d] \n", IEtaMax,k,j,i);
1885 }
1886 if (Gidx(i,j,k,user) == IZetMaxArg) {
1887 LOG_ALLOW(GLOBAL,LOG_INFO,"Max IZet = %le is at [%d][%d][%d] \n", IZetMax,k,j,i);
1888 }
1889 if (Gidx(i,j,k,user) == JCsiMaxArg) {
1890 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JCsi = %le is at [%d][%d][%d] \n", JCsiMax,k,j,i);
1891 }
1892 if (Gidx(i,j,k,user) == JEtaMaxArg) {
1893 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JEta = %le is at [%d][%d][%d] \n", JEtaMax,k,j,i);
1894 }
1895 if (Gidx(i,j,k,user) == JZetMaxArg) {
1896 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JZet = %le is at [%d][%d][%d] \n", JZetMax,k,j,i);
1897 }
1898 if (Gidx(i,j,k,user) == KCsiMaxArg) {
1899 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KCsi = %le is at [%d][%d][%d] \n", KCsiMax,k,j,i);
1900 }
1901 if (Gidx(i,j,k,user) == KEtaMaxArg) {
1902 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KEta = %le is at [%d][%d][%d] \n", KEtaMax,k,j,i);
1903 }
1904 if (Gidx(i,j,k,user) == KZetMaxArg) {
1905 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KZet = %le is at [%d][%d][%d] \n", KZetMax,k,j,i);
1906 }
1907 if (Gidx(i,j,k,user) == AjMaxArg) {
1908 LOG_ALLOW(GLOBAL,LOG_INFO,"Max Aj = %le is at [%d][%d][%d] \n", AjMax,k,j,i);
1909 }
1910 if (Gidx(i,j,k,user) == IAjMaxArg) {
1911 LOG_ALLOW(GLOBAL,LOG_INFO,"Max IAj = %le is at [%d][%d][%d] \n", IAjMax,k,j,i);
1912 }
1913 if (Gidx(i,j,k,user) == JAjMaxArg) {
1914 LOG_ALLOW(GLOBAL,LOG_INFO,"Max JAj = %le is at [%d][%d][%d] \n", JAjMax,k,j,i);
1915 }
1916 if (Gidx(i,j,k,user) == KAjMaxArg) {
1917 LOG_ALLOW(GLOBAL,LOG_INFO,"Max KAj = %le is at [%d][%d][%d] \n", KAjMax,k,j,i);
1918 }
1919 }
1920 }
1921 }
1922
1923 /*
1924 VecView(user->lCsi,PETSC_VIEWER_STDOUT_WORLD);
1925 VecView(user->lEta,PETSC_VIEWER_STDOUT_WORLD);
1926 VecView(user->lZet,PETSC_VIEWER_STDOUT_WORLD);
1927 */
1928
1930
1931 PetscFunctionReturn(0);
1932}
Vec lIEta
Definition variables.h:977
Vec lIZet
Definition variables.h:977
Vec lIAj
Definition variables.h:977
Vec lKEta
Definition variables.h:979
Vec lJCsi
Definition variables.h:978
Vec lKZet
Definition variables.h:979
Vec lJEta
Definition variables.h:978
Vec lKCsi
Definition variables.h:979
Vec lJZet
Definition variables.h:978
Vec lICsi
Definition variables.h:977
Vec lJAj
Definition variables.h:978
Vec lKAj
Definition variables.h:979
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

Orchestrates the calculation of all grid metrics.

Local to this translation unit.

Definition at line 1940 of file Metric.c.

1941{
1942 PetscErrorCode ierr;
1943 UserMG *usermg = &simCtx->usermg;
1944 MGCtx *mgctx = usermg->mgctx;
1945 PetscInt nblk = simCtx->block_number;
1946
1947 PetscFunctionBeginUser;
1948
1950
1951 LOG_ALLOW(GLOBAL, LOG_INFO, "Calculating grid metrics for all levels and blocks...\n");
1952
1953 // Loop through all levels and all blocks
1954 for (PetscInt level = usermg->mglevels -1 ; level >=0; level--) {
1955 for (PetscInt bi = 0; bi < nblk; bi++) {
1956 UserCtx *user = &mgctx[level].user[bi];
1957 LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Rank %d: Calculating metrics for level %d, block %d\n", simCtx->rank, level, bi);
1958
1959 // Call the modern, modular helper functions for each UserCtx.
1960 // These functions are self-contained and operate on the data within the provided context.
1961 ierr = ComputeFaceMetrics(user); CHKERRQ(ierr);
1962 ierr = ComputeCellCenteredJacobianInverse(user); CHKERRQ(ierr);
1963 ierr = CheckAndFixGridOrientation(user); CHKERRQ(ierr);
1964 ierr = ComputeCellCentersAndSpacing(user); CHKERRQ(ierr);
1965 ierr = ComputeIFaceMetrics(user); CHKERRQ(ierr);
1966 ierr = ComputeJFaceMetrics(user); CHKERRQ(ierr);
1967 ierr = ComputeKFaceMetrics(user); CHKERRQ(ierr);
1968
1969 // Apply Periodic Boundary Condition Adjustments if necessary
1970 ierr = ApplyMetricsPeriodicBCs(user); CHKERRQ(ierr);
1971 // Diagnostics
1972 ierr = ComputeMetricNorms(user);
1973 if (level == usermg->mglevels - 1) {
1974 ierr = ComputeMetricsDivergence(user); CHKERRQ(ierr);
1975 }
1976 }
1977 }
1978
1979 LOG_ALLOW(GLOBAL, LOG_INFO, "Grid metrics calculation complete.\n");
1980
1982
1983 PetscFunctionReturn(0);
1984}
PetscErrorCode ApplyMetricsPeriodicBCs(UserCtx *user)
(Orchestrator) Updates all metric-related fields in the local ghost cell regions for periodic boundar...
PetscErrorCode ComputeMetricNorms(UserCtx *user)
Internal helper implementation: ComputeMetricNorms().
Definition Metric.c:1808
PetscErrorCode CheckAndFixGridOrientation(UserCtx *user)
Internal helper implementation: CheckAndFixGridOrientation().
Definition Metric.c:313
PetscErrorCode ComputeCellCentersAndSpacing(UserCtx *user)
Internal helper implementation: ComputeCellCentersAndSpacing().
Definition Metric.c:993
PetscErrorCode ComputeJFaceMetrics(UserCtx *user)
Internal helper implementation: ComputeJFaceMetrics().
Definition Metric.c:1307
PetscErrorCode ComputeMetricsDivergence(UserCtx *user)
Internal helper implementation: ComputeMetricsDivergence().
Definition Metric.c:1716
PetscErrorCode ComputeFaceMetrics(UserCtx *user)
Internal helper implementation: ComputeFaceMetrics().
Definition Metric.c:637
PetscErrorCode ComputeCellCenteredJacobianInverse(UserCtx *user)
Implementation of ComputeCellCenteredJacobianInverse().
Definition Metric.c:849
PetscErrorCode ComputeKFaceMetrics(UserCtx *user)
Internal helper implementation: ComputeKFaceMetrics().
Definition Metric.c:1502
PetscErrorCode ComputeIFaceMetrics(UserCtx *user)
Internal helper implementation: ComputeIFaceMetrics().
Definition Metric.c:1096
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
Definition logging.h:253
UserCtx * user
Definition variables.h:571
PetscInt block_number
Definition variables.h:790
UserMG usermg
Definition variables.h:852
PetscInt mglevels
Definition variables.h:578
MGCtx * mgctx
Definition variables.h:581
Context for Multigrid operations.
Definition variables.h:570
User-defined context containing data specific to a single computational grid level.
Definition variables.h:906
User-level context for managing the entire multigrid hierarchy.
Definition variables.h:577
Here is the call graph for this function:
Here is the caller graph for this function: