PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
AnalyticalSolutions.c
Go to the documentation of this file.
1/**
2 * @file AnalyticalSolutions.c
3 * @brief Implements the analytical solution engine for initializing or driving the simulation.
4 *
5 * @details This file provides a modular and extensible framework for applying analytical solutions
6 * to the Eulerian fields. The primary entry point is `AnalyticalSolutionEngine`, which acts
7 * as a dispatcher based on user configuration.
8 *
9 * --- DESIGN PHILOSOPHY ---
10 * 1. **Non-Dimensional Core:** All calculations within this engine are performed in
11 * **non-dimensional units** (e.g., reference velocity U_ref=1.0, reference length L_ref=1.0).
12 * This is critical for consistency with the core numerical solver, which also operates on
13 * non-dimensional equations. The `simCtx->scaling` parameters are intentionally NOT used here;
14 * they are reserved for dimensionalization during I/O and post-processing only.
15 *
16 * 2. **Separation of Concerns:** The role of this engine is to set the **physical state** of the
17 * fluid at a given time `t`. This involves:
18 * - Setting the values of fields (`Ucat`, `P`) in the physical interior of the domain.
19 * - Declaring the physical values on the boundaries by populating the boundary condition
20 * vector (`user->Bcs.Ubcs`).
21 * It does NOT implement the numerical scheme for ghost cells. Instead, after setting the
22 * physical state, it relies on the solver's standard utility functions (`UpdateDummyCells`,
23 * `UpdateCornerNodes`) to correctly populate all ghost cell layers.
24 *
25 * 3. **Extensibility:** The dispatcher design makes it straightforward to add new analytical
26 * solutions. A developer only needs to add a new `else if` condition and a corresponding
27 * `static` implementation function, without modifying any other part of the solver.
28 */
29
30#include "AnalyticalSolutions.h" // The header that declares this file's functions
31#include <petscmath.h> // Provides PETSc-compatible math functions like sin, cos, exp
32
33// Forward-declare the private function for the TGV3D case.
34// This function is not visible outside this file, enforcing modularity.
35static PetscErrorCode SetAnalyticalSolution_TGV3D(SimCtx *simCtx);
36
37#undef __FUNCT__
38#define __FUNCT__ "SetAnalyticalGridInfo"
39/**
40 * @brief Sets the grid domain and resolution for analytical solution cases.
41 *
42 * @details This function is called when `eulerianSource` is "analytical". It is responsible for
43 * automatically configuring the grid based on the chosen `AnalyticalSolutionType`.
44 *
45 * @par TGV3D Multi-Block Decomposition
46 * If the analytical solution is "TGV3D", this function automatically decomposes the
47 * required `[0, 2*PI]` physical domain among the available blocks.
48 * - **Single Block (`nblk=1`):** The single block is assigned the full `[0, 2*PI]` domain.
49 * - **Multiple Blocks (`nblk>1`):** It requires that the number of blocks be a **perfect square**
50 * (e.g., 4, 9, 16). It then arranges the blocks in a `sqrt(nblk)` by `sqrt(nblk)` grid in the
51 * X-Y plane, partitioning the `[0, 2*PI]` domain in X and Y accordingly. The Z domain for all
52 * blocks remains `[0, 2*PI]`. If `nblk` is not a perfect square, the simulation is aborted
53 * with an error.
54 *
55 * After setting the domain bounds, it proceeds to read the grid resolution options
56 * (`-im`, `-jm`, `-km`) from the command line for the specific block.
57 *
58 * @param user Pointer to the `UserCtx` for a specific block. The function will
59 * populate the geometric fields (`IM`, `JM`, `KM`, `Min_X`, `Max_X`, etc.)
60 * within this struct.
61 * @return PetscErrorCode 0 on success, or a PETSc error code on failure.
62 */
63PetscErrorCode SetAnalyticalGridInfo(UserCtx *user)
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}
165
166
167/*================================================================================*
168 * PUBLIC ANALYTICAL SOLUTION ENGINE *
169 *================================================================================*/
170
171#undef __FUNCT__
172#define __FUNCT__ "AnalyticalSolutionEngine"
173/**
174 * @brief Dispatches to the appropriate analytical solution function based on simulation settings.
175 *
176 * This function acts as a router. It reads the `AnalyticalSolutionType` string from the
177 * simulation context and calls the corresponding private implementation function
178 * (e.g., for Taylor-Green Vortex). This design keeps the main simulation code clean
179 * and makes it easy to add new analytical test cases.
180 *
181 * @param[in] simCtx The main simulation context, containing all configuration and state.
182 * @return PetscErrorCode 0 on success, or a PETSc error code on failure.
183 */
184PetscErrorCode AnalyticalSolutionEngine(SimCtx *simCtx)
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}
219
220
221/*================================================================================*
222 * PRIVATE IMPLEMENTATIONS *
223 *================================================================================*/
224
225#undef __FUNCT__
226#define __FUNCT__ "SetAnalyticalSolution_TGV3D"
227/**
228 * @brief Sets the non-dimensional velocity and pressure fields to the 3D Taylor-Green Vortex solution.
229 *
230 * @details This function implements the classical decaying Taylor-Green vortex in non-dimensional
231 * form, consistent with the solver's internal state. It is fully compatible with the
232 * solver's curvilinear, parallel, cell-centered architecture.
233 *
234 * @par WORKFLOW
235 * 1. Defines non-dimensional parameters for the TGV solution (V0=1.0, rho=1.0).
236 * 2. Defines correct loop bounds (`lxs`, `lxe`, etc.) to iterate over ONLY the physical
237 * interior cells owned by the current MPI rank.
238 * 3. Sets the **interior** cell-centered velocity (`Ucat`) and pressure (`P`) by evaluating
239 * the analytical formula at the cell-center coordinates (read from the local `user->Cent` vector).
240 * 4. Sets the **boundary condition** vector (`user->Bcs.Ubcs`) by evaluating the analytical
241 * velocity at the true physical face-center locations (read from the local `user->Centx`,
242 * `user->Centy`, and `user->Centz` vectors).
243 * 5. Manually sets the **pressure ghost cells** on the faces (excluding edges/corners) to
244 * enforce a zero-gradient (Neumann) boundary condition, which is standard for pressure.
245 * 6. Calls the solver's utility functions `UpdateDummyCells` (for `Ucat`) and `UpdateCornerNodes`
246 * (for both `Ucat` and `P`) to finalize all ghost cell values, ensuring a fully consistent field.
247 *
248 * @param[in] simCtx The main simulation context.
249 * @return PetscErrorCode 0 on success, or a PETSc error code on failure.
250 */
251static PetscErrorCode SetAnalyticalSolution_TGV3D(SimCtx *simCtx)
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}
385
386#undef __FUNCT__
387#define __FUNCT__ "SetAnalyticalSolutionForParticles_TGV3D"
388/**
389@brief Sets the TGV3D analytical velocity solution for particles.
390
391@details Computes the 3D Taylor-Green Vortex velocity field at each particle position.
392 Assumes the vector contains interleaved xyz components [x0,y0,z0, x1,y1,z1, ...].
393
394@param tempVec The PETSc Vec containing particle positions, will be overwritten with velocities.
395@param simCtx The simulation context containing time and Reynolds number.
396@return PetscErrorCode Returns 0 on success.
397*/
398static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D(Vec tempVec, SimCtx *simCtx)
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}
434
435#undef __FUNCT__
436#define __FUNCT__ "SetAnalyticalSolutionForParticles"
437/**
438@brief Applies the analytical solution to particle velocity vector.
439
440@details Dispatcher function that calls the appropriate analytical solution based on
441 simCtx->AnalyticalSolutionType. Supports multiple solution types.
442
443@param tempVec The PETSc Vec containing particle positions which will be used to store velocities.
444@param simCtx The simulation context.
445@return PetscErrorCode Returns 0 on success.
446*/
447PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
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}
PetscErrorCode AnalyticalSolutionEngine(SimCtx *simCtx)
Dispatches to the appropriate analytical solution function based on simulation settings.
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Applies the analytical solution to particle velocity vector.
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.
static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D(Vec tempVec, SimCtx *simCtx)
Sets the TGV3D analytical velocity solution for particles.
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.
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 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
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:84
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:33
@ 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
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
PetscMPIInt rank
Definition variables.h:588
PetscInt block_number
Definition variables.h:649
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:731
Vec Centz
Definition variables.h:777
PetscReal Min_X
Definition variables.h:738
PetscInt KM
Definition variables.h:737
UserMG usermg
Definition variables.h:698
PetscReal ren
Definition variables.h:632
PetscInt _this
Definition variables.h:741
PetscReal ry
Definition variables.h:742
PetscReal Max_Y
Definition variables.h:738
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
PetscReal rz
Definition variables.h:742
PetscScalar z
Definition variables.h:101
Vec Ucat
Definition variables.h:755
PetscInt JM
Definition variables.h:737
PetscInt mglevels
Definition variables.h:481
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
DMDALocalInfo info
Definition variables.h:735
PetscScalar y
Definition variables.h:101
PetscInt IM
Definition variables.h:737
Vec Cent
Definition variables.h:776
MGCtx * mgctx
Definition variables.h:484
Vec Centy
Definition variables.h:777
PetscReal rx
Definition variables.h:742
PetscReal ti
Definition variables.h:594
PetscReal Max_Z
Definition variables.h:738
A 3D point or vector with PetscScalar components.
Definition variables.h:100
The master context for the entire simulation.
Definition variables.h:585
User-defined context containing data specific to a single computational grid level.
Definition variables.h:728