PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
AnalyticalSolutions.c File Reference

Implements the analytical solution engine for initializing or driving the simulation. More...

#include "AnalyticalSolutions.h"
#include <petscmath.h>
Include dependency graph for AnalyticalSolutions.c:

Go to the source code of this file.

Macros

#define __FUNCT__   "SetAnalyticalGridInfo"
 
#define __FUNCT__   "AnalyticalSolutionEngine"
 
#define __FUNCT__   "SetAnalyticalSolution_TGV3D"
 
#define __FUNCT__   "SetAnalyticalSolutionForParticles_TGV3D"
 
#define __FUNCT__   "SetAnalyticalSolutionForParticles"
 

Functions

static PetscErrorCode SetAnalyticalSolution_TGV3D (SimCtx *simCtx)
 Sets the non-dimensional velocity and pressure fields to the 3D Taylor-Green Vortex solution.
 
PetscErrorCode SetAnalyticalGridInfo (UserCtx *user)
 Sets the grid domain and resolution for analytical solution cases.
 
PetscErrorCode AnalyticalSolutionEngine (SimCtx *simCtx)
 Dispatches to the appropriate analytical solution function based on simulation settings.
 
static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D (Vec tempVec, SimCtx *simCtx)
 Sets the TGV3D analytical velocity solution for particles.
 
PetscErrorCode SetAnalyticalSolutionForParticles (Vec tempVec, SimCtx *simCtx)
 Applies the analytical solution to particle velocity vector.
 

Detailed Description

Implements the analytical solution engine for initializing or driving the simulation.

This file provides a modular and extensible framework for applying analytical solutions to the Eulerian fields. The primary entry point is AnalyticalSolutionEngine, which acts as a dispatcher based on user configuration.

— DESIGN PHILOSOPHY —

  1. Non-Dimensional Core: All calculations within this engine are performed in non-dimensional units (e.g., reference velocity U_ref=1.0, reference length L_ref=1.0). This is critical for consistency with the core numerical solver, which also operates on non-dimensional equations. The simCtx->scaling parameters are intentionally NOT used here; they are reserved for dimensionalization during I/O and post-processing only.
  2. Separation of Concerns: The role of this engine is to set the physical state of the fluid at a given time t. This involves:
    • Setting the values of fields (Ucat, P) in the physical interior of the domain.
    • Declaring the physical values on the boundaries by populating the boundary condition vector (user->Bcs.Ubcs). It does NOT implement the numerical scheme for ghost cells. Instead, after setting the physical state, it relies on the solver's standard utility functions (UpdateDummyCells, UpdateCornerNodes) to correctly populate all ghost cell layers.
  3. Extensibility: The dispatcher design makes it straightforward to add new analytical solutions. A developer only needs to add a new else if condition and a corresponding static implementation function, without modifying any other part of the solver.

Definition in file AnalyticalSolutions.c.

Macro Definition Documentation

◆ __FUNCT__ [1/5]

#define __FUNCT__   "SetAnalyticalGridInfo"

Definition at line 38 of file AnalyticalSolutions.c.

◆ __FUNCT__ [2/5]

#define __FUNCT__   "AnalyticalSolutionEngine"

Definition at line 38 of file AnalyticalSolutions.c.

◆ __FUNCT__ [3/5]

#define __FUNCT__   "SetAnalyticalSolution_TGV3D"

Definition at line 38 of file AnalyticalSolutions.c.

◆ __FUNCT__ [4/5]

#define __FUNCT__   "SetAnalyticalSolutionForParticles_TGV3D"

Definition at line 38 of file AnalyticalSolutions.c.

◆ __FUNCT__ [5/5]

#define __FUNCT__   "SetAnalyticalSolutionForParticles"

Definition at line 38 of file AnalyticalSolutions.c.

Function Documentation

◆ SetAnalyticalSolution_TGV3D()

static PetscErrorCode SetAnalyticalSolution_TGV3D ( SimCtx simCtx)
static

Sets the non-dimensional velocity and pressure fields to the 3D Taylor-Green Vortex solution.

This function implements the classical decaying Taylor-Green vortex in non-dimensional form, consistent with the solver's internal state. It is fully compatible with the solver's curvilinear, parallel, cell-centered architecture.

WORKFLOW
  1. Defines non-dimensional parameters for the TGV solution (V0=1.0, rho=1.0).
  2. Defines correct loop bounds (lxs, lxe, etc.) to iterate over ONLY the physical interior cells owned by the current MPI rank.
  3. Sets the interior cell-centered velocity (Ucat) and pressure (P) by evaluating the analytical formula at the cell-center coordinates (read from the local user->Cent vector).
  4. Sets the boundary condition vector (user->Bcs.Ubcs) by evaluating the analytical velocity at the true physical face-center locations (read from the local user->Centx, user->Centy, and user->Centz vectors).
  5. Manually sets the pressure ghost cells on the faces (excluding edges/corners) to enforce a zero-gradient (Neumann) boundary condition, which is standard for pressure.
  6. Calls the solver's utility functions UpdateDummyCells (for Ucat) and UpdateCornerNodes (for both Ucat and P) to finalize all ghost cell values, ensuring a fully consistent field.
Parameters
[in]simCtxThe main simulation context.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Definition at line 251 of file AnalyticalSolutions.c.

252{
253 PetscErrorCode ierr;
254 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
255
256 // --- NON-DIMENSIONAL TGV Parameters ---
257 const PetscReal V0 = 1.0; // Non-dimensional reference velocity.
258 const PetscReal rho = 1.0; // Non-dimensional reference density.
259 const PetscReal p0 = 0.0; // Non-dimensional reference pressure.
260
261 // Kinematic viscosity is derived from the non-dimensional Reynolds number.
262 const PetscReal nu = (simCtx->ren > 0) ? (1.0 / simCtx->ren) : 0.0;
263
264 const PetscReal k = 1.0; // Wavenumber, assumes a non-dimensional [0, 2*pi] domain.
265 const PetscReal t = simCtx->ti;
266
267 LOG_ALLOW(GLOBAL,LOG_TRACE,"TGV Setup: t = %.4f, V0* = %.4f, rho* = %.4f, k = %.4f, p0* = %4.f, nu = %.6f.\n",simCtx->ti,V0,rho,k,p0,nu);
268
269 const PetscReal vel_decay = exp(-2.0 * nu * k * k * t);
270 const PetscReal prs_decay = exp(-4.0 * nu * k * k * t);
271
272 PetscFunctionBeginUser;
273
274 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
275 UserCtx* user = &user_finest[bi];
276 DMDALocalInfo info = user->info;
277 PetscInt xs = info.xs, xe = info.xs + info.xm;
278 PetscInt ys = info.ys, ye = info.ys + info.ym;
279 PetscInt zs = info.zs, ze = info.zs + info.zm;
280 PetscInt mx = info.mx, my = info.my, mz = info.mz;
281
282 Cmpnts ***ucat, ***ubcs;
283 const Cmpnts ***cent, ***cent_x, ***cent_y, ***cent_z;
284 PetscReal ***p;
285
286 // Define loop bounds for physical interior cells owned by this rank.
287 PetscInt lxs = (xs == 0) ? xs + 1 : xs, lxe = (xe == mx) ? xe - 1 : xe;
288 PetscInt lys = (ys == 0) ? ys + 1 : ys, lye = (ye == my) ? ye - 1 : ye;
289 PetscInt lzs = (zs == 0) ? zs + 1 : zs, lze = (ze == mz) ? ze - 1 : ze;
290
291 // --- Get Arrays ---
292 ierr = DMDAVecGetArray(user->fda, user->Ucat, &ucat); CHKERRQ(ierr);
293 ierr = DMDAVecGetArray(user->da, user->P, &p); CHKERRQ(ierr);
294 ierr = DMDAVecGetArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
295 ierr = DMDAVecGetArrayRead(user->fda, user->Cent, &cent); CHKERRQ(ierr);
296 ierr = DMDAVecGetArrayRead(user->fda, user->Centx, &cent_x); CHKERRQ(ierr);
297 ierr = DMDAVecGetArrayRead(user->fda, user->Centy, &cent_y); CHKERRQ(ierr);
298 ierr = DMDAVecGetArrayRead(user->fda, user->Centz, &cent_z); CHKERRQ(ierr);
299
300 // --- Set INTERIOR cell-centered velocity (Ucat) ---
301 for (PetscInt k_cell = lzs; k_cell < lze; k_cell++) {
302 for (PetscInt j_cell = lys; j_cell < lye; j_cell++) {
303 for (PetscInt i_cell = lxs; i_cell < lxe; i_cell++) {
304 const PetscReal cx = cent[k_cell][j_cell][i_cell].x, cy = cent[k_cell][j_cell][i_cell].y, cz = cent[k_cell][j_cell][i_cell].z;
305 ucat[k_cell][j_cell][i_cell].x = V0 * sin(k*cx) * cos(k*cy) * cos(k*cz) * vel_decay;
306 ucat[k_cell][j_cell][i_cell].y = -V0 * cos(k*cx) * sin(k*cy) * cos(k*cz) * vel_decay;
307 ucat[k_cell][j_cell][i_cell].z = 0.0;
308 }
309 }
310 }
311
312
313 // --- Set INTERIOR cell-centered pressure (P) ---
314 for (PetscInt k_cell = lzs; k_cell < lze; k_cell++) {
315 for (PetscInt j_cell = lys; j_cell < lye; j_cell++) {
316 for (PetscInt i_cell = lxs; i_cell < lxe; i_cell++) {
317 const PetscReal cx = cent[k_cell][j_cell][i_cell].x, cy = cent[k_cell][j_cell][i_cell].y;
318 p[k_cell][j_cell][i_cell] = p0 + (rho * V0 * V0 / 4.0) * (cos(2*k*cx) + cos(2*k*cy)) * prs_decay;
319 }
320 }
321 }
322
323
324 // --- Set BOUNDARY condition vector for velocity (Ubcs) ---
325 if (xs == 0) for (PetscInt k=zs; k<ze; k++) for (PetscInt j=ys; j<ye; j++) {
326 const PetscReal fcx=cent_x[k][j][xs].x, fcy=cent_x[k][j][xs].y, fcz=cent_x[k][j][xs].z;
327 ubcs[k][j][xs].x = V0*sin(k*fcx)*cos(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][j][xs].y = -V0*cos(k*fcx)*sin(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][j][xs].z = 0.0;
328 }
329 if (xe == mx) for (PetscInt k=zs; k<ze; k++) for (PetscInt j=ys; j<ye; j++) {
330 const PetscReal fcx=cent_x[k][j][xe-1].x, fcy=cent_x[k][j][xe-1].y, fcz=cent_x[k][j][xe-1].z;
331 ubcs[k][j][xe-1].x = V0*sin(k*fcx)*cos(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][j][xe-1].y = -V0*cos(k*fcx)*sin(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][j][xe-1].z = 0.0;
332 }
333 if (ys == 0) for (PetscInt k=zs; k<ze; k++) for (PetscInt i=xs; i<xe; i++) {
334 const PetscReal fcx=cent_y[k][ys][i].x, fcy=cent_y[k][ys][i].y, fcz=cent_y[k][ys][i].z;
335 ubcs[k][ys][i].x = V0*sin(k*fcx)*cos(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][ys][i].y = -V0*cos(k*fcx)*sin(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][ys][i].z = 0.0;
336 }
337 if (ye == my) for (PetscInt k=zs; k<ze; k++) for (PetscInt i=xs; i<xe; i++) {
338 const PetscReal fcx=cent_y[k][ye-1][i].x, fcy=cent_y[k][ye-1][i].y, fcz=cent_y[k][ye-1][i].z;
339 ubcs[k][ye-1][i].x = V0*sin(k*fcx)*cos(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][ye-1][i].y = -V0*cos(k*fcx)*sin(k*fcy)*cos(k*fcz)*vel_decay; ubcs[k][ye-1][i].z = 0.0;
340 }
341 if (zs == 0) for (PetscInt j=ys; j<ye; j++) for (PetscInt i=xs; i<xe; i++) {
342 const PetscReal fcx=cent_z[zs][j][i].x, fcy=cent_z[zs][j][i].y, fcz=cent_z[zs][j][i].z;
343 ubcs[zs][j][i].x = V0*sin(k*fcx)*cos(k*fcy)*cos(k*fcz)*vel_decay; ubcs[zs][j][i].y = -V0*cos(k*fcx)*sin(k*fcy)*cos(k*fcz)*vel_decay; ubcs[zs][j][i].z = 0.0;
344 }
345 if (ze == mz) for (PetscInt j=ys; j<ye; j++) for (PetscInt i=xs; i<xe; i++) {
346 const PetscReal fcx=cent_z[ze-1][j][i].x, fcy=cent_z[ze-1][j][i].y, fcz=cent_z[ze-1][j][i].z;
347 ubcs[ze-1][j][i].x = V0*sin(k*fcx)*cos(k*fcy)*cos(k*fcz)*vel_decay; ubcs[ze-1][j][i].y = -V0*cos(k*fcx)*sin(k*fcy)*cos(k*fcz)*vel_decay; ubcs[ze-1][j][i].z = 0.0;
348 }
349
350 // --- Set PRESSURE GHOST CELLS (Neumann BC: P_ghost = P_interior) ---
351 if (xs == 0) for (PetscInt k=lzs; k<lze; k++) for (PetscInt j=lys; j<lye; j++) p[k][j][xs] = p[k][j][xs+1];
352 if (xe == mx) for (PetscInt k=lzs; k<lze; k++) for (PetscInt j=lys; j<lye; j++) p[k][j][xe-1] = p[k][j][xe-2];
353
354 if (ys == 0) for (PetscInt k=lzs; k<lze; k++) for (PetscInt i=lxs; i<lxe; i++) p[k][ys][i] = p[k][ys+1][i];
355 if (ye == my) for (PetscInt k=lzs; k<lze; k++) for (PetscInt i=lxs; i<lxe; i++) p[k][ye-1][i] = p[k][ye-2][i];
356
357 if (zs == 0) for (PetscInt j=lys; j<lye; j++) for (PetscInt i=lxs; i<lxe; i++) p[zs][j][i] = p[zs+1][j][i];
358 if (ze == mz) for (PetscInt j=lys; j<lye; j++) for (PetscInt i=lxs; i<lxe; i++) p[ze-1][j][i] = p[ze-2][j][i];
359
360 // --- Restore all arrays ---
361 ierr = DMDAVecRestoreArray(user->fda, user->Ucat, &ucat); CHKERRQ(ierr);
362 ierr = DMDAVecRestoreArray(user->da, user->P, &p); CHKERRQ(ierr);
363 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
364 ierr = DMDAVecRestoreArrayRead(user->fda, user->Cent, &cent); CHKERRQ(ierr);
365 ierr = DMDAVecRestoreArrayRead(user->fda, user->Centx, &cent_x); CHKERRQ(ierr);
366 ierr = DMDAVecRestoreArrayRead(user->fda, user->Centy, &cent_y); CHKERRQ(ierr);
367 ierr = DMDAVecRestoreArrayRead(user->fda, user->Centz, &cent_z); CHKERRQ(ierr);
368
369 // Pre-Dummy cell update synchronization.
370 ierr = UpdateLocalGhosts(user,"Ucat");
371 ierr = UpdateLocalGhosts(user,"P");
372
373 // --- Finalize all ghost cell values ---
374 ierr = UpdateDummyCells(user); CHKERRQ(ierr);
375 ierr = UpdateCornerNodes(user); CHKERRQ(ierr);
376
377 // Final Synchronization.
378 ierr = UpdateLocalGhosts(user,"Ucat");
379 ierr = UpdateLocalGhosts(user,"P");
380
381 }
382
383 PetscFunctionReturn(0);
384}
PetscErrorCode UpdateDummyCells(UserCtx *user)
Updates the dummy cells (ghost nodes) on the faces of the local domain for NON-PERIODIC boundaries.
PetscErrorCode UpdateCornerNodes(UserCtx *user)
Updates the corner and edge ghost nodes of the local domain by averaging.
#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
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:33
PetscErrorCode UpdateLocalGhosts(UserCtx *user, const char *fieldName)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1157
UserCtx * user
Definition variables.h:474
PetscInt block_number
Definition variables.h:649
Vec Centz
Definition variables.h:777
UserMG usermg
Definition variables.h:698
PetscReal ren
Definition variables.h:632
Vec Ubcs
Boundary condition velocity values. (Comment: "An ugly hack, waste of memory")
Definition variables.h:121
PetscScalar x
Definition variables.h:101
Vec Centx
Definition variables.h:777
BCS Bcs
Definition variables.h:749
PetscScalar z
Definition variables.h:101
Vec Ucat
Definition variables.h:755
PetscInt mglevels
Definition variables.h:481
DMDALocalInfo info
Definition variables.h:735
PetscScalar y
Definition variables.h:101
Vec Cent
Definition variables.h:776
MGCtx * mgctx
Definition variables.h:484
Vec Centy
Definition variables.h:777
PetscReal ti
Definition variables.h:594
A 3D point or vector with PetscScalar components.
Definition variables.h:100
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:

◆ SetAnalyticalGridInfo()

PetscErrorCode SetAnalyticalGridInfo ( UserCtx user)

Sets the grid domain and resolution for analytical solution cases.

This function is called when eulerianSource is "analytical". It is responsible for automatically configuring the grid based on the chosen AnalyticalSolutionType.

TGV3D Multi-Block Decomposition
If the analytical solution is "TGV3D", this function automatically decomposes the required [0, 2*PI] physical domain among the available blocks.
  • **Single Block (nblk=1):** The single block is assigned the full [0, 2*PI] domain.
  • **Multiple Blocks (nblk>1):** It requires that the number of blocks be a perfect square (e.g., 4, 9, 16). It then arranges the blocks in a sqrt(nblk) by sqrt(nblk) grid in the X-Y plane, partitioning the [0, 2*PI] domain in X and Y accordingly. The Z domain for all blocks remains [0, 2*PI]. If nblk is not a perfect square, the simulation is aborted with an error.

After setting the domain bounds, it proceeds to read the grid resolution options (-im, -jm, -km) from the command line for the specific block.

Parameters
userPointer to the UserCtx for a specific block. The function will populate the geometric fields (IM, JM, KM, Min_X, Max_X, etc.) within this struct.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Definition at line 63 of file AnalyticalSolutions.c.

64{
65 PetscErrorCode ierr;
66 SimCtx *simCtx = user->simCtx;
67 PetscInt nblk = simCtx->block_number;
68 PetscInt block_index = user->_this;
69
70 PetscFunctionBeginUser;
72
73 if (strcmp(simCtx->AnalyticalSolutionType, "TGV3D") == 0) {
74 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "Rank %d: Configuring grid for TGV3D analytical solution, block %d.\n", simCtx->rank, block_index);
75
76 if (nblk == 1) {
77 // --- Single Block Case ---
78 if (block_index == 0) {
79 LOG_ALLOW(GLOBAL, LOG_INFO, "Single block detected. Setting domain to [0, 2*PI].\n");
80 }
81 user->Min_X = 0.0; user->Max_X = 2.0 * PETSC_PI;
82 user->Min_Y = 0.0; user->Max_Y = 2.0 * PETSC_PI;
83 user->Min_Z = 0.0; user->Max_Z = 0.2 * PETSC_PI; //2.0 * PETSC_PI;
84
85 } else { // --- Multi-Block Case ---
86 PetscReal s = sqrt((PetscReal)nblk);
87
88 // Validate that nblk is a perfect square.
89 if (fabs(s - floor(s)) > 1e-9) {
90 SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP,
91 "\n\n*** CONFIGURATION ERROR FOR TGV3D ***\n"
92 "For multi-block TGV3D cases, the number of blocks must be a perfect square (e.g., 4, 9, 16).\n"
93 "You have specified %d blocks. Please adjust `-block_number`.\n", nblk);
94 }
95 PetscInt blocks_per_dim = (PetscInt)s;
96
97 if (block_index == 0) {
98 LOG_ALLOW(GLOBAL, LOG_INFO, "%d blocks detected. Decomposing domain into a %d x %d grid in the X-Y plane.\n", nblk, blocks_per_dim, blocks_per_dim);
99 }
100
101 // Determine the (row, col) position of this block in the 2D decomposition
102 PetscInt row = block_index / blocks_per_dim;
103 PetscInt col = block_index % blocks_per_dim;
104
105 // Calculate the width/height of each sub-domain
106 PetscReal block_width = (2.0 * PETSC_PI) / (PetscReal)blocks_per_dim;
107 PetscReal block_height = (2.0 * PETSC_PI) / (PetscReal)blocks_per_dim;
108
109 // Assign this block its specific sub-domain
110 user->Min_X = col * block_width;
111 user->Max_X = (col + 1) * block_width;
112 user->Min_Y = row * block_height;
113 user->Max_Y = (row + 1) * block_height;
114 user->Min_Z = 0.0;
115 user->Max_Z = 2.0 * PETSC_PI; // Z-domain is not decomposed
116 }
117 }
118 /*
119 * --- EXTENSIBILITY HOOK ---
120 * To add another analytical case with special grid requirements:
121 *
122 * else if (strcmp(simCtx->AnalyticalSolutionType, "ChannelFlow") == 0) {
123 * // ... implement logic to set domain for ChannelFlow case ...
124 * }
125 */
126 else {
127 // Fallback for other analytical solutions: require manual grid specification.
128 LOG(GLOBAL, LOG_INFO, "Analytical solution '%s' detected. Using user-provided grid generation inputs.\n", simCtx->AnalyticalSolutionType);
129 ierr = ReadGridGenerationInputs(user); CHKERRQ(ierr);
130 PetscFunctionReturn(0); // Return early as ReadGridGenerationInputs already handled everything.
131 }
132
133 // --- For TGV3D, we now read the grid resolution, as this is independent of the domain ---
134 PetscInt *IMs, *JMs, *KMs;
135 PetscBool found;
136 PetscInt count;
137
138 ierr = PetscMalloc3(nblk, &IMs, nblk, &JMs, nblk, &KMs); CHKERRQ(ierr);
139
140 // Set defaults first
141 for(PetscInt i=0; i<nblk; ++i) { IMs[i] = 10; JMs[i] = 10; KMs[i] = 10; }
142
143 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-im", IMs, &count, &found); CHKERRQ(ierr);
144 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-jm", JMs, &count, &found); CHKERRQ(ierr);
145 count = nblk; ierr = PetscOptionsGetIntArray(NULL, NULL, "-km", KMs, &count, &found); CHKERRQ(ierr);
146
147 user->IM = IMs[block_index];
148 user->JM = JMs[block_index];
149 user->KM = KMs[block_index];
150
151 // We can also read stretching ratios, as they are independent of the domain size
152 // For simplicity, we assume uniform grid unless specified.
153 user->rx = 1.0; user->ry = 1.0; user->rz = 1.0;
154
155 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d grid resolution set: IM=%d, JM=%d, KM=%d\n",
156 simCtx->rank, block_index, user->IM, user->JM, user->KM);
157 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d final bounds: X=[%.4f, %.4f], Y=[%.4f, %.4f], Z=[%.4f, %.4f]\n",
158 simCtx->rank, block_index, user->Min_X, user->Max_X, user->Min_Y, user->Max_Y, user->Min_Z, user->Max_Z);
159
160 ierr = PetscFree3(IMs, JMs, KMs); CHKERRQ(ierr);
161
163 PetscFunctionReturn(0);
164}
PetscErrorCode ReadGridGenerationInputs(UserCtx *user)
Parses command-line options for a programmatically generated grid for a SINGLE block.
Definition io.c:77
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
----— DEBUG ---------------------------------------— #define LOG_ALLOW(scope, level,...
Definition logging.h:267
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
Definition logging.h:746
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:84
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:737
PetscMPIInt rank
Definition variables.h:588
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:731
PetscReal Min_X
Definition variables.h:738
PetscInt KM
Definition variables.h:737
PetscInt _this
Definition variables.h:741
PetscReal ry
Definition variables.h:742
PetscReal Max_Y
Definition variables.h:738
PetscReal rz
Definition variables.h:742
PetscInt JM
Definition variables.h:737
PetscReal Min_Z
Definition variables.h:738
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:617
PetscReal Max_X
Definition variables.h:738
PetscReal Min_Y
Definition variables.h:738
PetscInt IM
Definition variables.h:737
PetscReal rx
Definition variables.h:742
PetscReal Max_Z
Definition variables.h:738
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:

◆ AnalyticalSolutionEngine()

PetscErrorCode AnalyticalSolutionEngine ( SimCtx simCtx)

Dispatches to the appropriate analytical solution function based on simulation settings.

This function acts as a router. It reads the AnalyticalSolutionType string from the simulation context and calls the corresponding private implementation function (e.g., for Taylor-Green Vortex). This design keeps the main simulation code clean and makes it easy to add new analytical test cases.

Parameters
[in]simCtxThe main simulation context, containing all configuration and state.
Returns
PetscErrorCode 0 on success, or a PETSc error code on failure.

Definition at line 184 of file AnalyticalSolutions.c.

185{
186 PetscErrorCode ierr;
187 PetscFunctionBeginUser;
189
190 // -- Before any operation, here is defensive test to ensure that the Corner->Center Interpolation method works
191 //ierr = TestCornerToCenterInterpolation(&(simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1]->user[0]));
192
193 // --- Dispatch based on the string provided by the user ---
194 if (strcmp(simCtx->AnalyticalSolutionType, "TGV3D") == 0) {
195 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Applying Analytical Solution: 3D Taylor-Green Vortex (TGV3D).\n");
196 ierr = SetAnalyticalSolution_TGV3D(simCtx); CHKERRQ(ierr);
197 }
198 /*
199 * --- EXTENSIBILITY HOOK ---
200 * To add a new analytical solution (e.g., "ChannelFlow"):
201 * 1. Add an `else if` block here:
202 *
203 * else if (strcmp(simCtx->AnalyticalSolutionType, "ChannelFlow") == 0) {
204 * LOG_ALLOW(GLOBAL, LOG_DEBUG, "Applying Analytical Solution: Channel Flow.\n");
205 * ierr = SetAnalyticalSolution_ChannelFlow(simCtx); CHKERRQ(ierr);
206 * }
207 *
208 * 2. Implement the static function `SetAnalyticalSolution_ChannelFlow(SimCtx *simCtx)`
209 * below, following the TGV3D pattern.
210 */
211 else {
212 // If the type is unknown, raise a fatal error to prevent silent failures.
213 SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown AnalyticalSolutionType specified: '%s'", simCtx->AnalyticalSolutionType);
214 }
215
217 PetscFunctionReturn(0);
218}
static PetscErrorCode SetAnalyticalSolution_TGV3D(SimCtx *simCtx)
Sets the non-dimensional velocity and pressure fields to the 3D Taylor-Green Vortex solution.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetAnalyticalSolutionForParticles_TGV3D()

static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D ( Vec  tempVec,
SimCtx simCtx 
)
static

Sets the TGV3D analytical velocity solution for particles.

Computes the 3D Taylor-Green Vortex velocity field at each particle position. Assumes the vector contains interleaved xyz components [x0,y0,z0, x1,y1,z1, ...].

Parameters
tempVecThe PETSc Vec containing particle positions, will be overwritten with velocities.
simCtxThe simulation context containing time and Reynolds number.
Returns
PetscErrorCode Returns 0 on success.

Definition at line 398 of file AnalyticalSolutions.c.

399{
400 PetscErrorCode ierr;
401 PetscInt nLocal;
402 PetscReal *data;
403
404 PetscFunctionBeginUser;
405
406 // TGV3D parameters (matching your Eulerian implementation)
407 const PetscReal V0 = 1.0;
408 const PetscReal k = 1.0;
409 const PetscReal nu = (simCtx->ren > 0) ? (1.0 / simCtx->ren) : 0.0;
410 const PetscReal t = simCtx->ti;
411 const PetscReal vel_decay = exp(-2.0 * nu * k * k * t);
412
413 LOG_ALLOW(GLOBAL, LOG_DEBUG, "TGV3D Particles: t=%.4f, V0=%.4f, k=%.4f, nu=%.6f\n", t, V0, k, nu);
414
415 ierr = VecGetLocalSize(tempVec, &nLocal); CHKERRQ(ierr);
416 ierr = VecGetArray(tempVec, &data); CHKERRQ(ierr);
417
418 // Process particles: data is interleaved [x0,y0,z0, x1,y1,z1, ...]
419 for (PetscInt i = 0; i < nLocal; i += 3) {
420 const PetscReal x = data[i];
421 const PetscReal y = data[i+1];
422 const PetscReal z = data[i+2];
423
424 // TGV3D velocity field
425 data[i] = V0 * sin(k*x) * cos(k*y) * cos(k*z) * vel_decay; // u
426 data[i+1] = -V0 * cos(k*x) * sin(k*y) * cos(k*z) * vel_decay; // v
427 data[i+2] = 0.0; // w
428 }
429
430 ierr = VecRestoreArray(tempVec, &data); CHKERRQ(ierr);
431
432 PetscFunctionReturn(0);
433}
Here is the caller graph for this function:

◆ SetAnalyticalSolutionForParticles()

PetscErrorCode SetAnalyticalSolutionForParticles ( Vec  tempVec,
SimCtx simCtx 
)

Applies the analytical solution to particle velocity vector.

Dispatcher function that calls the appropriate analytical solution based on simCtx->AnalyticalSolutionType. Supports multiple solution types.

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

Definition at line 447 of file AnalyticalSolutions.c.

448{
449 PetscErrorCode ierr;
450 PetscInt nLocal;
451 PetscReal *vels;
452
453 PetscFunctionBeginUser;
454
455 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Type: %s\n",
456 simCtx->AnalyticalSolutionType ? simCtx->AnalyticalSolutionType : "default");
457
458 // Check for specific analytical solution types
459 if (simCtx->AnalyticalSolutionType && strcmp(simCtx->AnalyticalSolutionType, "TGV3D") == 0) {
460 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Using TGV3D solution.\n");
461 ierr = SetAnalyticalSolutionForParticles_TGV3D(tempVec, simCtx); CHKERRQ(ierr);
462 return 0;
463 }
464
465 ierr = VecRestoreArray(tempVec, &vels); CHKERRQ(ierr);
466
467 PetscFunctionReturn(0);
468}
static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D(Vec tempVec, SimCtx *simCtx)
Sets the TGV3D analytical velocity solution for particles.
Here is the call graph for this function:
Here is the caller graph for this function: