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

Go to the source code of this file.

Functions

PetscErrorCode SetInitialInteriorField (UserCtx *user, const char *fieldName)
 Sets the initial values for the INTERIOR of a specified Eulerian field.
 
PetscErrorCode InitializeEulerianState (SimCtx *simCtx)
 High-level orchestrator to set the complete initial state of the Eulerian solver.
 

Function Documentation

◆ 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 // Check to ensure we only set initial conditions for PHYSICAL cells, not ghost cells.
112 // Ghost cells (at indices 0 and n) will be set later by ApplyBoundaryConditions.
113 //
114 // Grid structure: For n physical grid points, DMDA has size n+1
115 // - im_phys = mx - 1 = n (number of coordinate points, also equals number of cells + 1)
116 // - Physical cell indices: [1, im_phys-1] = [1, n-1] (gives n-1 physical cells)
117 // - Ghost cells at boundaries: index 0 and index im_phys (= n)
118 //
119 // Example: n=25 physical points → im_phys=25
120 // - Physical cells: indices 1..24 (24 cells)
121 // - Ghost cells: indices 0 and 25
122 const PetscBool is_interior = (i > 0 && i < im_phys &&
123 j > 0 && j < jm_phys &&
124 k > 0 && k < km_phys);
125
126 if (is_interior) {
127 Cmpnts ucont_val = {0.0, 0.0, 0.0}; // Default to zero velocity
128 PetscReal normal_velocity_mag = 0.0;
129
130 // Step A: Determine the magnitude of the desired physical normal velocity.
131 switch (simCtx->FieldInitialization) {
132 case 0: // Zero initial velocity
133 normal_velocity_mag = 0.0;
134 break;
135 case 1: /* Constant Normal Velocity */
138 normal_velocity_mag = uin.x;
140 normal_velocity_mag = uin.y;
141 } else {
142 normal_velocity_mag = uin.z;
143 }
144 break;
145 case 2: // Poiseuille Normal Velocity
146 {
147 // This profile assumes flow is aligned with the k-index direction.
148 // It uses grid indices (i,j) to define the cross-section, which works for bent geometries.
149 PetscReal u0 = 0.0;
150 if (user->identifiedInletBCFace <= BC_FACE_POS_X) u0 = uin.x;
151 else if (user->identifiedInletBCFace <= BC_FACE_POS_Y) u0 = uin.y;
152 else u0 = uin.z; // Assumes Z-like inlet direction
153
154 // Define channel geometry in "index space" based on global grid dimensions
155 // We subtract 2.0 because the interior runs from index 1 to mx-2 (or my-2).
156 const PetscReal i_width = (PetscReal)(im_phys - 2);
157 const PetscReal j_width = (PetscReal)(jm_phys - 2);
158 const PetscReal i_center = 1.0 + i_width / 2.0;
159 const PetscReal j_center = 1.0 + j_width / 2.0;
160
161 // Create normalized coordinates for the current point (i,j), ranging from -1 to 1
162 const PetscReal i_norm = (i - i_center) / (i_width / 2.0);
163 const PetscReal j_norm = (j - j_center) / (j_width / 2.0);
164
165 // Apply the parabolic profile for a rectangular/square channel
166 // V(i,j) = V_max * (1 - i_norm^2) * (1 - j_norm^2)
167 const PetscReal profile_i = 1.0 - i_norm * i_norm;
168 const PetscReal profile_j = 1.0 - j_norm * j_norm;
169 normal_velocity_mag = u0 * profile_i * profile_j;
170
171 // Clamp to zero for any points outside the channel (or due to minor float errors)
172 if (normal_velocity_mag < 0.0) {
173 normal_velocity_mag = 0.0;
174 }
175 }
176 break;
177 /*
178 PetscReal r_sq = 0.0;
179 const PetscInt i_local = i - xs_cell, j_local = j - ys_cell, k_local = k - zs_cell;
180 if (cent_coor && i_local >= 0 && i_local < xm_cell && j_local >= 0 && j_local < ym_cell && k_local >= 0 && k_local < zm_cell) {
181 const Cmpnts* center = &cent_coor[k_local][j_local][i_local];
182 if (user->identifiedInletBCFace <= BC_FACE_POS_X) r_sq = center->y * center->y + center->z * center->z;
183 else if (user->identifiedInletBCFace <= BC_FACE_POS_Y) r_sq = center->x * center->x + center->z * center->z;
184 else r_sq = center->x * center->x + center->y * center->y;
185 // pick the correct contravariant component for center‐line speed
186 PetscReal u0;
187 if (user->identifiedInletBCFace == BC_FACE_NEG_X ||
188 user->identifiedInletBCFace == BC_FACE_POS_X) {
189 u0 = uin.x;
190 } else if (user->identifiedInletBCFace == BC_FACE_NEG_Y ||
191 user->identifiedInletBCFace == BC_FACE_POS_Y) {
192 u0 = uin.y;
193 } else {
194 u0 = uin.z;
195 }
196 // now form the parabolic profile as before
197 normal_velocity_mag = 2.0 * u0 * (1.0 - 4.0 * r_sq);
198 }
199 }
200 break;
201 */
202 default:
203 LOG_ALLOW(LOCAL, LOG_WARNING, "Unrecognized FieldInitialization profile %d. Defaulting to zero.\n", simCtx->FieldInitialization);
204 normal_velocity_mag = 0.0;
205 break;
206 }
207
208 // Step B: Apply direction sign and set the correct contravariant component.
209 // The contravariant component U^n = v_n * Area_n, where v_n is the physical normal velocity.
210 if (normal_velocity_mag != 0.0) {
211 const PetscReal signed_normal_vel = normal_velocity_mag * flow_direction_sign*user->GridOrientation;
212
214 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);
215
216 ucont_val.x = signed_normal_vel * area_i;
217
218 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);
219 }
221 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);
222
223 ucont_val.y = signed_normal_vel * area_j;
224
225 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);
226 }
227 else { // Z-inlet
228 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);
229
230 ucont_val.z = signed_normal_vel * area_k;
231
232 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);
233 }
234 }
235 ucont_arr[k][j][i] = ucont_val;
236 } // end if(is_interior)
237 }
238 }
239 }
240 ierr = DMDAVecRestoreArray(fieldDM, fieldVec, &ucont_arr); CHKERRQ(ierr);
241
242 // --- 5. Cleanup: Restore arrays and free temporary memory ---
243 ierr = DMDAVecRestoreArrayRead(user->fda, localCoor, &coor_arr); CHKERRQ(ierr);
244 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCsi, &csi_arr); CHKERRQ(ierr);
245 ierr = DMDAVecRestoreArrayRead(user->fda, user->lEta, &eta_arr); CHKERRQ(ierr);
246 ierr = DMDAVecRestoreArrayRead(user->fda, user->lZet, &zet_arr); CHKERRQ(ierr);
247
248 if (cent_coor) {
249 ierr = Deallocate3DArray(cent_coor, zm_cell, ym_cell); CHKERRQ(ierr);
250 }
251
253
254 PetscFunctionReturn(0);
255}
#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:312
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
#define GLOBAL
Scope for global logging across all processes.
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:200
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:746
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:34
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:737
#define Allocate3DArray(array, nz, ny, nx)
Definition setup.h:27
#define Deallocate3DArray(array, nz, ny)
Definition setup.h:34
PetscErrorCode GetOwnedCellRange(const DMDALocalInfo *info_nodes, PetscInt dim, PetscInt *xs_cell_global, PetscInt *xm_cell_local)
Determines the global starting index and number of CELLS owned by the current processor in a specifie...
Definition setup.c:1756
BCFace identifiedInletBCFace
Definition variables.h:748
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:731
Vec lZet
Definition variables.h:776
PetscInt FieldInitialization
Definition variables.h:636
Vec Ucont
Definition variables.h:755
PetscScalar x
Definition variables.h:101
Vec lCsi
Definition variables.h:776
PetscScalar z
Definition variables.h:101
Cmpnts InitialConstantContra
Definition variables.h:637
PetscInt GridOrientation
Definition variables.h:741
PetscScalar y
Definition variables.h:101
Vec lEta
Definition variables.h:776
@ BC_FACE_NEG_X
Definition variables.h:204
@ BC_FACE_POS_Y
Definition variables.h:205
@ BC_FACE_POS_X
Definition variables.h:204
@ BC_FACE_NEG_Y
Definition variables.h:205
A 3D point or vector with PetscScalar components.
Definition variables.h:100
The master context for the entire simulation.
Definition variables.h:585
Here is the call graph for this function:
Here is the caller graph for this function:

◆ InitializeEulerianState()

PetscErrorCode InitializeEulerianState ( SimCtx simCtx)

High-level orchestrator to set the complete initial state of the Eulerian solver.

This function is called once from main() before the time loop begins. It inspects the simulation context to determine whether to perform a fresh start (t=0) or restart from saved files. It then delegates to the appropriate helper function. Finally, it initializes the solver's history vectors (Ucont_o, P_o, etc.) to ensure the first time step has the necessary data.

Definition at line 386 of file initialcondition.c.

387{
388 PetscErrorCode ierr;
389 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
390
391 PetscFunctionBeginUser;
392
394
395 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Initializing Eulerian State ---\n");
396
397 if (simCtx->StartStep > 0) {
398 if(strcmp(simCtx->eulerianSource,"analytical")==0){
399 LOG_ALLOW(GLOBAL,LOG_INFO,"Initializing Analytical Solution type: %s (t=%.4f, step=%d).\n",simCtx->AnalyticalSolutionType,simCtx->StartTime,simCtx->StartStep);
400 ierr = AnalyticalSolutionEngine(simCtx);
401 }
402 else{
403 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting from RESTART files (t=%.4f, step=%d).\n",
404 simCtx->StartTime, simCtx->StartStep);
405 ierr = SetInitialFluidState_Load(simCtx); CHKERRQ(ierr);
406 }
407 } else { // StartStep = 0
408 LOG_ALLOW(GLOBAL, LOG_INFO, "Performing a FRESH START (t=0, step=0).\n");
409 if(strcmp(simCtx->eulerianSource,"solve")==0){
410 ierr = SetInitialFluidState_FreshStart(simCtx); CHKERRQ(ierr);
411 }else if(strcmp(simCtx->eulerianSource,"load")==0){
412 LOG_ALLOW(GLOBAL,LOG_INFO,"FRESH START in LOAD mode. Reading files (t=%.4f,step=%d).\n",
413 simCtx->StartTime,simCtx->StartStep);
414 ierr=SetInitialFluidState_Load(simCtx);CHKERRQ(ierr);
415 }else if(strcmp(simCtx->eulerianSource,"analytical")==0){
416 LOG_ALLOW(GLOBAL,LOG_INFO,"FRESH START in ANALYTICAL mode. Initializing Analytical Solution type: %s (t=%.4f,step=%d).\n",
417 simCtx->AnalyticalSolutionType,simCtx->StartTime,simCtx->StartStep);
418 ierr=AnalyticalSolutionEngine(simCtx);CHKERRQ(ierr);
419 }
420 }
421
422 // This crucial step, taken from the end of the legacy setup, ensures
423 // that the history vectors (Ucont_o, Ucont_rm1, etc.) are correctly
424 // populated before the first call to the time-stepping loop.
425 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
426 ierr = UpdateSolverHistoryVectors(&user_finest[bi]); CHKERRQ(ierr);
427 }
428
429 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Eulerian State Initialized and History Vectors Populated ---\n");
430
432 PetscFunctionReturn(0);
433}
PetscErrorCode AnalyticalSolutionEngine(SimCtx *simCtx)
Dispatches to the appropriate analytical solution function based on simulation settings.
static PetscErrorCode SetInitialFluidState_Load(SimCtx *simCtx)
(HELPER) Reads fluid state for all blocks from restart files.
static PetscErrorCode SetInitialFluidState_FreshStart(SimCtx *simCtx)
(HELPER) Sets the t=0 fluid state for all blocks.
PetscErrorCode UpdateSolverHistoryVectors(UserCtx *user)
Copies the current time step's solution fields into history vectors (e.g., U(t_n) -> U_o,...
Definition simulation.c:23
UserCtx * user
Definition variables.h:474
PetscInt block_number
Definition variables.h:649
PetscReal StartTime
Definition variables.h:598
UserMG usermg
Definition variables.h:698
PetscInt StartStep
Definition variables.h:595
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:604
PetscInt mglevels
Definition variables.h:481
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:617
MGCtx * mgctx
Definition variables.h:484
User-defined context containing data specific to a single computational grid level.
Definition variables.h:728
Here is the call graph for this function:
Here is the caller graph for this function: