PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
AnalyticalSolution.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 "variables.h"
#include "ParticleSwarm.h"
#include "walkingsearch.h"
#include "grid.h"
#include "logging.h"
#include "io.h"
#include "setup.h"
#include "interpolation.h"
Include dependency graph for AnalyticalSolution.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define SetLocalCartesianField(fieldName, fieldValue, coor, FieldInitialization, Constant)
 Generic macro to select the appropriate local Cartesian field setter based on field type.
 

Functions

PetscErrorCode SetLocalCartesianField_Scalar (const char *fieldName, PetscReal *scalarField, Cmpnts *coor, PetscInt FieldInitialization, PetscReal Constant)
 Sets the local Cartesian scalar field based on input coordinates.
 
PetscErrorCode SetLocalCartesianField_Vector (const char *fieldName, Cmpnts *vecField, Cmpnts *coor, PetscInt FieldInitialization, PetscReal Constant)
 Sets the local Cartesian vector field based on input coordinates.
 
PetscErrorCode SetAnalyticalCartesianField (UserCtx *user, const char *fieldName)
 Sets an analytical Cartesian field (scalar or vector) for cell centers based on a field name.
 
PetscErrorCode SetAnalyticalContravariantField (UserCtx *user, const char *fieldName)
 Sets an analytical contravariant field (Ucont) at nodes, where each component is evaluated using the physical coordinates of its respective face center.
 
PetscErrorCode SetAnalyticalSolution (Vec tempVec, PetscInt FieldInitialization)
 Applies the analytical solution to the position vector.
 
PetscErrorCode ApplyAnalyticalBC (UserCtx *user, const char *fieldName)
 Applies analytical boundary conditions to a specified global vector or scalar field.
 
PetscErrorCode SetInitialInteriorField (UserCtx *user, const char *fieldName)
 Sets the initial values for the INTERIOR of a specified Eulerian field.
 

Macro Definition Documentation

◆ SetLocalCartesianField

#define SetLocalCartesianField (   fieldName,
  fieldValue,
  coor,
  FieldInitialization,
  Constant 
)
Value:
_Generic((fieldValue), \
)(fieldName, fieldValue, coor,FieldInitialization,Constant)
PetscErrorCode SetLocalCartesianField_Scalar(const char *fieldName, PetscReal *scalarField, Cmpnts *coor, PetscInt FieldInitialization, PetscReal Constant)
Sets the local Cartesian scalar field based on input coordinates.
PetscErrorCode SetLocalCartesianField_Vector(const char *fieldName, Cmpnts *vecField, Cmpnts *coor, PetscInt FieldInitialization, PetscReal Constant)
Sets the local Cartesian vector field based on input coordinates.
A 3D point or vector with PetscScalar components.
Definition variables.h:100

Generic macro to select the appropriate local Cartesian field setter based on field type.

This macro dispatches to:

  • SetLocalCartesianField_Vector if the field value pointer is of type Cmpnts*
  • SetLocalCartesianField_Scalar if the field value pointer is of type PetscReal*
Parameters
fieldNameField name for logging.
fieldValuePointer to the cell's field value (either Cmpnts* or PetscReal*).
coorPointer to the coordinate (Cmpnts*) to be used in the computation.

Definition at line 33 of file AnalyticalSolution.h.

36 )(fieldName, fieldValue, coor,FieldInitialization,Constant)

Function Documentation

◆ SetLocalCartesianField_Scalar()

PetscErrorCode SetLocalCartesianField_Scalar ( const char *  fieldName,
PetscReal *  scalarField,
Cmpnts coor,
PetscInt  FieldInitialization,
PetscReal  Constant 
)

Sets the local Cartesian scalar field based on input coordinates.

This function computes the scalar field value by combining the sine of the input coordinate values. In this example, the scalar field is computed as the sum of the sine functions of the x, y, and z coordinates.

Parameters
[in]fieldNamePointer to a string representing the field name (for logging purposes).
[in,out]scalarFieldPointer to the PetscReal where the computed scalar field value will be stored.
[in]coorPointer to the Cmpnts structure containing the input coordinate values.
Returns
PetscErrorCode Returns 0 on successful execution, non-zero on failure.

◆ SetLocalCartesianField_Vector()

PetscErrorCode SetLocalCartesianField_Vector ( const char *  fieldName,
Cmpnts vecField,
Cmpnts coor,
PetscInt  FieldInitialization,
PetscReal  Constant 
)

Sets the local Cartesian vector field based on input coordinates.

This function computes the vector components by applying the sine function to the input coordinate values along the x, y, and z directions.

Parameters
[in]fieldNamePointer to a string representing the field name (for logging purposes).
[in,out]vecFieldPointer to the Cmpnts structure where the computed vector field will be stored.
[in]coorPointer to the Cmpnts structure containing the input coordinate values.
Returns
PetscErrorCode Returns 0 on successful execution, non-zero on failure.

◆ SetAnalyticalCartesianField()

PetscErrorCode SetAnalyticalCartesianField ( UserCtx user,
const char *  fieldName 
)

Sets an analytical Cartesian field (scalar or vector) for cell centers based on a field name.

This function looks up the field within the user context by comparing the provided field name against the supported names:

  • Vector fields: "Ucat" and "Ucont"
  • Scalar fields: "P" and "nvert"

If the field is found, the function verifies that the DM block size matches the expected value (3 for vector fields and 1 for scalar fields), retrieves local DM information for both the coordinate DM (da) and the cell-centered DM (fda), interpolates the corner-based coordinates (from da) to cell centers, and then updates the field using the generic helper macro SetLocalCartesianField. Interior cells are updated with the interpolated coordinates, and boundary cells are updated using the original coordinate data.

If the field name is not found in the user context, the function throws an error.

Parameters
[in]userPointer to the UserCtx structure containing:
  • da: DM for coordinate (corner) data.
  • fda: DM for cell-centered data.
  • Ucat: vector field (Cmpnts ***)
  • Ucont: vector field (Cmpnts ***)
  • P: scalar field (PetscReal ***)
  • nvert: scalar field (PetscReal ***)
[in]fieldNameName of the field to update.
Returns
PetscErrorCode 0 on success, non-zero on failure.

◆ SetAnalyticalContravariantField()

PetscErrorCode SetAnalyticalContravariantField ( UserCtx user,
const char *  fieldName 
)

Sets an analytical contravariant field (Ucont) at nodes, where each component is evaluated using the physical coordinates of its respective face center.

This function:

  1. Interpolates nodal physical coordinates to the centers of i-faces, j-faces, and k-faces for the cells relevant to the current rank, storing them in temporary local arrays.
  2. For each node (i,j,k) owned by the current rank (where Ucont components are stored): a. Retrieves the pre-calculated physical coordinate of the i-face center. b. Evaluates the analytical function for U^1 using this i-face center coordinate. c. Retrieves the pre-calculated physical coordinate of the j-face center. d. Evaluates the analytical function for U^2 using this j-face center coordinate. e. Retrieves the pre-calculated physical coordinate of the k-face center. f. Evaluates the analytical function for U^3 using this k-face center coordinate. g. Stores these (U^1, U^2, U^3) into user->Ucont[k][j][i].
Parameters
[in]userPointer to the UserCtx structure.
[in]fieldNameName of the field to update (currently only "Ucont").
Returns
PetscErrorCode 0 on success, non-zero on failure.

◆ SetAnalyticalSolution()

PetscErrorCode SetAnalyticalSolution ( Vec  tempVec,
PetscInt  FieldInitialization 
)

Applies the analytical solution to the position vector.

This function updates each entry in the provided PETSc vector by computing its sine, thereby replacing each position with sin(position).

Parameters
tempVecThe PETSc Vec containing particle positions which will be used to store the velocities.
Returns
PetscErrorCode Returns 0 on success.

◆ ApplyAnalyticalBC()

PetscErrorCode ApplyAnalyticalBC ( UserCtx user,
const char *  fieldName 
)

Applies analytical boundary conditions to a specified global vector or scalar field.

This function acts as a dispatcher based on the fieldName. It determines the appropriate DM and Vec from the UserCtx and calls field-specific helper routines (e.g., ApplyAnalyticalBC_Vector, ApplyAnalyticalBC_Scalar) to set boundary values according to a predefined analytical function (e.g., sin(coord)).

This should be called AFTER setting interior values and BEFORE updating local ghosts.

Parameters
[in]userPointer to the UserCtx containing DMs, coordinates, and field Vecs.
[in]fieldNameName of the field to apply BCs to ("Ucat", "Ucont", "P", "Nvert").
Returns
PetscErrorCode 0 on success, non-zero on failure.

◆ SetInitialInteriorField()

PetscErrorCode SetInitialInteriorField ( UserCtx user,
const char *  fieldName 
)

Sets the initial values for the INTERIOR of a specified Eulerian field.

This function initializes the interior nodes of Ucont based on a profile selected by user->FieldInitialization. It explicitly skips any node that lies on a global boundary, as those values are set by the Boundary System's Initialize methods.

The initialization is directional, aligned with the primary INLET face that was identified by the parser. This ensures the initial flow is physically meaningful.

Supported user->FieldInitialization profiles for "Ucont":

  • 0: Zero Velocity. All interior components of Ucont are set to 0.
  • 1: Constant Normal Velocity. The contravariant velocity component normal to the inlet direction is set such that the physical velocity normal to those grid planes is a constant uin. Other contravariant components are zero.
  • 2: Poiseuille Normal Velocity. The contravariant component normal to the inlet direction is set with a parabolic profile.
Parameters
userThe main UserCtx struct, containing all simulation data and configuration.
fieldNameA string ("Ucont" or "P") identifying which field to initialize.
Returns
PetscErrorCode 0 on success.

Definition at line 32 of file initialcondition.c.

33{
34 PetscErrorCode ierr;
35 PetscFunctionBeginUser;
36
38
39 SimCtx *simCtx = user->simCtx;
40
41 LOG_ALLOW(GLOBAL, LOG_INFO, "Setting initial INTERIOR field for '%s' with profile %d.\n", fieldName, simCtx->FieldInitialization);
42
43 // This function currently only implements logic for Ucont.
44 if (strcmp(fieldName, "Ucont") != 0) {
45 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Skipping SetInitialInteriorField for non-Ucont field '%s'.\n", fieldName);
46
48
49 PetscFunctionReturn(0);
50 }
51
52 // --- 1. Get references to required data and PETSc arrays ---
53 DM fieldDM = user->fda;
54 Vec fieldVec = user->Ucont;
55 DMDALocalInfo info;
56 ierr = DMDAGetLocalInfo(fieldDM, &info); CHKERRQ(ierr);
57
58 Vec localCoor;
59 Cmpnts ***coor_arr;
60 ierr = DMGetCoordinatesLocal(user->da, &localCoor); CHKERRQ(ierr);
61 ierr = DMDAVecGetArrayRead(user->fda, localCoor, &coor_arr); CHKERRQ(ierr);
62
63 Cmpnts ***csi_arr, ***eta_arr, ***zet_arr;
64 ierr = DMDAVecGetArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
65 ierr = DMDAVecGetArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
66 ierr = DMDAVecGetArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
67
68 const PetscInt im_phys = info.mx - 1;
69 const PetscInt jm_phys = info.my - 1;
70 const PetscInt km_phys = info.mz - 1;
71
72 // --- 2. Compute Cell-Center Coordinates (only if needed by the selected profile) ---
73 Cmpnts ***cent_coor = NULL;
74 PetscInt xs_cell=0, xm_cell=0, ys_cell=0, ym_cell=0, zs_cell=0, zm_cell=0;
75
76 if (simCtx->FieldInitialization == 2) { // Profile 2 (Poiseuille) requires cell centers.
77
78 ierr = GetOwnedCellRange(&info, 0, &xs_cell, &xm_cell); CHKERRQ(ierr);
79 ierr = GetOwnedCellRange(&info, 1, &ys_cell, &ym_cell); CHKERRQ(ierr);
80 ierr = GetOwnedCellRange(&info, 2, &zs_cell, &zm_cell); CHKERRQ(ierr);
81
82 if (xm_cell > 0 && ym_cell > 0 && zm_cell > 0) {
83 ierr = Allocate3DArray(&cent_coor, zm_cell, ym_cell, xm_cell); CHKERRQ(ierr);
84 ierr = InterpolateFieldFromCornerToCenter(coor_arr, cent_coor, user); CHKERRQ(ierr);
85 LOG_ALLOW(LOCAL, LOG_DEBUG, "Computed temporary cell-center coordinates for Poiseuille profile.\n");
86 }
87 }
88
89 // --- 3. Loop Over Owned Nodes and Apply Initial Condition to Interior ---
90 Cmpnts ***ucont_arr;
91 ierr = DMDAVecGetArray(fieldDM, fieldVec, &ucont_arr); CHKERRQ(ierr);
92
93 PetscInt i, j, k;
94 const PetscInt mx = info.mx, my = info.my, mz = info.mz; // Global node dimensions
95 const PetscInt xs = info.xs, xe = info.xs + info.xm;
96 const PetscInt ys = info.ys, ye = info.ys + info.ym;
97 const PetscInt zs = info.zs, ze = info.zs + info.zm;
98
99 const Cmpnts uin = simCtx->InitialConstantContra; // Max/average velocity from user options
100 // Flow into a negative face (e.g., -Zeta at k=0) is in the positive physical direction (+z).
101 // Flow into a positive face (e.g., +Zeta at k=mz-1) is in the negative physical direction (-z).
102
103 LOG_ALLOW(GLOBAL,LOG_DEBUG,"Initial Constant Flux (Contravariant) = (%.3f, %.3f, %.3f)\n",(double)uin.x, (double)uin.y, (double)uin.z);
104
105 const PetscReal flow_direction_sign = (user->identifiedInletBCFace % 2 == 0) ? 1.0 : -1.0;
106
107 for (k = zs; k < ze; k++) {
108 for (j = ys; j < ye; j++) {
109 for (i = xs; i < xe; i++) {
110
111 // The crucial check to ensure we only modify interior nodes.
112 const PetscBool is_interior = (i > 0 && i < im_phys - 1 &&
113 j > 0 && j < jm_phys - 1 &&
114 k > 0 && k < km_phys - 1);
115
116 if (is_interior) {
117 Cmpnts ucont_val = {0.0, 0.0, 0.0}; // Default to zero velocity
118 PetscReal normal_velocity_mag = 0.0;
119
120 // Step A: Determine the magnitude of the desired physical normal velocity.
121 switch (simCtx->FieldInitialization) {
122 case 0: // Zero initial velocity
123 normal_velocity_mag = 0.0;
124 break;
125 case 1: /* Constant Normal Velocity */
128 normal_velocity_mag = uin.x;
130 normal_velocity_mag = uin.y;
131 } else {
132 normal_velocity_mag = uin.z;
133 }
134 break;
135 case 2: // Poiseuille Normal Velocity
136 {
137 // This profile assumes flow is aligned with the k-index direction.
138 // It uses grid indices (i,j) to define the cross-section, which works for bent geometries.
139 PetscReal u0 = 0.0;
140 if (user->identifiedInletBCFace <= BC_FACE_POS_X) u0 = uin.x;
141 else if (user->identifiedInletBCFace <= BC_FACE_POS_Y) u0 = uin.y;
142 else u0 = uin.z; // Assumes Z-like inlet direction
143
144 // Define channel geometry in "index space" based on global grid dimensions
145 // We subtract 2.0 because the interior runs from index 1 to mx-2 (or my-2).
146 const PetscReal i_width = (PetscReal)(im_phys - 2);
147 const PetscReal j_width = (PetscReal)(jm_phys - 2);
148 const PetscReal i_center = 1.0 + i_width / 2.0;
149 const PetscReal j_center = 1.0 + j_width / 2.0;
150
151 // Create normalized coordinates for the current point (i,j), ranging from -1 to 1
152 const PetscReal i_norm = (i - i_center) / (i_width / 2.0);
153 const PetscReal j_norm = (j - j_center) / (j_width / 2.0);
154
155 // Apply the parabolic profile for a rectangular/square channel
156 // V(i,j) = V_max * (1 - i_norm^2) * (1 - j_norm^2)
157 const PetscReal profile_i = 1.0 - i_norm * i_norm;
158 const PetscReal profile_j = 1.0 - j_norm * j_norm;
159 normal_velocity_mag = u0 * profile_i * profile_j;
160
161 // Clamp to zero for any points outside the channel (or due to minor float errors)
162 if (normal_velocity_mag < 0.0) {
163 normal_velocity_mag = 0.0;
164 }
165 }
166 break;
167 /*
168 PetscReal r_sq = 0.0;
169 const PetscInt i_local = i - xs_cell, j_local = j - ys_cell, k_local = k - zs_cell;
170 if (cent_coor && i_local >= 0 && i_local < xm_cell && j_local >= 0 && j_local < ym_cell && k_local >= 0 && k_local < zm_cell) {
171 const Cmpnts* center = &cent_coor[k_local][j_local][i_local];
172 if (user->identifiedInletBCFace <= BC_FACE_POS_X) r_sq = center->y * center->y + center->z * center->z;
173 else if (user->identifiedInletBCFace <= BC_FACE_POS_Y) r_sq = center->x * center->x + center->z * center->z;
174 else r_sq = center->x * center->x + center->y * center->y;
175 // pick the correct contravariant component for center‐line speed
176 PetscReal u0;
177 if (user->identifiedInletBCFace == BC_FACE_NEG_X ||
178 user->identifiedInletBCFace == BC_FACE_POS_X) {
179 u0 = uin.x;
180 } else if (user->identifiedInletBCFace == BC_FACE_NEG_Y ||
181 user->identifiedInletBCFace == BC_FACE_POS_Y) {
182 u0 = uin.y;
183 } else {
184 u0 = uin.z;
185 }
186 // now form the parabolic profile as before
187 normal_velocity_mag = 2.0 * u0 * (1.0 - 4.0 * r_sq);
188 }
189 }
190 break;
191 */
192 default:
193 LOG_ALLOW(LOCAL, LOG_WARNING, "Unrecognized FieldInitialization profile %d. Defaulting to zero.\n", simCtx->FieldInitialization);
194 normal_velocity_mag = 0.0;
195 break;
196 }
197
198 // Step B: Apply direction sign and set the correct contravariant component.
199 // The contravariant component U^n = v_n * Area_n, where v_n is the physical normal velocity.
200 if (normal_velocity_mag != 0.0) {
201 const PetscReal signed_normal_vel = normal_velocity_mag * flow_direction_sign*user->GridOrientation;
202
204 const PetscReal area_i = sqrt(csi_arr[k][j][i].x * csi_arr[k][j][i].x + csi_arr[k][j][i].y * csi_arr[k][j][i].y + csi_arr[k][j][i].z * csi_arr[k][j][i].z);
205
206 ucont_val.x = signed_normal_vel * area_i;
207
208 LOG_LOOP_ALLOW(GLOBAL,LOG_VERBOSE,k,50," ucont_val.x = %.6f (signed_normal_vel=%.3f × area=%.4f)\n",ucont_val.x, signed_normal_vel, area_i);
209 }
211 const PetscReal area_j = sqrt(eta_arr[k][j][i].x * eta_arr[k][j][i].x + eta_arr[k][j][i].y * eta_arr[k][j][i].y + eta_arr[k][j][i].z * eta_arr[k][j][i].z);
212
213 ucont_val.y = signed_normal_vel * area_j;
214
215 LOG_LOOP_ALLOW(GLOBAL,LOG_VERBOSE,k,50," ucont_val.y = %.6f (signed_normal_vel=%.3f × area=%.4f)\n",ucont_val.y, signed_normal_vel, area_j);
216 }
217 else { // Z-inlet
218 const PetscReal area_k = sqrt(zet_arr[k][j][i].x * zet_arr[k][j][i].x + zet_arr[k][j][i].y * zet_arr[k][j][i].y + zet_arr[k][j][i].z * zet_arr[k][j][i].z);
219
220 ucont_val.z = signed_normal_vel * area_k;
221
222 LOG_LOOP_ALLOW(GLOBAL,LOG_VERBOSE,k,50," i,j,k,ucont_val.z = %d, %d, %d, %.6f (signed_normal_vel=%.3f × area=%.4f)\n",i,j,k,ucont_val.z, signed_normal_vel, area_k);
223 }
224 }
225 ucont_arr[k][j][i] = ucont_val;
226 } // end if(is_interior)
227 }
228 }
229 }
230 ierr = DMDAVecRestoreArray(fieldDM, fieldVec, &ucont_arr); CHKERRQ(ierr);
231
232 // --- 5. Cleanup: Restore arrays and free temporary memory ---
233 ierr = DMDAVecRestoreArrayRead(user->fda, localCoor, &coor_arr); CHKERRQ(ierr);
234 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
235 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
236 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
237
238 if (cent_coor) {
239 ierr = Deallocate3DArray(cent_coor, zm_cell, ym_cell); CHKERRQ(ierr);
240 }
241
243
244 PetscFunctionReturn(0);
245}
#define InterpolateFieldFromCornerToCenter(field, centfield, user)
Generic macro to call the appropriate interpolation function based on the field type.
#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt,...)
Logs a message inside a loop, but only every interval iterations.
Definition logging.h:313
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:46
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:47
#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
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:740
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:32
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:33
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:35
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:731
#define Allocate3DArray(array, nz, ny, nx)
Definition setup.h:28
#define Deallocate3DArray(array, nz, ny)
Definition setup.h:35
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
BCFace identifiedInletBCFace
Definition variables.h:681
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:664
Vec lZet
Definition variables.h:705
PetscInt FieldInitialization
Definition variables.h:582
Vec Ucont
Definition variables.h:688
PetscScalar x
Definition variables.h:101
Vec lCsi
Definition variables.h:705
PetscScalar z
Definition variables.h:101
Cmpnts InitialConstantContra
Definition variables.h:583
PetscInt GridOrientation
Definition variables.h:674
PetscScalar y
Definition variables.h:101
Vec lEta
Definition variables.h:705
@ BC_FACE_NEG_X
Definition variables.h:201
@ BC_FACE_POS_Y
Definition variables.h:202
@ BC_FACE_POS_X
Definition variables.h:201
@ BC_FACE_NEG_Y
Definition variables.h:202
The master context for the entire simulation.
Definition variables.h:538
Here is the call graph for this function: