PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
interpolation.h File Reference
#include <petscpf.h>
#include <petscdmswarm.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <petsctime.h>
#include <petscdmcomposite.h>
#include <petscerror.h>
#include <petscsys.h>
#include "variables.h"
#include "ParticleSwarm.h"
#include "walkingsearch.h"
#include "grid.h"
#include "logging.h"
#include "io.h"
#include "setup.h"
Include dependency graph for interpolation.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define NUM_WEIGHTS   8
 
#define InterpolateFieldFromCornerToCenter(field, centfield, user)
 Generic macro to call the appropriate interpolation function based on the field type.
 
#define InterpolateFieldFromCenterToCorner(blockSize, centfield_ptr, corner_ptr, user_ctx)
 Macro to dispatch to the correct scalar or vector center-to-corner function based on a runtime block size variable.
 
#define InterpolateCornerToFaceCenter(corner_arr, faceX_arr, faceY_arr, faceZ_arr, user_ctx)
 A type-generic macro that interpolates a field from corner nodes to all face centers.
 
#define PieceWiseLinearInterpolation(fieldName, fieldPtr, i, j, k, outPtr)
 Macro that calls either the scalar or vector piecewise interpolation function based on the type of the fieldPtr parameter (3D array).
 
#define TrilinearInterpolation(fieldName, fieldPtr, i, j, k, a1, a2, a3, outPtr)
 Macro that calls either the scalar or vector trilinear interpolation function based on the type of the fieldPtr parameter (3D array).
 

Functions

PetscErrorCode TrilinearInterpolation_Scalar (const char *fieldName, PetscReal ***fieldScal, PetscInt i, PetscInt j, PetscInt k, PetscReal a1, PetscReal a2, PetscReal a3, PetscReal *val)
 Computes the trilinear interpolated scalar at a given point.
 
PetscErrorCode TrilinearInterpolation_Vector (const char *fieldName, Cmpnts ***fieldVec, PetscInt i, PetscInt j, PetscInt k, PetscReal a1, PetscReal a2, PetscReal a3, Cmpnts *vec)
 Computes the trilinear interpolated vector (e.g., velocity) at a given point.
 
PetscErrorCode InterpolateEulerFieldToSwarm (UserCtx *user, Vec fieldLocal_cellCentered, const char *fieldName, const char *swarmOutFieldName)
 Interpolates a cell-centered field (scalar or vector) onto DMSwarm particles, using a robust, PETSc-idiomatic two-stage process.
 
PetscErrorCode InterpolateAllFieldsToSwarm (UserCtx *user)
 Interpolates all relevant fields from the DMDA to the DMSwarm.
 
PetscErrorCode InterpolateParticleVelocities (UserCtx *user)
 Interpolates particle velocities using trilinear interpolation.
 
PetscErrorCode InterpolateFieldFromCornerToCenter_Scalar (PetscReal ***field, PetscReal ***centfield, UserCtx *user)
 Safely interpolate a scalar field from corner nodes (from the coordinate DM) to cell centers (from the cell-centered DM) using the provided UserCtx.
 
PetscErrorCode InterpolateFieldFromCornerToCenter_Vector (Cmpnts ***field, Cmpnts ***centfield, UserCtx *user)
 Safely interpolate a vector field from corner nodes (from the coordinate DM) to cell centers (from the cell-centered DM) using the provided UserCtx.
 
PetscErrorCode TestCornerToCenterInterpolation (UserCtx *user)
 Tests the InterpolateFieldFromCornerToCenter function by reproducing the Cent vector.
 
PetscErrorCode InterpolateFieldFromCenterToCorner_Vector (Cmpnts ***centfield_arr, Cmpnts ***corner_arr, UserCtx *user)
 Interpolates a vector field from cell centers to corner nodes.
 
PetscErrorCode InterpolateFieldFromCenterToCorner_Scalar (PetscReal ***centfield_arr, PetscReal ***corner_arr, UserCtx *user)
 Interpolates a scalar field from cell centers to corner nodes.
 
PetscErrorCode GetScatterTargetInfo (UserCtx *user, const char *particleFieldName, DM *targetDM, PetscInt *expected_dof)
 Determines the target Eulerian DM and expected DOF for scattering a given particle field.
 
PetscErrorCode GetPersistentLocalVector (UserCtx *user, const char *fieldName, Vec *localVec)
 Retrieves the persistent local vector (e.g., lPsi, lUcat) for a given field name.
 
PetscErrorCode AccumulateParticleField (DM swarm, const char *particleFieldName, DM gridSumDM, Vec gridSumVec)
 Accumulates a particle field (scalar or vector) into a target grid sum vector.
 
PetscErrorCode NormalizeGridVectorByCount (DM countDM, Vec countVec, DM dataDM, Vec sumVec, Vec avgVec)
 Normalizes a grid vector of sums by a grid vector of counts to produce an average.
 
PetscErrorCode ScatterParticleFieldToEulerField (UserCtx *user, const char *particleFieldName, Vec eulerFieldAverageVec)
 Scatters a particle field (scalar or vector) to the corresponding Eulerian field average.
 
PetscErrorCode ScatterAllParticleFieldsToEulerFields (UserCtx *user)
 Scatters a predefined set of particle fields to their corresponding Eulerian fields.
 
PetscErrorCode InterpolateCornerToFaceCenter_Scalar (PetscReal ***corner_arr, PetscReal ***faceX_arr, PetscReal ***faceY_arr, PetscReal ***faceZ_arr, UserCtx *user)
 Interpolates a scalar field from corner nodes to all face centers.
 
PetscErrorCode InterpolateCornerToFaceCenter_Vector (Cmpnts ***corner_arr, Cmpnts ***faceX_arr, Cmpnts ***faceY_arr, Cmpnts ***faceZ_arr, UserCtx *user)
 Interpolates a vector field from corner nodes to all face centers.
 

Macro Definition Documentation

◆ NUM_WEIGHTS

#define NUM_WEIGHTS   8

Definition at line 24 of file interpolation.h.

◆ InterpolateFieldFromCornerToCenter

#define InterpolateFieldFromCornerToCenter (   field,
  centfield,
  user 
)
Value:
( (void)sizeof(char[1 - 2*!!(!__builtin_types_compatible_p(typeof(field), typeof(centfield)))]),\
_Generic((field), \
)(field, centfield, user) )
PetscErrorCode InterpolateFieldFromCornerToCenter_Vector(Cmpnts ***field, Cmpnts ***centfield, UserCtx *user)
Safely interpolate a vector field from corner nodes (from the coordinate DM) to cell centers (from th...
PetscErrorCode InterpolateFieldFromCornerToCenter_Scalar(PetscReal ***field, PetscReal ***centfield, UserCtx *user)
Safely interpolate a scalar field from corner nodes (from the coordinate DM) to cell centers (from th...
A 3D point or vector with PetscScalar components.
Definition variables.h:100

Generic macro to call the appropriate interpolation function based on the field type.

This macro will select either the scalar or vector interpolation function based on the type of the 'field' pointer. It also performs a compile-time check that 'centfield' is of the same type as 'field'. If the types are not the same, a compile-time error is produced.

Usage: InterpolateFieldFromCornerToCenter(field, centfield, user);

Definition at line 36 of file interpolation.h.

◆ InterpolateFieldFromCenterToCorner

#define InterpolateFieldFromCenterToCorner (   blockSize,
  centfield_ptr,
  corner_ptr,
  user_ctx 
)
Value:
( (blockSize) == 1 ? \
InterpolateFieldFromCenterToCorner_Scalar((PetscReal***)(centfield_ptr), (PetscReal***)(corner_ptr), (user_ctx)) : \
InterpolateFieldFromCenterToCorner_Vector((Cmpnts***)(centfield_ptr), (Cmpnts***)(corner_ptr), (user_ctx)) \
)
PetscErrorCode InterpolateFieldFromCenterToCorner_Vector(Cmpnts ***centfield_arr, Cmpnts ***corner_arr, UserCtx *user)
Interpolates a vector field from cell centers to corner nodes.
PetscErrorCode InterpolateFieldFromCenterToCorner_Scalar(PetscReal ***centfield_arr, PetscReal ***corner_arr, UserCtx *user)
Interpolates a scalar field from cell centers to corner nodes.

Macro to dispatch to the correct scalar or vector center-to-corner function based on a runtime block size variable.

This macro uses a ternary operator to inspect the runtime value of 'blockSize' and select the appropriate implementation. It expects the input and output pointers to be void* and handles casting them to the correct, strongly-typed pointers.

Parameters
blockSizeThe runtime block size (1 for scalar, 3 for vector).
centfield_ptrThe input void* pointer to the 3D cell-centered data array.
corner_ptrThe output void* pointer to the 3D corner data array.
user_ctxThe UserCtx structure.

Definition at line 56 of file interpolation.h.

58 : \
59 InterpolateFieldFromCenterToCorner_Vector((Cmpnts***)(centfield_ptr), (Cmpnts***)(corner_ptr), (user_ctx)) \
60 )

◆ InterpolateCornerToFaceCenter

#define InterpolateCornerToFaceCenter (   corner_arr,
  faceX_arr,
  faceY_arr,
  faceZ_arr,
  user_ctx 
)
Value:
_Generic((corner_arr), \
)(corner_arr, faceX_arr, faceY_arr, faceZ_arr, user_ctx)
PetscErrorCode InterpolateCornerToFaceCenter_Vector(Cmpnts ***corner_arr, Cmpnts ***faceX_arr, Cmpnts ***faceY_arr, Cmpnts ***faceZ_arr, UserCtx *user)
Interpolates a vector field from corner nodes to all face centers.
PetscErrorCode InterpolateCornerToFaceCenter_Scalar(PetscReal ***corner_arr, PetscReal ***faceX_arr, PetscReal ***faceY_arr, PetscReal ***faceZ_arr, UserCtx *user)
Interpolates a scalar field from corner nodes to all face centers.

A type-generic macro that interpolates a field from corner nodes to all face centers.

This macro uses C11's _Generic feature to dispatch to the appropriate underlying function based on the type of the input corner_arr.

  • If corner_arr is of type PetscReal***, it calls InterpolateCornerToFaceCenter_Scalar.
  • If corner_arr is of type Cmpnts***, it calls InterpolateCornerToFaceCenter_Vector.
Parameters
corner_arrGhosted node-centered array (global indexing). The type of this argument determines which function is called.
faceX_arrLocal array for X-faces.
faceY_arrLocal array for Y-faces.
faceZ_arrLocal array for Z-faces.
user_ctxUser context containing DMDA 'fda'.

Definition at line 79 of file interpolation.h.

83 )(corner_arr, faceX_arr, faceY_arr, faceZ_arr, user_ctx)

◆ PieceWiseLinearInterpolation

#define PieceWiseLinearInterpolation (   fieldName,
  fieldPtr,
  i,
  j,
  k,
  outPtr 
)
Value:
_Generic((fieldPtr), \
)(fieldName, fieldPtr, i, j, k, outPtr)
PetscErrorCode PieceWiseLinearInterpolation_Scalar(const char *fieldName, PetscReal ***fieldScal, PetscInt iCell, PetscInt jCell, PetscInt kCell, PetscReal *val)
Retrieves the scalar value at the cell (iCell, jCell, kCell).
PetscErrorCode PieceWiseLinearInterpolation_Vector(const char *fieldName, Cmpnts ***fieldVec, PetscInt iCell, PetscInt jCell, PetscInt kCell, Cmpnts *vec)
Retrieves the vector (Cmpnts) at the cell (iCell, jCell, kCell).

Macro that calls either the scalar or vector piecewise interpolation function based on the type of the fieldPtr parameter (3D array).

Usage example:

// For scalar: PetscReal ***fieldScal; PetscReal outVal; PieceWiseLinearInterpolation(fieldName, fieldScal, i, j, k, &outVal);

// For vector: Cmpnts ***fieldVec; Cmpnts vec; PieceWiseLinearInterpolation(fieldName, fieldVec, i, j, k, &vec);

Definition at line 101 of file interpolation.h.

105 )(fieldName, fieldPtr, i, j, k, outPtr)

◆ TrilinearInterpolation

#define TrilinearInterpolation (   fieldName,
  fieldPtr,
  i,
  j,
  k,
  a1,
  a2,
  a3,
  outPtr 
)
Value:
_Generic((fieldPtr), \
)(fieldName, fieldPtr, i, j, k, a1, a2, a3, outPtr)
PetscErrorCode TrilinearInterpolation_Vector(const char *fieldName, Cmpnts ***fieldVec, PetscInt i, PetscInt j, PetscInt k, PetscReal a1, PetscReal a2, PetscReal a3, Cmpnts *vec)
Computes the trilinear interpolated vector (e.g., velocity) at a given point.
PetscErrorCode TrilinearInterpolation_Scalar(const char *fieldName, PetscReal ***fieldScal, PetscInt i, PetscInt j, PetscInt k, PetscReal a1, PetscReal a2, PetscReal a3, PetscReal *val)
Computes the trilinear interpolated scalar at a given point.

Macro that calls either the scalar or vector trilinear interpolation function based on the type of the fieldPtr parameter (3D array).

Usage example:

PetscReal result; Cmpnts vec;

// For scalars: TrilinearInterpolation(fieldName, fieldScal, i, j, k, a1, a2, a3, &result);

// For vectors: TrilinearInterpolation(fieldName, fieldVec, i, j, k, a1, a2, a3, &vec);

Definition at line 122 of file interpolation.h.

126 )(fieldName, fieldPtr, i, j, k, a1, a2, a3, outPtr)

Function Documentation

◆ TrilinearInterpolation_Scalar()

PetscErrorCode TrilinearInterpolation_Scalar ( const char *  fieldName,
PetscReal ***  fieldScal,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscReal  a1,
PetscReal  a2,
PetscReal  a3,
PetscReal *  val 
)

Computes the trilinear interpolated scalar at a given point.

Parameters
[in]fieldNameA string representing the name of the scalar field (e.g., "temperature").
[in]fieldScal3D array of the field from a DMDA (indexed as [k][j][i]), each cell a PetscReal.
[in]i,j,kIntegral cell indices (the "lower" corner in each dimension).
[in]a1,a2,a3Normalized coordinates within the cell ([0,1] range).
[out]valPointer to a PetscReal that will store the interpolated scalar.

This function uses the standard 8-corner trilinear formula via ComputeTrilinearWeights(). If a different scheme is desired, implement a new function with the same interface.

Computes the trilinear interpolated scalar at a given point.

Parameters
[in]fieldNameA string representing the name of the scalar field (e.g., "temperature").
[in]fieldScal3D array of the field from a DMDA (indexed as [k][j][i]), each cell a PetscReal.
[in]i,j,kIntegral cell indices (the "lower" corner in each dimension).
[in]a1,a2,a3Normalized coordinates within the cell ([0,1] range).
[out]valPointer to a PetscReal that will store the Interpolateted scalar.

This function uses the standard 8-corner trilinear formula via ComputeTrilinearWeights(). If a different scheme is desired, implement a new function with the same PetscInterface.

Definition at line 661 of file interpolation.c.

671{
672 PetscFunctionBegin; // PETSc macro for error/stack tracing
673
674 // Compute the 8 corner weights
675 PetscReal wcorner[8];
676 ComputeTrilinearWeights(a1, a2, a3, wcorner);
677
678 // Offsets for cell corners
679 PetscInt i1 = i + 1;
680 PetscInt j1 = j + 1;
681 PetscInt k1 = k + 1;
682
683 // Initialize the output scalar
684 PetscReal sum = 0.0;
685
686 // Corner 0 => (i, j, k)
687 sum += wcorner[0] * fieldScal[k ][j ][i ];
688 // Corner 1 => (i+1, j, k)
689 sum += wcorner[1] * fieldScal[k ][j ][i1];
690 // Corner 2 => (i, j+1, k)
691 sum += wcorner[2] * fieldScal[k ][j1][i ];
692 // Corner 3 => (i+1, j+1, k)
693 sum += wcorner[3] * fieldScal[k ][j1][i1];
694 // Corner 4 => (i, j, k+1)
695 sum += wcorner[4] * fieldScal[k1][j ][i ];
696 // Corner 5 => (i+1, j, k+1)
697 sum += wcorner[5] * fieldScal[k1][j ][i1];
698 // Corner 6 => (i, j+1, k+1)
699 sum += wcorner[6] * fieldScal[k1][j1][i ];
700 // Corner 7 => (i+1, j+1, k+1)
701 sum += wcorner[7] * fieldScal[k1][j1][i1];
702
703 *val = sum;
704
705 // Logging (optional)
707 "Field '%s' at (i=%d, j=%d, k=%d), "
708 "a1=%.6f, a2=%.6f, a3=%.6f -> val=%.6f.\n",
709 fieldName, i, j, k, a1, a2, a3, *val);
710
711 // LOG_ALLOW_SYNC(GLOBAL, LOG_INFO,
712 // "TrilinearInterpolation_Scalar: Completed interpolation for field '%s' across local cells.\n",
713 // fieldName);
714
715 PetscFunctionReturn(0);
716}
static void ComputeTrilinearWeights(PetscReal a1, PetscReal a2, PetscReal a3, PetscReal *w)
Computes the trilinear interpolation weights from the interpolation coefficients.
#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_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:34
Here is the call graph for this function:

◆ TrilinearInterpolation_Vector()

PetscErrorCode TrilinearInterpolation_Vector ( const char *  fieldName,
Cmpnts ***  fieldVec,
PetscInt  i,
PetscInt  j,
PetscInt  k,
PetscReal  a1,
PetscReal  a2,
PetscReal  a3,
Cmpnts vec 
)

Computes the trilinear interpolated vector (e.g., velocity) at a given point.

Parameters
[in]fieldNameA string representing the name of the vector field (e.g., "velocity").
[in]fieldVec3D array of the field from a DMDA (indexed as [k][j][i]), each cell of type Cmpnts.
[in]i,j,kIntegral cell indices (the "lower" corner in each dimension).
[in]a1,a2,a3Normalized coordinates within the cell ([0,1] range).
[out]vecPointer to a Cmpnts struct that will store the interpolated vector (x, y, z).

This function uses the standard 8-corner trilinear formula via ComputeTrilinearWeights(). If a different scheme is desired, implement a new function with the same interface.

Computes the trilinear interpolated vector (e.g., velocity) at a given point.

Parameters
[in]fieldNameA string representing the name of the vector field (e.g., "velocity").
[in]fieldVec3D array of the field from a DMDA (indexed as [k][j][i]), each cell of type Cmpnts.
[in]i,j,kIntegral cell indices (the "lower" corner in each dimension).
[in]a1,a2,a3Normalized coordinates within the cell ([0,1] range).
[out]vecPointer to a Cmpnts struct that will store the Interpolateted vector (x, y, z).

This function uses the standard 8-corner trilinear formula via ComputeTrilinearWeights(). If a different scheme is desired, implement a new function with the same PetscInterface.

Computes the trilinear Interpolateted vector at a given point, with partial weighting if corners go out of range.

If any of the 8 corners (i or i+1, j or j+1, k or k+1) is out of [0..mx), [0..my), [0..mz), that corner is skipped and the corresponding weight is omitted. The total is normalized by the sum of used weights, so we get a partial interpolation near boundaries.

Definition at line 741 of file interpolation.c.

751{
752 PetscFunctionBegin; // PETSc macro for error/stack tracing
753
754 // Compute the 8 corner weights
755 PetscErrorCode ierr;
756 PetscReal wcorner[8];
757 PetscMPIInt rank;
758
759 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);
760
761 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d] Computing Trilinear Weights.\n",rank);
762 ComputeTrilinearWeights(a1, a2, a3, wcorner);
763
764 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d] Trilinear weights computed for local cell %d,%d,%d.\n",rank,i,j,k);
765
766 // For partial interpolation, we'll keep track of how many corners are valid
767 // and how much sum of weights is used. Then we do a final normalization.
768 PetscReal sumW = 0.0;
769 Cmpnts accum = {0.0, 0.0, 0.0};
770
771 // The eight corner indices, with their weights:
772 // corners: (i,j,k), (i+1,j,k), (i,j+1,k), (i+1,j+1,k), etc.
773 // We store them in an array to iterate cleanly.
774 const PetscInt cornerOffsets[8][3] = {
775 {0, 0, 0},
776 {1, 0, 0},
777 {0, 1, 0},
778 {1, 1, 0},
779 {0, 0, 1},
780 {1, 0, 1},
781 {0, 1, 1},
782 {1, 1, 1}
783 };
784
785 // Weighted partial sum
786 for (PetscInt c = 0; c < 8; c++) {
787 const PetscInt di = cornerOffsets[c][0];
788 const PetscInt dj = cornerOffsets[c][1];
789 const PetscInt dk = cornerOffsets[c][2];
790 PetscInt iC = i + di;
791 PetscInt jC = j + dj;
792 PetscInt kC = k + dk;
793
794 /*
795 // skip if out of domain
796 // (Assuming you know global domain is [0..mx), [0..my), [0..mz).)
797 if (iC < 0 || iC >= (PetscInt)userGlobalMx ||
798 jC < 0 || jC >= (PetscInt)userGlobalMy ||
799 kC < 0 || kC >= (PetscInt)userGlobalMz)
800 {
801 // skip this corner
802 continue;
803 }
804
805 */
806
807 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d] %s[%d][%d][%d] = (%.4f,%.4f,%.4f).\n",rank,fieldName,kC,jC,iC,fieldVec[kC][jC][iC].x,fieldVec[kC][jC][iC].y,fieldVec[kC][jC][iC].z);
808
809 // Otherwise, accumulate
810 accum.x += wcorner[c] * fieldVec[kC][jC][iC].x;
811 accum.y += wcorner[c] * fieldVec[kC][jC][iC].y;
812 accum.z += wcorner[c] * fieldVec[kC][jC][iC].z;
813 sumW += wcorner[c];
814 }
815
816 // If sumW=0 => out-of-range or zero weighting => set (0,0,0)
817 if (sumW > 1.0e-14) {
818 vec->x = accum.x / sumW;
819 vec->y = accum.y / sumW;
820 vec->z = accum.z / sumW;
821 } else {
822 vec->x = 0.0; vec->y = 0.0; vec->z = 0.0;
823 }
824
825 PetscFunctionReturn(0);
826}
PetscScalar x
Definition variables.h:101
PetscScalar z
Definition variables.h:101
PetscScalar y
Definition variables.h:101
Here is the call graph for this function:

◆ InterpolateEulerFieldToSwarm()

PetscErrorCode InterpolateEulerFieldToSwarm ( UserCtx user,
Vec  fieldLocal_cellCentered,
const char *  fieldName,
const char *  swarmOutFieldName 
)

Interpolates a cell-centered field (scalar or vector) onto DMSwarm particles, using a robust, PETSc-idiomatic two-stage process.

This function first converts the cell-centered input data to corner-node data, storing this intermediate result in a PETSc Vec to correctly handle the communication of ghost-point information across parallel ranks. It then performs a final trilinear interpolation from the ghosted corner data to each particle's location.

Workflow:

  1. Create temporary PETSc Vecs (cornerGlobal, cornerLocal) to manage the intermediate corner-node data, using the existing nodal DMDA (user->fda).
  2. Call a dispatch macro that uses the runtime block size (bs) to select the correct underlying center-to-corner function, writing results into cornerGlobal.
  3. Perform a ghost-point exchange (DMGlobalToLocal) to transfer the boundary data from cornerGlobal into the ghost regions of cornerLocal.
  4. Loop over all local particles. For each particle: a. Convert its global cell index to a local index relative to the ghosted array. b. Check if the particle's interpolation stencil is fully contained within the owned+ghost region. If not, log a warning and set the result to zero. c. Perform the final trilinear interpolation using the ghosted cornerLocal data.
  5. Restore all PETSc objects to prevent memory leaks.
Parameters
[in]userUser context with DMDA, DMSwarm, etc.
[in]fieldGlobal_cellCenteredVec (from fda) with cell-centered data (e.g., Ucat).
[in]fieldNameHuman-readable field name for logging (e.g., "Ucat").
[in]swarmOutFieldNameName of the DMSwarm field where interpolation results go.
Returns
PetscErrorCode 0 on success.

This function first converts the cell-centered input data to corner-node data, storing this intermediate result in a PETSc Vec to correctly handle the communication of ghost-point information across parallel ranks. It then performs a final trilinear interpolation from the ghosted corner data to each particle's location.

Workflow:

  1. Create temporary PETSc Vecs (cornerGlobal, cornerLocal) to manage the intermediate corner-node data, using the existing nodal DMDA (user->fda).
  2. Call a dispatch macro that uses the runtime block size (bs) to select the correct underlying center-to-corner function, writing results into cornerGlobal.
  3. Perform a ghost-point exchange (DMGlobalToLocal) to transfer the boundary data from cornerGlobal into the ghost regions of cornerLocal.
  4. Loop over all local particles. For each particle: a. Convert its global cell index to a local index relative to the ghosted array. b. Check if the particle's interpolation stencil is fully contained within the owned+ghost region. If not, log a warning and set the result to zero. c. Perform the final trilinear interpolation using the ghosted cornerLocal data.
  5. Restore all PETSc objects to prevent memory leaks.
Parameters
[in]userUser context with DMDA, DMSwarm, etc.
[in]fieldlocal_cellCenteredVec (from fda) with cell-centered data (e.g., Ucat).
[in]fieldNameHuman-readable field name for logging (e.g., "Ucat").
[in]swarmOutFieldNameName of the DMSwarm field where interpolation results go.
Returns
PetscErrorCode 0 on success.

Definition at line 997 of file interpolation.c.

1002{
1003 PetscErrorCode ierr;
1004 DM fda = user->fda;
1005 DM swarm = user->swarm;
1006 PetscInt bs;
1007 DMDALocalInfo info;
1008 PetscMPIInt rank;
1009
1010 // Generic pointers to the raw data arrays
1011 void *cellCenterPtr_read;
1012 void *cornerPtr_read_with_ghosts;
1013
1014 // Swarm-related pointers
1015 PetscInt *cellIDs = NULL;
1016 PetscReal *weights = NULL;
1017 PetscInt64 *pids = NULL; // For logging particle IDs in warnings
1018 void *swarmOut = NULL;
1019 PetscReal *pos = NULL;
1020 PetscInt *status = NULL;
1021 PetscInt nLocal;
1022
1023 PetscFunctionBegin;
1025 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1026 ierr = DMDAGetLocalInfo(fda, &info); CHKERRQ(ierr);
1027 ierr = VecGetBlockSize(fieldLocal_cellCentered, &bs); CHKERRQ(ierr);
1028 if (bs != 1 && bs != 3) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "BlockSize must be 1 or 3.");
1029
1030 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting for field '%s'... \n", fieldName);
1031 // Select the appropriate DM for intermediate corner data based on block size
1032 DM dm_corner = (bs == 3) ? user->fda : user->da;
1033
1034 /* STAGE 1: Center-to-Corner Calculation with Communication */
1035
1036 // (A) Create or reuse the corner vectors.
1037 if(user->CellFieldAtCorner){
1038 PetscInt cached_bs;
1039 ierr = VecGetBlockSize(user->CellFieldAtCorner, &cached_bs); CHKERRQ(ierr);
1040 if(cached_bs != bs){
1041 LOG_ALLOW(LOCAL, LOG_WARNING, "[Rank %d] Block size mismatch for existing corner vector and current field %s(Cached: %d, New: %d). Replacing.\n", rank, fieldName, cached_bs, bs);
1042 ierr = VecDestroy(&user->CellFieldAtCorner); CHKERRQ(ierr);
1043 ierr = VecDestroy(&user->lCellFieldAtCorner); CHKERRQ(ierr);
1044 user->CellFieldAtCorner = NULL;
1045 user->lCellFieldAtCorner = NULL;
1046 }
1047 }
1048
1049 if(user->CellFieldAtCorner == NULL){
1050 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Creating new global corner vector for field '%s'.\n", rank, fieldName);
1051 ierr = DMCreateGlobalVector(dm_corner, &user->CellFieldAtCorner); CHKERRQ(ierr);
1052 }else{
1053 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Reusing existing global corner vector for field '%s'.\n", rank, fieldName);
1054 }
1055
1056 ierr = VecSet(user->CellFieldAtCorner,0.0); CHKERRQ(ierr);
1057 Vec cornerGlobal = user->CellFieldAtCorner;
1058
1059 if(user->lCellFieldAtCorner == NULL){
1060 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Creating new local corner vector for field '%s'.\n", rank, fieldName);
1061 ierr = DMCreateLocalVector(dm_corner, &user->lCellFieldAtCorner); CHKERRQ(ierr);
1062 }else{
1063 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Reusing existing local corner vector for field '%s'.\n", rank, fieldName);
1064 }
1065
1066 ierr = VecSet(user->lCellFieldAtCorner,0.0); CHKERRQ(ierr);
1067 Vec cornerLocal = user->lCellFieldAtCorner;
1068
1069 // (B) Get a read-only array from the input cell-centered vector
1070 ierr = DMDAVecGetArrayRead(dm_corner, fieldLocal_cellCentered, &cellCenterPtr_read); CHKERRQ(ierr);
1071
1072 PetscInt size;
1073 ierr = VecGetSize(cornerGlobal, &size); CHKERRQ(ierr);
1074 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Corner global vector size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1075
1076 size = 0;
1077
1078 ierr = VecGetSize(cornerLocal, &size); CHKERRQ(ierr);
1079 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Corner local vector size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1080
1081 size = 0;
1082
1083 ierr = VecGetSize(fieldLocal_cellCentered, &size); CHKERRQ(ierr);
1084 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Cell-centered local vector size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1085
1086 PetscInt xs,ys,zs,gxs,gys,gzs;
1087
1088 ierr = DMDAGetCorners(dm_corner,&xs,&ys,&zs,NULL,NULL,NULL); CHKERRQ(ierr);
1089 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] DMDAGetCorners for field '%s': xs=%d, ys=%d, zs=%d.\n", rank, fieldName, (PetscInt)xs, (PetscInt)ys, (PetscInt)zs);
1090
1091 ierr = DMDAGetGhostCorners(dm_corner,&gxs,&gys,&gzs,NULL,NULL,NULL); CHKERRQ(ierr);
1092 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] DMDAGetGhostCorners for field '%s': gxs=%d, gys=%d, gzs=%d.\n", rank, fieldName, (PetscInt)gxs, (PetscInt)gys, (PetscInt)gzs);
1093
1094 // DEBUG: Inspect Ucat ghost cells before interpolation
1095 /*
1096 if (bs == 3) {
1097 Cmpnts ***ucat_array = (Cmpnts***)cellCenterPtr_read;
1098 DMDALocalInfo info_debug;
1099 ierr = DMDAGetLocalInfo(fda, &info_debug); CHKERRQ(ierr);
1100
1101 // Only print on rank 0 to avoid clutter
1102 if (rank == 0) {
1103 PetscPrintf(PETSC_COMM_SELF, "\nDEBUG: Inspecting Ucat Ghost Cells...\n");
1104 PetscPrintf(PETSC_COMM_SELF, "--------------------------------------------------\n");
1105
1106 // --- Check the MINIMUM-SIDE (-Xi) ---
1107 // The first physical cell is at index info.xs (local index).
1108 // The first ghost cell is at info.xs - 1.
1109 PetscInt i_first_phys = info_debug.xs;
1110 PetscInt i_first_ghost = info_debug.xs - 1;
1111 PetscInt j_mid = info_debug.ys + info_debug.ym / 2;
1112 PetscInt k_mid = info_debug.zs + info_debug.zm / 2;
1113
1114 PetscPrintf(PETSC_COMM_SELF, "MIN-SIDE (-Xi):\n");
1115 PetscPrintf(PETSC_COMM_SELF, " Ghost Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1116 k_mid, j_mid, i_first_ghost,
1117 ucat_array[k_mid][j_mid][i_first_ghost].x,
1118 ucat_array[k_mid][j_mid][i_first_ghost].y,
1119 ucat_array[k_mid][j_mid][i_first_ghost].z);
1120 PetscPrintf(PETSC_COMM_SELF, " First Phys Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1121 k_mid, j_mid, i_first_phys,
1122 ucat_array[k_mid][j_mid][i_first_phys].x,
1123 ucat_array[k_mid][j_mid][i_first_phys].y,
1124 ucat_array[k_mid][j_mid][i_first_phys].z);
1125
1126
1127 // --- Check the MAXIMUM-SIDE (+Xi) ---
1128 // The last physical cell is at index info.xs + info.xm - 1.
1129 // The first ghost cell on the max side is at info.xs + info.xm.
1130 PetscInt i_last_phys = info_debug.xs + info_debug.xm - 1;
1131 PetscInt i_last_ghost = info_debug.xs + info_debug.xm;
1132
1133 PetscPrintf(PETSC_COMM_SELF, "MAX-SIDE (+Xi):\n");
1134 PetscPrintf(PETSC_COMM_SELF, " Last Phys Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1135 k_mid, j_mid, i_last_phys,
1136 ucat_array[k_mid][j_mid][i_last_phys].x,
1137 ucat_array[k_mid][j_mid][i_last_phys].y,
1138 ucat_array[k_mid][j_mid][i_last_phys].z);
1139 PetscPrintf(PETSC_COMM_SELF, " Ghost Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1140 k_mid, j_mid, i_last_ghost,
1141 ucat_array[k_mid][j_mid][i_last_ghost].x,
1142 ucat_array[k_mid][j_mid][i_last_ghost].y,
1143 ucat_array[k_mid][j_mid][i_last_ghost].z);
1144 PetscPrintf(PETSC_COMM_SELF, "--------------------------------------------------\n\n");
1145 }
1146 }
1147 */
1148 // DEBUG
1149
1150 // (C) Perform the center-to-corner interpolation directly into the global corner vector
1151 void *cornerPtr_write = NULL;
1152 ierr = DMDAVecGetArray(dm_corner, cornerGlobal, &cornerPtr_write); CHKERRQ(ierr);
1153
1154 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Starting center-to-corner interpolation for '%s'.\n", rank, fieldName);
1155
1156 // SINGLE, CLEAN CALL SITE: The macro handles the runtime dispatch based on 'bs'.
1157 ierr = InterpolateFieldFromCenterToCorner(bs, cellCenterPtr_read, cornerPtr_write, user); CHKERRQ(ierr);
1158
1159 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Finished center-to-corner interpolation for '%s'.\n", rank, fieldName);
1160 ierr = DMDAVecRestoreArray(dm_corner, cornerGlobal, &cornerPtr_write); CHKERRQ(ierr);
1161
1162 ierr = DMDAVecRestoreArrayRead(dm_corner, fieldLocal_cellCentered, &cellCenterPtr_read); CHKERRQ(ierr);
1163
1164 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
1165
1166 //////////// DEBUG
1167 /*
1168 // Log a synchronized header message from all ranks.
1169 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Dumping cornerGlobal BEFORE ghost exchange...\n");
1170
1171 // VecView prints to a PETSc viewer. PETSC_VIEWER_STDOUT_WORLD is a global, synchronized viewer.
1172 // We only need to call it if logging is active for this function.
1173 if (is_function_allowed(__func__) && (int)(LOG_DEBUG) <= (int)get_log_level()) {
1174 ierr = VecView(cornerGlobal, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
1175 }
1176
1177 // Log a synchronized footer message.
1178 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Finished dumping cornerGlobal.\n");
1179 */
1180 ////////// DEBUG
1181
1182 // ierr = PetscBarrier((PetscObject)cornerGlobal); CHKERRQ(ierr);
1183
1184 // (D) CRITICAL STEP: Communicate the newly computed corner data to fill ghost regions
1185 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Beginning ghost exchange for corner data...\n", rank);
1186
1187 ierr = DMGlobalToLocalBegin(dm_corner, cornerGlobal, INSERT_VALUES, cornerLocal); CHKERRQ(ierr);
1188 ierr = DMGlobalToLocalEnd(dm_corner, cornerGlobal, INSERT_VALUES, cornerLocal); CHKERRQ(ierr);
1189
1190 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Ghost exchange for corner data complete.\n", rank);
1191
1192 LOG_ALLOW_SYNC(GLOBAL, LOG_VERBOSE, "getting array from %s on all ranks.\n", dm_corner == user->fda ? "fda" : "da");
1193 if (is_function_allowed(__func__) && (int)(LOG_VERBOSE) <= (int)get_log_level()) {
1194 // DEBUG: Inspect cornerLocal after ghost exchange
1195
1196 ierr = LOG_FIELD_ANATOMY(user,"CornerField", "After Corner Velocity Interpolated"); CHKERRQ(ierr);
1197
1198 // DEBUG
1199 //ierr = DMView(user->fda, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
1200 }
1201
1202 /////// DEBUG
1203 /*
1204 // Log a synchronized header message from all ranks.
1205 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Dumping cornerLocal AFTER ghost exchange...\n");
1206
1207 // Here, we want each rank to print its own local vector.
1208 // PETSC_VIEWER_STDOUT_SELF is the correct tool for this. The LOG_ALLOW_SYNC
1209 // wrapper will ensure the output from each rank is printed sequentially.
1210 if (is_function_allowed(__func__) && (int)(LOG_DEBUG) <= (int)get_log_level()) {
1211 PetscMPIInt rank_d;
1212 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank_d); CHKERRQ(ierr);
1213
1214 // Use a synchronized print to create a clean header for each rank's output
1215 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "\n--- cornerLocal (Rank %d) ---\n", rank_d);
1216 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT);
1217
1218 // Print the local vector's contents for this rank
1219 ierr = VecView(cornerLocal, PETSC_VIEWER_STDOUT_SELF); CHKERRQ(ierr);
1220
1221 // Use a synchronized print to create a clean footer
1222 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--- End cornerLocal (Rank %d) ---\n", rank_d);
1223 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT);
1224 }
1225
1226 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Finished dumping cornerLocal.\n");
1227 */
1228 ///// DEBUG
1229
1230 // STAGE 2: Particle Interpolation using Ghosted Corner Data */
1231
1232 // (E) Get the local, GHOSTED array of corner data for the final interpolation step
1233 ierr = DMDAVecGetArrayRead(dm_corner, cornerLocal, &cornerPtr_read_with_ghosts); CHKERRQ(ierr);
1234
1235 // (F) Retrieve swarm fields for the particle loop
1236 ierr = DMSwarmGetLocalSize(swarm, &nLocal); CHKERRQ(ierr);
1237 ierr = DMSwarmGetField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
1238 ierr = DMSwarmGetField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&pids); CHKERRQ(ierr);
1239 ierr = DMSwarmGetField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
1240 ierr = DMSwarmGetField(swarm, "position", NULL, NULL, (void**)&pos); CHKERRQ(ierr);
1241 ierr = DMSwarmGetField(swarm, "DMSwarm_location_status", NULL, NULL, (void**)&status); CHKERRQ(ierr);
1242 ierr = DMSwarmGetField(swarm, swarmOutFieldName, NULL, NULL, &swarmOut); CHKERRQ(ierr);
1243
1244 LOG_ALLOW(LOCAL,LOG_TRACE," Rank %d holds data upto & including %d,%d,%d.\n",rank,info.gxs + info.gxm,info.gys+info.gym,info.gzs+info.gzm);
1245
1246 // (G) Loop over each local particle
1247 for (PetscInt p = 0; p < nLocal; p++) {
1248
1249 Particle particle;
1250
1251 ierr = UnpackSwarmFields(p,pids,weights,pos,cellIDs,NULL,status,NULL,NULL,NULL,&particle); CHKERRQ(ierr);
1252
1254 "[Rank %d] Particle PID %lld: global cell=(%d,%d,%d), weights=(%.4f,%.4f,%.4f)\n",
1255 rank, (long long)particle.PID, particle.cell[0], particle.cell[1], particle.cell[2],
1256 particle.weights.x, particle.weights.y, particle.weights.z);
1257 // Safety check: Ensure the entire 8-node stencil is within the valid memory
1258 // region (owned + ghosts) of the local array.
1259
1260 if (particle.cell[0] < info.gxs || particle.cell[0] >= info.gxs + info.gxm - 1 ||
1261 particle.cell[1] < info.gys || particle.cell[1] >= info.gys + info.gym - 1 ||
1262 particle.cell[2] < info.gzs || particle.cell[2] >= info.gzs + info.gzm - 1)
1263 {
1265 "[Rank %d] Particle PID %lld in global cell (%d,%d,%d) is in an un-interpolatable region (requires ghosts of ghosts or is out of bounds). Zeroing field '%s'.\n",
1266 rank, (long long)particle.PID, particle.cell[0], particle.cell[1], particle.cell[2], fieldName);
1267 if (bs == 3) {
1268 ((PetscReal*)swarmOut)[3*p + 0] = 0.0;
1269 ((PetscReal*)swarmOut)[3*p + 1] = 0.0;
1270 ((PetscReal*)swarmOut)[3*p + 2] = 0.0;
1271 } else {
1272 ((PetscReal*)swarmOut)[p] = 0.0;
1273 }
1274 continue;
1275 }
1276
1278 fieldName,
1279 cornerPtr_read_with_ghosts,
1280 &particle,
1281 swarmOut, p, bs);
1282 CHKERRQ(ierr);
1283 }
1284
1285 // (H) Restore all retrieved arrays and vectors */
1286 ierr = DMDAVecRestoreArrayRead(dm_corner, cornerLocal, &cornerPtr_read_with_ghosts); CHKERRQ(ierr);
1287
1288 // (I) Restore swarm fields
1289 ierr = DMSwarmRestoreField(swarm, swarmOutFieldName, NULL, NULL, &swarmOut); CHKERRQ(ierr);
1290 ierr = DMSwarmRestoreField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
1291 ierr = DMSwarmRestoreField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&pids); CHKERRQ(ierr);
1292 ierr = DMSwarmRestoreField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
1293 ierr = DMSwarmRestoreField(swarm, "position", NULL, NULL, (void**)&pos); CHKERRQ(ierr);
1294 ierr = DMSwarmRestoreField(swarm, "DMSwarm_location_status", NULL, NULL, (void**)&status); CHKERRQ(ierr);
1295 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished for field '%s'.\n", fieldName);
1297 PetscFunctionReturn(0);
1298}
PetscErrorCode UnpackSwarmFields(PetscInt i, const PetscInt64 *PIDs, const PetscReal *weights, const PetscReal *positions, const PetscInt *cellIndices, PetscReal *velocities, PetscInt *LocStatus, PetscReal *diffusivity, Cmpnts *diffusivitygradient, PetscReal *psi, Particle *particle)
Initializes a Particle struct with data from DMSwarm fields.
static PetscErrorCode InterpolateEulerFieldToSwarmForParticle(const char *fieldName, void *fieldPtr, Particle *particle, void *swarmOut, PetscInt p, PetscInt blockSize)
Interpolates a single field (scalar or vector) for one particle, storing the result in a swarm array.
#define InterpolateFieldFromCenterToCorner(blockSize, centfield_ptr, corner_ptr, user_ctx)
Macro to dispatch to the correct scalar or vector center-to-corner function based on a runtime block ...
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:157
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
----— DEBUG ---------------------------------------— #define LOG_ALLOW(scope, level,...
Definition logging.h:267
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:746
PetscErrorCode LOG_FIELD_ANATOMY(UserCtx *user, const char *field_name, const char *stage_name)
Logs the anatomy of a specified field at key boundary locations, respecting the solver's specific gri...
Definition logging.c:1460
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:39
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:33
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:737
PetscInt cell[3]
Definition variables.h:167
Vec lCellFieldAtCorner
Definition variables.h:764
Vec CellFieldAtCorner
Definition variables.h:764
Cmpnts weights
Definition variables.h:170
PetscInt64 PID
Definition variables.h:166
Defines a particle's core properties for Lagrangian tracking.
Definition variables.h:165
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InterpolateAllFieldsToSwarm()

PetscErrorCode InterpolateAllFieldsToSwarm ( UserCtx user)

Interpolates all relevant fields from the DMDA to the DMSwarm.

Currently, it interpolates:

  • user->Ucat (vector field) into the DMSwarm field "swarmVelocity".

To add more fields, duplicate the call to InterpolateOneFieldOverSwarm and provide:

  • The global Vec for that field (e.g. user->Tcat for temperature),
  • A human-readable field name (for logging),
  • A DMSwarm output field name (e.g. "swarmTemperature").
Parameters
[in,out]userPointer to a UserCtx containing:
  • user->da (DM for the grid),
  • user->swarm (DMSwarm for particles),
  • user->Ucat (Vec for the vector field),
  • possibly more fields like user->Tcat, user->Pcat, etc.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Currently, it Interpolatetes:

  • user->Ucat (vector field) into the DMSwarm field "swarmVelocity".

To add more fields, duplicate the call to InterpolateOneFieldOverSwarm and provide:

  • The global Vec for that field (e.g. user->Tcat for temperature),
  • A human-readable field name (for logging),
  • A DMSwarm output field name (e.g. "swarmTemperature").
Parameters
[in,out]userPointer to a UserCtx containing:
  • user->da (DM for the grid),
  • user->swarm (DMSwarm for particles),.
  • user->Ucat (Vec for the vector field),
  • possibly more fields like user->Tcat, user->Pcat, etc.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Definition at line 1321 of file interpolation.c.

1322{
1323 PetscErrorCode ierr;
1324 PetscMPIInt rank;
1325 PetscFunctionBegin;
1326
1328
1329 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
1330
1331 /*
1332 1) Interpolate the 'velocity' field (user->Ucat) into DMSwarm's "swarmVelocity".
1333 - The function InterpolateOneFieldOverSwarm() loops over all local particles,
1334 retrieves iCell, jCell, kCell, (a1,a2,a3) from the DMSwarm,
1335 and calls the appropriate trilinear interpolation routine.
1336
1337 - "velocity" => just a label used in logging or debugging.
1338 - "swarmVelocity" => the DMSwarm field name where we store the result
1339 (assume dof=3 if user->Ucat has blockSize=3).
1340 */
1341
1343 " Interpolation of ucat to velocity begins on rank %d.\n",rank);
1344 // Make sure to pass the *LOCAL* Vector to the function below!
1345 ierr = InterpolateEulerFieldToSwarm(user, user->lUcat,
1346 "Ucat",
1347 "velocity"); CHKERRQ(ierr);
1349 "Diffusivity", "Diffusivity"); CHKERRQ(ierr);
1350
1352 "DiffusivityGradient", "DiffusivityGradient"); CHKERRQ(ierr);
1353 /* Add fields as necessary here*/
1354
1355 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
1357 "[rank %d]Completed Interpolateting all fields to the swarm.\n",rank);
1358
1360
1361 PetscFunctionReturn(0);
1362}
PetscErrorCode InterpolateEulerFieldToSwarm(UserCtx *user, Vec fieldLocal_cellCentered, const char *fieldName, const char *swarmOutFieldName)
Interpolates a cell-centered field (scalar or vector) onto DMSwarm particles, using a robust,...
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
Vec lDiffusivityGradient
Definition variables.h:759
Vec lUcat
Definition variables.h:755
Vec lDiffusivity
Definition variables.h:758
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InterpolateParticleVelocities()

PetscErrorCode InterpolateParticleVelocities ( UserCtx user)

Interpolates particle velocities using trilinear interpolation.

Parameters
[in]userPointer to the user-defined context containing grid and swarm information.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

◆ InterpolateFieldFromCornerToCenter_Scalar()

PetscErrorCode InterpolateFieldFromCornerToCenter_Scalar ( PetscReal ***  field_arr,
PetscReal ***  centfield_arr,
UserCtx user 
)

Safely interpolate a scalar field from corner nodes (from the coordinate DM) to cell centers (from the cell-centered DM) using the provided UserCtx.

For each cell center in the physical region of the cell-centered DM (fda), this function averages the up to 8 surrounding scalar values from the coordinate DM (da). On boundaries, where fewer corners are available, a partial average is computed.

The coordinate DM (da) is built on corners (IM+1 x JM+1 x KM+1) while the cell-centered DM (fda) covers the physical cells (IM x JM x KM). Index offsets are adjusted via DMDAGetLocalInfo.

Parameters
[in]field3D array of corner-based scalar data (from user->da).
[out]centfield3D array for the interpolated cell-center scalar data (for user->fda).
[in]userUser context containing:
  • da : DM for the coordinate (corner) data.
  • fda : DM for the cell-centered data.
Returns
PetscErrorCode 0 on success.

Safely interpolate a scalar field from corner nodes (from the coordinate DM) to cell centers (from the cell-centered DM) using the provided UserCtx.

For each interior computational cell (k,j,i), this function calculates the cell-centered value as the arithmetic average of the values at its 8 surrounding corner nodes.

This function adheres to the convention that the valid computational domain for cell-centered quantities excludes the first and last indices in each direction (e.g., cells at i=0 and i=IM). The loop bounds are constructed to match this.

Parameters
[in]field_arrInput: Ghosted 3D array of corner-node data, accessed via GLOBAL indices.
[out]centfield_arrOutput: 3D array for interpolated cell-center values, accessed via GLOBAL indices.
[in]userUser context containing DMDA information.
Returns
PetscErrorCode 0 on success.

Definition at line 111 of file interpolation.c.

115{
116 PetscErrorCode ierr;
117 DMDALocalInfo info;
118
119 PetscFunctionBeginUser;
120
121 ierr = DMDAGetLocalInfo(user->da, &info); CHKERRQ(ierr);
122
123 // Get local and global grid dimensions
124 PetscInt xs = info.xs, xe = info.xs + info.xm;
125 PetscInt ys = info.ys, ye = info.ys + info.ym;
126 PetscInt zs = info.zs, ze = info.zs + info.zm;
127 PetscInt mx = info.mx, my = info.my, mz = info.mz;
128
129 // Determine loop bounds to compute for interior cells only, matching the code's convention.
130 // Start at index 1 if the process owns the global boundary at index 0.
131 PetscInt is = (xs == 0) ? 1 : xs;
132 PetscInt js = (ys == 0) ? 1 : ys;
133 PetscInt ks = (zs == 0) ? 1 : zs;
134
135 // Stop one cell short if the process owns the global boundary at the max index.
136 PetscInt ie = (xe == mx) ? xe - 1 : xe;
137 PetscInt je = (ye == my) ? ye - 1 : ye;
138 PetscInt ke = (ze == mz) ? ze - 1 : ze;
139
140 // Loop over the locally owned INTERIOR cells.
141 for (PetscInt k = ks; k < ke; k++) {
142 for (PetscInt j = js; j < je; j++) {
143 for (PetscInt i = is; i < ie; i++) {
144 // Calculate cell center value as the average of its 8 corner nodes
145 centfield_arr[k][j][i] = 0.125 * (field_arr[k][j][i] + field_arr[k][j-1][i] +
146 field_arr[k-1][j][i] + field_arr[k-1][j-1][i] +
147 field_arr[k][j][i-1] + field_arr[k][j-1][i-1] +
148 field_arr[k-1][j][i-1] + field_arr[k-1][j-1][i-1]);
149 }
150 }
151 }
152
153 PetscFunctionReturn(0);
154}

◆ InterpolateFieldFromCornerToCenter_Vector()

PetscErrorCode InterpolateFieldFromCornerToCenter_Vector ( Cmpnts ***  field_arr,
Cmpnts ***  centfield_arr,
UserCtx user 
)

Safely interpolate a vector field from corner nodes (from the coordinate DM) to cell centers (from the cell-centered DM) using the provided UserCtx.

For each cell center in the physical region of the cell-centered DM (fda), this function averages the 8 surrounding corner values from the coordinate DM (da). The coordinate DM (da) is built on corners (IM+1 x JM+1 x KM+1) while the cell-centered DM (fda) covers the physical cells (IM x JM x KM). Index offsets are adjusted using DMDAGetLocalInfo.

Parameters
[in]field3D array of corner-based vector data (from user->da).
[out]centfield3D array for the interpolated cell-center vector data (for user->fda).
[in]userUser context containing:
  • da : DM for the coordinate (corner) data.
  • fda : DM for the cell-centered data.
Returns
PetscErrorCode 0 on success.

Safely interpolate a vector field from corner nodes (from the coordinate DM) to cell centers (from the cell-centered DM) using the provided UserCtx.

For each interior computational cell (k,j,i), this function calculates the cell-centered value as the arithmetic average of the values at its 8 surrounding corner nodes.

This function adheres to the convention that the valid computational domain for cell-centered quantities excludes the first and last indices in each direction (e.g., cells at i=0 and i=IM). The loop bounds are constructed to match this, making it a direct counterpart to functions like ComputeCellCentersAndSpacing.

Parameters
[in]field_arrInput: Ghosted 3D array of corner-node data, accessed via GLOBAL indices.
[out]centfield_arrOutput: 3D array for interpolated cell-center values, accessed via GLOBAL indices.
[in]userUser context containing DMDA information.
Returns
PetscErrorCode 0 on success.

Definition at line 38 of file interpolation.c.

42{
43 PetscErrorCode ierr;
44 DMDALocalInfo info;
45
46 PetscFunctionBeginUser;
47
48 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
49
50 // Get local and global grid dimensions
51 PetscInt xs = info.xs, xe = info.xs + info.xm;
52 PetscInt ys = info.ys, ye = info.ys + info.ym;
53 PetscInt zs = info.zs, ze = info.zs + info.zm;
54 PetscInt mx = info.mx, my = info.my, mz = info.mz;
55
56 // Determine loop bounds to compute for interior cells only, matching the code's convention.
57 // Start at index 1 if the process owns the global boundary at index 0.
58 PetscInt is = (xs == 0) ? 1 : xs;
59 PetscInt js = (ys == 0) ? 1 : ys;
60 PetscInt ks = (zs == 0) ? 1 : zs;
61
62 // Stop one cell short if the process owns the global boundary at the max index.
63 PetscInt ie = (xe == mx) ? xe - 1 : xe;
64 PetscInt je = (ye == my) ? ye - 1 : ye;
65 PetscInt ke = (ze == mz) ? ze - 1 : ze;
66
67 // Loop over the locally owned INTERIOR cells.
68 for (PetscInt k = ks; k < ke; k++) {
69 for (PetscInt j = js; j < je; j++) {
70 for (PetscInt i = is; i < ie; i++) {
71 // Calculate cell center value as the average of its 8 corner nodes
72 centfield_arr[k][j][i].x = 0.125 * (field_arr[k][j][i].x + field_arr[k][j-1][i].x +
73 field_arr[k-1][j][i].x + field_arr[k-1][j-1][i].x +
74 field_arr[k][j][i-1].x + field_arr[k][j-1][i-1].x +
75 field_arr[k-1][j][i-1].x + field_arr[k-1][j-1][i-1].x);
76
77 centfield_arr[k][j][i].y = 0.125 * (field_arr[k][j][i].y + field_arr[k][j-1][i].y +
78 field_arr[k-1][j][i].y + field_arr[k-1][j-1][i].y +
79 field_arr[k][j][i-1].y + field_arr[k][j-1][i-1].y +
80 field_arr[k-1][j][i-1].y + field_arr[k-1][j-1][i-1].y);
81
82 centfield_arr[k][j][i].z = 0.125 * (field_arr[k][j][i].z + field_arr[k][j-1][i].z +
83 field_arr[k-1][j][i].z + field_arr[k-1][j-1][i].z +
84 field_arr[k][j][i-1].z + field_arr[k][j-1][i-1].z +
85 field_arr[k-1][j][i-1].z + field_arr[k-1][j-1][i-1].z);
86 }
87 }
88 }
89
90 PetscFunctionReturn(0);
91}

◆ TestCornerToCenterInterpolation()

PetscErrorCode TestCornerToCenterInterpolation ( UserCtx user)

Tests the InterpolateFieldFromCornerToCenter function by reproducing the Cent vector.

This function serves as a unit test. It performs the following steps:

  1. Takes the corner-centered nodal coordinates (from DMGetCoordinatesLocal) as input.
  2. Uses the InterpolateFieldFromCornerToCenter macro to interpolate these coordinates to the cell centers, storing the result in a new temporary vector.
  3. Compares this new vector with the user->Cent vector, which is assumed to have been computed by ComputeCellCentersAndSpacing and serves as the ground truth.
  4. A 2-norm of the difference is computed. If it is below a small tolerance, the test passes.
Note
This function should be called immediately after ComputeCellCentersAndSpacing has been successfully executed.
Parameters
userThe UserCtx for a specific grid level.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Definition at line 175 of file interpolation.c.

176{
177 PetscErrorCode ierr;
178 Vec lCoords, TestCent;
179 Cmpnts ***coor_arr, ***test_cent_arr;
180 PetscReal diff_norm;
181
182 PetscFunctionBeginUser;
183
184 // 1. Create a temporary vector to hold the result of our interpolation.
185 // It must have the same layout and size as the ground-truth user->Cent vector.
186 ierr = VecDuplicate(user->Cent, &TestCent); CHKERRQ(ierr);
187
188 // 2. Get the input (corner coordinates) and output (our test vector) arrays.
189 ierr = DMGetCoordinatesLocal(user->da, &lCoords); CHKERRQ(ierr);
190 ierr = DMDAVecGetArrayRead(user->fda, lCoords, &coor_arr); CHKERRQ(ierr);
191 ierr = DMDAVecGetArray(user->fda, TestCent, &test_cent_arr); CHKERRQ(ierr);
192
193 // 3. Call the generic interpolation macro.
194 // The macro will see that `coor_arr` is of type `Cmpnts***` and correctly
195 // call the `InterpolateFieldFromCornerToCenter_Vector` function.
196 ierr = InterpolateFieldFromCornerToCenter(coor_arr, test_cent_arr, user); CHKERRQ(ierr);
197
198 // 4. Restore the arrays.
199 ierr = DMDAVecRestoreArrayRead(user->fda, lCoords, &coor_arr); CHKERRQ(ierr);
200 ierr = DMDAVecRestoreArray(user->fda, TestCent, &test_cent_arr); CHKERRQ(ierr);
201
202 // 5. IMPORTANT: Assemble the vector so its values are communicated across processors
203 // and it's ready for global operations like VecNorm.
204 ierr = VecAssemblyBegin(TestCent); CHKERRQ(ierr);
205 ierr = VecAssemblyEnd(TestCent); CHKERRQ(ierr);
206
207 // 6. Compare the result with the ground truth.
208 // We compute TestCent = -1.0 * user->Cent + 1.0 * TestCent.
209 // This calculates the difference vector: TestCent - user->Cent.
210 ierr = VecAXPY(TestCent, -1.0, user->Cent); CHKERRQ(ierr);
211
212 // Now, compute the L2 norm of the difference vector. If the functions are
213 // identical, the norm should be zero (or very close due to floating point).
214 ierr = VecNorm(TestCent, NORM_2, &diff_norm); CHKERRQ(ierr);
215
216 // 7. Report the result and clean up.
217 if (diff_norm < 1.0e-12) {
218 LOG_ALLOW(GLOBAL,LOG_DEBUG,"[SUCCESS] Test passed. Norm of difference is %g.\n", (double)diff_norm);
219 } else {
220 LOG_ALLOW(GLOBAL,LOG_DEBUG, "[FAILURE] Test failed. Norm of difference is %g.\n", (double)diff_norm);
221 }
222
223 ierr = VecDestroy(&TestCent); CHKERRQ(ierr);
224
225 PetscFunctionReturn(0);
226}
#define InterpolateFieldFromCornerToCenter(field, centfield, user)
Generic macro to call the appropriate interpolation function based on the field type.
Vec Cent
Definition variables.h:776

◆ InterpolateFieldFromCenterToCorner_Vector()

PetscErrorCode InterpolateFieldFromCenterToCorner_Vector ( Cmpnts ***  centfield_arr,
Cmpnts ***  corner_arr,
UserCtx user 
)

Interpolates a vector field from cell centers to corner nodes.

This version is adapted to write directly into a ghosted local array obtained from DMDAVecGetArray(), which allows using GLOBAL indices for writing to the OWNED portion of the array.

Parameters
[in]centfield_arrInput: 3D array (ghosted) of cell-centered data, accessed via GLOBAL indices.
[out]corner_arrOutput: 3D array (ghosted) where interpolated node values are stored, also accessed via GLOBAL indices for the owned part.
[in]userUser context containing DMDA information.
Returns
PetscErrorCode 0 on success.
Parameters
[in]centfield_arrInput: 3D array (ghosted) of cell-centered data, accessed via GLOBAL indices.
[out]corner_arrOutput: 3D array where interpolated node values are stored, also accessed via GLOBAL indices for the owned part.
[in]userUser context containing DMDA information.
Returns
PetscErrorCode 0 on success.

Definition at line 241 of file interpolation.c.

245{
246 PetscErrorCode ierr;
247 DMDALocalInfo info;
248 PetscMPIInt rank;
250 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
251 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
252
253 // Node ownership range (GLOBAL indices)
254 PetscInt xs_node = info.xs, xm_node = info.xm, xe_node = xs_node + xm_node;
255 PetscInt ys_node = info.ys, ym_node = info.ym, ye_node = ys_node + ym_node;
256 PetscInt zs_node = info.zs, zm_node = info.zm, ze_node = zs_node + zm_node;
257
258 PetscInt nCellsX = info.mx - 2; // Number of cells in x-direction
259 PetscInt nCellsY = info.my - 2; // Number of cells in y-direction
260 PetscInt nCellsZ = info.mz - 2; // Number of cells in z-direction
261
262
263 // Global grid dimensions (used for valid cell check)
264 PetscInt IM = info.mx - 1; // Total nodes in i-direction
265 PetscInt JM = info.my - 1; // Total nodes in j-direction
266 PetscInt KM = info.mz - 1; // Total nodes in k-direction
267
268 // Ghosted array starting indices (from the same info struct)
269 PetscInt gxs = info.gxs;
270 PetscInt gys = info.gys;
271 PetscInt gzs = info.gzs;
272
273 PetscInt xs = info.xs;
274 PetscInt ys = info.ys;
275 PetscInt zs = info.zs;
276
278 "[Rank %d] Starting -- Node ownership k=%d..%d, j=%d..%d, i=%d..%d\n",
279 rank, zs_node, ze_node-1, ys_node, ye_node-1, xs_node, xe_node-1);
280
281 // Loop over the GLOBAL indices of the NODES owned by this processor
282 for (PetscInt k = zs_node; k < ze_node; k++) {
283 for (PetscInt j = ys_node; j < ye_node; j++) {
284 for (PetscInt i = xs_node; i < xe_node; i++) {
285 Cmpnts sum = {0.0, 0.0, 0.0};
286 PetscInt count = 0;
287
288 // DEBUG 1 TEST
289 /*
290 if(rank == 1 && i == 24 && j == 12 && k == 49){
291 PetscInt i_cell_A = i - 1;
292 PetscInt i_cell_B = i;
293
294 Cmpnts ucat_A = centfield_arr[k][j][i_cell_A]; // 23
295 Cmpnts ucat_B = centfield_arr[k][j][i_cell_B]; // 24 (out-of-bounds if IM=25)
296
297 PetscPrintf(PETSC_COMM_WORLD,"[Rank %d] DEBUG TEST at Node(k,j,i)=%d,%d,%d: Read { Valid Cell }Ucat[%d][%d][%d]=(%.2f,%.2f,%.2f) and {Out-of-Bounds Cell}Ucat[%d][%d][%d]=(%.2f,%.2f,%.2f)\n",
298 rank, k, j, i,
299 k, j, i_cell_A, ucat_A.x, ucat_A.y, ucat_A.z,
300 k, j, i_cell_B, ucat_B.x, ucat_B.y, ucat_B.z);
301
302 }
303 */
304
305 // Skip processing the unused last node in each dimension.
306 if(i >= IM || j >= JM || k >= KM){
307 continue;
308 }
309 // Loop over the 8 potential cells surrounding node N(k,j,i) and accumulate values.
310 // The index offsets correspond to the relative position of the indices(shifted) that represent cell-centered field values of cells that share the node N(k,j,i) as a corner
311 for (PetscInt dk_offset = -1; dk_offset <= 0; dk_offset++) {
312 for (PetscInt dj_offset = -1; dj_offset <= 0; dj_offset++) {
313 for (PetscInt di_offset = -1; di_offset <= 0; di_offset++) {
314
315 // These are still GLOBAL cell indices
316 PetscInt global_cell_k = k + dk_offset;
317 PetscInt global_cell_j = j + dj_offset;
318 PetscInt global_cell_i = i + di_offset;
319
320 // Check if this corresponds to a valid GLOBAL cell index
321 if (global_cell_i >= 0 && global_cell_i < nCellsX &&
322 global_cell_j >= 0 && global_cell_j < nCellsY &&
323 global_cell_k >= 0 && global_cell_k < nCellsZ)
324 {
325 Cmpnts cell_val = centfield_arr[global_cell_k + 1][global_cell_j + 1][global_cell_i + 1];
326
327 LOG_LOOP_ALLOW_EXACT(LOCAL, LOG_VERBOSE,k,49,"[Rank %d] successful read from [%d][%d][%d] -> (%.2f, %.2f, %.2f)\n",
328 rank,global_cell_k,global_cell_j,global_cell_i,cell_val.x, cell_val.y, cell_val.z);
329
330 sum.x += cell_val.x;
331 sum.y += cell_val.y;
332 sum.z += cell_val.z;
333 count++;
334 }
335 }
336 }
337 }
338
339 PetscInt i_global_write = i; // Global index in GLOBAL array.
340 PetscInt j_global_write = j;
341 PetscInt k_global_write = k;
342
343 // We write directly into the array using the global loop indices.
344 if (count > 0) {
345 corner_arr[k_global_write][j_global_write][i_global_write].x = sum.x / (PetscReal)count;
346 corner_arr[k_global_write][j_global_write][i_global_write].y = sum.y / (PetscReal)count;
347 corner_arr[k_global_write][j_global_write][i_global_write].z = sum.z / (PetscReal)count;
348 } else {
349 // This case should ideally not happen for a valid owned node, but as a failsafe:
350 corner_arr[k_global_write][j_global_write][i_global_write] = (Cmpnts){0.0, 0.0, 0.0};
351 }
352
353 // DEBUG 2
354 /*
355 if(rank == 1){
356 if(i == 11 && j == 11 && k == 49){
357 Cmpnts ucat_node = corner_arr[k][j][i];
358 PetscPrintf(PETSC_COMM_WORLD,"[Rank %d] DEBUG TEST at Node(k,j,i)=%d,%d,%d: Wrote CornerUcat[%d][%d][%d]=(%.2f,%.2f,%.2f)\n",
359 rank, k, j, i,
360 k, j, i, ucat_node.x, ucat_node.y, ucat_node.z);
361 }
362 }
363
364 if(rank == 0 && i == 24 && j == 12 && k == 0){
365 Cmpnts ucat_node = corner_arr[k][j][i];
366 PetscPrintf(PETSC_COMM_WORLD,"[Rank %d] DEBUG TEST at Node(k,j,i)=%d,%d,%d: Wrote CornerUcat[%d][%d][%d]=(%.2f,%.2f,%.2f)\n",
367 rank, k, j, i,
368 k, j, i, ucat_node.x, ucat_node.y, ucat_node.z);
369 }
370 */
371 // LOG_LOOP_ALLOW_EXACT(LOCAL, LOG_VERBOSE,k,48,"[Rank %d] Node(k,j,i)=%d,%d,%d finished loops and write.\n", rank, k, j, i);
372 }
373 }
374 }
376 return 0;
377}
#define LOG_LOOP_ALLOW_EXACT(scope, level, var, val, fmt,...)
Logs a custom message if a variable equals a specific value.
Definition logging.h:348

◆ InterpolateFieldFromCenterToCorner_Scalar()

PetscErrorCode InterpolateFieldFromCenterToCorner_Scalar ( PetscReal ***  centfield_arr,
PetscReal ***  corner_arr,
UserCtx user 
)

Interpolates a scalar field from cell centers to corner nodes.

This version is adapted to write directly into a ghosted local array obtained from DMDAVecGetArray(), which allows using GLOBAL indices for writing to the OWNED portion of the array.

Parameters
[in]centfield_arrInput: 3D array (ghosted) of scalar data at cell centers, accessed via GLOBAL indices.
[out]corner_arrOutput: 3D array (ghosted) where interpolated node values are stored, also accessed via GLOBAL indices for the owned part.
[in]userUser context containing DMDA information.
Returns
PetscErrorCode 0 on success.
Parameters
[in]centfield_arrInput: 3D array (ghosted) of cell-centered data, accessed via GLOBAL indices.
[out]corner_arrOutput: 3D array where interpolated node values are stored, also accessed via GLOBAL indices for the owned part.
[in]userUser context containing DMDA information.
Returns
PetscErrorCode 0 on success.

Definition at line 392 of file interpolation.c.

396{
397 PetscErrorCode ierr;
398 DMDALocalInfo info;
399 PetscMPIInt rank;
401 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
402 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
403
404 // Node ownership range (GLOBAL indices)
405 PetscInt xs_node = info.xs, xm_node = info.xm, xe_node = xs_node + xm_node;
406 PetscInt ys_node = info.ys, ym_node = info.ym, ye_node = ys_node + ym_node;
407 PetscInt zs_node = info.zs, zm_node = info.zm, ze_node = zs_node + zm_node;
408
409 PetscInt nCellsX = info.mx - 2; // Number of cells in x-direction
410 PetscInt nCellsY = info.my - 2; // Number of cells in y-direction
411 PetscInt nCellsZ = info.mz - 2; // Number of cells in z-direction
412
413
414 // Global grid dimensions (used for valid cell check)
415 PetscInt IM = info.mx - 1; // Total nodes in i-direction
416 PetscInt JM = info.my - 1; // Total nodes in j-direction
417 PetscInt KM = info.mz - 1; // Total nodes in k-direction
418
419 // Ghosted array starting indices (from the same info struct)
420 PetscInt gxs = info.gxs;
421 PetscInt gys = info.gys;
422 PetscInt gzs = info.gzs;
423
424 PetscInt xs = info.xs;
425 PetscInt ys = info.ys;
426 PetscInt zs = info.zs;
427
429 "[Rank %d] Starting -- Node ownership k=%d..%d, j=%d..%d, i=%d..%d\n",
430 rank, zs_node, ze_node-1, ys_node, ye_node-1, xs_node, xe_node-1);
431
432 // Loop over the GLOBAL indices of the NODES owned by this processor
433 for (PetscInt k = zs_node; k < ze_node; k++) {
434 for (PetscInt j = ys_node; j < ye_node; j++) {
435 for (PetscInt i = xs_node; i < xe_node; i++) {
436 PetscReal sum = 0.0;
437 PetscInt count = 0;
438
439 // DEBUG 1 TEST
440 /*
441 if(rank == 1 && i == 24 && j == 12 && k == 49){
442 PetscInt i_cell_A = i - 1;
443 PetscInt i_cell_B = i;
444
445 Cmpnts ucat_A = centfield_arr[k][j][i_cell_A]; // 23
446 Cmpnts ucat_B = centfield_arr[k][j][i_cell_B]; // 24 (out-of-bounds if IM=25)
447
448 PetscPrintf(PETSC_COMM_WORLD,"[Rank %d] DEBUG TEST at Node(k,j,i)=%d,%d,%d: Read { Valid Cell }Ucat[%d][%d][%d]=(%.2f,%.2f,%.2f) and {Out-of-Bounds Cell}Ucat[%d][%d][%d]=(%.2f,%.2f,%.2f)\n",
449 rank, k, j, i,
450 k, j, i_cell_A, ucat_A.x, ucat_A.y, ucat_A.z,
451 k, j, i_cell_B, ucat_B.x, ucat_B.y, ucat_B.z);
452
453 }
454 */
455
456 // Skip processing the unused last node in each dimension.
457 if(i >= IM || j >= JM || k >= KM){
458 continue;
459 }
460 // Loop over the 8 potential cells surrounding node N(k,j,i) and accumulate values.
461 // The index offsets correspond to the relative position of the indices(shifted) that represent cell-centered field values of cells that share the node N(k,j,i) as a corner
462 for (PetscInt dk_offset = -1; dk_offset <= 0; dk_offset++) {
463 for (PetscInt dj_offset = -1; dj_offset <= 0; dj_offset++) {
464 for (PetscInt di_offset = -1; di_offset <= 0; di_offset++) {
465
466 // These are still GLOBAL cell indices
467 PetscInt global_cell_k = k + dk_offset;
468 PetscInt global_cell_j = j + dj_offset;
469 PetscInt global_cell_i = i + di_offset;
470
471 // Check if this corresponds to a valid GLOBAL cell index
472 if (global_cell_i >= 0 && global_cell_i < nCellsX &&
473 global_cell_j >= 0 && global_cell_j < nCellsY &&
474 global_cell_k >= 0 && global_cell_k < nCellsZ)
475 {
476 PetscReal cell_val = centfield_arr[global_cell_k + 1][global_cell_j + 1][global_cell_i + 1];
477
478 LOG_LOOP_ALLOW_EXACT(LOCAL, LOG_VERBOSE,k,49,"[Rank %d] successful read from [%d][%d][%d] -> (%.2f)\n",
479 rank,global_cell_k,global_cell_j,global_cell_i,cell_val);
480
481 sum += cell_val;
482 count++;
483 }
484 }
485 }
486 }
487
488 PetscInt i_global_write = i; // Global index in GLOBAL array.
489 PetscInt j_global_write = j;
490 PetscInt k_global_write = k;
491
492 // We write directly into the array using the global loop indices.
493 if (count > 0) {
494 corner_arr[k_global_write][j_global_write][i_global_write] = sum / (PetscReal)count;
495 } else {
496 // This case should ideally not happen for a valid owned node, but as a failsafe:
497 corner_arr[k_global_write][j_global_write][i_global_write] = 0.0;
498 }
499
500 // DEBUG 2
501 /*
502 if(rank == 1){
503 if(i == 11 && j == 11 && k == 49){
504 Cmpnts ucat_node = corner_arr[k][j][i];
505 PetscPrintf(PETSC_COMM_WORLD,"[Rank %d] DEBUG TEST at Node(k,j,i)=%d,%d,%d: Wrote CornerUcat[%d][%d][%d]=(%.2f,%.2f,%.2f)\n",
506 rank, k, j, i,
507 k, j, i, ucat_node.x, ucat_node.y, ucat_node.z);
508 }
509 }
510
511 if(rank == 0 && i == 24 && j == 12 && k == 0){
512 Cmpnts ucat_node = corner_arr[k][j][i];
513 PetscPrintf(PETSC_COMM_WORLD,"[Rank %d] DEBUG TEST at Node(k,j,i)=%d,%d,%d: Wrote CornerUcat[%d][%d][%d]=(%.2f,%.2f,%.2f)\n",
514 rank, k, j, i,
515 k, j, i, ucat_node.x, ucat_node.y, ucat_node.z);
516 }
517 */
518 // LOG_LOOP_ALLOW_EXACT(LOCAL, LOG_VERBOSE,k,48,"[Rank %d] Node(k,j,i)=%d,%d,%d finished loops and write.\n", rank, k, j, i);
519 }
520 }
521 }
523 return 0;
524}

◆ InterpolateCornerToFaceCenter_Scalar()

PetscErrorCode InterpolateCornerToFaceCenter_Scalar ( PetscReal ***  corner_arr,
PetscReal ***  faceX_arr,
PetscReal ***  faceY_arr,
PetscReal ***  faceZ_arr,
UserCtx user 
)

Interpolates a scalar field from corner nodes to all face centers.

This routine computes the average of the four corner-node values defining each face of a hexahedral cell:

  • X-faces (perpendicular to X): face between (i-1,i) in X-dir
  • Y-faces (perpendicular to Y): face between (j-1,j) in Y-dir
  • Z-faces (perpendicular to Z): face between (k-1,k) in Z-dir
Parameters
[in]corner_arrGhosted node-centered array (global indexing) from user->fda.
[out]faceX_arrLocal array for X-faces sized [zm][ym][xm+1].
[out]faceY_arrLocal array for Y-faces sized [zm][ym+1][xm].
[out]faceZ_arrLocal array for Z-faces sized [zm+1][ym][xm].
[in]userUser context containing DMDA 'fda' and GetOwnedCellRange.
Returns
PetscErrorCode 0 on success, non-zero on failure.

Definition at line 2228 of file interpolation.c.

2234{
2235 PetscErrorCode ierr;
2236 DMDALocalInfo info;
2237
2238 PetscFunctionBeginUser;
2239
2241
2242 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2243
2244 // Determine owned-cell ranges based on corner-node ownership
2245 PetscInt xs, xm, ys, ym, zs, zm;
2246 ierr = GetOwnedCellRange(&info, 0, &xs, &xm); CHKERRQ(ierr);
2247 ierr = GetOwnedCellRange(&info, 1, &ys, &ym); CHKERRQ(ierr);
2248 ierr = GetOwnedCellRange(&info, 2, &zs, &zm); CHKERRQ(ierr);
2249
2250 // Global exclusive end indices for cells
2251 PetscInt xe = xs + xm;
2252 PetscInt ye = ys + ym;
2253 PetscInt ze = zs + zm;
2254
2255 // --- X‐faces: loops k=zs..ze-1, j=ys..ye-1, i=xs..xe (xm+1 faces per row) ---
2256 for (PetscInt k = zs; k < ze; ++k) {
2257 PetscInt k_loc = k - zs;
2258 for (PetscInt j = ys; j < ye; ++j) {
2259 PetscInt j_loc = j - ys;
2260 for (PetscInt i = xs; i <= xe; ++i) {
2261 PetscInt i_loc = i - xs; // 0..xm
2262 // Average the four corners of the Y-Z face at X = i
2263 PetscReal sum = corner_arr[k ][j ][i]
2264 + corner_arr[k+1][j ][i]
2265 + corner_arr[k ][j+1][i]
2266 + corner_arr[k+1][j+1][i];
2267 faceX_arr[k_loc][j_loc][i_loc] = sum * 0.25;
2268 }
2269 }
2270 }
2271
2272 // --- Y‐faces: loops k=zs..ze-1, j=ys..ye (ym+1 faces), i=xs..xe-1 ---
2273 for (PetscInt k = zs; k < ze; ++k) {
2274 PetscInt k_loc = k - zs;
2275 for (PetscInt j = ys; j <= ye; ++j) {
2276 PetscInt j_loc = j - ys; // 0..ym
2277 for (PetscInt i = xs; i < xe; ++i) {
2278 PetscInt i_loc = i - xs;
2279 // Average the four corners of the X-Z face at Y = j
2280 PetscReal sum = corner_arr[k ][j][i ]
2281 + corner_arr[k+1][j][i ]
2282 + corner_arr[k ][j][i+1]
2283 + corner_arr[k+1][j][i+1];
2284 faceY_arr[k_loc][j_loc][i_loc] = sum * 0.25;
2285 }
2286 }
2287 }
2288
2289 // --- Z‐faces: loops k=zs..ze (zm+1), j=ys..ye-1, i=xs..xe-1 ---
2290 for (PetscInt k = zs; k <= ze; ++k) {
2291 PetscInt k_loc = k - zs;
2292 for (PetscInt j = ys; j < ye; ++j) {
2293 PetscInt j_loc = j - ys;
2294 for (PetscInt i = xs; i < xe; ++i) {
2295 PetscInt i_loc = i - xs;
2296 // Average the four corners of the X-Y face at Z = k
2297 PetscReal sum = corner_arr[k][j ][i ]
2298 + corner_arr[k][j ][i+1]
2299 + corner_arr[k][j+1][i ]
2300 + corner_arr[k][j+1][i+1];
2301 faceZ_arr[k_loc][j_loc][i_loc] = sum * 0.25;
2302 }
2303 }
2304 }
2305
2307
2308 PetscFunctionReturn(0);
2309}
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global, PetscInt *xm_cell_local)
Determines the global starting index and number of CELLS owned by the current processor in a specifie...
Definition setup.c:1756
Here is the call graph for this function:

◆ InterpolateCornerToFaceCenter_Vector()

PetscErrorCode InterpolateCornerToFaceCenter_Vector ( Cmpnts ***  corner_arr,
Cmpnts ***  faceX_arr,
Cmpnts ***  faceY_arr,
Cmpnts ***  faceZ_arr,
UserCtx user 
)

Interpolates a vector field from corner nodes to all face centers.

Identical to the scalar version, except it averages each component of the Cmpnts struct at the four corner-nodes per face.

Parameters
[in]corner_arrGhosted 3-component array (global node indices).
[out]faceX_arrLocal array of Cmpnts for X-faces sized [zm][ym][xm+1].
[out]faceY_arrLocal array of Cmpnts for Y-faces sized [zm][ym+1][xm].
[out]faceZ_arrLocal array of Cmpnts for Z-faces sized [zm+1][ym][xm].
[in]userUser context containing DMDA 'fda'.
Returns
PetscErrorCode 0 on success.

Definition at line 2328 of file interpolation.c.

2334{
2335 PetscErrorCode ierr;
2336 DMDALocalInfo info;
2337 PetscMPIInt rank;
2338
2339 PetscFunctionBeginUser;
2340
2342
2343 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2345 "Rank %d starting InterpolateFieldFromCornerToFaceCenter_Vector.\n", rank);
2346
2347 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2348
2349 PetscInt xs, xm, ys, ym, zs, zm;
2350 ierr = GetOwnedCellRange(&info, 0, &xs, &xm); CHKERRQ(ierr);
2351 ierr = GetOwnedCellRange(&info, 1, &ys, &ym); CHKERRQ(ierr);
2352 ierr = GetOwnedCellRange(&info, 2, &zs, &zm); CHKERRQ(ierr);
2353
2354 PetscInt xe = xs + xm;
2355 PetscInt ye = ys + ym;
2356 PetscInt ze = zs + zm;
2357
2358 // X-faces
2359 for (PetscInt k = zs; k < ze; ++k) {
2360 PetscInt k_loc = k - zs;
2361 for (PetscInt j = ys; j < ye; ++j) {
2362 PetscInt j_loc = j - ys;
2363 for (PetscInt i = xs; i <= xe; ++i) {
2364 PetscInt i_loc = i - xs;
2365 Cmpnts sum = {0,0,0};
2366 sum.x = corner_arr[k ][j ][i].x + corner_arr[k+1][j ][i].x
2367 + corner_arr[k ][j+1][i].x + corner_arr[k+1][j+1][i].x;
2368 sum.y = corner_arr[k ][j ][i].y + corner_arr[k+1][j ][i].y
2369 + corner_arr[k ][j+1][i].y + corner_arr[k+1][j+1][i].y;
2370 sum.z = corner_arr[k ][j ][i].z + corner_arr[k+1][j ][i].z
2371 + corner_arr[k ][j+1][i].z + corner_arr[k+1][j+1][i].z;
2372 faceX_arr[k_loc][j_loc][i_loc].x = sum.x * 0.25;
2373 faceX_arr[k_loc][j_loc][i_loc].y = sum.y * 0.25;
2374 faceX_arr[k_loc][j_loc][i_loc].z = sum.z * 0.25;
2375 }
2376 }
2377 }
2378
2380 "Rank %d x-face Interpolation complete.\n", rank);
2381
2382 // Y-faces
2383 for (PetscInt k = zs; k < ze; ++k) {
2384 PetscInt k_loc = k - zs;
2385 for (PetscInt j = ys; j <= ye; ++j) {
2386 PetscInt j_loc = j - ys;
2387 for (PetscInt i = xs; i < xe; ++i) {
2388 PetscInt i_loc = i - xs;
2389 Cmpnts sum = {0,0,0};
2390 sum.x = corner_arr[k ][j][i ].x + corner_arr[k+1][j][i ].x
2391 + corner_arr[k ][j][i+1].x + corner_arr[k+1][j][i+1].x;
2392 sum.y = corner_arr[k ][j][i ].y + corner_arr[k+1][j][i ].y
2393 + corner_arr[k ][j][i+1].y + corner_arr[k+1][j][i+1].y;
2394 sum.z = corner_arr[k ][j][i ].z + corner_arr[k+1][j][i ].z
2395 + corner_arr[k ][j][i+1].z + corner_arr[k+1][j][i+1].z;
2396 faceY_arr[k_loc][j_loc][i_loc].x = sum.x * 0.25;
2397 faceY_arr[k_loc][j_loc][i_loc].y = sum.y * 0.25;
2398 faceY_arr[k_loc][j_loc][i_loc].z = sum.z * 0.25;
2399 }
2400 }
2401 }
2402
2404 "Rank %d y-face Interpolation complete.\n", rank);
2405
2406 // Z-faces
2407 for (PetscInt k = zs; k <= ze; ++k) {
2408 PetscInt k_loc = k - zs;
2409 for (PetscInt j = ys; j < ye; ++j) {
2410 PetscInt j_loc = j - ys;
2411 for (PetscInt i = xs; i < xe; ++i) {
2412 PetscInt i_loc = i - xs;
2413 Cmpnts sum = {0,0,0};
2414 sum.x = corner_arr[k][j ][i ].x + corner_arr[k][j ][i+1].x
2415 + corner_arr[k][j+1][i ].x + corner_arr[k][j+1][i+1].x;
2416 sum.y = corner_arr[k][j ][i ].y + corner_arr[k][j ][i+1].y
2417 + corner_arr[k][j+1][i ].y + corner_arr[k][j+1][i+1].y;
2418 sum.z = corner_arr[k][j ][i ].z + corner_arr[k][j ][i+1].z
2419 + corner_arr[k][j+1][i ].z + corner_arr[k][j+1][i+1].z;
2420 faceZ_arr[k_loc][j_loc][i_loc].x = sum.x * 0.25;
2421 faceZ_arr[k_loc][j_loc][i_loc].y = sum.y * 0.25;
2422 faceZ_arr[k_loc][j_loc][i_loc].z = sum.z * 0.25;
2423 }
2424 }
2425 }
2426
2428 "Rank %d z-face Interpolation complete.\n", rank);
2429
2431 PetscFunctionReturn(0);
2432}
Here is the call graph for this function: