PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Functions
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 "runloop.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.

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

Local to this translation unit.

Definition at line 14 of file initialcondition.c.

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

Parameters
simCtxSimulation context controlling the operation.
Returns
PetscErrorCode 0 on success.

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

Local to this translation unit.

Definition at line 360 of file initialcondition.c.

361{
362 PetscErrorCode ierr;
363 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
364
365 PetscFunctionBeginUser;
366
368
369 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Initializing Eulerian State ---\n");
370
371 if (simCtx->StartStep > 0) {
372 if(strcmp(simCtx->eulerianSource,"analytical")==0){
373 LOG_ALLOW(GLOBAL,LOG_INFO,"Initializing Analytical Solution type: %s (t=%.4f, step=%d).\n",simCtx->AnalyticalSolutionType,simCtx->StartTime,simCtx->StartStep);
374 ierr = AnalyticalSolutionEngine(simCtx);
375 }
376 else{
377 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting from RESTART files (t=%.4f, step=%d).\n",
378 simCtx->StartTime, simCtx->StartStep);
379 ierr = SetInitialFluidState_Load(simCtx); CHKERRQ(ierr);
380 }
381 } else { // StartStep = 0
382 LOG_ALLOW(GLOBAL, LOG_INFO, "Performing a FRESH START (t=0, step=0).\n");
383 if(strcmp(simCtx->eulerianSource,"solve")==0){
384 ierr = SetInitialFluidState_FreshStart(simCtx); CHKERRQ(ierr);
385 }else if(strcmp(simCtx->eulerianSource,"load")==0){
386 LOG_ALLOW(GLOBAL,LOG_INFO,"FRESH START in LOAD mode. Reading files (t=%.4f,step=%d).\n",
387 simCtx->StartTime,simCtx->StartStep);
388 ierr=SetInitialFluidState_Load(simCtx);CHKERRQ(ierr);
389 }else if(strcmp(simCtx->eulerianSource,"analytical")==0){
390 LOG_ALLOW(GLOBAL,LOG_INFO,"FRESH START in ANALYTICAL mode. Initializing Analytical Solution type: %s (t=%.4f,step=%d).\n",
391 simCtx->AnalyticalSolutionType,simCtx->StartTime,simCtx->StartStep);
392 ierr=AnalyticalSolutionEngine(simCtx);CHKERRQ(ierr);
393 }
394 }
395
396 // This crucial step, taken from the end of the legacy setup, ensures
397 // that the history vectors (Ucont_o, Ucont_rm1, etc.) are correctly
398 // populated before the first call to the time-stepping loop.
399 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
400 ierr = UpdateSolverHistoryVectors(&user_finest[bi]); CHKERRQ(ierr);
401 }
402
403 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Eulerian State Initialized and History Vectors Populated ---\n");
404
406 PetscFunctionReturn(0);
407}
PetscErrorCode AnalyticalSolutionEngine(SimCtx *simCtx)
Dispatches to the appropriate analytical solution function based on simulation settings.
static PetscErrorCode SetInitialFluidState_Load(SimCtx *simCtx)
Internal helper implementation: SetInitialFluidState_Load().
static PetscErrorCode SetInitialFluidState_FreshStart(SimCtx *simCtx)
Internal helper implementation: SetInitialFluidState_FreshStart().
PetscErrorCode UpdateSolverHistoryVectors(UserCtx *user)
Copies the current time step's solution fields into history vectors (e.g., U(t_n) -> U_o,...
Definition runloop.c:319
UserCtx * user
Definition variables.h:528
PetscInt block_number
Definition variables.h:712
PetscReal StartTime
Definition variables.h:657
UserMG usermg
Definition variables.h:764
PetscInt StartStep
Definition variables.h:653
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:663
PetscInt mglevels
Definition variables.h:535
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:676
MGCtx * mgctx
Definition variables.h:538
User-defined context containing data specific to a single computational grid level.
Definition variables.h:811
Here is the call graph for this function:
Here is the caller graph for this function: