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 InterpolateFieldFromCenterToCorner_Scalar (PetscReal ***field_arr, PetscReal ***centfield_arr, UserCtx *user)
 Interpolates a scalar field from cell centers to corner nodes.
 
PetscErrorCode InterpolateFieldFromCenterToCorner_Vector (Cmpnts ***field_arr, Cmpnts ***centfield_arr, UserCtx *user)
 Interpolates a vector field from cell centers to corner nodes.
 
PetscErrorCode InterpolateFieldFromCenterToCorner_Vector_Petsc (Cmpnts ***centfield_arr, Cmpnts ***corner_arr, UserCtx *user)
 Interpolates a vector field from cell centers to corner nodes.
 
PetscErrorCode InterpolateFieldFromCenterToCorner_Scalar_Petsc (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 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_Petsc((PetscReal***)(centfield_ptr), (PetscReal***)(corner_ptr), (user_ctx)) : \
InterpolateFieldFromCenterToCorner_Vector_Petsc((Cmpnts***)(centfield_ptr), (Cmpnts***)(corner_ptr), (user_ctx)) \
)
PetscErrorCode InterpolateFieldFromCenterToCorner_Vector_Petsc(Cmpnts ***centfield_arr, Cmpnts ***corner_arr, UserCtx *user)
Interpolates a vector field from cell centers to corner nodes.
PetscErrorCode InterpolateFieldFromCenterToCorner_Scalar_Petsc(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 64 of file interpolation.h.

66 : \
67 InterpolateFieldFromCenterToCorner_Vector_Petsc((Cmpnts***)(centfield_ptr), (Cmpnts***)(corner_ptr), (user_ctx)) \
68 )

◆ 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 87 of file interpolation.h.

91 )(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 109 of file interpolation.h.

113 )(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 130 of file interpolation.h.

134 )(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 622 of file interpolation.c.

632{
633 PetscFunctionBegin; // PETSc macro for error/stack tracing
634
635 // Compute the 8 corner weights
636 PetscReal wcorner[8];
637 ComputeTrilinearWeights(a1, a2, a3, wcorner);
638
639 // Offsets for cell corners
640 PetscInt i1 = i + 1;
641 PetscInt j1 = j + 1;
642 PetscInt k1 = k + 1;
643
644 // Initialize the output scalar
645 PetscReal sum = 0.0;
646
647 // Corner 0 => (i, j, k)
648 sum += wcorner[0] * fieldScal[k ][j ][i ];
649 // Corner 1 => (i+1, j, k)
650 sum += wcorner[1] * fieldScal[k ][j ][i1];
651 // Corner 2 => (i, j+1, k)
652 sum += wcorner[2] * fieldScal[k ][j1][i ];
653 // Corner 3 => (i+1, j+1, k)
654 sum += wcorner[3] * fieldScal[k ][j1][i1];
655 // Corner 4 => (i, j, k+1)
656 sum += wcorner[4] * fieldScal[k1][j ][i ];
657 // Corner 5 => (i+1, j, k+1)
658 sum += wcorner[5] * fieldScal[k1][j ][i1];
659 // Corner 6 => (i, j+1, k+1)
660 sum += wcorner[6] * fieldScal[k1][j1][i ];
661 // Corner 7 => (i+1, j+1, k+1)
662 sum += wcorner[7] * fieldScal[k1][j1][i1];
663
664 *val = sum;
665
666 // Logging (optional)
668 "Field '%s' at (i=%d, j=%d, k=%d), "
669 "a1=%.6f, a2=%.6f, a3=%.6f -> val=%.6f.\n",
670 fieldName, i, j, k, a1, a2, a3, *val);
671
672 // LOG_ALLOW_SYNC(GLOBAL, LOG_INFO,
673 // "TrilinearInterpolation_Scalar: Completed interpolation for field '%s' across local cells.\n",
674 // fieldName);
675
676 PetscFunctionReturn(0);
677}
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:46
#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:201
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:35
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 702 of file interpolation.c.

712{
713 PetscFunctionBegin; // PETSc macro for error/stack tracing
714
715 // Compute the 8 corner weights
716 PetscErrorCode ierr;
717 PetscReal wcorner[8];
718 PetscMPIInt rank;
719
720 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);
721
722 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d] Computing Trilinear Weights.\n",rank);
723 ComputeTrilinearWeights(a1, a2, a3, wcorner);
724
725 LOG_ALLOW(LOCAL,LOG_VERBOSE,"[Rank %d] Trilinear weights computed for local cell %d,%d,%d.\n",rank,i,j,k);
726
727 // For partial interpolation, we'll keep track of how many corners are valid
728 // and how much sum of weights is used. Then we do a final normalization.
729 PetscReal sumW = 0.0;
730 Cmpnts accum = {0.0, 0.0, 0.0};
731
732 // The eight corner indices, with their weights:
733 // corners: (i,j,k), (i+1,j,k), (i,j+1,k), (i+1,j+1,k), etc.
734 // We store them in an array to iterate cleanly.
735 const PetscInt cornerOffsets[8][3] = {
736 {0, 0, 0},
737 {1, 0, 0},
738 {0, 1, 0},
739 {1, 1, 0},
740 {0, 0, 1},
741 {1, 0, 1},
742 {0, 1, 1},
743 {1, 1, 1}
744 };
745
746 // Weighted partial sum
747 for (PetscInt c = 0; c < 8; c++) {
748 const PetscInt di = cornerOffsets[c][0];
749 const PetscInt dj = cornerOffsets[c][1];
750 const PetscInt dk = cornerOffsets[c][2];
751 PetscInt iC = i + di;
752 PetscInt jC = j + dj;
753 PetscInt kC = k + dk;
754
755 /*
756 // skip if out of domain
757 // (Assuming you know global domain is [0..mx), [0..my), [0..mz).)
758 if (iC < 0 || iC >= (PetscInt)userGlobalMx ||
759 jC < 0 || jC >= (PetscInt)userGlobalMy ||
760 kC < 0 || kC >= (PetscInt)userGlobalMz)
761 {
762 // skip this corner
763 continue;
764 }
765
766 */
767
768 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);
769
770 // Otherwise, accumulate
771 accum.x += wcorner[c] * fieldVec[kC][jC][iC].x;
772 accum.y += wcorner[c] * fieldVec[kC][jC][iC].y;
773 accum.z += wcorner[c] * fieldVec[kC][jC][iC].z;
774 sumW += wcorner[c];
775 }
776
777 // If sumW=0 => out-of-range or zero weighting => set (0,0,0)
778 if (sumW > 1.0e-14) {
779 vec->x = accum.x / sumW;
780 vec->y = accum.y / sumW;
781 vec->z = accum.z / sumW;
782 } else {
783 vec->x = 0.0; vec->y = 0.0; vec->z = 0.0;
784 }
785
786 PetscFunctionReturn(0);
787}
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.

Definition at line 958 of file interpolation.c.

963{
964 PetscErrorCode ierr;
965 DM fda = user->fda;
966 DM swarm = user->swarm;
967 PetscInt bs;
968 DMDALocalInfo info;
969 PetscMPIInt rank;
970
971 // Generic pointers to the raw data arrays
972 void *cellCenterPtr_read;
973 void *cornerPtr_read_with_ghosts;
974
975 // Swarm-related pointers
976 PetscInt *cellIDs = NULL;
977 PetscReal *weights = NULL;
978 PetscInt *pids = NULL; // For logging particle IDs in warnings
979 void *swarmOut = NULL;
980 PetscInt nLocal;
981
982 PetscFunctionBegin;
984 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
985 ierr = DMDAGetLocalInfo(fda, &info); CHKERRQ(ierr);
986 ierr = VecGetBlockSize(fieldLocal_cellCentered, &bs); CHKERRQ(ierr);
987 if (bs != 1 && bs != 3) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "BlockSize must be 1 or 3.");
988
989 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting for field '%s'... \n", fieldName);
990
991 /* STAGE 1: Center-to-Corner Calculation with Communication */
992
993 // (A) Create the corner vectors.
994 if(user->CellFieldAtCorner == NULL){
995 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Creating new global corner vector for field '%s'.\n", rank, fieldName);
996 ierr = DMCreateGlobalVector(fda, &user->CellFieldAtCorner); CHKERRQ(ierr);
997 }else{
998 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Reusing existing global corner vector for field '%s'.\n", rank, fieldName);
999 }
1000
1001 ierr = VecSet(user->CellFieldAtCorner,0.0); CHKERRQ(ierr);
1002 Vec cornerGlobal = user->CellFieldAtCorner;
1003
1004 if(user->lCellFieldAtCorner == NULL){
1005 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Creating new local corner vector for field '%s'.\n", rank, fieldName);
1006 ierr = DMCreateLocalVector(fda, &user->lCellFieldAtCorner); CHKERRQ(ierr);
1007 }else{
1008 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Reusing existing local corner vector for field '%s'.\n", rank, fieldName);
1009 }
1010
1011 ierr = VecSet(user->lCellFieldAtCorner,0.0); CHKERRQ(ierr);
1012 Vec cornerLocal = user->lCellFieldAtCorner;
1013
1014 // (B) Get a read-only array from the input cell-centered vector
1015 ierr = DMDAVecGetArrayRead(fda, fieldLocal_cellCentered, &cellCenterPtr_read); CHKERRQ(ierr);
1016
1017 PetscInt size;
1018 ierr = VecGetSize(cornerGlobal, &size); CHKERRQ(ierr);
1019 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Corner global vector size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1020
1021 size = 0;
1022
1023 ierr = VecGetSize(fieldLocal_cellCentered, &size); CHKERRQ(ierr);
1024 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Cell-centered local vector size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1025
1026 size = 0;
1027
1028 ierr = VecGetLocalSize(cornerGlobal, &size); CHKERRQ(ierr);
1029 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Corner global vector LOCAL size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1030
1031 size = 0;
1032
1033 ierr = VecGetLocalSize(fieldLocal_cellCentered, &size); CHKERRQ(ierr);
1034 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Cell-centered local vector LOCAL size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1035
1036 size = 0;
1037
1038 ierr = VecGetSize(cornerLocal, &size); CHKERRQ(ierr);
1039 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Corner local vector size for field '%s': %d.\n", rank, fieldName, (PetscInt)size);
1040
1041 PetscInt xs,ys,zs,gxs,gys,gzs;
1042 ierr = DMDAGetCorners(fda,&xs,&ys,&zs,NULL,NULL,NULL); CHKERRQ(ierr);
1043 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);
1044
1045 ierr = DMDAGetGhostCorners(fda,&gxs,&gys,&gzs,NULL,NULL,NULL); CHKERRQ(ierr);
1046 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);
1047
1048 // DEBUG: Inspect Ucat ghost cells before interpolation
1049 /*
1050 if (bs == 3) {
1051 Cmpnts ***ucat_array = (Cmpnts***)cellCenterPtr_read;
1052 DMDALocalInfo info_debug;
1053 ierr = DMDAGetLocalInfo(fda, &info_debug); CHKERRQ(ierr);
1054
1055 // Only print on rank 0 to avoid clutter
1056 if (rank == 0) {
1057 PetscPrintf(PETSC_COMM_SELF, "\nDEBUG: Inspecting Ucat Ghost Cells...\n");
1058 PetscPrintf(PETSC_COMM_SELF, "--------------------------------------------------\n");
1059
1060 // --- Check the MINIMUM-SIDE (-Xi) ---
1061 // The first physical cell is at index info.xs (local index).
1062 // The first ghost cell is at info.xs - 1.
1063 PetscInt i_first_phys = info_debug.xs;
1064 PetscInt i_first_ghost = info_debug.xs - 1;
1065 PetscInt j_mid = info_debug.ys + info_debug.ym / 2;
1066 PetscInt k_mid = info_debug.zs + info_debug.zm / 2;
1067
1068 PetscPrintf(PETSC_COMM_SELF, "MIN-SIDE (-Xi):\n");
1069 PetscPrintf(PETSC_COMM_SELF, " Ghost Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1070 k_mid, j_mid, i_first_ghost,
1071 ucat_array[k_mid][j_mid][i_first_ghost].x,
1072 ucat_array[k_mid][j_mid][i_first_ghost].y,
1073 ucat_array[k_mid][j_mid][i_first_ghost].z);
1074 PetscPrintf(PETSC_COMM_SELF, " First Phys Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1075 k_mid, j_mid, i_first_phys,
1076 ucat_array[k_mid][j_mid][i_first_phys].x,
1077 ucat_array[k_mid][j_mid][i_first_phys].y,
1078 ucat_array[k_mid][j_mid][i_first_phys].z);
1079
1080
1081 // --- Check the MAXIMUM-SIDE (+Xi) ---
1082 // The last physical cell is at index info.xs + info.xm - 1.
1083 // The first ghost cell on the max side is at info.xs + info.xm.
1084 PetscInt i_last_phys = info_debug.xs + info_debug.xm - 1;
1085 PetscInt i_last_ghost = info_debug.xs + info_debug.xm;
1086
1087 PetscPrintf(PETSC_COMM_SELF, "MAX-SIDE (+Xi):\n");
1088 PetscPrintf(PETSC_COMM_SELF, " Last Phys Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1089 k_mid, j_mid, i_last_phys,
1090 ucat_array[k_mid][j_mid][i_last_phys].x,
1091 ucat_array[k_mid][j_mid][i_last_phys].y,
1092 ucat_array[k_mid][j_mid][i_last_phys].z);
1093 PetscPrintf(PETSC_COMM_SELF, " Ghost Cell Ucat[%d][%d][%d] = (% .6f, % .6f, % .6f)\n",
1094 k_mid, j_mid, i_last_ghost,
1095 ucat_array[k_mid][j_mid][i_last_ghost].x,
1096 ucat_array[k_mid][j_mid][i_last_ghost].y,
1097 ucat_array[k_mid][j_mid][i_last_ghost].z);
1098 PetscPrintf(PETSC_COMM_SELF, "--------------------------------------------------\n\n");
1099 }
1100 }
1101 */
1102 // DEBUG
1103
1104 // (C) Perform the center-to-corner interpolation directly into the global corner vector
1105 void *cornerPtr_write = NULL;
1106 ierr = DMDAVecGetArray(fda, cornerGlobal, &cornerPtr_write); CHKERRQ(ierr);
1107
1108 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Starting center-to-corner interpolation for '%s'.\n", rank, fieldName);
1109
1110 // SINGLE, CLEAN CALL SITE: The macro handles the runtime dispatch based on 'bs'.
1111 ierr = InterpolateFieldFromCenterToCorner(bs, cellCenterPtr_read, cornerPtr_write, user); CHKERRQ(ierr);
1112
1113 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Finished center-to-corner interpolation for '%s'.\n", rank, fieldName);
1114 ierr = DMDAVecRestoreArray(fda, cornerGlobal, &cornerPtr_write); CHKERRQ(ierr);
1115
1116 ierr = DMDAVecRestoreArrayRead(fda, fieldLocal_cellCentered, &cellCenterPtr_read); CHKERRQ(ierr);
1117
1118 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
1119
1120 //////////// DEBUG
1121 /*
1122 // Log a synchronized header message from all ranks.
1123 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Dumping cornerGlobal BEFORE ghost exchange...\n");
1124
1125 // VecView prints to a PETSc viewer. PETSC_VIEWER_STDOUT_WORLD is a global, synchronized viewer.
1126 // We only need to call it if logging is active for this function.
1127 if (is_function_allowed(__func__) && (int)(LOG_DEBUG) <= (int)get_log_level()) {
1128 ierr = VecView(cornerGlobal, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
1129 }
1130
1131 // Log a synchronized footer message.
1132 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Finished dumping cornerGlobal.\n");
1133 */
1134 ////////// DEBUG
1135
1136 // ierr = PetscBarrier((PetscObject)cornerGlobal); CHKERRQ(ierr);
1137
1138 // (D) CRITICAL STEP: Communicate the newly computed corner data to fill ghost regions
1139 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Beginning ghost exchange for corner data...\n", rank);
1140
1141 ierr = DMGlobalToLocalBegin(fda, cornerGlobal, INSERT_VALUES, cornerLocal); CHKERRQ(ierr);
1142 ierr = DMGlobalToLocalEnd(fda, cornerGlobal, INSERT_VALUES, cornerLocal); CHKERRQ(ierr);
1143
1144 LOG_ALLOW(LOCAL, LOG_TRACE, "[Rank %d] Ghost exchange for corner data complete.\n", rank);
1145
1146 LOG_ALLOW_SYNC(GLOBAL, LOG_VERBOSE, "getting array from FDA on all ranks.\n");
1147 if (is_function_allowed(__func__) && (int)(LOG_VERBOSE) <= (int)get_log_level()) {
1148 // DEBUG: Inspect cornerLocal after ghost exchange
1149
1150 ierr = LOG_FIELD_ANATOMY(user,"CornerField", "After Corner Velocity Interpolated"); CHKERRQ(ierr);
1151
1152 // DEBUG
1153 //ierr = DMView(user->fda, PETSC_VIEWER_STDOUT_WORLD); CHKERRQ(ierr);
1154 }
1155
1156 /////// DEBUG
1157 /*
1158 // Log a synchronized header message from all ranks.
1159 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Dumping cornerLocal AFTER ghost exchange...\n");
1160
1161 // Here, we want each rank to print its own local vector.
1162 // PETSC_VIEWER_STDOUT_SELF is the correct tool for this. The LOG_ALLOW_SYNC
1163 // wrapper will ensure the output from each rank is printed sequentially.
1164 if (is_function_allowed(__func__) && (int)(LOG_DEBUG) <= (int)get_log_level()) {
1165 PetscMPIInt rank_d;
1166 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank_d); CHKERRQ(ierr);
1167
1168 // Use a synchronized print to create a clean header for each rank's output
1169 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "\n--- cornerLocal (Rank %d) ---\n", rank_d);
1170 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT);
1171
1172 // Print the local vector's contents for this rank
1173 ierr = VecView(cornerLocal, PETSC_VIEWER_STDOUT_SELF); CHKERRQ(ierr);
1174
1175 // Use a synchronized print to create a clean footer
1176 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--- End cornerLocal (Rank %d) ---\n", rank_d);
1177 PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT);
1178 }
1179
1180 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "DEBUG: Finished dumping cornerLocal.\n");
1181 */
1182 ///// DEBUG
1183
1184 /* STAGE 2: Particle Interpolation using Ghosted Corner Data */
1185
1186 // (E) Get the local, GHOSTED array of corner data for the final interpolation step
1187 ierr = DMDAVecGetArrayRead(fda, cornerLocal, &cornerPtr_read_with_ghosts); CHKERRQ(ierr);
1188
1189 // (F) Retrieve swarm fields for the particle loop
1190 ierr = DMSwarmGetLocalSize(swarm, &nLocal); CHKERRQ(ierr);
1191 ierr = DMSwarmGetField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
1192 ierr = DMSwarmGetField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&pids); CHKERRQ(ierr);
1193 ierr = DMSwarmGetField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
1194 ierr = DMSwarmGetField(swarm, swarmOutFieldName, NULL, NULL, &swarmOut); CHKERRQ(ierr);
1195
1196 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);
1197
1198 // (G) Loop over each local particle
1199 for (PetscInt p = 0; p < nLocal; p++) {
1200 PetscInt iCell_global = cellIDs[3 * p + 0];
1201 PetscInt jCell_global = cellIDs[3 * p + 1];
1202 PetscInt kCell_global = cellIDs[3 * p + 2];
1203
1204
1206 "[Rank %d] Particle PID %lld: global cell=(%d,%d,%d), weights=(%.4f,%.4f,%.4f)\n",
1207 rank, (long long)pids[p], iCell_global, jCell_global, kCell_global,
1208 weights[3 * p + 0], weights[3 * p + 1], weights[3 * p + 2]);
1209 // Safety check: Ensure the entire 8-node stencil is within the valid memory
1210 // region (owned + ghosts) of the local array.
1211
1212 if (iCell_global < info.gxs || iCell_global >= info.gxs + info.gxm - 1 ||
1213 jCell_global < info.gxs || jCell_global >= info.gys + info.gym - 1 ||
1214 kCell_global < info.gxs || kCell_global >= info.gzs + info.gzm - 1)
1215 {
1217 "[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",
1218 rank, (long long)pids[p], iCell_global, jCell_global, kCell_global, fieldName);
1219
1220 if (bs == 3) {
1221 ((PetscReal*)swarmOut)[3*p + 0] = 0.0;
1222 ((PetscReal*)swarmOut)[3*p + 1] = 0.0;
1223 ((PetscReal*)swarmOut)[3*p + 2] = 0.0;
1224 } else {
1225 ((PetscReal*)swarmOut)[p] = 0.0;
1226 }
1227 continue;
1228 }
1229
1230 PetscReal a1 = weights[3 * p + 0];
1231 PetscReal a2 = weights[3 * p + 1];
1232 PetscReal a3 = weights[3 * p + 2];
1233
1235 fieldName,
1236 cornerPtr_read_with_ghosts,
1237 iCell_global, jCell_global, kCell_global,
1238 a1, a2, a3,
1239 swarmOut, p, bs);
1240 CHKERRQ(ierr);
1241 }
1242
1243 /* (H) Restore all retrieved arrays and vectors */
1244 ierr = DMDAVecRestoreArrayRead(fda, cornerLocal, &cornerPtr_read_with_ghosts); CHKERRQ(ierr);
1245 ierr = DMSwarmRestoreField(swarm, swarmOutFieldName, NULL, NULL, &swarmOut); CHKERRQ(ierr);
1246 ierr = DMSwarmRestoreField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
1247 ierr = DMSwarmRestoreField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&pids); CHKERRQ(ierr);
1248 ierr = DMSwarmRestoreField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
1249
1250 LOG_ALLOW(GLOBAL, LOG_INFO, "Finished for field '%s'.\n", fieldName);
1252 PetscFunctionReturn(0);
1253}
static PetscErrorCode InterpolateEulerFieldToSwarmForParticle(const char *fieldName, void *fieldPtr, PetscInt iCell, PetscInt jCell, PetscInt kCell, PetscReal a1, PetscReal a2, PetscReal a3, 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:268
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:47
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:740
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:1435
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:34
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:32
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:731
Vec lCellFieldAtCorner
Definition variables.h:693
Vec CellFieldAtCorner
Definition variables.h:693
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 1276 of file interpolation.c.

1277{
1278 PetscErrorCode ierr;
1279 PetscMPIInt rank;
1280 PetscFunctionBegin;
1281
1283
1284 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
1285
1286 /*
1287 1) Interpolate the 'velocity' field (user->Ucat) into DMSwarm's "swarmVelocity".
1288 - The function InterpolateOneFieldOverSwarm() loops over all local particles,
1289 retrieves iCell, jCell, kCell, (a1,a2,a3) from the DMSwarm,
1290 and calls the appropriate trilinear interpolation routine.
1291
1292 - "velocity" => just a label used in logging or debugging.
1293 - "swarmVelocity" => the DMSwarm field name where we store the result
1294 (assume dof=3 if user->Ucat has blockSize=3).
1295 */
1296
1298 " Interpolation of ucat to velocity begins on rank %d.\n",rank);
1299 // Make sure to pass the *GLOBAL* Vector to the function below!
1300 ierr = InterpolateEulerFieldToSwarm(user, user->lUcat,
1301 "Ucat",
1302 "velocity"); CHKERRQ(ierr);
1303 /*
1304 2) (OPTIONAL) If you have more fields, you can Interpolatete them similarly.
1305
1306 For example, if user->Tcat is a scalar Vec for "temperature" and the DMSwarm
1307 has a field "Temperature" (with dof=1), you could do:
1308
1309 ierr = InterpolateOneFieldOverSwarm(user, user->Tcat,
1310 "temperature",
1311 "swarmTemperature"); CHKERRQ(ierr);
1312
1313 For pressure:
1314 ierr = InterpolateOneFieldOverSwarm(user, user->Pcat,
1315 "pressure",
1316 "swarmPressure"); CHKERRQ(ierr);
1317
1318 ...and so forth.
1319 */
1320
1321 /*
1322 3) Optionally, synchronize or log that all fields are done
1323 */
1324 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
1326 "[rank %d]Completed Interpolateting all fields to the swarm.\n",rank);
1327
1329
1330 PetscFunctionReturn(0);
1331}
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:33
Vec lUcat
Definition variables.h:688
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.

This function estimates the value of a scalar field at the center of each computational cell (whose origin node is owned by this rank) by averaging the values from the 8 corner nodes defining that cell.

Parameters
[in]field_arrInput: 3D array view (ghosted) of scalar data at nodes, obtained from a Vec associated with user->da. Accessed via GLOBAL node indices. Ghost values must be up-to-date.
[out]centfield_arrOutput: 3D local array (0-indexed) where interpolated cell center values are stored. Sized [zm_cell_local][ym_cell_local][xm_cell_local] by the caller. centfield_arr[k_loc][j_loc][i_loc] stores the value for the cell corresponding to the (i_loc, j_loc, k_loc)-th owned cell origin.
[in]userUser context containing DMDA information (da, IM, JM, KM).
Returns
PetscErrorCode 0 on success.

Definition at line 166 of file interpolation.c.

170{
171 PetscErrorCode ierr;
172 PetscMPIInt rank;
173 PetscFunctionBeginUser;
175 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
177 "Rank %d starting InterpolateFieldFromCornerToCenter_Scalar.\n", rank);
178
179 // Get local info based on user->da (which is node-based but defines cell origins)
180 DMDALocalInfo info_da_nodes;
181 ierr = DMDAGetLocalInfo(user->da, &info_da_nodes); CHKERRQ(ierr);
182
183 // Determine owned CELL ranges based on owning their origin NODES (from user->da)
184 PetscInt xs_cell_global_i, xm_cell_local_i; // Global start cell index, local count of owned cells
185 PetscInt ys_cell_global_j, ym_cell_local_j;
186 PetscInt zs_cell_global_k, zm_cell_local_k;
187
188 ierr = GetOwnedCellRange(&info_da_nodes, 0, &xs_cell_global_i, &xm_cell_local_i); CHKERRQ(ierr);
189 ierr = GetOwnedCellRange(&info_da_nodes, 1, &ys_cell_global_j, &ym_cell_local_j); CHKERRQ(ierr);
190 ierr = GetOwnedCellRange(&info_da_nodes, 2, &zs_cell_global_k, &zm_cell_local_k); CHKERRQ(ierr);
191
192 // Exclusive end global cell indices
193 PetscInt xe_cell_global_i_excl = xs_cell_global_i + xm_cell_local_i;
194 PetscInt ye_cell_global_j_excl = ys_cell_global_j + ym_cell_local_j;
195 PetscInt ze_cell_global_k_excl = zs_cell_global_k + zm_cell_local_k;
196
197 LOG_ALLOW(LOCAL, LOG_TRACE, "Rank %d: Processing Owned Cells (global indices) k=%d..%d (count %d), j=%d..%d (count %d), i=%d..%d (count %d)\n",
198 rank,
199 zs_cell_global_k, ze_cell_global_k_excl -1, zm_cell_local_k,
200 ys_cell_global_j, ye_cell_global_j_excl -1, ym_cell_local_j,
201 xs_cell_global_i, xe_cell_global_i_excl -1, xm_cell_local_i);
202
203 // Loop over the GLOBAL indices of the CELLS whose origin nodes are owned by this processor
204 // (according to user->da partitioning)
205 for (PetscInt k_glob_cell = zs_cell_global_k; k_glob_cell < ze_cell_global_k_excl; k_glob_cell++) {
206 PetscInt k_local = k_glob_cell - zs_cell_global_k; // 0-based local index for centfield_arr
207
208 for (PetscInt j_glob_cell = ys_cell_global_j; j_glob_cell < ye_cell_global_j_excl; j_glob_cell++) {
209 PetscInt j_local = j_glob_cell - ys_cell_global_j; // 0-based local index
210
211 for (PetscInt i_glob_cell = xs_cell_global_i; i_glob_cell < xe_cell_global_i_excl; i_glob_cell++) {
212 PetscInt i_local = i_glob_cell - xs_cell_global_i; // 0-based local index
213
214 PetscReal sum = 0.0;
215 // Count is always 8 for a hexahedral cell if all nodes are accessible
216 // PetscInt count = 0;
217
218 // Loop over the 8 NODE indices that define cell C(i_glob_cell, j_glob_cell, k_glob_cell)
219 for (PetscInt dk = 0; dk < 2; dk++) {
220 for (PetscInt dj = 0; dj < 2; dj++) {
221 for (PetscInt di = 0; di < 2; di++) {
222 PetscInt ni_glob = i_glob_cell + di; // Global NODE index for corner
223 PetscInt nj_glob = j_glob_cell + dj; // Global NODE index for corner
224 PetscInt nk_glob = k_glob_cell + dk; // Global NODE index for corner
225
226 // Access the input 'field_arr' (node values) using GLOBAL node indices.
227 sum += field_arr[nk_glob][nj_glob][ni_glob];
228 // count++;
229 }
230 }
231 }
232
233 PetscReal center_value = sum / 8.0;
234
235 // Store the calculated cell center value into the output array 'centfield_arr'
236 // using the LOCAL 0-based cell index.
237 // Defensive check (should not be strictly necessary if caller allocated centfield_arr correctly)
238 if (i_local < 0 || i_local >= xm_cell_local_i ||
239 j_local < 0 || j_local >= ym_cell_local_j ||
240 k_local < 0 || k_local >= zm_cell_local_k) {
241 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local index out of bounds for centfield_arr write in Scalar version!");
242 }
243 centfield_arr[k_local][j_local][i_local] = center_value;
244
245 } // End loop i_glob_cell
246 } // End loop j_glob_cell
247 } // End loop k_glob_cell
248
250 "Rank %d completed InterpolateFieldFromCornerToCenter_Scalar.\n", rank);
251
253
254 PetscFunctionReturn(0);
255}
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:1663
Here is the call graph for this function:

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

This function estimates the value of a vector field at the center of each computational cell (whose origin node is owned by this rank) by averaging the values from the 8 corner nodes defining that cell.

Parameters
[in]field_arrInput: 3D array view (ghosted) of vector data at nodes, obtained from a Vec associated with user->fda. Accessed via GLOBAL node indices. Ghost values must be up-to-date.
[out]centfield_arrOutput: 3D local array (0-indexed) where interpolated cell center values are stored. Sized [zm_cell_local][ym_cell_local][xm_cell_local] by the caller. centfield_arr[k_loc][j_loc][i_loc] stores the value for the cell corresponding to the (i_loc, j_loc, k_loc)-th owned cell origin.
[in]userUser context containing DMDA information (fda, IM, JM, KM).
Returns
PetscErrorCode 0 on success.

Definition at line 39 of file interpolation.c.

43{
44 PetscErrorCode ierr;
45 PetscMPIInt rank;
46 PetscFunctionBeginUser;
48
49 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
51 "Rank %d starting InterpolateFieldFromCornerToCenter_Vector.\n", rank);
52
53 // Get local info based on the NODE-based DMDA (user->fda)
54 // This DM defines the ownership of the nodes from which we interpolate,
55 // and thus defines the cells whose centers we will compute.
56 DMDALocalInfo info_fda;
57 ierr = DMDAGetLocalInfo(user->fda, &info_fda); CHKERRQ(ierr);
58
59 // Determine owned CELL ranges based on owning their origin NODES (from user->fda)
60 PetscInt xs_cell_global_i, xm_cell_local_i; // Global start cell index, local count of owned cells
61 PetscInt ys_cell_global_j, ym_cell_local_j;
62 PetscInt zs_cell_global_k, zm_cell_local_k;
63
64
65 ierr = GetOwnedCellRange(&info_fda, 0, &xs_cell_global_i, &xm_cell_local_i); CHKERRQ(ierr);
66 ierr = GetOwnedCellRange(&info_fda, 1, &ys_cell_global_j, &ym_cell_local_j); CHKERRQ(ierr);
67 ierr = GetOwnedCellRange(&info_fda, 2, &zs_cell_global_k, &zm_cell_local_k); CHKERRQ(ierr);
68
69 // Exclusive end global cell indices
70 PetscInt xe_cell_global_i_excl = xs_cell_global_i + xm_cell_local_i;
71 PetscInt ye_cell_global_j_excl = ys_cell_global_j + ym_cell_local_j;
72 PetscInt ze_cell_global_k_excl = zs_cell_global_k + zm_cell_local_k;
73
74 LOG_ALLOW(LOCAL, LOG_TRACE, "Rank %d : Processing Owned Cells (global indices) k=%d..%d (count %d), j=%d..%d (count %d), i=%d..%d (count %d)\n",
75 rank,
76 zs_cell_global_k, ze_cell_global_k_excl -1, zm_cell_local_k,
77 ys_cell_global_j, ye_cell_global_j_excl -1, ym_cell_local_j,
78 xs_cell_global_i, xe_cell_global_i_excl -1, xm_cell_local_i);
79
80 // Loop over the GLOBAL indices of the CELLS whose origin nodes are owned by this processor
81 // (according to user->fda partitioning)
82 for (PetscInt k_glob_cell = zs_cell_global_k; k_glob_cell < ze_cell_global_k_excl; k_glob_cell++) {
83 PetscInt k_local = k_glob_cell - zs_cell_global_k; // 0-based local index for centfield_arr
84
85 for (PetscInt j_glob_cell = ys_cell_global_j; j_glob_cell < ye_cell_global_j_excl; j_glob_cell++) {
86 PetscInt j_local = j_glob_cell - ys_cell_global_j; // 0-based local index
87
88 for (PetscInt i_glob_cell = xs_cell_global_i; i_glob_cell < xe_cell_global_i_excl; i_glob_cell++) {
89 PetscInt i_local = i_glob_cell - xs_cell_global_i; // 0-based local index
90
91 Cmpnts sum = {0.0, 0.0, 0.0};
92 // Count is always 8 for a hexahedral cell
93 // PetscInt count = 0; // Not strictly needed if we assume 8 corners
94
95 // Loop over the 8 corner NODES that define cell C(i_glob_cell, j_glob_cell, k_glob_cell)
96 for (PetscInt dk = 0; dk < 2; dk++) {
97 for (PetscInt dj = 0; dj < 2; dj++) {
98 for (PetscInt di = 0; di < 2; di++) {
99 PetscInt ni_glob = i_glob_cell + di; // Global NODE index i or i+1
100 PetscInt nj_glob = j_glob_cell + dj; // Global NODE index j or j+1
101 PetscInt nk_glob = k_glob_cell + dk; // Global NODE index k or k+1
102
103 // Access the input 'field_arr' (node values) using GLOBAL node indices.
104 // Ghosts in field_arr must be valid.
105 // DMDAVecGetArrayRead handles mapping global indices to local memory.
106 sum.x += field_arr[nk_glob][nj_glob][ni_glob].x;
107 sum.y += field_arr[nk_glob][nj_glob][ni_glob].y;
108 sum.z += field_arr[nk_glob][nj_glob][ni_glob].z;
109 // count++;
110 }
111 }
112 }
113
114 // Calculate average value representing the cell center
115 Cmpnts center_value;
116 center_value.x = sum.x / 8.0;
117 center_value.y = sum.y / 8.0;
118 center_value.z = sum.z / 8.0;
119
120 // Store result into the local, 0-indexed output array 'centfield_arr'
121 // Defensive check (should not be strictly necessary if caller allocated centfield_arr
122 // with dimensions xm_cell_local_i, ym_cell_local_j, zm_cell_local_k)
123 if (i_local < 0 || i_local >= xm_cell_local_i ||
124 j_local < 0 || j_local >= ym_cell_local_j ||
125 k_local < 0 || k_local >= zm_cell_local_k) {
126 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Local index out of bounds for centfield_arr write!");
127 }
128 centfield_arr[k_local][j_local][i_local] = center_value;
129
130 } // End loop i_glob_cell
131 } // End loop j_glob_cell
132 } // End loop k_glob_cell
133
135 "Rank %d completed InterpolateFieldFromCornerToCenter_Vector.\n", rank);
136
138
139 PetscFunctionReturn(0);
140}
Here is the call graph for this function:

◆ InterpolateFieldFromCenterToCorner_Scalar()

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

Interpolates a scalar field from cell centers to corner nodes.

This function estimates the value of a scalar field at each grid node by averaging the values from the cell centers of the cells surrounding that node (up to 8). It handles physical boundaries by averaging only the available adjacent cells.

Assumes input centfield_arr is from a ghosted local vector associated with user->da (DOF=1, s=2) and output field_arr is from a ghosted local vector also associated with user->da (DOF=1, s=2). Input array uses GLOBAL cell indices, output array uses GLOBAL node indices.

Parameters
[in]centfield_arrInput: 3D array (ghosted) of scalar data at cell centers, accessed via GLOBAL cell indices (k=0..KM-1, j=0..JM-1, i=0..IM-1).
[out]field_arrOutput: 3D array (ghosted) where interpolated node values are stored, accessed via GLOBAL node indices (k=0..KM, j=0..JM, i=0..IM).
[in]userUser context containing DMDA information (da).
Returns
PetscErrorCode 0 on success.

◆ InterpolateFieldFromCenterToCorner_Vector()

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

Interpolates a vector field from cell centers to corner nodes.

This function estimates the value of a vector field at each grid node by averaging the vector values from the cell centers of the cells surrounding that node (up to 8). It handles physical boundaries by averaging only the available adjacent cells.

Assumes input centfield_arr is from a ghosted local vector (e.g., representing ucat, stored using node-indexing convention) and output field_arr is a ghosted local vector associated with user->fda (DOF=3, s=2), accessed using global node indices.

Parameters
[in]centfield_arrInput: 3D array (ghosted) of vector data conceptually at cell centers, accessed via GLOBAL indices respecting the storage convention (e.g., ucat[k][j][i] uses node index i but represents cell C(i,j,k) for interior).
[out]field_arrOutput: 3D array (ghosted) where interpolated node values are stored, accessed via GLOBAL node indices (k=0..KM, j=0..JM, i=0..IM).
[in]userUser context containing DMDA information (da and fda).
Returns
PetscErrorCode 0 on success.

◆ InterpolateFieldFromCenterToCorner_Vector_Petsc()

PetscErrorCode InterpolateFieldFromCenterToCorner_Vector_Petsc ( 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 270 of file interpolation.c.

274{
275 PetscErrorCode ierr;
276 DMDALocalInfo info;
277 PetscMPIInt rank;
279 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
280 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
281
282 // Node ownership range (GLOBAL indices)
283 PetscInt xs_node = info.xs, xm_node = info.xm, xe_node = xs_node + xm_node;
284 PetscInt ys_node = info.ys, ym_node = info.ym, ye_node = ys_node + ym_node;
285 PetscInt zs_node = info.zs, zm_node = info.zm, ze_node = zs_node + zm_node;
286
287 PetscInt nCellsX = info.mx - 2; // Number of cells in x-direction
288 PetscInt nCellsY = info.my - 2; // Number of cells in y-direction
289 PetscInt nCellsZ = info.mz - 2; // Number of cells in z-direction
290
291
292 // Global grid dimensions (used for valid cell check)
293 PetscInt IM = info.mx - 1; // Total nodes in i-direction
294 PetscInt JM = info.my - 1; // Total nodes in j-direction
295 PetscInt KM = info.mz - 1; // Total nodes in k-direction
296
297 // Ghosted array starting indices (from the same info struct)
298 PetscInt gxs = info.gxs;
299 PetscInt gys = info.gys;
300 PetscInt gzs = info.gzs;
301
302 PetscInt xs = info.xs;
303 PetscInt ys = info.ys;
304 PetscInt zs = info.zs;
305
307 "[Rank %d] Starting InterpolateFieldFromCenterToCorner_Vector_Petsc: Node ownership k=%d..%d, j=%d..%d, i=%d..%d\n",
308 rank, zs_node, ze_node-1, ys_node, ye_node-1, xs_node, xe_node-1);
309
310 // Loop over the GLOBAL indices of the NODES owned by this processor
311 for (PetscInt k = zs_node; k < ze_node; k++) {
312 for (PetscInt j = ys_node; j < ye_node; j++) {
313 for (PetscInt i = xs_node; i < xe_node; i++) {
314 Cmpnts sum = {0.0, 0.0, 0.0};
315 PetscInt count = 0;
316
317 // DEBUG 1 TEST
318 /*
319 if(rank == 1 && i == 24 && j == 12 && k == 49){
320 PetscInt i_cell_A = i - 1;
321 PetscInt i_cell_B = i;
322
323 Cmpnts ucat_A = centfield_arr[k][j][i_cell_A]; // 23
324 Cmpnts ucat_B = centfield_arr[k][j][i_cell_B]; // 24 (out-of-bounds if IM=25)
325
326 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",
327 rank, k, j, i,
328 k, j, i_cell_A, ucat_A.x, ucat_A.y, ucat_A.z,
329 k, j, i_cell_B, ucat_B.x, ucat_B.y, ucat_B.z);
330
331 }
332 */
333
334 // Skip processing the unused last node in each dimension.
335 if(i >= IM || j >= JM || k >= KM){
336 continue;
337 }
338 // Loop over the 8 potential cells surrounding node N(k,j,i) and accumulate values.
339 // 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
340 for (PetscInt dk_offset = -1; dk_offset <= 0; dk_offset++) {
341 for (PetscInt dj_offset = -1; dj_offset <= 0; dj_offset++) {
342 for (PetscInt di_offset = -1; di_offset <= 0; di_offset++) {
343
344 // These are still GLOBAL cell indices
345 PetscInt global_cell_k = k + dk_offset;
346 PetscInt global_cell_j = j + dj_offset;
347 PetscInt global_cell_i = i + di_offset;
348
349 // Check if this corresponds to a valid GLOBAL cell index
350 if (global_cell_i >= 0 && global_cell_i < nCellsX &&
351 global_cell_j >= 0 && global_cell_j < nCellsY &&
352 global_cell_k >= 0 && global_cell_k < nCellsZ)
353 {
354 Cmpnts cell_val = centfield_arr[global_cell_k + 1][global_cell_j + 1][global_cell_i + 1];
355
356 LOG_LOOP_ALLOW_EXACT(LOCAL, LOG_VERBOSE,k,49,"[Rank %d] successful read from [%d][%d][%d] -> (%.2f, %.2f, %.2f)\n",
357 rank,global_cell_k,global_cell_j,global_cell_i,cell_val.x, cell_val.y, cell_val.z);
358
359 sum.x += cell_val.x;
360 sum.y += cell_val.y;
361 sum.z += cell_val.z;
362 count++;
363 }
364 }
365 }
366 }
367
368 PetscInt i_global_write = i; // Global index in GLOBAL array.
369 PetscInt j_global_write = j;
370 PetscInt k_global_write = k;
371
372 // We write directly into the array using the global loop indices.
373 if (count > 0) {
374 corner_arr[k_global_write][j_global_write][i_global_write].x = sum.x / (PetscReal)count;
375 corner_arr[k_global_write][j_global_write][i_global_write].y = sum.y / (PetscReal)count;
376 corner_arr[k_global_write][j_global_write][i_global_write].z = sum.z / (PetscReal)count;
377 } else {
378 // This case should ideally not happen for a valid owned node, but as a failsafe:
379 corner_arr[k_global_write][j_global_write][i_global_write] = (Cmpnts){0.0, 0.0, 0.0};
380 }
381
382 // DEBUG 2
383 /*
384 if(rank == 1){
385 if(i == 11 && j == 11 && k == 49){
386 Cmpnts ucat_node = corner_arr[k][j][i];
387 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",
388 rank, k, j, i,
389 k, j, i, ucat_node.x, ucat_node.y, ucat_node.z);
390 }
391 }
392
393 if(rank == 0 && i == 24 && j == 12 && k == 0){
394 Cmpnts ucat_node = corner_arr[k][j][i];
395 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",
396 rank, k, j, i,
397 k, j, i, ucat_node.x, ucat_node.y, ucat_node.z);
398 }
399 */
400 // 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);
401 }
402 }
403 }
405 return 0;
406}
#define LOG_LOOP_ALLOW_EXACT(scope, level, var, val, fmt,...)
Logs a custom message if a variable equals a specific value.
Definition logging.h:349

◆ InterpolateFieldFromCenterToCorner_Scalar_Petsc()

PetscErrorCode InterpolateFieldFromCenterToCorner_Scalar_Petsc ( 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.

Definition at line 424 of file interpolation.c.

428{
429 PetscErrorCode ierr;
430 DMDALocalInfo info;
432 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
433
434 // Node ownership range (GLOBAL indices)
435 PetscInt xs_node = info.xs, xe_node = info.xs + info.xm;
436 PetscInt ys_node = info.ys, ye_node = info.ys + info.ym;
437 PetscInt zs_node = info.zs, ze_node = info.zs + info.zm;
438
439 // Global grid dimensions (number of nodes)
440 PetscInt IM = info.mx-1;
441 PetscInt JM = info.my-1;
442 PetscInt KM = info.mz-1;
443
444 // Loop over the GLOBAL indices of the NODES owned by this processor
445 for (PetscInt k = zs_node; k < ze_node; k++) {
446 for (PetscInt j = ys_node; j < ye_node; j++) {
447 for (PetscInt i = xs_node; i < xe_node; i++) {
448 PetscReal sum = 0.0;
449 PetscInt count = 0;
450
451 // Loop over the 8 potential cells surrounding node N(k,j,i)
452 for (PetscInt dk_offset = -1; dk_offset <= 0; dk_offset++) {
453 for (PetscInt dj_offset = -1; dj_offset <= 0; dj_offset++) {
454 for (PetscInt di_offset = -1; di_offset <= 0; di_offset++) {
455 // This is the global index of the cell-centered data point
456 PetscInt cell_idx_k = k + dk_offset;
457 PetscInt cell_idx_j = j + dj_offset;
458 PetscInt cell_idx_i = i + di_offset;
459
460 // Check if this corresponds to a valid GLOBAL cell index.
461 // Cell indices run from 0 to NumberOfNodes-2.
462 if (cell_idx_i >= 0 && cell_idx_i < IM - 1 &&
463 cell_idx_j >= 0 && cell_idx_j < JM - 1 &&
464 cell_idx_k >= 0 && cell_idx_k < KM - 1)
465 {
466 sum += centfield_arr[cell_idx_k][cell_idx_j][cell_idx_i];
467 count++;
468 }
469 }
470 }
471 }
472
473 // Calculate average and write to the output array using GLOBAL indices
474 if (count > 0) {
475 corner_arr[k][j][i] = sum / (PetscReal)count;
476 } else {
477 corner_arr[k][j][i] = 0.0; // Failsafe
478 }
479 }
480 }
481 }
483 return 0;
484}

◆ 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 2004 of file interpolation.c.

2010{
2011 PetscErrorCode ierr;
2012 DMDALocalInfo info;
2013
2014 PetscFunctionBeginUser;
2015
2017
2018 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2019
2020 // Determine owned-cell ranges based on corner-node ownership
2021 PetscInt xs, xm, ys, ym, zs, zm;
2022 ierr = GetOwnedCellRange(&info, 0, &xs, &xm); CHKERRQ(ierr);
2023 ierr = GetOwnedCellRange(&info, 1, &ys, &ym); CHKERRQ(ierr);
2024 ierr = GetOwnedCellRange(&info, 2, &zs, &zm); CHKERRQ(ierr);
2025
2026 // Global exclusive end indices for cells
2027 PetscInt xe = xs + xm;
2028 PetscInt ye = ys + ym;
2029 PetscInt ze = zs + zm;
2030
2031 // --- X‐faces: loops k=zs..ze-1, j=ys..ye-1, i=xs..xe (xm+1 faces per row) ---
2032 for (PetscInt k = zs; k < ze; ++k) {
2033 PetscInt k_loc = k - zs;
2034 for (PetscInt j = ys; j < ye; ++j) {
2035 PetscInt j_loc = j - ys;
2036 for (PetscInt i = xs; i <= xe; ++i) {
2037 PetscInt i_loc = i - xs; // 0..xm
2038 // Average the four corners of the Y-Z face at X = i
2039 PetscReal sum = corner_arr[k ][j ][i]
2040 + corner_arr[k+1][j ][i]
2041 + corner_arr[k ][j+1][i]
2042 + corner_arr[k+1][j+1][i];
2043 faceX_arr[k_loc][j_loc][i_loc] = sum * 0.25;
2044 }
2045 }
2046 }
2047
2048 // --- Y‐faces: loops k=zs..ze-1, j=ys..ye (ym+1 faces), i=xs..xe-1 ---
2049 for (PetscInt k = zs; k < ze; ++k) {
2050 PetscInt k_loc = k - zs;
2051 for (PetscInt j = ys; j <= ye; ++j) {
2052 PetscInt j_loc = j - ys; // 0..ym
2053 for (PetscInt i = xs; i < xe; ++i) {
2054 PetscInt i_loc = i - xs;
2055 // Average the four corners of the X-Z face at Y = j
2056 PetscReal sum = corner_arr[k ][j][i ]
2057 + corner_arr[k+1][j][i ]
2058 + corner_arr[k ][j][i+1]
2059 + corner_arr[k+1][j][i+1];
2060 faceY_arr[k_loc][j_loc][i_loc] = sum * 0.25;
2061 }
2062 }
2063 }
2064
2065 // --- Z‐faces: loops k=zs..ze (zm+1), j=ys..ye-1, i=xs..xe-1 ---
2066 for (PetscInt k = zs; k <= ze; ++k) {
2067 PetscInt k_loc = k - zs;
2068 for (PetscInt j = ys; j < ye; ++j) {
2069 PetscInt j_loc = j - ys;
2070 for (PetscInt i = xs; i < xe; ++i) {
2071 PetscInt i_loc = i - xs;
2072 // Average the four corners of the X-Y face at Z = k
2073 PetscReal sum = corner_arr[k][j ][i ]
2074 + corner_arr[k][j ][i+1]
2075 + corner_arr[k][j+1][i ]
2076 + corner_arr[k][j+1][i+1];
2077 faceZ_arr[k_loc][j_loc][i_loc] = sum * 0.25;
2078 }
2079 }
2080 }
2081
2083
2084 PetscFunctionReturn(0);
2085}
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 2104 of file interpolation.c.

2110{
2111 PetscErrorCode ierr;
2112 DMDALocalInfo info;
2113 PetscMPIInt rank;
2114
2115 PetscFunctionBeginUser;
2116
2118
2119 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2121 "Rank %d starting InterpolateFieldFromCornerToFaceCenter_Vector.\n", rank);
2122
2123 ierr = DMDAGetLocalInfo(user->fda, &info); CHKERRQ(ierr);
2124
2125 PetscInt xs, xm, ys, ym, zs, zm;
2126 ierr = GetOwnedCellRange(&info, 0, &xs, &xm); CHKERRQ(ierr);
2127 ierr = GetOwnedCellRange(&info, 1, &ys, &ym); CHKERRQ(ierr);
2128 ierr = GetOwnedCellRange(&info, 2, &zs, &zm); CHKERRQ(ierr);
2129
2130 PetscInt xe = xs + xm;
2131 PetscInt ye = ys + ym;
2132 PetscInt ze = zs + zm;
2133
2134 // X-faces
2135 for (PetscInt k = zs; k < ze; ++k) {
2136 PetscInt k_loc = k - zs;
2137 for (PetscInt j = ys; j < ye; ++j) {
2138 PetscInt j_loc = j - ys;
2139 for (PetscInt i = xs; i <= xe; ++i) {
2140 PetscInt i_loc = i - xs;
2141 Cmpnts sum = {0,0,0};
2142 sum.x = corner_arr[k ][j ][i].x + corner_arr[k+1][j ][i].x
2143 + corner_arr[k ][j+1][i].x + corner_arr[k+1][j+1][i].x;
2144 sum.y = corner_arr[k ][j ][i].y + corner_arr[k+1][j ][i].y
2145 + corner_arr[k ][j+1][i].y + corner_arr[k+1][j+1][i].y;
2146 sum.z = corner_arr[k ][j ][i].z + corner_arr[k+1][j ][i].z
2147 + corner_arr[k ][j+1][i].z + corner_arr[k+1][j+1][i].z;
2148 faceX_arr[k_loc][j_loc][i_loc].x = sum.x * 0.25;
2149 faceX_arr[k_loc][j_loc][i_loc].y = sum.y * 0.25;
2150 faceX_arr[k_loc][j_loc][i_loc].z = sum.z * 0.25;
2151 }
2152 }
2153 }
2154
2156 "Rank %d x-face Interpolation complete.\n", rank);
2157
2158 // Y-faces
2159 for (PetscInt k = zs; k < ze; ++k) {
2160 PetscInt k_loc = k - zs;
2161 for (PetscInt j = ys; j <= ye; ++j) {
2162 PetscInt j_loc = j - ys;
2163 for (PetscInt i = xs; i < xe; ++i) {
2164 PetscInt i_loc = i - xs;
2165 Cmpnts sum = {0,0,0};
2166 sum.x = corner_arr[k ][j][i ].x + corner_arr[k+1][j][i ].x
2167 + corner_arr[k ][j][i+1].x + corner_arr[k+1][j][i+1].x;
2168 sum.y = corner_arr[k ][j][i ].y + corner_arr[k+1][j][i ].y
2169 + corner_arr[k ][j][i+1].y + corner_arr[k+1][j][i+1].y;
2170 sum.z = corner_arr[k ][j][i ].z + corner_arr[k+1][j][i ].z
2171 + corner_arr[k ][j][i+1].z + corner_arr[k+1][j][i+1].z;
2172 faceY_arr[k_loc][j_loc][i_loc].x = sum.x * 0.25;
2173 faceY_arr[k_loc][j_loc][i_loc].y = sum.y * 0.25;
2174 faceY_arr[k_loc][j_loc][i_loc].z = sum.z * 0.25;
2175 }
2176 }
2177 }
2178
2180 "Rank %d y-face Interpolation complete.\n", rank);
2181
2182 // Z-faces
2183 for (PetscInt k = zs; k <= ze; ++k) {
2184 PetscInt k_loc = k - zs;
2185 for (PetscInt j = ys; j < ye; ++j) {
2186 PetscInt j_loc = j - ys;
2187 for (PetscInt i = xs; i < xe; ++i) {
2188 PetscInt i_loc = i - xs;
2189 Cmpnts sum = {0,0,0};
2190 sum.x = corner_arr[k][j ][i ].x + corner_arr[k][j ][i+1].x
2191 + corner_arr[k][j+1][i ].x + corner_arr[k][j+1][i+1].x;
2192 sum.y = corner_arr[k][j ][i ].y + corner_arr[k][j ][i+1].y
2193 + corner_arr[k][j+1][i ].y + corner_arr[k][j+1][i+1].y;
2194 sum.z = corner_arr[k][j ][i ].z + corner_arr[k][j ][i+1].z
2195 + corner_arr[k][j+1][i ].z + corner_arr[k][j+1][i+1].z;
2196 faceZ_arr[k_loc][j_loc][i_loc].x = sum.x * 0.25;
2197 faceZ_arr[k_loc][j_loc][i_loc].y = sum.y * 0.25;
2198 faceZ_arr[k_loc][j_loc][i_loc].z = sum.z * 0.25;
2199 }
2200 }
2201 }
2202
2204 "Rank %d z-face Interpolation complete.\n", rank);
2205
2207 PetscFunctionReturn(0);
2208}
Here is the call graph for this function: