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 * - For most types (TGV3D, ZERO_FLOW): setting `Ucat` and `P` directly.
19 * - For curvilinear-aware types (UNIFORM_FLOW): setting `Ucont` via metric
20 * dot products and deriving `Ucat` through `Contra2Cart`.
21 * - Declaring the physical values on the boundaries by populating the boundary condition
22 * vector (`user->Bcs.Ubcs`).
23 * It does NOT implement the numerical scheme for ghost cells. Instead, after setting the
24 * physical state, it relies on the solver's standard utility functions (`UpdateDummyCells`,
25 * `UpdateCornerNodes`) to correctly populate all ghost cell layers.
26 *
27 * 3. **Extensibility:** The dispatcher design makes it straightforward to add new analytical
28 * solutions. A developer only needs to add a new `else if` condition and a corresponding
29 * `static` implementation function, without modifying any other part of the solver.
30 */
31
32#include "AnalyticalSolutions.h" // The header that declares this file's functions
33#include <petscmath.h> // Provides PETSc-compatible math functions like sin, cos, exp
34
35// Forward-declare the private function for the TGV3D case.
36// This function is not visible outside this file, enforcing modularity.
37static PetscErrorCode SetAnalyticalSolution_TGV3D(SimCtx *simCtx);
38static PetscErrorCode SetAnalyticalSolution_ZeroFlow(SimCtx *simCtx);
39static PetscErrorCode SetAnalyticalSolution_UniformFlow(SimCtx *simCtx);
40static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D(Vec tempVec, SimCtx *simCtx);
41static PetscErrorCode SetAnalyticalSolutionForParticles_UniformFlow(Vec tempVec, SimCtx *simCtx);
42static PetscErrorCode EvaluateConfiguredScalarProfile(const VerificationScalarConfig *cfg,
43 PetscReal x,
44 PetscReal y,
45 PetscReal z,
46 PetscReal *value);
47
48/**
49 * @brief Implementation of \ref AnalyticalTypeRequiresCustomGeometry().
50 * @details Full API contract (arguments, ownership, side effects) is documented with
51 * the header declaration in `include/AnalyticalSolutions.h`.
52 * @see AnalyticalTypeRequiresCustomGeometry()
53 */
54
55PetscBool AnalyticalTypeRequiresCustomGeometry(const char *analytical_type)
56{
57 if (!analytical_type) return PETSC_FALSE;
58 return (strcmp(analytical_type, "TGV3D") == 0) ? PETSC_TRUE : PETSC_FALSE;
59}
60
61/**
62 * @brief Implementation of \ref AnalyticalTypeSupportsInterpolationError().
63 * @details Full API contract (arguments, ownership, side effects) is documented with
64 * the header declaration in `include/AnalyticalSolutions.h`.
65 * @see AnalyticalTypeSupportsInterpolationError()
66 */
67PetscBool AnalyticalTypeSupportsInterpolationError(const char *analytical_type)
68{
69 if (!analytical_type) return PETSC_FALSE;
70 if (strcmp(analytical_type, "ZERO_FLOW") == 0 || strcmp(analytical_type, "UNIFORM_FLOW") == 0) return PETSC_FALSE;
71 return PETSC_TRUE;
72}
73
74#undef __FUNCT__
75#define __FUNCT__ "SetAnalyticalGridInfo"
76/**
77 * @brief Internal helper implementation: `SetAnalyticalGridInfo()`.
78 * @details Local to this translation unit.
79 */
80PetscErrorCode SetAnalyticalGridInfo(UserCtx *user)
81{
82 SimCtx *simCtx = user->simCtx;
83 PetscInt nblk = simCtx->block_number;
84 PetscInt block_index = user->_this;
85
86 PetscFunctionBeginUser;
88
90 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
91 "SetAnalyticalGridInfo called for analytical type '%s' that does not require custom geometry.",
93 }
94 if (user->IM <= 0 || user->JM <= 0 || user->KM <= 0) {
95 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONGSTATE,
96 "Analytical grid resolution is not initialized. Ensure IM/JM/KM are preloaded before SetAnalyticalGridInfo.");
97 }
98
99 if (strcmp(simCtx->AnalyticalSolutionType, "TGV3D") == 0) {
100 LOG_ALLOW_SYNC(GLOBAL, LOG_DEBUG, "Rank %d: Configuring grid for TGV3D analytical solution, block %d.\n", simCtx->rank, block_index);
101
102 if (nblk == 1) {
103 // --- Single Block Case ---
104 if (block_index == 0) {
105 LOG_ALLOW(GLOBAL, LOG_INFO, "Single block detected. Setting domain to [0, 2*PI].\n");
106 }
107 user->Min_X = 0.0; user->Max_X = 2.0 * PETSC_PI;
108 user->Min_Y = 0.0; user->Max_Y = 2.0 * PETSC_PI;
109 user->Min_Z = 0.0; user->Max_Z = 0.2 * PETSC_PI; //2.0 * PETSC_PI;
110
111 } else { // --- Multi-Block Case ---
112 PetscReal s = sqrt((PetscReal)nblk);
113
114 // Validate that nblk is a perfect square.
115 if (fabs(s - floor(s)) > 1e-9) {
116 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP,
117 "\n\n*** CONFIGURATION ERROR FOR TGV3D ***\n"
118 "For multi-block TGV3D cases, the number of blocks must be a perfect square (e.g., 4, 9, 16).\n"
119 "You have specified %d blocks. Please adjust `-block_number`.\n", nblk);
120 }
121 PetscInt blocks_per_dim = (PetscInt)s;
122
123 if (block_index == 0) {
124 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);
125 }
126
127 // Determine the (row, col) position of this block in the 2D decomposition
128 PetscInt row = block_index / blocks_per_dim;
129 PetscInt col = block_index % blocks_per_dim;
130
131 // Calculate the width/height of each sub-domain
132 PetscReal block_width = (2.0 * PETSC_PI) / (PetscReal)blocks_per_dim;
133 PetscReal block_height = (2.0 * PETSC_PI) / (PetscReal)blocks_per_dim;
134
135 // Assign this block its specific sub-domain
136 user->Min_X = col * block_width;
137 user->Max_X = (col + 1) * block_width;
138 user->Min_Y = row * block_height;
139 user->Max_Y = (row + 1) * block_height;
140 user->Min_Z = 0.0;
141 user->Max_Z = 2.0 * PETSC_PI; // Z-domain is not decomposed
142 }
143 }
144 /*
145 * --- EXTENSIBILITY HOOK ---
146 * To add another analytical case with special grid requirements:
147 *
148 * else if (strcmp(simCtx->AnalyticalSolutionType, "ChannelFlow") == 0) {
149 * // ... implement logic to set domain for ChannelFlow case ...
150 * }
151 */
152 else {
153 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_UNKNOWN_TYPE,
154 "Analytical type '%s' has no custom geometry implementation.",
155 simCtx->AnalyticalSolutionType);
156 }
157
158 // We can also read stretching ratios, as they are independent of the domain size
159 // For simplicity, we assume uniform grid unless specified.
160 user->rx = 1.0; user->ry = 1.0; user->rz = 1.0;
161
162 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d grid resolution set: IM=%d, JM=%d, KM=%d\n",
163 simCtx->rank, block_index, user->IM, user->JM, user->KM);
164 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d: Block %d final bounds: X=[%.4f, %.4f], Y=[%.4f, %.4f], Z=[%.4f, %.4f]\n",
165 simCtx->rank, block_index, user->Min_X, user->Max_X, user->Min_Y, user->Max_Y, user->Min_Z, user->Max_Z);
166
168 PetscFunctionReturn(0);
169}
170
171
172/*================================================================================*
173 * PUBLIC ANALYTICAL SOLUTION ENGINE *
174 *================================================================================*/
175
176#undef __FUNCT__
177#define __FUNCT__ "AnalyticalSolutionEngine"
178/**
179 * @brief Implementation of \ref AnalyticalSolutionEngine().
180 * @details Full API contract (arguments, ownership, side effects) is documented with
181 * the header declaration in `include/AnalyticalSolutions.h`.
182 * @see AnalyticalSolutionEngine()
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 else if (strcmp(simCtx->AnalyticalSolutionType, "ZERO_FLOW") == 0) {
199 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Applying Analytical Solution: Zero Background Flow (ZERO_FLOW).\n");
200 ierr = SetAnalyticalSolution_ZeroFlow(simCtx); CHKERRQ(ierr);
201 }
202 else if (strcmp(simCtx->AnalyticalSolutionType, "UNIFORM_FLOW") == 0) {
203 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Applying Analytical Solution: Uniform Background Flow (UNIFORM_FLOW).\n");
204 ierr = SetAnalyticalSolution_UniformFlow(simCtx); CHKERRQ(ierr);
205 }
206 /*
207 * --- EXTENSIBILITY HOOK ---
208 * To add a new analytical solution (e.g., "ChannelFlow"):
209 * 1. Add an `else if` block here:
210 *
211 * else if (strcmp(simCtx->AnalyticalSolutionType, "ChannelFlow") == 0) {
212 * LOG_ALLOW(GLOBAL, LOG_DEBUG, "Applying Analytical Solution: Channel Flow.\n");
213 * ierr = SetAnalyticalSolution_ChannelFlow(simCtx); CHKERRQ(ierr);
214 * }
215 *
216 * 2. Implement the static function `SetAnalyticalSolution_ChannelFlow(SimCtx *simCtx)`
217 * below, following the TGV3D pattern.
218 */
219 else {
220 // If the type is unknown, raise a fatal error to prevent silent failures.
221 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown AnalyticalSolutionType specified: '%s'", simCtx->AnalyticalSolutionType);
222 }
223
225 PetscFunctionReturn(0);
226}
227
228
229/*================================================================================*
230 * PRIVATE IMPLEMENTATIONS *
231 *================================================================================*/
232
233#undef __FUNCT__
234#define __FUNCT__ "SetAnalyticalSolution_TGV3D"
235/**
236 * @brief Populate the Eulerian field vectors with the Taylor--Green vortex at the current time.
237 */
238static PetscErrorCode SetAnalyticalSolution_TGV3D(SimCtx *simCtx)
239{
240 PetscErrorCode ierr;
241 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
242
243 // --- NON-DIMENSIONAL TGV Parameters ---
244 const PetscReal V0 = 1.0; // Non-dimensional reference velocity.
245 const PetscReal rho = 1.0; // Non-dimensional reference density.
246 const PetscReal p0 = 0.0; // Non-dimensional reference pressure.
247
248 // Kinematic viscosity is derived from the non-dimensional Reynolds number.
249 const PetscReal nu = (simCtx->ren > 0) ? (1.0 / simCtx->ren) : 0.0;
250
251 const PetscReal k = 1.0; // Wavenumber, assumes a non-dimensional [0, 2*pi] domain.
252 const PetscReal t = simCtx->ti;
253
254 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);
255
256 const PetscReal vel_decay = exp(-2.0 * nu * k * k * t);
257 const PetscReal prs_decay = exp(-4.0 * nu * k * k * t);
258
259 PetscFunctionBeginUser;
260
261 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
262 UserCtx* user = &user_finest[bi];
263 DMDALocalInfo info = user->info;
264 PetscInt xs = info.xs, xe = info.xs + info.xm;
265 PetscInt ys = info.ys, ye = info.ys + info.ym;
266 PetscInt zs = info.zs, ze = info.zs + info.zm;
267 PetscInt mx = info.mx, my = info.my, mz = info.mz;
268
269 Cmpnts ***ucat, ***ubcs;
270 const Cmpnts ***cent, ***cent_x, ***cent_y, ***cent_z;
271 PetscReal ***p;
272
273 // Define loop bounds for physical interior cells owned by this rank.
274 PetscInt lxs = (xs == 0) ? xs + 1 : xs, lxe = (xe == mx) ? xe - 1 : xe;
275 PetscInt lys = (ys == 0) ? ys + 1 : ys, lye = (ye == my) ? ye - 1 : ye;
276 PetscInt lzs = (zs == 0) ? zs + 1 : zs, lze = (ze == mz) ? ze - 1 : ze;
277
278 // --- Get Arrays ---
279 ierr = DMDAVecGetArray(user->fda, user->Ucat, &ucat); CHKERRQ(ierr);
280 ierr = DMDAVecGetArray(user->da, user->P, &p); CHKERRQ(ierr);
281 ierr = DMDAVecGetArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
282 ierr = DMDAVecGetArrayRead(user->fda, user->Cent, &cent); CHKERRQ(ierr);
283 ierr = DMDAVecGetArrayRead(user->fda, user->lCentx, &cent_x); CHKERRQ(ierr);
284 ierr = DMDAVecGetArrayRead(user->fda, user->lCenty, &cent_y); CHKERRQ(ierr);
285 ierr = DMDAVecGetArrayRead(user->fda, user->lCentz, &cent_z); CHKERRQ(ierr);
286
287 // --- Set INTERIOR cell-centered velocity (Ucat) ---
288 for (PetscInt k_cell = lzs; k_cell < lze; k_cell++) {
289 for (PetscInt j_cell = lys; j_cell < lye; j_cell++) {
290 for (PetscInt i_cell = lxs; i_cell < lxe; i_cell++) {
291 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;
292 ucat[k_cell][j_cell][i_cell].x = V0 * sin(k*cx) * cos(k*cy) * cos(k*cz) * vel_decay;
293 ucat[k_cell][j_cell][i_cell].y = -V0 * cos(k*cx) * sin(k*cy) * cos(k*cz) * vel_decay;
294 ucat[k_cell][j_cell][i_cell].z = 0.0;
295 }
296 }
297 }
298
299
300 // --- Set INTERIOR cell-centered pressure (P) ---
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;
305 p[k_cell][j_cell][i_cell] = p0 + (rho * V0 * V0 / 4.0) * (cos(2*k*cx) + cos(2*k*cy)) * prs_decay;
306 }
307 }
308 }
309
310
311 // --- Set BOUNDARY condition vector for velocity (Ubcs) ---
312 if (xs == 0) for (PetscInt k=zs; k<ze; k++) for (PetscInt j=ys; j<ye; j++) {
313 const PetscReal fcx=cent_x[k][j][xs].x, fcy=cent_x[k][j][xs].y, fcz=cent_x[k][j][xs].z;
314 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;
315 }
316 if (xe == mx) for (PetscInt k=zs; k<ze; k++) for (PetscInt j=ys; j<ye; j++) {
317 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;
318 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;
319 }
320 if (ys == 0) for (PetscInt k=zs; k<ze; k++) for (PetscInt i=xs; i<xe; i++) {
321 const PetscReal fcx=cent_y[k][ys][i].x, fcy=cent_y[k][ys][i].y, fcz=cent_y[k][ys][i].z;
322 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;
323 }
324 if (ye == my) for (PetscInt k=zs; k<ze; k++) for (PetscInt i=xs; i<xe; i++) {
325 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;
326 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;
327 }
328 if (zs == 0) for (PetscInt j=ys; j<ye; j++) for (PetscInt i=xs; i<xe; i++) {
329 const PetscReal fcx=cent_z[zs][j][i].x, fcy=cent_z[zs][j][i].y, fcz=cent_z[zs][j][i].z;
330 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;
331 }
332 if (ze == mz) for (PetscInt j=ys; j<ye; j++) for (PetscInt i=xs; i<xe; i++) {
333 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;
334 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;
335 }
336
337 // --- Set PRESSURE GHOST CELLS (Neumann BC: P_ghost = P_interior) ---
338 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];
339 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];
340
341 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];
342 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];
343
344 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];
345 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];
346
347 // --- Restore all arrays ---
348 ierr = DMDAVecRestoreArray(user->fda, user->Ucat, &ucat); CHKERRQ(ierr);
349 ierr = DMDAVecRestoreArray(user->da, user->P, &p); CHKERRQ(ierr);
350 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
351 ierr = DMDAVecRestoreArrayRead(user->fda, user->Cent, &cent); CHKERRQ(ierr);
352 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCentx, &cent_x); CHKERRQ(ierr);
353 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCenty, &cent_y); CHKERRQ(ierr);
354 ierr = DMDAVecRestoreArrayRead(user->fda, user->lCentz, &cent_z); CHKERRQ(ierr);
355
356 // Pre-Dummy cell update synchronization.
357 ierr = UpdateLocalGhosts(user, FIELD_ID_UCAT);
358 ierr = UpdateLocalGhosts(user, FIELD_ID_P);
359
360 // --- Finalize all ghost cell values ---
361 ierr = UpdateDummyCells(user); CHKERRQ(ierr);
362 ierr = UpdateCornerNodes(user); CHKERRQ(ierr);
363
364 // Final Synchronization.
365 ierr = UpdateLocalGhosts(user, FIELD_ID_UCAT);
366 ierr = UpdateLocalGhosts(user, FIELD_ID_P);
367
368 }
369
370 PetscFunctionReturn(0);
371}
372
373#undef __FUNCT__
374#define __FUNCT__ "SetAnalyticalSolution_ZeroFlow"
375/**
376 * @brief Set every analytical Eulerian field to the quiescent zero-flow reference state.
377 */
378static PetscErrorCode SetAnalyticalSolution_ZeroFlow(SimCtx *simCtx)
379{
380 PetscErrorCode ierr;
381 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
382
383 PetscFunctionBeginUser;
384
385 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
386 UserCtx *user = &user_finest[bi];
387
388 ierr = VecZeroEntries(user->Ucat); CHKERRQ(ierr);
389 ierr = VecZeroEntries(user->P); CHKERRQ(ierr);
390 ierr = VecZeroEntries(user->Bcs.Ubcs); CHKERRQ(ierr);
391
392 // Ghost-cell finalization — identical sequence to TGV3D
393 ierr = UpdateLocalGhosts(user, FIELD_ID_UCAT); CHKERRQ(ierr);
394 ierr = UpdateLocalGhosts(user, FIELD_ID_P); CHKERRQ(ierr);
395 ierr = UpdateDummyCells(user); CHKERRQ(ierr);
396 ierr = UpdateCornerNodes(user); CHKERRQ(ierr);
397 ierr = UpdateLocalGhosts(user, FIELD_ID_UCAT); CHKERRQ(ierr);
398 ierr = UpdateLocalGhosts(user, FIELD_ID_P); CHKERRQ(ierr);
399 }
400
401 PetscFunctionReturn(0);
402}
403
404#undef __FUNCT__
405#define __FUNCT__ "SetAnalyticalSolution_UniformFlow"
406/**
407 * @brief Fill the analytical Eulerian fields with the configured spatially uniform flow state.
408 */
409static PetscErrorCode SetAnalyticalSolution_UniformFlow(SimCtx *simCtx)
410{
411 PetscErrorCode ierr;
412 UserCtx *user_finest = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
413 const Cmpnts uniform_velocity = simCtx->AnalyticalUniformVelocity;
414 const PetscReal u = uniform_velocity.x;
415 const PetscReal v = uniform_velocity.y;
416 const PetscReal w = uniform_velocity.z;
417
418 PetscFunctionBeginUser;
419
420 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
421 UserCtx *user = &user_finest[bi];
422 DMDALocalInfo info = user->info;
423 PetscInt xs = info.xs, xe = info.xs + info.xm;
424 PetscInt ys = info.ys, ye = info.ys + info.ym;
425 PetscInt zs = info.zs, ze = info.zs + info.zm;
426 PetscInt mx = info.mx, my = info.my, mz = info.mz;
427
428 // --- Step 1: Set Ucont (contravariant flux) via Cart2Contra ---
429 ierr = UniformCart2Contra(user, u, v, w); CHKERRQ(ierr);
430
431 // --- Step 2: Set Ubcs at boundaries (physical Cartesian velocity) ---
432 Cmpnts ***ubcs;
433 ierr = DMDAVecGetArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
434 if (xs == 0) for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) ubcs[k][j][xs] = uniform_velocity;
435 if (xe == mx) for (PetscInt k = zs; k < ze; k++) for (PetscInt j = ys; j < ye; j++) ubcs[k][j][xe - 1] = uniform_velocity;
436 if (ys == 0) for (PetscInt k = zs; k < ze; k++) for (PetscInt i = xs; i < xe; i++) ubcs[k][ys][i] = uniform_velocity;
437 if (ye == my) for (PetscInt k = zs; k < ze; k++) for (PetscInt i = xs; i < xe; i++) ubcs[k][ye - 1][i] = uniform_velocity;
438 if (zs == 0) for (PetscInt j = ys; j < ye; j++) for (PetscInt i = xs; i < xe; i++) ubcs[zs][j][i] = uniform_velocity;
439 if (ze == mz) for (PetscInt j = ys; j < ye; j++) for (PetscInt i = xs; i < xe; i++) ubcs[ze - 1][j][i] = uniform_velocity;
440 ierr = DMDAVecRestoreArray(user->fda, user->Bcs.Ubcs, &ubcs); CHKERRQ(ierr);
441
442 // --- Step 3: Zero pressure ---
443 ierr = VecZeroEntries(user->P); CHKERRQ(ierr);
444
445 // --- Step 4: Finalize state — derive Ucat from Ucont via metric inversion ---
446 const FieldId staggered_fields[] = {FIELD_ID_UCONT};
447 ierr = SynchronizePeriodicStaggeredFields(user, 1, staggered_fields); CHKERRQ(ierr);
448 ierr = Contra2Cart(user); CHKERRQ(ierr);
449 ierr = UpdateLocalGhosts(user, FIELD_ID_UCAT); CHKERRQ(ierr);
450 ierr = UpdateLocalGhosts(user, FIELD_ID_P); CHKERRQ(ierr);
451 ierr = UpdateDummyCells(user); CHKERRQ(ierr);
452 ierr = UpdateCornerNodes(user); CHKERRQ(ierr);
453 ierr = UpdateLocalGhosts(user, FIELD_ID_UCAT); CHKERRQ(ierr);
454 ierr = UpdateLocalGhosts(user, FIELD_ID_P); CHKERRQ(ierr);
455 }
456
457 PetscFunctionReturn(0);
458}
459
460#undef __FUNCT__
461#define __FUNCT__ "SetAnalyticalSolutionForParticles_TGV3D"
462/**
463 * @brief Evaluate Taylor--Green velocities at swarm particle positions and store them in `tempVec`.
464 */
465static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D(Vec tempVec, SimCtx *simCtx)
466{
467 PetscErrorCode ierr;
468 PetscInt nLocal;
469 PetscReal *data;
470
471 PetscFunctionBeginUser;
472
473 // TGV3D parameters (matching your Eulerian implementation)
474 const PetscReal V0 = 1.0;
475 const PetscReal k = 1.0;
476 const PetscReal nu = (simCtx->ren > 0) ? (1.0 / simCtx->ren) : 0.0;
477 const PetscReal t = simCtx->ti;
478 const PetscReal vel_decay = exp(-2.0 * nu * k * k * t);
479
480 LOG_ALLOW(GLOBAL, LOG_DEBUG, "TGV3D Particles: t=%.4f, V0=%.4f, k=%.4f, nu=%.6f\n", t, V0, k, nu);
481
482 ierr = VecGetLocalSize(tempVec, &nLocal); CHKERRQ(ierr);
483 ierr = VecGetArray(tempVec, &data); CHKERRQ(ierr);
484
485 // Process particles: data is interleaved [x0,y0,z0, x1,y1,z1, ...]
486 for (PetscInt i = 0; i < nLocal; i += 3) {
487 const PetscReal x = data[i];
488 const PetscReal y = data[i+1];
489 const PetscReal z = data[i+2];
490
491 // TGV3D velocity field
492 data[i] = V0 * sin(k*x) * cos(k*y) * cos(k*z) * vel_decay; // u
493 data[i+1] = -V0 * cos(k*x) * sin(k*y) * cos(k*z) * vel_decay; // v
494 data[i+2] = 0.0; // w
495 }
496
497 ierr = VecRestoreArray(tempVec, &data); CHKERRQ(ierr);
498
499 PetscFunctionReturn(0);
500}
501
502#undef __FUNCT__
503#define __FUNCT__ "SetAnalyticalSolutionForParticles_UniformFlow"
504/**
505 * @brief Fill the particle velocity vector with the configured uniform analytical flow.
506 */
507static PetscErrorCode SetAnalyticalSolutionForParticles_UniformFlow(Vec tempVec, SimCtx *simCtx)
508{
509 PetscErrorCode ierr;
510 PetscInt nLocal;
511 PetscReal *data;
512 const Cmpnts uniform_velocity = simCtx->AnalyticalUniformVelocity;
513
514 PetscFunctionBeginUser;
515
516 ierr = VecGetLocalSize(tempVec, &nLocal); CHKERRQ(ierr);
517 ierr = VecGetArray(tempVec, &data); CHKERRQ(ierr);
518 for (PetscInt i = 0; i < nLocal; i += 3) {
519 data[i] = uniform_velocity.x;
520 data[i + 1] = uniform_velocity.y;
521 data[i + 2] = uniform_velocity.z;
522 }
523 ierr = VecRestoreArray(tempVec, &data); CHKERRQ(ierr);
524
525 PetscFunctionReturn(0);
526}
527
528#undef __FUNCT__
529#define __FUNCT__ "SetAnalyticalSolutionForParticles"
530/**
531 * @brief Implementation of \ref SetAnalyticalSolutionForParticles().
532 * @details Full API contract (arguments, ownership, side effects) is documented with
533 * the header declaration in `include/AnalyticalSolutions.h`.
534 * @see SetAnalyticalSolutionForParticles()
535 */
536PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
537{
538 PetscErrorCode ierr;
539 const char *analytical_type = simCtx->AnalyticalSolutionType[0] ? simCtx->AnalyticalSolutionType : "default";
540
541 PetscFunctionBeginUser;
542
543 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Type: %s\n", analytical_type);
544
545 // Check for specific analytical solution types
546 if (strcmp(simCtx->AnalyticalSolutionType, "TGV3D") == 0) {
547 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Using TGV3D solution.\n");
548 ierr = SetAnalyticalSolutionForParticles_TGV3D(tempVec, simCtx); CHKERRQ(ierr);
549 return 0;
550 }
551 if (strcmp(simCtx->AnalyticalSolutionType, "UNIFORM_FLOW") == 0) {
552 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Using UNIFORM_FLOW solution.\n");
553 ierr = SetAnalyticalSolutionForParticles_UniformFlow(tempVec, simCtx); CHKERRQ(ierr);
554 return 0;
555 }
556
557 PetscFunctionReturn(0);
558}
559
560/**
561 * @brief Internal helper that evaluates the configured scalar verification profile.
562 * @details Local to this translation unit.
563 */
565 PetscReal x,
566 PetscReal y,
567 PetscReal z,
568 PetscReal *value)
569{
570 PetscFunctionBeginUser;
571 if (!cfg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "VerificationScalarConfig cannot be NULL.");
572 if (!value) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Scalar output pointer cannot be NULL.");
573
574 if (strcmp(cfg->profile, "CONSTANT") == 0) {
575 *value = cfg->value;
576 } else if (strcmp(cfg->profile, "LINEAR_X") == 0) {
577 *value = cfg->phi0 + cfg->slope_x * x;
578 } else if (strcmp(cfg->profile, "SIN_PRODUCT") == 0) {
579 *value = cfg->amplitude *
580 PetscSinReal(cfg->kx * x) *
581 PetscSinReal(cfg->ky * y) *
582 PetscSinReal(cfg->kz * z);
583 } else {
584 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
585 "Unsupported verification scalar profile '%s'.", cfg->profile);
586 }
587
588 PetscFunctionReturn(0);
589}
590
591#undef __FUNCT__
592#define __FUNCT__ "EvaluateAnalyticalScalarProfile"
593/**
594 * @brief Implementation of \ref EvaluateAnalyticalScalarProfile().
595 * @details Full API contract (arguments, ownership, side effects) is documented with
596 * the header declaration in `include/AnalyticalSolutions.h`.
597 * @see EvaluateAnalyticalScalarProfile()
598 */
599PetscErrorCode EvaluateAnalyticalScalarProfile(const SimCtx *simCtx,
600 PetscReal x,
601 PetscReal y,
602 PetscReal z,
603 PetscReal t,
604 PetscReal *value)
605{
606 PetscFunctionBeginUser;
607 (void)t;
608 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL.");
609 if (!simCtx->verificationScalar.enabled) {
610 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE,
611 "EvaluateAnalyticalScalarProfile requires verification scalar mode to be enabled.");
612 }
613 PetscCall(EvaluateConfiguredScalarProfile(&simCtx->verificationScalar, x, y, z, value));
614 PetscFunctionReturn(0);
615}
616
617#undef __FUNCT__
618#define __FUNCT__ "SetAnalyticalScalarFieldOnParticles"
619/**
620 * @brief Implementation of \ref SetAnalyticalScalarFieldOnParticles().
621 * @details Full API contract (arguments, ownership, side effects) is documented with
622 * the header declaration in `include/AnalyticalSolutions.h`.
623 * @see SetAnalyticalScalarFieldOnParticles()
624 */
625PetscErrorCode SetAnalyticalScalarFieldOnParticles(UserCtx *user, ParticleFieldId particle_field_id)
626{
627 PetscErrorCode ierr;
628 PetscInt nlocal = 0;
629 PetscReal *positions = NULL;
630 PetscReal *scalar_values = NULL;
631 const ParticleFieldDescriptor *descriptor = NULL;
632 const char *swarm_field_name = NULL;
633
634 PetscFunctionBeginUser;
635 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
636 if (!user->swarm) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "UserCtx->swarm is NULL.");
637
638 ierr = ParticleFieldGetDescriptor(particle_field_id, &descriptor); CHKERRQ(ierr);
639 PetscCheck(descriptor->components == 1 && descriptor->data_type == PETSC_REAL,
640 PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP,
641 "Analytical scalar assignment requires a one-component PETSC_REAL particle field; '%s' has %d components and type %s.",
642 descriptor->canonical_name, descriptor->components, PetscDataTypes[descriptor->data_type]);
643 swarm_field_name = descriptor->canonical_name;
644
645 ierr = DMSwarmGetLocalSize(user->swarm, &nlocal); CHKERRQ(ierr);
646 if (nlocal == 0) PetscFunctionReturn(0);
647
648 ierr = DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void **)&positions); CHKERRQ(ierr);
649 ierr = DMSwarmGetField(user->swarm, swarm_field_name, NULL, NULL, (void **)&scalar_values); CHKERRQ(ierr);
650
651 for (PetscInt p = 0; p < nlocal; ++p) {
652 PetscReal value = 0.0;
654 positions[3 * p + 0],
655 positions[3 * p + 1],
656 positions[3 * p + 2],
657 user->simCtx->ti,
658 &value); CHKERRQ(ierr);
659 scalar_values[p] = value;
660 }
661
662 ierr = DMSwarmRestoreField(user->swarm, swarm_field_name, NULL, NULL, (void **)&scalar_values); CHKERRQ(ierr);
663 ierr = DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), NULL, NULL, (void **)&positions); CHKERRQ(ierr);
664 PetscFunctionReturn(0);
665}
666
667#undef __FUNCT__
668#define __FUNCT__ "SetAnalyticalScalarFieldAtCellCenters"
669/**
670 * @brief Implementation of \ref SetAnalyticalScalarFieldAtCellCenters().
671 * @details Full API contract (arguments, ownership, side effects) is documented with
672 * the header declaration in `include/AnalyticalSolutions.h`.
673 * @see SetAnalyticalScalarFieldAtCellCenters()
674 */
675PetscErrorCode SetAnalyticalScalarFieldAtCellCenters(UserCtx *user, Vec targetVec)
676{
677 PetscErrorCode ierr;
678 PetscReal ***target = NULL;
679 const Cmpnts ***cent = NULL;
680 DMDALocalInfo info;
681 PetscInt xs, xe, ys, ye, zs, ze, mx, my, mz;
682 PetscInt lxs, lxe, lys, lye, lzs, lze;
683
684 PetscFunctionBeginUser;
685 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
686 if (!targetVec) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "targetVec cannot be NULL.");
687
688 info = user->info;
689 xs = info.xs; xe = info.xs + info.xm;
690 ys = info.ys; ye = info.ys + info.ym;
691 zs = info.zs; ze = info.zs + info.zm;
692 mx = info.mx; my = info.my; mz = info.mz;
693 lxs = (xs == 0) ? xs + 1 : xs; lxe = (xe == mx) ? xe - 1 : xe;
694 lys = (ys == 0) ? ys + 1 : ys; lye = (ye == my) ? ye - 1 : ye;
695 lzs = (zs == 0) ? zs + 1 : zs; lze = (ze == mz) ? ze - 1 : ze;
696
697 ierr = VecSet(targetVec, 0.0); CHKERRQ(ierr);
698 ierr = DMDAVecGetArray(user->da, targetVec, &target); CHKERRQ(ierr);
699 ierr = DMDAVecGetArrayRead(user->fda, user->Cent, &cent); CHKERRQ(ierr);
700
701 for (PetscInt k = lzs; k < lze; ++k) {
702 for (PetscInt j = lys; j < lye; ++j) {
703 for (PetscInt i = lxs; i < lxe; ++i) {
704 PetscReal value = 0.0;
706 cent[k][j][i].x,
707 cent[k][j][i].y,
708 cent[k][j][i].z,
709 user->simCtx->ti,
710 &value); CHKERRQ(ierr);
711 target[k][j][i] = value;
712 }
713 }
714 }
715
716 ierr = DMDAVecRestoreArrayRead(user->fda, user->Cent, &cent); CHKERRQ(ierr);
717 ierr = DMDAVecRestoreArray(user->da, targetVec, &target); CHKERRQ(ierr);
718 PetscFunctionReturn(0);
719}
static PetscErrorCode SetAnalyticalSolution_ZeroFlow(SimCtx *simCtx)
Set every analytical Eulerian field to the quiescent zero-flow reference state.
static PetscErrorCode SetAnalyticalSolution_UniformFlow(SimCtx *simCtx)
Fill the analytical Eulerian fields with the configured spatially uniform flow state.
PetscErrorCode EvaluateAnalyticalScalarProfile(const SimCtx *simCtx, PetscReal x, PetscReal y, PetscReal z, PetscReal t, PetscReal *value)
Implementation of EvaluateAnalyticalScalarProfile().
PetscErrorCode SetAnalyticalScalarFieldAtCellCenters(UserCtx *user, Vec targetVec)
Implementation of SetAnalyticalScalarFieldAtCellCenters().
PetscErrorCode SetAnalyticalScalarFieldOnParticles(UserCtx *user, ParticleFieldId particle_field_id)
Implementation of SetAnalyticalScalarFieldOnParticles().
static PetscErrorCode SetAnalyticalSolutionForParticles_UniformFlow(Vec tempVec, SimCtx *simCtx)
Fill the particle velocity vector with the configured uniform analytical flow.
static PetscErrorCode EvaluateConfiguredScalarProfile(const VerificationScalarConfig *cfg, PetscReal x, PetscReal y, PetscReal z, PetscReal *value)
Internal helper that evaluates the configured scalar verification profile.
PetscErrorCode AnalyticalSolutionEngine(SimCtx *simCtx)
Implementation of AnalyticalSolutionEngine().
PetscBool AnalyticalTypeRequiresCustomGeometry(const char *analytical_type)
Implementation of AnalyticalTypeRequiresCustomGeometry().
PetscBool AnalyticalTypeSupportsInterpolationError(const char *analytical_type)
Implementation of AnalyticalTypeSupportsInterpolationError().
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Implementation of SetAnalyticalSolutionForParticles().
static PetscErrorCode SetAnalyticalSolution_TGV3D(SimCtx *simCtx)
Populate the Eulerian field vectors with the Taylor–Green vortex at the current time.
PetscErrorCode SetAnalyticalGridInfo(UserCtx *user)
Internal helper implementation: SetAnalyticalGridInfo().
static PetscErrorCode SetAnalyticalSolutionForParticles_TGV3D(Vec tempVec, SimCtx *simCtx)
Evaluate Taylor–Green velocities at swarm particle positions and store them in tempVec.
PetscErrorCode UpdateDummyCells(UserCtx *user)
Updates the dummy cells (ghost nodes) on the faces of the local domain for NON-PERIODIC boundaries.
PetscErrorCode SynchronizePeriodicStaggeredFields(UserCtx *user, PetscInt num_fields, const FieldId field_ids[])
Synchronizes persistent component-staggered vector fields.
PetscErrorCode UpdateCornerNodes(UserCtx *user)
Updates the corner and edge ghost nodes of the local domain by averaging.
FieldId
Compile-time identity for a catalogued Eulerian field.
@ FIELD_ID_UCAT
@ FIELD_ID_UCONT
@ FIELD_ID_P
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
Definition logging.h:253
#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:859
@ 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:850
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
ParticleFieldId
Compile-time identity for a persistent solver-particle field.
@ PARTICLE_FIELD_ID_POSITION
PetscErrorCode ParticleFieldGetDescriptor(ParticleFieldId field_id, const ParticleFieldDescriptor **descriptor)
Return immutable metadata for a valid particle field ID.
Immutable metadata for one persistent particle field.
PetscErrorCode UniformCart2Contra(UserCtx *user, PetscReal u, PetscReal v, PetscReal w)
Populate contravariant fluxes from one uniform Cartesian velocity.
Definition setup.c:2853
PetscErrorCode Contra2Cart(UserCtx *user)
Reconstructs Cartesian velocity (Ucat) at cell centers from contravariant velocity (Ucont) defined on...
Definition setup.c:2649
PetscErrorCode UpdateLocalGhosts(UserCtx *user, FieldId field_id)
Updates the local vector (including ghost points) from its corresponding global vector.
Definition setup.c:1838
UserCtx * user
Definition variables.h:571
PetscMPIInt rank
Definition variables.h:698
PetscInt block_number
Definition variables.h:790
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:909
PetscReal Min_X
Definition variables.h:921
PetscInt KM
Definition variables.h:920
UserMG usermg
Definition variables.h:852
PetscReal ren
Definition variables.h:744
PetscInt _this
Definition variables.h:924
PetscReal ry
Definition variables.h:925
PetscReal Max_Y
Definition variables.h:921
Vec Ubcs
Physical Cartesian velocity at boundary faces. Full 3D array but only boundary-face entries are meani...
Definition variables.h:123
PetscScalar x
Definition variables.h:103
BCS Bcs
Definition variables.h:934
VerificationScalarConfig verificationScalar
Definition variables.h:778
PetscReal rz
Definition variables.h:925
Cmpnts AnalyticalUniformVelocity
Definition variables.h:760
PetscScalar z
Definition variables.h:103
Vec Ucat
Definition variables.h:939
PetscInt JM
Definition variables.h:920
Vec lCenty
Definition variables.h:976
PetscInt mglevels
Definition variables.h:578
PetscReal Min_Z
Definition variables.h:921
char AnalyticalSolutionType[PETSC_MAX_PATH_LEN]
Definition variables.h:729
PetscReal Max_X
Definition variables.h:921
Vec lCentx
Definition variables.h:976
PetscReal Min_Y
Definition variables.h:921
DMDALocalInfo info
Definition variables.h:918
PetscScalar y
Definition variables.h:103
PetscInt IM
Definition variables.h:920
Vec Cent
Definition variables.h:974
MGCtx * mgctx
Definition variables.h:581
PetscReal rx
Definition variables.h:925
Vec lCentz
Definition variables.h:976
PetscReal ti
Definition variables.h:704
PetscReal Max_Z
Definition variables.h:921
A 3D point or vector with PetscScalar components.
Definition variables.h:102
The master context for the entire simulation.
Definition variables.h:695
User-defined context containing data specific to a single computational grid level.
Definition variables.h:906
Verification-only analytical scalar override settings.
Definition variables.h:224