PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
logging.c
Go to the documentation of this file.
1// logging.c
2#include "logging.h"
3
4/* Maximum temporary buffer size for converting numbers to strings */
5#define TMP_BUF_SIZE 128
6
7// --------------------- Static Variable for Log Level ---------------------
8
9/**
10 * @brief Static variable to cache the current logging level.
11 *
12 * Initialized to -1 to indicate that the log level has not been set yet.
13 */
15
16// --------------------- Static Variables for Allow-List -------------------
17
18/**
19 * @brief Global/static array of function names allowed to log.
20 */
21static char** gAllowedFunctions = NULL;
22
23/**
24 * @brief Number of entries in the gAllowedFunctions array.
25 */
26static int gNumAllowed = 0;
27
28
29
30
31//----------------------------- Logging Events definition (PetscLog) ---------------------
32
33PetscLogEvent EVENT_Individualwalkingsearch = 0 ; //Individual walking search in (walkingsearch.c/LocateParticleInGrid()
34PetscLogEvent EVENT_walkingsearch = 0 ; // Total walking search in (ParticleSwarm.c/LocateAllParticlesInGrid()
35PetscLogEvent EVENT_GlobalParticleLocation = 0; // Global Particle Location routine (Search + Hand-Off)
36PetscLogEvent EVENT_IndividualLocation = 0;
37
38// --------------------- Function Implementations ---------------------
39
40/**
41 * @brief Retrieves the current logging level from the environment variable `LOG_LEVEL`.
42 *
43 * The function checks the `LOG_LEVEL` environment variable and sets the logging level accordingly.
44 * Supported levels are "DEBUG", "INFO", "WARNING", and defaults to "ERROR" if not set or unrecognized.
45 * The log level is cached after the first call to avoid repeated environment variable checks.
46 *
47 * @return LogLevel The current logging level.
48 */
50 if (current_log_level == -1) { // Log level not set yet
51 const char *env = getenv("LOG_LEVEL");
52 if (!env) {
53 current_log_level = LOG_ERROR; // Default level
54 }
55 else if (strcmp(env, "DEBUG") == 0) {
57 }
58 else if (strcmp(env, "INFO") == 0) {
60 }
61 else if (strcmp(env, "WARNING") == 0) {
63 }
64 else if (strcmp(env, "PROFILE") == 0) { // <-- New profile level
66 }
67 else {
68 current_log_level = LOG_ERROR; // Default if unrecognized
69 }
70 }
71 return current_log_level;
72}
73
74/**
75 * @brief Prints the current logging level to the console.
76 *
77 * This function retrieves the log level using `get_log_level()` and prints
78 * the corresponding log level name. It helps verify the logging configuration
79 * at runtime.
80 *
81 * @note The log level is determined from the `LOG_LEVEL` environment variable.
82 * If `LOG_LEVEL` is not set, it defaults to `LOG_INFO`.
83 *
84 * @see get_log_level()
85 */
86PetscErrorCode print_log_level(void)
87{
88 PetscMPIInt rank;
89 PetscErrorCode ierr;
90 int level;
91 const char *level_name;
92
93 PetscFunctionBeginUser;
94 /* get MPI rank */
95 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRMPI(ierr);
96
97 /* decide level name */
98 level = get_log_level();
99 level_name = (level == LOG_ERROR) ? "ERROR" :
100 (level == LOG_WARNING) ? "WARNING" :
101 (level == LOG_INFO) ? "INFO" :
102 (level == LOG_DEBUG) ? "DEBUG" :
103 (level == LOG_PROFILE) ? "PROFILE" : "UNKNOWN";
104
105 /* print it out */
106 ierr = PetscPrintf(PETSC_COMM_SELF,
107 "Current log level: %s (%d) | rank: %d\n",
108 level_name, level, (int)rank);
109 CHKERRMPI(ierr);
110
111 PetscFunctionReturn(PETSC_SUCCESS);
112}
113
114/**
115 * @brief Sets the global list of function names that are allowed to log.
116 *
117 * @param functionList An array of function name strings (e.g., {"foo", "bar"}).
118 * @param count The number of entries in the array.
119 *
120 * The existing allow-list is cleared and replaced by the new one.
121 * If you pass an empty list (count = 0), then no function will be allowed
122 * unless you change it later.
123 */
124void set_allowed_functions(const char** functionList, int count)
125{
126 // 1. Free any existing entries
127 if (gAllowedFunctions) {
128 for (int i = 0; i < gNumAllowed; ++i) {
129 free(gAllowedFunctions[i]); // each was strdup'ed
130 }
131 free(gAllowedFunctions);
132 gAllowedFunctions = NULL;
133 gNumAllowed = 0;
134 }
135
136 // 2. Allocate new array
137 if (count > 0) {
138 gAllowedFunctions = (char**)malloc(sizeof(char*) * count);
139 }
140
141 // 3. Copy the new entries
142 for (int i = 0; i < count; ++i) {
143 // strdup is a POSIX function. If not available, implement your own string copy.
144 gAllowedFunctions[i] = strdup(functionList[i]);
145 }
146 gNumAllowed = count;
147}
148
149/**
150 * @brief Checks if the given function name is in the allow-list.
151 *
152 * @param functionName The name of the function to check.
153 * @return PETSC_TRUE if functionName is allowed, otherwise PETSC_FALSE.
154 *
155 * If no functions are in the list, nothing is allowed by default.
156 * You can reverse this logic if you prefer to allow everything
157 * unless specified otherwise.
158 */
159PetscBool is_function_allowed(const char* functionName)
160{
161 /* no list β‡’ allow all */
162 if (gNumAllowed == 0) {
163 return PETSC_TRUE;
164 }
165
166 /* otherwise only the listed functions are allowed */
167 for (int i = 0; i < gNumAllowed; ++i) {
168 if (strcmp(gAllowedFunctions[i], functionName) == 0) {
169 return PETSC_TRUE;
170 }
171 }
172 return PETSC_FALSE;
173}
174
175/**
176 * @brief Prints the coordinates of a cell's vertices.
177 *
178 * This function iterates through the eight vertices of a given cell and prints their
179 * coordinates. It is primarily used for debugging purposes to verify the correctness
180 * of cell vertex assignments.
181 *
182 * @param[in] cell Pointer to a `Cell` structure representing the cell, containing its vertices.
183 * @param[in] rank MPI rank for identification (useful in parallel environments).
184 * @return PetscErrorCode Returns 0 to indicate successful execution. Non-zero on failure.
185 *
186 * @note
187 * - Ensure that the `cell` pointer is not `NULL` before calling this function..
188 */
189PetscErrorCode LOG_CELL_VERTICES(const Cell *cell, PetscMPIInt rank)
190{
191
192 // Validate input pointers
193 if (cell == NULL) {
194 LOG_ALLOW(LOCAL,LOG_ERROR, "LOG_CELL_VERTICES - 'cell' is NULL.\n");
195 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "LOG_CELL_VERTICES - Input parameter 'cell' is NULL.");
196 }
197
198 LOG_ALLOW(LOCAL,LOG_DEBUG, "LOG_CELL_VERTICES - Rank %d, Cell Vertices:\n", rank);
199 for(int i = 0; i < 8; i++){
200 LOG_ALLOW(LOCAL,LOG_DEBUG, " Vertex[%d]: (%.2f, %.2f, %.2f)\n",
201 i, cell->vertices[i].x, cell->vertices[i].y, cell->vertices[i].z);
202 }
203
204 return 0; // Indicate successful execution
205}
206
207
208/**
209 * @brief Prints the signed distances to each face of the cell.
210 *
211 * This function iterates through the six signed distances from a point to each face of a given cell
212 * and prints their values. It is primarily used for debugging purposes to verify the correctness
213 * of distance calculations.
214 *
215 * @param[in] d An array of six `PetscReal` values representing the signed distances.
216 * The indices correspond to:
217 * - d[LEFT]: Left Face
218 * - d[RIGHT]: Right Face
219 * - d[BOTTOM]: Bottom Face
220 * - d[TOP]: Top Face
221 * - d[FRONT]: Front Face
222 * - d[BACK]: Back Face
223 *
224 * @return PetscErrorCode Returns 0 to indicate successful execution. Non-zero on failure.
225 *
226 * @note
227 * - Ensure that the `d` array is correctly populated with signed distances before calling this function.
228 */
229PetscErrorCode LOG_FACE_DISTANCES(PetscReal* d)
230{
231
232 // Validate input array
233 if (d == NULL) {
234 LOG_ALLOW(LOCAL,LOG_ERROR, " LOG_FACE_DISTANCES - 'd' is NULL.\n");
235 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, " LOG_FACE_DISTANCES - Input array 'd' is NULL.");
236 }
237
238 PetscPrintf(PETSC_COMM_SELF, " LOG_FACE_DISTANCES - Face Distances:\n");
239 PetscPrintf(PETSC_COMM_SELF, " LEFT(%d): %.15f\n", LEFT, d[LEFT]);
240 PetscPrintf(PETSC_COMM_SELF, " RIGHT(%d): %.15f\n", RIGHT, d[RIGHT]);
241 PetscPrintf(PETSC_COMM_SELF, " BOTTOM(%d): %.15f\n", BOTTOM, d[BOTTOM]);
242 PetscPrintf(PETSC_COMM_SELF, " TOP(%d): %.15f\n", TOP, d[TOP]);
243 PetscPrintf(PETSC_COMM_SELF, " FRONT(%d): %.15f\n", FRONT, d[FRONT]);
244 PetscPrintf(PETSC_COMM_SELF, " BACK(%d): %.15f\n", BACK, d[BACK]);
245
246 return 0; // Indicate successful execution
247}
248
249/*
250 * Helper function: Converts an integer (of type int) to a string.
251 */
252static void IntToStr(int value, char *buf, size_t bufsize)
253{
254 snprintf(buf, bufsize, "%d", value);
255}
256
257/*
258 * Helper function: Converts a 64‐bit integer to a string.
259 */
260static void Int64ToStr(PetscInt64 value, char *buf, size_t bufsize)
261{
262 snprintf(buf, bufsize, "%ld", value);
263}
264
265/*
266 * Helper function: Converts three integers into a formatted string "(i, j, k)".
267 */
268static void CellToStr(const PetscInt *cell, char *buf, size_t bufsize)
269{
270 snprintf(buf, bufsize, "(%d, %d, %d)", cell[0], cell[1], cell[2]);
271}
272
273/*
274 * Helper function: Converts three PetscReal values into a formatted string "(x, y, z)".
275 */
276static void TripleRealToStr(const PetscReal *arr, char *buf, size_t bufsize)
277{
278 snprintf(buf, bufsize, "(%.4f, %.4f, %.4f)", arr[0], arr[1], arr[2]);
279}
280
281/*
282 * Helper function: Computes the maximum string length for each column (across all particles).
283 *
284 * The function examines every particle (from 0 to nParticles-1) and converts the value to a
285 * string using the helper functions above. The maximum length is stored in the pointers provided.
286 *
287 * @param nParticles Number of particles.
288 * @param ranks Array of particle MPI ranks.
289 * @param pids Array of particle IDs.
290 * @param cellIDs Array of cell IDs (stored consecutively, 3 per particle).
291 * @param positions Array of positions (3 per particle).
292 * @param velocities Array of velocities (3 per particle).
293 * @param weights Array of weights (3 per particle).
294 * @param wRank [out] Maximum width for Rank column.
295 * @param wPID [out] Maximum width for PID column.
296 * @param wCell [out] Maximum width for Cell column.
297 * @param wPos [out] Maximum width for Position column.
298 * @param wVel [out] Maximum width for Velocity column.
299 * @param wWt [out] Maximum width for Weights column.
300 */
301static PetscErrorCode ComputeMaxColumnWidths(PetscInt nParticles,
302 const PetscMPIInt *ranks,
303 const PetscInt64 *pids,
304 const PetscInt *cellIDs,
305 const PetscReal *positions,
306 const PetscReal *velocities,
307 const PetscReal *weights,
308 int *wRank, int *wPID, int *wCell,
309 int *wPos, int *wVel, int *wWt)
310{
311 char tmp[TMP_BUF_SIZE];
312
313 *wRank = strlen("Rank"); /* Start with the header label lengths */
314 *wPID = strlen("PID");
315 *wCell = strlen("Cell (i,j,k)");
316 *wPos = strlen("Position (x,y,z)");
317 *wVel = strlen("Velocity (x,y,z)");
318 *wWt = strlen("Weights (a1,a2,a3)");
319
320 for (PetscInt i = 0; i < nParticles; i++) {
321 /* Rank */
322 IntToStr(ranks[i], tmp, TMP_BUF_SIZE);
323 if ((int)strlen(tmp) > *wRank) *wRank = (int)strlen(tmp);
324
325 /* PID */
326 Int64ToStr(pids[i], tmp, TMP_BUF_SIZE);
327 if ((int)strlen(tmp) > *wPID) *wPID = (int)strlen(tmp);
328
329 /* Cell: use the three consecutive values */
330 CellToStr(&cellIDs[3 * i], tmp, TMP_BUF_SIZE);
331 if ((int)strlen(tmp) > *wCell) *wCell = (int)strlen(tmp);
332
333 /* Position */
334 TripleRealToStr(&positions[3 * i], tmp, TMP_BUF_SIZE);
335 if ((int)strlen(tmp) > *wPos) *wPos = (int)strlen(tmp);
336
337 /* Velocity */
338 TripleRealToStr(&velocities[3 * i], tmp, TMP_BUF_SIZE);
339 if ((int)strlen(tmp) > *wVel) *wVel = (int)strlen(tmp);
340
341 /* Weights */
342 TripleRealToStr(&weights[3 * i], tmp, TMP_BUF_SIZE);
343 if ((int)strlen(tmp) > *wWt) *wWt = (int)strlen(tmp);
344 }
345 return 0;
346}
347
348/*
349 * Helper function: Builds a format string for a table row.
350 *
351 * The format string will include proper width specifiers for each column.
352 * For example, it might create something like:
353 *
354 * "| %-6s | %-8s | %-20s | %-25s | %-25s | %-25s |\n"
355 *
356 * @param wRank Maximum width for the Rank column.
357 * @param wPID Maximum width for the PID column.
358 * @param wCell Maximum width for the Cell column.
359 * @param wPos Maximum width for the Position column.
360 * @param wVel Maximum width for the Velocity column.
361 * @param wWt Maximum width for the Weights column.
362 * @param fmtStr Buffer in which to build the format string.
363 * @param bufSize Size of fmtStr.
364 */
365static void BuildRowFormatString(PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt, char *fmtStr, size_t bufSize)
366{
367 // Build a format string using snprintf.
368 // We assume that the Rank is an int (%d), PID is a 64-bit int (%ld)
369 // and the remaining columns are strings (which have been formatted already).
370 snprintf(fmtStr, bufSize,
371 "| %%-%dd | %%-%dd | %%-%ds | %%-%ds | %%-%ds | %%-%ds |\n",
372 wRank, wPID, wCell, wPos, wVel, wWt);
373}
374
375/*
376 * Helper function: Builds a header string for the table using column titles.
377 */
378static void BuildHeaderString(char *headerStr, size_t bufSize, PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt)
379{
380 snprintf(headerStr, bufSize,
381 "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |\n",
382 (int)wRank, "Rank",
383 (int)wPID, "PID",
384 (int)wCell, "Cell (i,j,k)",
385 (int)wPos, "Position (x,y,z)",
386 (int)wVel, "Velocity (x,y,z)",
387 (int)wWt, "Weights (a1,a2,a3)");
388}
389
390/**
391 * @brief Prints particle fields in a table that automatically adjusts its column widths.
392 *
393 * This function retrieves data from the particle swarm and prints a table where the
394 * width of each column is determined by the maximum width needed to display the data.
395 * Only every 'printInterval'-th particle is printed.
396 *
397 * @param[in] user Pointer to the UserCtx structure.
398 * @param[in] printInterval Only every printInterval‑th particle is printed.
399 *
400 * @return PetscErrorCode Returns 0 on success.
401 */
402PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx* user, PetscInt printInterval)
403{
404 DM swarm = user->swarm;
405 PetscErrorCode ierr;
406 PetscInt localNumParticles;
407 PetscReal *positions = NULL;
408 PetscInt64 *particleIDs = NULL;
409 PetscMPIInt *particleRanks = NULL;
410 PetscInt *cellIDs = NULL;
411 PetscReal *weights = NULL;
412 PetscReal *velocities = NULL;
413 PetscMPIInt rank;
414
415 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
416 LOG_ALLOW(LOCAL,LOG_INFO, "PrintParticleFields - Rank %d is retrieving particle data.\n", rank);
417
418 ierr = DMSwarmGetLocalSize(swarm, &localNumParticles); CHKERRQ(ierr);
419 LOG_ALLOW(LOCAL,LOG_DEBUG,"PrintParticleFields - Rank %d has %d particles.\n", rank, localNumParticles);
420
421 ierr = DMSwarmGetField(swarm, "position", NULL, NULL, (void**)&positions); CHKERRQ(ierr);
422 ierr = DMSwarmGetField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
423 ierr = DMSwarmGetField(swarm, "DMSwarm_rank", NULL, NULL, (void**)&particleRanks); CHKERRQ(ierr);
424 ierr = DMSwarmGetField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
425 ierr = DMSwarmGetField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
426 ierr = DMSwarmGetField(swarm, "velocity", NULL, NULL, (void**)&velocities); CHKERRQ(ierr);
427
428 /* Compute maximum column widths. */
429 int wRank, wPID, wCell, wPos, wVel, wWt;
430 wRank = wPID = wCell = wPos = wVel = wWt = 0;
431 ierr = ComputeMaxColumnWidths(localNumParticles, particleRanks, particleIDs, cellIDs,
432 positions, velocities, weights,
433 &wRank, &wPID, &wCell, &wPos, &wVel, &wWt); CHKERRQ(ierr);
434
435 /* Build a header string and a row format string. */
436 char headerFmt[256];
437 char rowFmt[256];
438 BuildHeaderString(headerFmt, sizeof(headerFmt), wRank, wPID, wCell, wPos, wVel, wWt);
439 BuildRowFormatString(wRank, wPID, wCell, wPos, wVel, wWt, rowFmt, sizeof(rowFmt));
440
441 /* Print header (using synchronized printing for parallel output). */
442 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--------------------------------------------------------------------------------------------------------------\n"); CHKERRQ(ierr);
443 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", headerFmt); CHKERRQ(ierr);
444 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--------------------------------------------------------------------------------------------------------------\n"); CHKERRQ(ierr);
445
446 /* Loop over particles and print every printInterval-th row. */
447 char rowStr[256];
448 for (PetscInt i = 0; i < localNumParticles; i++) {
449 if (i % printInterval == 0) {
450 // ------- DEBUG
451 //char cellStr[TMP_BUF_SIZE], posStr[TMP_BUF_SIZE], velStr[TMP_BUF_SIZE], wtStr[TMP_BUF_SIZE];
452 //CellToStr(&cellIDs[3*i], cellStr, TMP_BUF_SIZE);
453 //TripleRealToStr(&positions[3*i], posStr, TMP_BUF_SIZE);
454 //TripleRealToStr(&velocities[3*i], velStr, TMP_BUF_SIZE);
455 // TripleRealToStr(&weights[3*i], wtStr, TMP_BUF_SIZE);
456
457 // if (rank == 0) { // Or whatever rank is Rank 0
458 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Particle %lld: PID=%lld, Rank=%d\n", (long long)i, (long long)particleIDs[i], particleRanks[i]);
459 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Raw Pos: (%.10e, %.10e, %.10e)\n", positions[3*i+0], positions[3*i+1], positions[3*i+2]);
460 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Str Pos: %s\n", posStr);
461 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Raw Vel: (%.10e, %.10e, %.10e)\n", velocities[3*i+0], velocities[3*i+1], velocities[3*i+2]);
462 // PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Str Vel: %s\n", velStr);
463 // Add similar for cell, weights
464 // PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] About to build rowStr for particle %lld\n", (long long)i);
465 // fflush(stdout);
466 // }
467
468 // snprintf(rowStr, sizeof(rowStr), rowFmt,
469 // particleRanks[i],
470 // particleIDs[i],
471 // cellStr,
472 // posStr,
473 // velStr,
474 // wtStr);
475
476
477 // ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", rowStr); CHKERRQ(ierr);
478
479 // ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", rowStr); CHKERRQ(ierr);
480
481 // -------- DEBUG
482 /* Format the row by converting each field to a string first.
483 * We use temporary buffers and then build the row string.
484 */
485
486 char cellStr[TMP_BUF_SIZE], posStr[TMP_BUF_SIZE], velStr[TMP_BUF_SIZE], wtStr[TMP_BUF_SIZE];
487 CellToStr(&cellIDs[3*i], cellStr, TMP_BUF_SIZE);
488 TripleRealToStr(&positions[3*i], posStr, TMP_BUF_SIZE);
489 TripleRealToStr(&velocities[3*i], velStr, TMP_BUF_SIZE);
490 TripleRealToStr(&weights[3*i], wtStr, TMP_BUF_SIZE);
491
492 /* Build the row string. Note that for the integer fields we can use the row format string. */
493 snprintf(rowStr, sizeof(rowStr), rowFmt,
494 particleRanks[i],
495 particleIDs[i],
496 cellStr,
497 posStr,
498 velStr,
499 wtStr);
500 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", rowStr); CHKERRQ(ierr);
501 }
502 }
503
504
505 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--------------------------------------------------------------------------------------------------------------\n"); CHKERRQ(ierr);
506 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "\n"); CHKERRQ(ierr);
507 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
508
509 LOG_ALLOW_SYNC(GLOBAL,LOG_DEBUG,"PrintParticleFields - Completed printing on Rank %d.\n", rank);
510
511 /* Restore fields */
512 ierr = DMSwarmRestoreField(swarm, "position", NULL, NULL, (void**)&positions); CHKERRQ(ierr);
513 ierr = DMSwarmRestoreField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
514 ierr = DMSwarmRestoreField(swarm, "DMSwarm_rank", NULL, NULL, (void**)&particleRanks); CHKERRQ(ierr);
515 ierr = DMSwarmRestoreField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
516 ierr = DMSwarmRestoreField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
517 ierr = DMSwarmRestoreField(swarm, "velocity", NULL, NULL, (void**)&velocities); CHKERRQ(ierr);
518
519 LOG_ALLOW(LOCAL,LOG_DEBUG, "PrintParticleFields - Restored all particle fields.\n");
520 return 0;
521}
522
523
524static void trim(char *s)
525{
526 if (!s) return;
527
528 /* ---- 1. strip leading blanks ----------------------------------- */
529 char *p = s;
530 while (*p && isspace((unsigned char)*p))
531 ++p;
532
533 if (p != s) /* move the trimmed text forward */
534 memmove(s, p, strlen(p) + 1); /* +1 to copy the final NUL */
535
536 /* ---- 2. strip trailing blanks ---------------------------------- */
537 size_t len = strlen(s);
538 while (len > 0 && isspace((unsigned char)s[len - 1]))
539 s[--len] = '\0';
540}
541
542/* ------------------------------------------------------------------------- */
543/**
544 * @brief Load function names from a text file.
545 *
546 * The file is expected to contain **one identifier per line**. Blank lines and
547 * lines whose first non‑blank character is a <tt>#</tt> are silently skipped so
548 * the file can include comments. Example:
549 *
550 * @code{.txt}
551 * # Allowed function list
552 * main
553 * InitializeSimulation
554 * InterpolateAllFieldsToSwarm # inline comments are OK, too
555 * @endcode
556 *
557 * The routine allocates memory as needed (growing an internal buffer with
558 * @c PetscRealloc()) and returns the resulting array and its length to the
559 * caller. Use FreeAllowedFunctions() to clean up when done.
560 *
561 * @param[in] filename Path of the configuration file to read.
562 * @param[out] funcsOut On success, points to a freshly‑allocated array of
563 * <tt>char*</tt> (size @p nOut).
564 * @param[out] nOut Number of valid entries in @p funcsOut.
565 *
566 * @return 0 on success, or a PETSc error code on failure (e.g. I/O error, OOM).
567 */
568PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[],
569 char ***funcsOut,
570 PetscInt *nOut)
571{
572 FILE *fp = NULL;
573 char **funcs = NULL;
574 size_t cap = 16; /* initial capacity */
575 size_t n = 0; /* number of names */
576 char line[PETSC_MAX_PATH_LEN];
577 PetscErrorCode ierr;
578
579 PetscFunctionBegin;
580
581 /* ---------------------------------------------------------------------- */
582 /* 1. Open file */
583 fp = fopen(filename, "r");
584 if (!fp) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
585 "Cannot open %s", filename);
586
587 /* 2. Allocate initial pointer array */
588 ierr = PetscMalloc1(cap, &funcs); CHKERRQ(ierr);
589
590 /* 3. Read file line by line */
591 while (fgets(line, sizeof line, fp)) {
592 /* Strip everything after a comment character '#'. */
593 char *hash = strchr(line, '#');
594 if (hash) *hash = '\0';
595
596 trim(line); /* remove leading/trailing blanks */
597 if (!*line) continue; /* skip if empty */
598
599 /* Grow the array if necessary */
600 if (n == cap) {
601 cap *= 2;
602 ierr = PetscRealloc(cap * sizeof(*funcs), (void **)&funcs); CHKERRQ(ierr);
603 }
604
605 /* Deep‑copy the cleaned identifier */
606 ierr = PetscStrallocpy(line, &funcs[n++]); CHKERRQ(ierr);
607 }
608 fclose(fp);
609
610 /* 4. Return results to caller */
611 *funcsOut = funcs;
612 *nOut = (PetscInt)n;
613
614 PetscFunctionReturn(0);
615}
616
617/* ------------------------------------------------------------------------- */
618/**
619 * @brief Free an array previously returned by LoadAllowedFunctionsFromFile().
620 *
621 * @param[in,out] funcs Array of strings to release (may be @c NULL).
622 * @param[in] n Number of entries in @p funcs. Ignored if @p funcs is
623 * @c NULL.
624 *
625 * @return 0 on success or a PETSc error code.
626 */
627PetscErrorCode FreeAllowedFunctions(char **funcs, PetscInt n)
628{
629 PetscErrorCode ierr;
630 PetscFunctionBegin;
631 if (funcs) {
632 for (PetscInt i = 0; i < n; ++i) {
633 ierr = PetscFree(funcs[i]); CHKERRQ(ierr);
634 }
635 ierr = PetscFree(funcs); CHKERRQ(ierr);
636 }
637 PetscFunctionReturn(0);
638}
639
640/**
641 * @brief Helper function to convert BCFace enum to a string representation.
642 * @param[in] face The BCFace enum value.
643 * @return Pointer to a constant string representing the face.
644 */
645const char* BCFaceToString(BCFace face) {
646 switch (face) {
647 case BC_FACE_NEG_X: return "-Xi (I-Min)";
648 case BC_FACE_POS_X: return "+Xi (I-Max)";
649 case BC_FACE_NEG_Y: return "-Eta (J-Min)";
650 case BC_FACE_POS_Y: return "+Eta (J-Max)";
651 case BC_FACE_NEG_Z: return "-Zeta (K-Min)";
652 case BC_FACE_POS_Z: return "+Zeta (K-Max)";
653 default: return "Unknown Face";
654 }
655}
656
657/**
658 * @brief Helper function to convert BCType enum to a string representation.
659 * @param[in] type The BCType enum value.
660 * @return Pointer to a constant string representing the BC type.
661 */
662const char* BCTypeToString(BCType type) {
663 switch (type) {
664 // case DIRICHLET: return "DIRICHLET";
665 // case NEUMANN: return "NEUMANN";
666 case WALL: return "WALL";
667 case INLET: return "INLET";
668 case OUTLET: return "OUTLET";
669 case FARFIELD: return "FARFIELD";
670 case PERIODIC: return "PERIODIC";
671 case INTERFACE: return "INTERFACE";
672 case NOGRAD: return "NOGRAD";
673
674 // case CUSTOM: return "CUSTOM";
675 default: return "Unknown BC Type";
676 }
677}
678
679/**
680 * @brief Converts a BCHandlerType enum to its string representation.
681 *
682 * Provides a descriptive string for a specific boundary condition implementation strategy.
683 * This is crucial for logging the exact behavior configured for a face.
684 *
685 * @param handler_type The BCHandlerType enum value (e.g., BC_HANDLER_WALL_NOSLIP).
686 * @return A constant character string corresponding to the enum. Returns
687 * "UNKNOWN_HANDLER" if the enum value is not recognized.
688 */
689const char* BCHandlerTypeToString(BCHandlerType handler_type) {
690 switch (handler_type) {
691 // Wall & Symmetry Handlers
692 case BC_HANDLER_WALL_NOSLIP: return "noslip";
693 case BC_HANDLER_WALL_MOVING: return "moving";
694 case BC_HANDLER_SYMMETRY_PLANE: return "symmetry_plane";
695
696 // Inlet Handlers
697 case BC_HANDLER_INLET_CONSTANT_VELOCITY: return "constant_velocity";
698 case BC_HANDLER_INLET_PULSANTILE_FLUX: return "pulsatile_flux";
699 case BC_HANDLER_INLET_PARABOLIC: return "parabolic";
700
701 // Outlet Handlers
702 case BC_HANDLER_OUTLET_CONSERVATION: return "conservation";
703 case BC_HANDLER_OUTLET_PRESSURE: return "pressure";
704
705 // Other Physical Handlers
706 case BC_HANDLER_FARFIELD_NONREFLECTING: return "nonreflecting";
707 case BC_HANDLER_NOGRAD_COPY_GHOST: return "no_gradient";
708
709 // Multi-Block / Interface Handlers
710 case BC_HANDLER_PERIODIC: return "periodic";
711 case BC_HANDLER_INTERFACE_OVERSET: return "overset";
712
713 // Default case
715 default: return "UNKNOWN_HANDLER";
716 }
717}
718
719/**
720 * @brief Destroys the DualMonitorCtx.
721 *
722 * This function is passed to KSPMonitorSet to ensure the viewer is
723 * properly destroyed and the context memory is freed when the KSP is destroyed.
724 * @param Ctx a pointer to the context pointer to be destroyed
725 * @return PetscErrorCode
726 */
727PetscErrorCode DualMonitorDestroy(void **ctx)
728{
729 DualMonitorCtx *monctx = (DualMonitorCtx*)*ctx;
730 PetscErrorCode ierr;
731 PetscMPIInt rank;
732
733 PetscFunctionBeginUser;
734 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
735 if(!rank && monctx->file_handle){
736 fclose(monctx->file_handle);
737 }
738
739 ierr = PetscFree(monctx); CHKERRQ(ierr);
740 *ctx = NULL;
741 PetscFunctionReturn(0);
742}
743
744/**
745 * @brief A custom KSP monitor that logs the true residual to a file and optionally to the console.
746 *
747 * This function replicates the behavior of KSPMonitorTrueResidualNorm by calculating
748 * the true residual norm ||b - Ax|| itself. It unconditionally logs to a file
749 * viewer and conditionally logs to the console based on a flag in the context.
750 *
751 * @param ksp The Krylov subspace context.
752 * @param it The current iteration number.
753 * @param rnorm The preconditioned residual norm (ignored, we compute our own).
754 * @param ctx A pointer to the DualMonitorCtx structure.
755 * @return PetscErrorCode 0 on success.
756 */
757#undef __FUNCT__
758#define __FUNCT__ "DualKSPMonitor"
759PetscErrorCode DualKSPMonitor(KSP ksp, PetscInt it, PetscReal rnorm, void *ctx)
760{
761 DualMonitorCtx *monctx = (DualMonitorCtx*)ctx;
762 PetscErrorCode ierr;
763 PetscReal trnorm, relnorm;
764 Vec r;
765 char norm_buf[256];
766 PetscMPIInt rank;
767
768 PetscFunctionBeginUser;
769 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
770
771 // 1. Calculate the true residual norm.
772 ierr = KSPBuildResidual(ksp, NULL, NULL, &r); CHKERRQ(ierr);
773 ierr = VecNorm(r, NORM_2, &trnorm); CHKERRQ(ierr);
774
775 // 2. On the first iteration, compute and store the norm of the RHS vector `b`.
776 if (it == 0) {
777 Vec b;
778 ierr = KSPGetRhs(ksp, &b); CHKERRQ(ierr);
779 ierr = VecNorm(b, NORM_2, &monctx->bnorm); CHKERRQ(ierr);
780 }
781
782 if(!rank){
783 // 3. Compute the relative norm and format the output string.
784 if (monctx->bnorm > 1.e-15) {
785 relnorm = trnorm / monctx->bnorm;
786 sprintf(norm_buf, "ts: %-5d | block: %-2d | iter: %-3d | Unprecond Norm: %12.5e | True Norm: %12.5e | Rel Norm: %12.5e",(int)monctx->step, (int)monctx->block_id, (int)it, (double)rnorm, (double)trnorm, (double)relnorm);
787 } else {
788 sprintf(norm_buf,"ts: %-5d | block: %-2d | iter: %-3d | Unprecond Norm: %12.5e | True Norm: %12.5e",(int)monctx->step, (int)monctx->block_id, (int)it, (double)rnorm, (double)trnorm);
789 }
790
791 // 4. Log to the file viewer (unconditionally).
792 if(monctx->file_handle){
793 ierr = PetscFPrintf(PETSC_COMM_SELF,monctx->file_handle,"%s\n", norm_buf); CHKERRQ(ierr);
794 }
795 // 5. Log to the console (conditionally).
796 if (monctx->log_to_console) {
797 PetscFPrintf(PETSC_COMM_SELF,stdout, "%s\n", norm_buf); CHKERRQ(ierr);
798 }
799
800 } //rank
801
802 PetscFunctionReturn(0);
803}
804
805/**
806 * @brief Logs continuity metrics for a single block to a file.
807 *
808 * This function should be called for each block, once per timestep. It opens a
809 * central log file in append mode. To ensure the header is written only once,
810 * it checks if it is processing block 0 on the simulation's start step.
811 *
812 * @param user A pointer to the UserCtx for the specific block whose metrics
813 * are to be logged. The function accesses both global (SimCtx)
814 * and local (user->...) data.
815 * @return PetscErrorCode 0 on success.
816 */
817#undef __FUNCT__
818#define __FUNCT__ "LOG_CONTINUITY_METRICS"
819PetscErrorCode LOG_CONTINUITY_METRICS(UserCtx *user)
820{
821 PetscErrorCode ierr;
822 PetscMPIInt rank;
823 SimCtx *simCtx = user->simCtx; // Get the shared SimCtx
824 const PetscInt bi = user->_this; // Get this block's specific ID
825 const PetscInt ti = simCtx->step; // Get the current timestep
826
827 PetscFunctionBeginUser;
828 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
829
830 // Only rank 0 performs file I/O.
831 if (!rank) {
832 FILE *f;
833 char filen[128];
834 sprintf(filen, "logs/Continuity_Metrics.log");
835
836 // Open the log file in append mode.
837 f = fopen(filen, "a");
838 if (!f) {
839 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
840 }
841
842 // Write a header only for the very first block (bi=0) on the very
843 // first timestep (ti=StartStep). This ensures it's written only once.
844 if (ti == simCtx->StartStep && bi == 0) {
845 PetscFPrintf(PETSC_COMM_SELF, f, "%-10s | %-6s | %-18s | %-30s | %-18s | %-18s | %-18s | %-18s\n",
846 "Timestep", "Block", "Max Divergence", "Max Divergence Location ([k][j][i]=idx)", "Sum(RHS)","Total Flux In", "Total Flux Out", "Net Flux");
847 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------------------------------\n");
848 }
849
850 // Prepare the data strings and values for the current block.
851 PetscReal net_flux = simCtx->FluxInSum - simCtx->FluxOutSum;
852 char location_str[64];
853 sprintf(location_str, "([%d][%d][%d] = %d)", (int)simCtx->MaxDivz, (int)simCtx->MaxDivy, (int)simCtx->MaxDivx, (int)simCtx->MaxDivFlatArg);
854
855 // Write the formatted line for the current block.
856 PetscFPrintf(PETSC_COMM_SELF, f, "%-10d | %-6d | %-18.10e | %-39s | %-18.10e | %-18.10e | %-18.10e | %-18.10e\n",
857 (int)ti,
858 (int)bi,
859 (double)simCtx->MaxDiv,
860 location_str,
861 (double)simCtx->summationRHS,
862 (double)simCtx->FluxInSum,
863 (double)simCtx->FluxOutSum,
864 (double)net_flux);
865
866 fclose(f);
867 }
868
869 PetscFunctionReturn(0);
870}
871
872/**
873 * @brief A function that outputs the name of the current level in the ParticleLocation enum.
874 * @param level The ParticleLocation enum value.
875 * @return A constant character string corresponding to the enum. Returns
876 * "UNKNOWN_LEVEL" if the enum value is not recognized.
877 */
879{
880 switch (level) {
881 case NEEDS_LOCATION: return "NEEDS_LOCATION";
882 case ACTIVE_AND_LOCATED: return "ACTIVE_AND_LOCATED";
883 case MIGRATING_OUT: return "MIGRATING_OUT";
884 case LOST: return "LOST";
885 case UNINITIALIZED: return "UNINITIALIZED";
886 default: return "UNKNOWN_LEVEL";
887 }
888}
889
890///////// Profiling System /////////
891
892// Data structure to hold profiling info for one function
893typedef struct {
894 const char *name;
899 double start_time; // Timer for the current call
900 PetscBool always_log;
902
903// Global registry for all profiled functions
905static PetscInt g_profiler_count = 0;
906static PetscInt g_profiler_capacity = 0;
907
908// Internal helper to find a function in the registry or create it
909static PetscErrorCode _FindOrCreateEntry(const char *func_name, PetscInt *idx)
910{
911 PetscFunctionBeginUser;
912 // Search for existing entry
913 for (PetscInt i = 0; i < g_profiler_count; ++i) {
914 if (strcmp(g_profiler_registry[i].name, func_name) == 0) {
915 *idx = i;
916 PetscFunctionReturn(0);
917 }
918 }
919
920 // Not found, create a new entry
922 PetscInt new_capacity = g_profiler_capacity == 0 ? 16 : g_profiler_capacity * 2;
923 PetscErrorCode ierr = PetscRealloc(sizeof(ProfiledFunction) * new_capacity, &g_profiler_registry); CHKERRQ(ierr);
924 g_profiler_capacity = new_capacity;
925 }
926
927 *idx = g_profiler_count;
928 g_profiler_registry[*idx].name = func_name;
934 g_profiler_registry[*idx].always_log = PETSC_FALSE;
936
937 PetscFunctionReturn(0);
938}
939
940// --- Public API Implementation ---
941/**
942 * @brief Initializes the custom profiling system using configuration from SimCtx.
943 *
944 * This function sets up the internal data structures for tracking function
945 * performance. It reads the list of "critical functions" from the provided
946 * SimCtx and marks them for per-step logging at LOG_INFO level.
947 *
948 * It should be called once at the beginning of the application, after
949 * CreateSimulationContext() but before the main time loop.
950 *
951 * @param simCtx The master simulation context, which contains the list of
952 * critical function names to always log.
953 * @return PetscErrorCode
954 */
955PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
956{
957 PetscFunctionBeginUser;
958 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingInitialize");
959
960 // Iterate through the list of critical functions provided in SimCtx
961 for (PetscInt i = 0; i < simCtx->nCriticalFuncs; ++i) {
962 PetscInt idx;
963 const char *func_name = simCtx->criticalFuncs[i];
964 PetscErrorCode ierr = _FindOrCreateEntry(func_name, &idx); CHKERRQ(ierr);
965 g_profiler_registry[idx].always_log = PETSC_TRUE;
966
967 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Marked '%s' as a critical function for profiling.\n", func_name);
968 }
969 PetscFunctionReturn(0);
970}
971
972void _ProfilingStart(const char *func_name)
973{
974 PetscInt idx;
975 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
976 PetscTime(&g_profiler_registry[idx].start_time);
977}
978
979void _ProfilingEnd(const char *func_name)
980{
981 double end_time;
982 PetscTime(&end_time);
983
984 PetscInt idx;
985 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
986
987 double elapsed = end_time - g_profiler_registry[idx].start_time;
988 g_profiler_registry[idx].total_time += elapsed;
992}
993
994PetscErrorCode ProfilingLogTimestepSummary(PetscInt step)
995{
996 LogLevel log_level = get_log_level();
997 PetscBool should_print = PETSC_FALSE;
998
999 PetscFunctionBeginUser;
1000
1001 // Decide if we should print anything at all
1002 if (log_level >= LOG_INFO) {
1003 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1004 if (g_profiler_registry[i].current_step_call_count > 0) {
1005 if (log_level == LOG_PROFILE || g_profiler_registry[i].always_log) {
1006 should_print = PETSC_TRUE;
1007 break;
1008 }
1009 }
1010 }
1011 }
1012
1013 if (should_print) {
1014 PetscPrintf(MPI_COMM_WORLD, "[PROFILE] ----- Timestep %d Summary -----\n", step);
1015 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1016 if (g_profiler_registry[i].current_step_call_count > 0) {
1017 if (log_level == LOG_PROFILE || g_profiler_registry[i].always_log) {
1018 PetscPrintf(MPI_COMM_WORLD, "[PROFILE] %-25s: %.6f s (%lld calls)\n",
1019 g_profiler_registry[i].name,
1020 g_profiler_registry[i].current_step_time,
1021 g_profiler_registry[i].current_step_call_count);
1022 }
1023 }
1024 }
1025 }
1026
1027 // Reset per-step counters for the next iteration
1028 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1031 }
1032 PetscFunctionReturn(0);
1033}
1034
1035// Comparison function for qsort to sort by total_time in descending order
1036static int _CompareProfiledFunctions(const void *a, const void *b)
1037{
1038 const ProfiledFunction *func_a = (const ProfiledFunction *)a;
1039 const ProfiledFunction *func_b = (const ProfiledFunction *)b;
1040
1041 if (func_a->total_time < func_b->total_time) return 1;
1042 if (func_a->total_time > func_b->total_time) return -1;
1043 return 0;
1044}
1045
1046PetscErrorCode ProfilingFinalize(void)
1047{
1048 PetscFunctionBeginUser;
1049 if (get_log_level() >= LOG_PROFILE) {
1050
1051 // --- Step 1: Sort the data for readability ---
1053
1054 // --- Step 2: Dynamically determine the width for the function name column ---
1055 PetscInt max_name_len = strlen("Function"); // Start with the header's length
1056 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1057 if (g_profiler_registry[i].total_call_count > 0) {
1058 PetscInt len = strlen(g_profiler_registry[i].name);
1059 if (len > max_name_len) {
1060 max_name_len = len;
1061 }
1062 }
1063 }
1064 // Add a little padding
1065 max_name_len += 2;
1066
1067 // --- Step 3: Define fixed widths for numeric columns for consistent alignment ---
1068 const int time_width = 18;
1069 const int count_width = 15;
1070 const int avg_width = 22;
1071
1072 // --- Step 4: Print the formatted table ---
1073 PetscPrintf(MPI_COMM_WORLD, "\n=======================================================================================\n");
1074 PetscPrintf(MPI_COMM_WORLD, " FINAL PROFILING SUMMARY (Sorted by Total Time)\n");
1075 PetscPrintf(MPI_COMM_WORLD, "=======================================================================================\n");
1076
1077 // Header Row
1078 PetscPrintf(MPI_COMM_WORLD, "%-*s | %-*s | %-*s | %-*s\n",
1079 max_name_len, "Function",
1080 time_width, "Total Time (s)",
1081 count_width, "Call Count",
1082 avg_width, "Avg. Time/Call (ms)");
1083
1084 // Separator Line (dynamically sized)
1085 for (int i = 0; i < max_name_len; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1086 PetscPrintf(MPI_COMM_WORLD, "-|-");
1087 for (int i = 0; i < time_width; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1088 PetscPrintf(MPI_COMM_WORLD, "-|-");
1089 for (int i = 0; i < count_width; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1090 PetscPrintf(MPI_COMM_WORLD, "-|-");
1091 for (int i = 0; i < avg_width; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1092 PetscPrintf(MPI_COMM_WORLD, "\n");
1093
1094 // Data Rows
1095 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1096 if (g_profiler_registry[i].total_call_count > 0) {
1097 double avg_time_ms = (g_profiler_registry[i].total_time / g_profiler_registry[i].total_call_count) * 1000.0;
1098 PetscPrintf(MPI_COMM_WORLD, "%-*s | %*.*f | %*lld | %*.*f\n",
1099 max_name_len, g_profiler_registry[i].name,
1100 time_width, 6, g_profiler_registry[i].total_time,
1101 count_width, g_profiler_registry[i].total_call_count,
1102 avg_width, 6, avg_time_ms);
1103 }
1104 }
1105 PetscPrintf(MPI_COMM_WORLD, "=======================================================================================\n");
1106 }
1107
1108 // --- Final Cleanup ---
1109 PetscFree(g_profiler_registry);
1110 g_profiler_registry = NULL;
1111 g_profiler_count = 0;
1113 PetscFunctionReturn(0);
1114}
PetscLogEvent EVENT_walkingsearch
Definition logging.c:34
void set_allowed_functions(const char **functionList, int count)
Sets the global list of function names that are allowed to log.
Definition logging.c:124
PetscBool always_log
Definition logging.c:900
const char * BCHandlerTypeToString(BCHandlerType handler_type)
Converts a BCHandlerType enum to its string representation.
Definition logging.c:689
PetscBool is_function_allowed(const char *functionName)
Checks if the given function name is in the allow-list.
Definition logging.c:159
static PetscInt g_profiler_count
Definition logging.c:905
PetscErrorCode DualMonitorDestroy(void **ctx)
Destroys the DualMonitorCtx.
Definition logging.c:727
#define TMP_BUF_SIZE
Definition logging.c:5
static char ** gAllowedFunctions
Global/static array of function names allowed to log.
Definition logging.c:21
static LogLevel current_log_level
Static variable to cache the current logging level.
Definition logging.c:14
const char * BCFaceToString(BCFace face)
Helper function to convert BCFace enum to a string representation.
Definition logging.c:645
PetscErrorCode FreeAllowedFunctions(char **funcs, PetscInt n)
Free an array previously returned by LoadAllowedFunctionsFromFile().
Definition logging.c:627
PetscErrorCode print_log_level(void)
Prints the current logging level to the console.
Definition logging.c:86
long long total_call_count
Definition logging.c:897
static PetscInt g_profiler_capacity
Definition logging.c:906
static void BuildRowFormatString(PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt, char *fmtStr, size_t bufSize)
Definition logging.c:365
PetscLogEvent EVENT_IndividualLocation
Definition logging.c:36
static void trim(char *s)
Definition logging.c:524
PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[], char ***funcsOut, PetscInt *nOut)
Load function names from a text file.
Definition logging.c:568
static int gNumAllowed
Number of entries in the gAllowedFunctions array.
Definition logging.c:26
double total_time
Definition logging.c:895
static void BuildHeaderString(char *headerStr, size_t bufSize, PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt)
Definition logging.c:378
static PetscErrorCode _FindOrCreateEntry(const char *func_name, PetscInt *idx)
Definition logging.c:909
static void CellToStr(const PetscInt *cell, char *buf, size_t bufsize)
Definition logging.c:268
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:49
PetscErrorCode LOG_FACE_DISTANCES(PetscReal *d)
Prints the signed distances to each face of the cell.
Definition logging.c:229
PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx *user, PetscInt printInterval)
Prints particle fields in a table that automatically adjusts its column widths.
Definition logging.c:402
void _ProfilingEnd(const char *func_name)
Definition logging.c:979
static void TripleRealToStr(const PetscReal *arr, char *buf, size_t bufsize)
Definition logging.c:276
static void Int64ToStr(PetscInt64 value, char *buf, size_t bufsize)
Definition logging.c:260
const char * BCTypeToString(BCType type)
Helper function to convert BCType enum to a string representation.
Definition logging.c:662
const char * ParticleLocationStatusToString(ParticleLocationStatus level)
A function that outputs the name of the current level in the ParticleLocation enum.
Definition logging.c:878
static int _CompareProfiledFunctions(const void *a, const void *b)
Definition logging.c:1036
PetscErrorCode DualKSPMonitor(KSP ksp, PetscInt it, PetscReal rnorm, void *ctx)
A custom KSP monitor that logs to a file and optionally to the console.
Definition logging.c:759
PetscErrorCode LOG_CONTINUITY_METRICS(UserCtx *user)
Logs continuity metrics for a single block to a file.
Definition logging.c:819
double current_step_time
Definition logging.c:896
long long current_step_call_count
Definition logging.c:898
PetscErrorCode ProfilingFinalize(void)
Prints the final, cumulative performance summary and cleans up resources.
Definition logging.c:1046
static ProfiledFunction * g_profiler_registry
Definition logging.c:904
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
Definition logging.c:955
PetscErrorCode LOG_CELL_VERTICES(const Cell *cell, PetscMPIInt rank)
Prints the coordinates of a cell's vertices.
Definition logging.c:189
static void IntToStr(int value, char *buf, size_t bufsize)
Definition logging.c:252
static PetscErrorCode ComputeMaxColumnWidths(PetscInt nParticles, const PetscMPIInt *ranks, const PetscInt64 *pids, const PetscInt *cellIDs, const PetscReal *positions, const PetscReal *velocities, const PetscReal *weights, int *wRank, int *wPID, int *wCell, int *wPos, int *wVel, int *wWt)
Definition logging.c:301
PetscLogEvent EVENT_GlobalParticleLocation
Definition logging.c:35
PetscLogEvent EVENT_Individualwalkingsearch
Definition logging.c:33
double start_time
Definition logging.c:899
PetscErrorCode ProfilingLogTimestepSummary(PetscInt step)
Logs the performance summary for the current timestep and resets timers.
Definition logging.c:994
void _ProfilingStart(const char *func_name)
Definition logging.c:972
const char * name
Definition logging.c:894
Logging utilities and macros for PETSc-based applications.
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
----β€” DEBUG ---------------------------------------β€” #define LOG_ALLOW(scope, level,...
Definition logging.h:274
PetscBool log_to_console
Definition logging.h:65
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:207
PetscReal bnorm
Definition logging.h:66
PetscInt step
Definition logging.h:67
LogLevel
Enumeration of logging levels.
Definition logging.h:28
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
@ LOG_PROFILE
Exclusive log level for performance timing and profiling.
Definition logging.h:31
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:32
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:33
FILE * file_handle
Definition logging.h:64
PetscInt block_id
Definition logging.h:68
Context for a dual-purpose KSP monitor.
Definition logging.h:63
BCType
Defines the general mathematical/physical category of a boundary.
Definition variables.h:206
@ INLET
Definition variables.h:210
@ NOGRAD
Definition variables.h:216
@ INTERFACE
Definition variables.h:208
@ FARFIELD
Definition variables.h:211
@ OUTLET
Definition variables.h:211
@ PERIODIC
Definition variables.h:211
@ WALL
Definition variables.h:209
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:633
ParticleLocationStatus
Defines the state of a particle with respect to its location and migration status during the iterativ...
Definition variables.h:134
@ LOST
Definition variables.h:138
@ NEEDS_LOCATION
Definition variables.h:135
@ ACTIVE_AND_LOCATED
Definition variables.h:136
@ UNINITIALIZED
Definition variables.h:139
@ MIGRATING_OUT
Definition variables.h:137
PetscReal FluxOutSum
Definition variables.h:571
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:220
@ BC_HANDLER_INLET_PULSANTILE_FLUX
Definition variables.h:224
@ BC_HANDLER_INLET_PARABOLIC
Definition variables.h:223
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
Definition variables.h:224
@ BC_HANDLER_INTERFACE_OVERSET
Definition variables.h:227
@ BC_HANDLER_WALL_MOVING
Definition variables.h:222
@ BC_HANDLER_NOGRAD_COPY_GHOST
Definition variables.h:221
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:222
@ BC_HANDLER_OUTLET_CONSERVATION
Definition variables.h:225
@ BC_HANDLER_PERIODIC
Definition variables.h:227
@ BC_HANDLER_FARFIELD_NONREFLECTING
Definition variables.h:226
@ BC_HANDLER_OUTLET_PRESSURE
Definition variables.h:225
@ BC_HANDLER_SYMMETRY_PLANE
Definition variables.h:223
@ BC_HANDLER_UNDEFINED
Definition variables.h:221
PetscInt _this
Definition variables.h:643
char ** criticalFuncs
Definition variables.h:611
PetscInt StartStep
Definition variables.h:523
PetscScalar x
Definition variables.h:100
PetscReal MaxDiv
Definition variables.h:606
PetscInt MaxDivx
Definition variables.h:607
PetscInt MaxDivy
Definition variables.h:607
PetscInt MaxDivz
Definition variables.h:607
PetscInt MaxDivFlatArg
Definition variables.h:607
PetscReal FluxInSum
Definition variables.h:571
PetscScalar z
Definition variables.h:100
PetscInt step
Definition variables.h:521
PetscScalar y
Definition variables.h:100
@ TOP
Definition variables.h:144
@ FRONT
Definition variables.h:144
@ BOTTOM
Definition variables.h:144
@ BACK
Definition variables.h:144
@ LEFT
Definition variables.h:144
@ RIGHT
Definition variables.h:144
PetscInt nCriticalFuncs
Definition variables.h:612
PetscReal summationRHS
Definition variables.h:605
Cmpnts vertices[8]
Coordinates of the eight vertices of the cell.
Definition variables.h:160
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:199
@ BC_FACE_NEG_X
Definition variables.h:200
@ BC_FACE_POS_Z
Definition variables.h:202
@ BC_FACE_POS_Y
Definition variables.h:201
@ BC_FACE_NEG_Z
Definition variables.h:202
@ BC_FACE_POS_X
Definition variables.h:200
@ BC_FACE_NEG_Y
Definition variables.h:201
Defines the vertices of a single hexahedral grid cell.
Definition variables.h:159
The master context for the entire simulation.
Definition variables.h:513
User-defined context containing data specific to a single computational grid level.
Definition variables.h:630