PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
simulation.c
Go to the documentation of this file.
1/**
2 * @file simulation.c // code for simulation loop
3 * @brief Test program for DMSwarm interpolation using the fdf-curvIB method.
4 * Provides the setup to start any simulation with DMSwarm and DMDAs.
5 **/
6
7#include "simulation.h"
8
9/**
10 * @brief Copies the current time step's solution fields into history vectors
11 * (e.g., U(t_n) -> U_o, U_o -> U_rm1) for the next time step's calculations.
12 *
13 * This function is critical for multi-step time integration schemes (like BDF2)
14 * used by the legacy solver. It must be called at the end of every time step,
15 * after the new solution has been fully computed.
16 *
17 * The order of operations is important to avoid overwriting data prematurely.
18 *
19 * @param user The UserCtx for a single block. The function modifies the history
20 * vectors (Ucont_o, Ucont_rm1, etc.) within this context.
21 * @return PetscErrorCode 0 on success.
22 */
24{
25 PetscErrorCode ierr;
26 SimCtx *simCtx = user->simCtx; // Access global settings if needed
27
28 PetscFunctionBeginUser;
29 LOG_ALLOW(LOCAL, LOG_DEBUG, "Rank %d, Block %d: Updating solver history vectors.\n",
30 simCtx->rank, user->_this);
31
32 // --- Primary Contravariant Velocity History ---
33 // The order is critical here.
34 // 1. First, move the n-1 state (Ucont_o) to the n-2 slot (Ucont_rm1).
35 ierr = VecCopy(user->Ucont_o, user->Ucont_rm1); CHKERRQ(ierr);
36 // 2. Then, move the new n state (Ucont) to the n-1 slot (Ucont_o).
37 ierr = VecCopy(user->Ucont, user->Ucont_o); CHKERRQ(ierr);
38
39 LOG_ALLOW(LOCAL,LOG_DEBUG, "Rank %d, Block %d, Ucont history updated.\n",simCtx->rank,user->_this);
40
41 // --- Update History for Other Fields ---
42 // These are typically only needed at the n-1 state.
43 ierr = VecCopy(user->Ucat, user->Ucat_o); CHKERRQ(ierr);
44 ierr = VecCopy(user->P, user->P_o); CHKERRQ(ierr);
45 LOG_ALLOW(LOCAL,LOG_DEBUG, "Rank %d, Block %d, Ucat & P history updated.\n",simCtx->rank,user->_this);
46
47 if (simCtx->immersed) {
48 ierr = VecCopy(user->Nvert, user->Nvert_o); CHKERRQ(ierr);
49 }
50
51 // --- Update History for Turbulence Models (if active) ---
52 if (simCtx->rans) {
53 ierr = VecCopy(user->K_Omega, user->K_Omega_o); CHKERRQ(ierr);
54 }
55
56 // --- Synchronize Local Ghost Regions for the new history vectors ---
57 // This is essential so that stencils in the next time step's calculations
58 // have correct values from neighboring processes.
59 ierr = DMGlobalToLocalBegin(user->fda, user->Ucont_o, INSERT_VALUES, user->lUcont_o); CHKERRQ(ierr);
60 ierr = DMGlobalToLocalEnd(user->fda, user->Ucont_o, INSERT_VALUES, user->lUcont_o); CHKERRQ(ierr);
61
62 ierr = DMGlobalToLocalBegin(user->fda, user->Ucont_rm1, INSERT_VALUES, user->lUcont_rm1); CHKERRQ(ierr);
63 ierr = DMGlobalToLocalEnd(user->fda, user->Ucont_rm1, INSERT_VALUES, user->lUcont_rm1); CHKERRQ(ierr);
64
65 if (simCtx->immersed) {
66 ierr = DMGlobalToLocalBegin(user->da, user->Nvert_o, INSERT_VALUES, user->lNvert_o); CHKERRQ(ierr);
67 ierr = DMGlobalToLocalEnd(user->da, user->Nvert_o, INSERT_VALUES, user->lNvert_o); CHKERRQ(ierr);
68 }
69
70 if (simCtx->rans) {
71 ierr = DMGlobalToLocalBegin(user->fda2, user->K_Omega_o, INSERT_VALUES, user->lK_Omega_o); CHKERRQ(ierr);
72 ierr = DMGlobalToLocalEnd(user->fda2, user->K_Omega_o, INSERT_VALUES, user->lK_Omega_o); CHKERRQ(ierr);
73 }
74
75 PetscFunctionReturn(0);
76}
77
78#undef __FUNCT__
79#define __FUNCT__ "PerformInitialSetup"
80/**
81 * @brief Finalizes the simulation setup at t=0, ensuring a consistent state before time marching.
82 *
83 * This function is called from main() after the initial Eulerian and Lagrangian states have been
84 * created but before the main time loop begins. Its responsibilities are:
85 *
86 * 1. Settling the particle swarm: Migrates particles to their correct owner ranks and finds their
87 * initial host cells. This includes handling special surface initializations.
88 * 2. Coupling the fields: Interpolates the initial Eulerian fields to the settled particle locations.
89 * 3. Preparing for the first step: Scatters particle data back to the grid.
90 * 4. Writing the initial output for step 0.
91 *
92 * @param simCtx Pointer to the main simulation context structure.
93 * @return PetscErrorCode 0 on success, non-zero on failure.
94 */
96{
97 PetscErrorCode ierr;
98 // --- Get pointers from SimCtx instead of passing them as arguments ---
99 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels-1].user;
100 BoundingBox *bboxlist = simCtx->bboxlist;
101
102 PetscFunctionBeginUser;
103
104 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Performing initial particle setup procedures.\n", simCtx->ti, simCtx->step);
105
106 // --- 0. Loop over all blocks to compute Eulerian diffusivity.
107 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
108 ierr = ComputeEulerianDiffusivity(&user[bi]); CHKERRQ(ierr);
109 ierr = ComputeEulerianDiffusivityGradient(&user[bi]); CHKERRQ(ierr);
110 }
111
112 // --- 1. Initial Particle Settlement (Location and Migration) ---
113 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Initial Settlement: Locating and migrating all particles...\n", simCtx->ti, simCtx->step);
114 ierr = LocateAllParticlesInGrid(user, bboxlist); CHKERRQ(ierr);
115
117 LOG_ALLOW(GLOBAL, LOG_DEBUG, "[T=%.4f, Step=%d] Particle field states after Initial settlement...\n", simCtx->ti, simCtx->step);
118 ierr = LOG_PARTICLE_FIELDS(user,simCtx->LoggingFrequency); CHKERRQ(ierr);
119 }
120
121 // --- 2. Re-initialize Particles on Inlet Surface (if applicable) ---
124 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Re-initializing particles on inlet surface...\n", simCtx->ti, simCtx->step);
125 ierr = ReinitializeParticlesOnInletSurface(user, simCtx->ti, simCtx->step); CHKERRQ(ierr);
126
127 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Resetting statuses for post-reinitialization settlement.\n", simCtx->ti, simCtx->step);
128 ierr = ResetAllParticleStatuses(user); CHKERRQ(ierr);
129
130 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Post-Reinitialization Settlement...\n", simCtx->ti, simCtx->step);
131 ierr = LocateAllParticlesInGrid(user, bboxlist); CHKERRQ(ierr);
132
133 }
134
135 // --- 3. Finalize State for t=0 ---
136 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Interpolating initial fields to settled particles.\n", simCtx->ti, simCtx->step);
137 ierr = InterpolateAllFieldsToSwarm(user); CHKERRQ(ierr);
138 //ierr = ScatterAllParticleFieldsToEulerFields(user); CHKERRQ(ierr);
139
140 // --- 4. Initial History and Output ---
141 // Update solver history vectors with the t=0 state before the first real step
142 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
143 ierr = UpdateSolverHistoryVectors(&user[bi]); CHKERRQ(ierr);
144 }
145
146 if (simCtx->OutputFreq > 0 || (simCtx->StepsToRun == 0 && simCtx->StartStep == 0)) {
147 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Writing initial simulation data.\n", simCtx->ti, simCtx->step);
148
149 // --- Particle Output (assumes functions operate on the master user context) ---
150 if(get_log_level() == LOG_DEBUG){
151 LOG(GLOBAL, LOG_DEBUG, "[T=%.4f, Step=%d] Initial Particle field.\n", simCtx->ti, simCtx->step);
152 ierr = LOG_PARTICLE_FIELDS(user,simCtx->LoggingFrequency); CHKERRQ(ierr);
153 }
154 ierr = WriteAllSwarmFields(user); CHKERRQ(ierr);
155
156 // --- Eulerian Field Output (MUST loop over all blocks) --- // <<< CHANGED/FIXED
157 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
158 ierr = WriteSimulationFields(&user[bi]); CHKERRQ(ierr);
159 }
160 }
161
162 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Initial setup complete. Ready for time marching. ---\n");
163 PetscFunctionReturn(0);
164}
165
166#undef __FUNCT__
167#define __FUNCT__ "PerformLoadedParticleSetup"
168/**
169 * @brief Finalizes the simulation state after particle and fluid data have been loaded from a restart.
170 *
171 * This helper function performs the critical sequence of operations required to ensure
172 * the loaded Lagrangian and Eulerian states are fully consistent and the solver is
173 * ready to proceed. This includes:
174 * 1. Verifying particle locations in the grid and building runtime links.
175 * 2. Synchronizing particle velocity with the authoritative grid velocity via interpolation.
176 * 3. Scattering particle source terms (e.g., volume fraction) back to the grid.
177 * 4. Updating the solver's history vectors with the final, fully-coupled state.
178 * 5. Writing the complete, consistent state to output files for the restart step.
179 *
180 * @param simCtx The main simulation context.
181 * @return PetscErrorCode 0 on success.
182 */
183PetscErrorCode PerformLoadedParticleSetup(SimCtx *simCtx)
184{
185 PetscErrorCode ierr;
186 PetscFunctionBeginUser;
187 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels-1].user;
188
189 // --- 0. Re-compute Eulerian Diffusivity from loaded fields.
190 LOG_ALLOW(GLOBAL, LOG_INFO, "Re-computing Eulerian Diffusivity from loaded fields...\n");
191 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
192 ierr = ComputeEulerianDiffusivity(&user[bi]); CHKERRQ(ierr);
193 ierr = ComputeEulerianDiffusivityGradient(&user[bi]); CHKERRQ(ierr);
194 }
195
196 // 0.1 This moves particles to their correct ranks immediately using the loaded Cell ID.
197 LOG_ALLOW(GLOBAL, LOG_INFO, "Performing fast restart migration using preloaded Cell IDs...\n");
198 ierr = MigrateRestartParticlesUsingCellID(user); CHKERRQ(ierr);
199
200 // 1. To catch any edge cases (particles with invalid CellIDs or newcomers).
201 // Because we kept the statuses, this function will now SKIP all the particles
202 // that are already on the correct rank,
203 ierr = LocateAllParticlesInGrid(user, simCtx->bboxlist); CHKERRQ(ierr);
204
205 if(get_log_level() == LOG_DEBUG){
206 LOG(GLOBAL, LOG_DEBUG, "[T=%.4f, Step=%d] Particle field states after locating loaded particles...\n", simCtx->ti, simCtx->step);
207 ierr = LOG_PARTICLE_FIELDS(user,simCtx->LoggingFrequency); CHKERRQ(ierr);
208 }
209
210 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Interpolating initial fields to settled particles.\n", simCtx->ti, simCtx->step);
211
212 // 2. Ensure particles have velocity from the authoritative loaded grid for consistency.
213 ierr = InterpolateAllFieldsToSwarm(user); CHKERRQ(ierr);
214
215 // 3. Update Eulerian source terms from the loaded particle data.
216 ierr = ScatterAllParticleFieldsToEulerFields(user); CHKERRQ(ierr);
217
218 // --- 4. Initial History and Output ---
219 // Update solver history vectors with the t=0 state before the first real step
220 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
221 ierr = UpdateSolverHistoryVectors(&user[bi]); CHKERRQ(ierr);
222 }
223
224 if (simCtx->OutputFreq > 0 || (simCtx->StepsToRun == 0 && simCtx->StartStep == 0)) {
225 LOG_ALLOW(GLOBAL, LOG_INFO, "[T=%.4f, Step=%d] Writing initial simulation data.\n", simCtx->ti, simCtx->step);
226
227 // --- Particle Output (assumes functions operate on the master user context) ---
228 if(get_log_level() >=LOG_INFO) ierr = LOG_PARTICLE_FIELDS(user, simCtx->LoggingFrequency); CHKERRQ(ierr);
229 ierr = WriteAllSwarmFields(user); CHKERRQ(ierr);
230
231 // --- Eulerian Field Output (MUST loop over all blocks) --- // <<< CHANGED/FIXED
232 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
233 ierr = WriteSimulationFields(&user[bi]); CHKERRQ(ierr);
234 }
235 }
236
237 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Initial setup complete. Ready for time marching. ---\n");
238 PetscFunctionReturn(0);
239}
240
241#undef __FUNCT__
242#define __FUNCT__ "FinalizeRestartState"
243/**
244 * @brief Performs post-load/post-init consistency checks for a restarted simulation.
245 *
246 * This function is called from main() ONLY when a restart is being performed
247 * (i.e., StartStep > 0). It inspects the particle restart mode to determine the
248 * correct finalization procedure for the Lagrangian swarm.
249 *
250 * - If particles were loaded from a file (`mode == "load"`), it verifies their
251 * locations within the grid to establish necessary runtime links.
252 * - If new particles were initialized into the restarted flow (`mode == "init"`),
253 * it runs the full `PerformInitialSetup` sequence to migrate, locate, and
254 * couple the new particles with the existing fluid state.
255 *
256 * @param simCtx The main simulation context.
257 * @return PetscErrorCode 0 on success.
258 */
259PetscErrorCode FinalizeRestartState(SimCtx *simCtx)
260{
261 PetscErrorCode ierr;
262 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
263
264 PetscFunctionBeginUser;
265
266 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Finalizing RESTART from state (step=%d, t=%.4f) ---\n", simCtx->StartStep, simCtx->ti);
267
268 // This function only needs to handle the particle finalization logic.
269 // The Eulerian state is assumed to be fully loaded and consistent at this point.
270 if (simCtx->np > 0) {
271
272 // Use the particle restart mode to decide the workflow.
273 if (strcmp(simCtx->particleRestartMode, "load") == 0) {
274 // PARTICLES WERE LOADED: The state is complete, but we must verify
275 // the loaded CellIDs and build the in-memory grid-to-particle links.
276 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Mode 'load': Verifying particle locations and building grid links...\n");
277 ierr = PerformLoadedParticleSetup(simCtx); CHKERRQ(ierr);
278
279 } else { // Mode must be "init"
280 // PARTICLES WERE RE-INITIALIZED: They need to be fully settled and coupled
281 // to the surrounding (restarted) fluid state.
282 LOG_ALLOW(GLOBAL, LOG_INFO, "Particle Mode 'init': Running full initial setup for new particles in restarted flow.\n");
283 ierr = PerformInitializedParticleSetup(simCtx); CHKERRQ(ierr);
284 }
285 } else {
286 LOG_ALLOW(GLOBAL, LOG_INFO, "No particles in simulation, restart finalization is complete.\n");
287
288 // Write the initial eulerian fields (this is done in PerformInitialSetup if particles exist.)
289 for(PetscInt bi = 0; bi < simCtx->block_number; bi ++){
290 ierr = WriteSimulationFields(&user[bi]); CHKERRQ(ierr);
291 }
292 }
293
294 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Restart state successfully finalized. --\n");
295
296 PetscFunctionReturn(0);
297}
298
299#undef __FUNCT__
300#define __FUNCT__ "AdvanceSimulation"
301/**
302 * @brief Executes the main time-marching loop for the coupled Euler-Lagrange simulation.
303 *
304 * This function orchestrates the advancement of the simulation from the configured
305 * StartStep to the final step. It does NOT perform the initial t=0 setup, as that
306 * is handled by InitializeEulerianState and PerformInitialSetup in main().
307 *
308 * For each timestep, it performs the following sequence:
309 * 1. **Pre-Solver Actions:** Updates time-dependent boundary conditions (e.g., fluxin)
310 * and resets particle states for the new step.
311 * 2. **Eulerian Solve:** Calls the refactored legacy FlowSolver to advance the
312 * entire fluid field by one time step.
313 * 3. **Lagrangian Update:** Executes the full particle workflow: advection based
314 * on the previous step's velocity, followed by settling (location/migration)
315 * in the new grid, and finally interpolation of the new fluid velocity.
316 * 4. **Two-Way Coupling:** Scatters particle data back to the grid to act as source
317 * terms for the subsequent time step.
318 * 5. **History & I/O:** Updates the solver's history vectors and writes output files
319 * at the specified frequency.
320 *
321 * @param user Array of UserCtx structures for the finest grid level.
322 * @return PetscErrorCode 0 on success, non-zero on failure.
323 */
324PetscErrorCode AdvanceSimulation(SimCtx *simCtx)
325{
326 PetscErrorCode ierr;
327 // Get the master context from the first block. All blocks share it.
328 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels-1].user;
329
330 // Retrieve control parameters from SimCtx for clarity
331 const PetscInt StartStep = simCtx->StartStep;
332 const PetscInt StepsToRun = simCtx->StepsToRun;
333 const PetscInt OutputFreq = simCtx->OutputFreq;
334 const PetscReal dt = simCtx->dt;
335
336 // Variables for particle removal statistics
337 //PetscInt removed_local_ob, removed_global_ob;
338 PetscInt removed_local_lost, removed_global_lost;
339
340 PetscFunctionBeginUser;
342 LOG_ALLOW(GLOBAL, LOG_INFO, "Starting main time-marching loop: %d steps from step %d (t=%.4f), dt=%.4f\n",
343 StepsToRun, StartStep, simCtx->StartTime, dt);
344
345 // --- Main Time-Marching Loop ---
346 for (PetscInt step = StartStep; step < StartStep + StepsToRun; step++) {
347
348 // =================================================================
349 // 1. PRE-STEP SETUP
350 // =================================================================
351
352 // Update simulation time and step counters in the master context
353 simCtx->step = step + 1;
354 simCtx->ti += simCtx->dt; //simCtx->StartTime + step * simCtx->dt;
355
356 LOG_ALLOW(GLOBAL, LOG_INFO, "--- Advancing Step %d (To t=%.4f) ---\n", simCtx->step, simCtx->ti);
357
358
359 // For particles, reset their status to prepare for the new advection/location cycle
360 if (simCtx->np > 0) {
361 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Resetting all particle statuses to NEEDS_LOCATION.\n");
362 ierr = ResetAllParticleStatuses(user); CHKERRQ(ierr);
363 }
364
365 // =================================================================
366 // 2. EULERIAN SOLVER STEP
367 // =================================================================
369 ierr = LOG_FIELD_ANATOMY(&user[0],"Coordinates","PreFlowSolver"); CHKERRQ(ierr);
370 ierr = LOG_FIELD_ANATOMY(&user[0],"Csi","PreFlowSolver"); CHKERRQ(ierr);
371 ierr = LOG_FIELD_ANATOMY(&user[0],"Eta","PreFlowSolver"); CHKERRQ(ierr);
372 ierr = LOG_FIELD_ANATOMY(&user[0],"Zet","PreFlowSolver"); CHKERRQ(ierr);
373 ierr = LOG_FIELD_ANATOMY(&user[0],"Center-Coordinates","PreFlowSolver"); CHKERRQ(ierr);
374 ierr = LOG_FIELD_ANATOMY(&user[0],"X-Face-Centers","PreFlowSolver"); CHKERRQ(ierr);
375 ierr = LOG_FIELD_ANATOMY(&user[0],"Y-Face-Centers","PreFlowSolver"); CHKERRQ(ierr);
376 ierr = LOG_FIELD_ANATOMY(&user[0],"Z-Face-Centers","PreFlowSolver"); CHKERRQ(ierr);
377 ierr = LOG_FIELD_ANATOMY(&user[0],"Ucat","PreFlowSolver"); CHKERRQ(ierr);
378 }
379 LOG_ALLOW(GLOBAL, LOG_INFO, "Updating Eulerian Field ...\n");
380 if(strcmp(simCtx->eulerianSource,"load")==0){
381 //LOAD mode: Read pre-computed fields for the current step.
382 LOG_ALLOW(GLOBAL,LOG_INFO,"Eulerian Source 'load': Reading fields (t=%.4f,step=%d)...\n",simCtx->ti,simCtx->step);
383 for(PetscInt bi = 0; bi < simCtx->block_number;bi++){
384 ierr = ReadSimulationFields(&user[bi],simCtx->step); CHKERRQ(ierr);
385 }
386 }else if(strcmp(simCtx->eulerianSource,"analytical")==0){
387 // ANALYTICAL mode:Call the Analytical Solution Prescription Engine to enable a variety of analytical functions
388 LOG_ALLOW(GLOBAL,LOG_INFO,"Eulerian Source 'analytical'. Updating Eulerian field via the Analytical Solution Engine ...\n");
389 ierr = AnalyticalSolutionEngine(simCtx); CHKERRQ(ierr);
390 }else if(strcmp(simCtx->eulerianSource,"solve")==0){
391 // SOLVE mode:Call the refactored, high-level legacy solver. This single function
392 // advances the entire multi-block fluid field from t_n to t_{n+1}.
393 LOG_ALLOW(GLOBAL,LOG_INFO,"Eulerian Source 'solve'. Updating Eulerian field via Solver...\n");
394 ierr = FlowSolver(simCtx); CHKERRQ(ierr);
395 }
396 LOG_ALLOW(GLOBAL, LOG_INFO, "Eulerian Field Updated ...\n");
398 LOG_ALLOW(GLOBAL, LOG_VERBOSE, "Post FlowSolver field states:\n");
399 ierr = LOG_FIELD_ANATOMY(&user[0],"Ucat","PostFlowSolver"); CHKERRQ(ierr);
400 ierr = LOG_FIELD_ANATOMY(&user[0],"P","PostFlowSolver"); CHKERRQ(ierr);
401 ierr = LOG_FIELD_ANATOMY(&user[0],"Ucont","PostFlowSolver"); CHKERRQ(ierr);
402 }
403
404
405 // =================================================================
406 // 3. LAGRANGIAN PARTICLE STEP
407 // =================================================================
408
409 if (simCtx->np > 0) {
410 LOG_ALLOW(GLOBAL, LOG_INFO, "Updating Lagrangian particle system...\n");
411
412 // a. Update Eulerian Transport Properties:
413 // Optimization: Only recalculate if turbulence is active (Nu_t changes).
414 // For Laminar flow, the value calculated at Setup is constant.
415 if (simCtx->les || simCtx->rans) {
416 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
417 ierr = ComputeEulerianDiffusivity(&user[bi]); CHKERRQ(ierr);
418 ierr = ComputeEulerianDiffusivityGradient(&user[bi]); CHKERRQ(ierr);
419 }
420 }
421
422 // a.1 (Optional) Log Eulerian Diffusivity min/max and anatomy for debugging.
424 LOG_ALLOW(GLOBAL, LOG_VERBOSE, "Updated Diffusivity Min/Max:\n");
425 ierr = LOG_FIELD_MIN_MAX(&user[0],"Diffusivity"); CHKERRQ(ierr);
426 ierr = LOG_FIELD_MIN_MAX(&user[0],"DiffusivityGradient"); CHKERRQ(ierr);
427 //LOG_ALLOW(GLOBAL, LOG_VERBOSE, "Updated Diffusivity Anatomy:\n");
428 ierr = LOG_FIELD_ANATOMY(&user[0],"Diffusivity","PostDiffusivityUpdate"); CHKERRQ(ierr);
429 }
430 // b. Advect particles using the velocity interpolated from the *previous* step.
431 // P(t_{n+1}) = P(t_n) + V_p(t_n) * dt
432 ierr = UpdateAllParticlePositions(user); CHKERRQ(ierr);
433
434 // c. Settle all particles: find their new host cells and migrate them across ranks.
435 ierr = LocateAllParticlesInGrid(user, simCtx->bboxlist); CHKERRQ(ierr);
436
437 // d. Remove any particles that are now lost or out of the global domain.
438 ierr = CheckAndRemoveLostParticles(user, &removed_local_lost, &removed_global_lost); CHKERRQ(ierr);
439 //ierr = CheckAndRemoveOutOfBoundsParticles(user, &removed_local_ob, &removed_global_ob, simCtx->bboxlist); CHKERRQ(ierr);
440 if (removed_global_lost> 0) { // if(removed_global_lost + removed_global_ob > 0){
441 LOG_ALLOW(GLOBAL, LOG_INFO, "Removed %d particles globally this step.\n", removed_global_lost); // removed_global_lost + removed_global_ob;
442 simCtx->particlesLostLastStep = removed_global_lost;
443 }
444
445 // e. Interpolate the NEW fluid velocity (just computed by FlowSolver) onto the
446 // particles' new positions. This gives them V_p(t_{n+1}) for the *next* advection step.
447 ierr = InterpolateAllFieldsToSwarm(user); CHKERRQ(ierr);
448
449 // f. Update the Particle Fields (e.g., temperature, concentration) if applicable.
450 // This can be extended to include reactions, growth, etc.
451 ierr = UpdateAllParticleFields(user); CHKERRQ(ierr);
452
453 // g. (For Two-Way Coupling) Scatter particle data back to the grid to act as a source term.
454 ierr = CalculateParticleCountPerCell(user); CHKERRQ(ierr);
455 ierr = ScatterAllParticleFieldsToEulerFields(user); CHKERRQ(ierr);
456
457 // h. (Optional) Calculate advanced particle metrics for logging/debugging.
458 ierr = CalculateAdvancedParticleMetrics(user); CHKERRQ(ierr);
459
460 ierr = LOG_PARTICLE_METRICS(user, "Timestep Metrics"); CHKERRQ(ierr);
461
462
464 LOG_ALLOW(GLOBAL, LOG_VERBOSE, "Post Lagrangian update field states:\n");
465 ierr = LOG_FIELD_MIN_MAX(&user[0],"Psi"); CHKERRQ(ierr);
466 }
467 }
468
469 // =================================================================
470 // 4. UPDATE HISTORY & I/O
471 // =================================================================
472
473 // Copy the newly computed fields (Ucont, P, etc.) to the history vectors
474 // (_o, _rm1) to prepare for the next time step.
475 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
476 ierr = UpdateSolverHistoryVectors(&user[bi]); CHKERRQ(ierr);
477 }
478
479 //ierr = LOG_UCAT_ANATOMY(&user[0],"Final"); CHKERRQ(ierr);
480
481 // Handle periodic file output
482 if (OutputFreq > 0 && (step + 1) % OutputFreq == 0) {
483 LOG_ALLOW(GLOBAL, LOG_INFO, "Writing output for step %d.\n",simCtx->step);
484 for (PetscInt bi = 0; bi < simCtx->block_number; bi++) {
485 ierr = WriteSimulationFields(&user[bi]); CHKERRQ(ierr);
486 }
487 if (simCtx->np > 0) {
488 ierr = WriteAllSwarmFields(user); CHKERRQ(ierr);
489 if(get_log_level() >= LOG_INFO){
490 LOG(GLOBAL, LOG_INFO, "Particle states at step %d:\n", simCtx->step);
492 if(strcmp(simCtx->eulerianSource,"analytical") == 0){
494 }
495 }
496 }
497 }
498
500
501 // Update Progress Bar
502 if(simCtx->rank == 0) {
503 PrintProgressBar(step,StartStep,StepsToRun,simCtx->ti);
504 if(get_log_level()>=LOG_WARNING) PetscPrintf(PETSC_COMM_SELF,"\n");
505 }
506 } // --- End of Time-Marching Loop ---
507
508 // After the loop, print the 100% complete bar on rank 0 and add a newline
509 // to ensure subsequent terminal output starts on a fresh line.
510 if (simCtx->rank == 0 && StepsToRun > 0) {
511 PrintProgressBar(StartStep + StepsToRun - 1, StartStep, StepsToRun, simCtx->ti);
512 PetscPrintf(PETSC_COMM_SELF, "\n");
513 fflush(stdout);
514 }
515
516 LOG_ALLOW(GLOBAL, LOG_INFO, "Time marching completed. Final time t=%.4f.\n", simCtx->ti);
518 PetscFunctionReturn(0);
519}
PetscErrorCode AnalyticalSolutionEngine(SimCtx *simCtx)
Dispatches to the appropriate analytical solution function based on simulation settings.
PetscErrorCode MigrateRestartParticlesUsingCellID(UserCtx *user)
Fast-path migration for restart particles using preloaded Cell IDs.
PetscErrorCode UpdateAllParticlePositions(UserCtx *user)
Loops over all local particles in the DMSwarm, updating their positions based on velocity and the glo...
PetscErrorCode LocateAllParticlesInGrid(UserCtx *user, BoundingBox *bboxlist)
Orchestrates the complete particle location and migration process for one timestep.
PetscErrorCode ResetAllParticleStatuses(UserCtx *user)
This function is designed to be called at the end of a full timestep, after all particle-based calcul...
PetscErrorCode ReinitializeParticlesOnInletSurface(UserCtx *user, PetscReal currentTime, PetscInt step)
Re-initializes the positions of particles currently on this rank if this rank owns part of the design...
PetscErrorCode CheckAndRemoveLostParticles(UserCtx *user, PetscInt *removedCountLocal, PetscInt *removedCountGlobal)
Removes particles that have been definitively flagged as LOST by the location algorithm.
PetscErrorCode UpdateAllParticleFields(UserCtx *user)
Orchestrates the update of all physical properties for particles.
PetscErrorCode CalculateParticleCountPerCell(UserCtx *user)
Counts particles in each cell of the DMDA 'da' and stores the result in user->ParticleCount.
PetscErrorCode ScatterAllParticleFieldsToEulerFields(UserCtx *user)
Scatters a predefined set of particle fields to their corresponding Eulerian fields.
PetscErrorCode InterpolateAllFieldsToSwarm(UserCtx *user)
Interpolates all relevant fields from the DMDA to the DMSwarm.
PetscErrorCode WriteAllSwarmFields(UserCtx *user)
Writes a predefined set of PETSc Swarm fields to files.
Definition io.c:2061
PetscErrorCode ReadSimulationFields(UserCtx *user, PetscInt ti)
Reads binary field data for velocity, pressure, and other required vectors.
Definition io.c:1231
PetscErrorCode WriteSimulationFields(UserCtx *user)
Writes simulation fields to files.
Definition io.c:1761
PetscErrorCode LOG_PARTICLE_METRICS(UserCtx *user, const char *stageName)
Logs particle swarm metrics, adapting its behavior based on a boolean flag in SimCtx.
Definition logging.c:1851
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:157
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
PetscErrorCode LOG_INTERPOLATION_ERROR(UserCtx *user)
Logs the interpolation error between the analytical and computed solutions.
Definition logging.c:1727
#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
PetscErrorCode LOG_FIELD_MIN_MAX(UserCtx *user, const char *fieldName)
Computes and logs the local and global min/max values of a 3-component vector field.
Definition logging.c:1293
void PrintProgressBar(PetscInt step, PetscInt startStep, PetscInt totalSteps, PetscReal currentTime)
Prints a progress bar to the console.
Definition logging.c:1227
PetscErrorCode LOG_FIELD_ANATOMY(UserCtx *user, const char *field_name, const char *stage_name)
Logs the anatomy of a specified field at key boundary locations, respecting the solver's specific gri...
Definition logging.c:1460
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:39
PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx *user, PetscInt printInterval)
Prints particle fields in a table that automatically adjusts its column widths.
Definition logging.c:400
PetscErrorCode CalculateAdvancedParticleMetrics(UserCtx *user)
Computes advanced particle statistics and stores them in SimCtx.
Definition logging.c:1790
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:34
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
Definition logging.h:737
PetscErrorCode ProfilingLogTimestepSummary(PetscInt step)
Logs the performance summary for the current timestep and resets timers.
Definition logging.c:1064
PetscErrorCode ComputeEulerianDiffusivityGradient(UserCtx *user)
Computes the gradient of the scalar Diffusivity field (Drift Vector).
Definition rhs.c:2115
PetscErrorCode ComputeEulerianDiffusivity(UserCtx *user)
Computes the effective diffusivity scalar field ($\Gamma_{eff}$) on the Eulerian grid.
Definition rhs.c:1985
PetscErrorCode AdvanceSimulation(SimCtx *simCtx)
Executes the main time-marching loop for the coupled Euler-Lagrange simulation.
Definition simulation.c:324
PetscErrorCode UpdateSolverHistoryVectors(UserCtx *user)
Copies the current time step's solution fields into history vectors (e.g., U(t_n) -> U_o,...
Definition simulation.c:23
PetscErrorCode FinalizeRestartState(SimCtx *simCtx)
Performs post-load/post-init consistency checks for a restarted simulation.
Definition simulation.c:259
PetscErrorCode PerformInitializedParticleSetup(SimCtx *simCtx)
Finalizes the simulation setup at t=0, ensuring a consistent state before time marching.
Definition simulation.c:95
PetscErrorCode PerformLoadedParticleSetup(SimCtx *simCtx)
Finalizes the simulation state after particle and fluid data have been loaded from a restart.
Definition simulation.c:183
#define __FUNCT__
Definition simulation.c:79
PetscErrorCode FlowSolver(SimCtx *simCtx)
Orchestrates a single time step of the Eulerian fluid solver.
Definition solvers.c:26
UserCtx * user
Definition variables.h:474
PetscBool inletFaceDefined
Definition variables.h:747
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
PetscInt rans
Definition variables.h:669
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:466
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
Definition variables.h:469
PetscReal StartTime
Definition variables.h:598
Vec K_Omega_o
Definition variables.h:783
PetscInt particlesLostLastStep
Definition variables.h:682
UserMG usermg
Definition variables.h:698
Vec K_Omega
Definition variables.h:783
Vec lUcont_rm1
Definition variables.h:763
PetscInt _this
Definition variables.h:741
PetscReal dt
Definition variables.h:599
PetscInt StepsToRun
Definition variables.h:596
PetscInt np
Definition variables.h:676
Vec Ucont
Definition variables.h:755
PetscInt StartStep
Definition variables.h:595
Vec lUcont_o
Definition variables.h:762
Vec Ucat_o
Definition variables.h:762
char particleRestartMode[16]
Definition variables.h:681
BoundingBox * bboxlist
Definition variables.h:679
char eulerianSource[PETSC_MAX_PATH_LEN]
Definition variables.h:604
ParticleInitializationType ParticleInitialization
Definition variables.h:680
PetscInt OutputFreq
Definition variables.h:602
Vec lK_Omega_o
Definition variables.h:783
Vec Ucat
Definition variables.h:755
Vec Ucont_o
Definition variables.h:762
PetscInt mglevels
Definition variables.h:481
Vec Nvert_o
Definition variables.h:762
Vec Ucont_rm1
Definition variables.h:763
PetscInt step
Definition variables.h:593
PetscInt les
Definition variables.h:669
Vec Nvert
Definition variables.h:755
MGCtx * mgctx
Definition variables.h:484
Vec lNvert_o
Definition variables.h:762
PetscReal ti
Definition variables.h:594
PetscInt immersed
Definition variables.h:614
PetscInt LoggingFrequency
Definition variables.h:703
Vec P_o
Definition variables.h:762
Defines a 3D axis-aligned bounding box.
Definition variables.h:154
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