PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
logging.h
Go to the documentation of this file.
1/**
2 * @file logging.h
3 * @brief Logging utilities and macros for PETSc-based applications.
4 *
5 * This header defines logging levels, scopes, and macros for consistent logging throughout the application.
6 * It provides functions to retrieve the current logging level and macros to simplify logging with scope control.
7 */
8
9#ifndef LOGGING_H
10#define LOGGING_H
11
12// Include necessary headers
13#include <petsc.h> // PETSc library header
14#include <stdlib.h>
15#include <string.h>
16#include <petscsys.h>
17#include <ctype.h>
18#include "variables.h"
19#include "Boundaries.h"
20// --------------------- Logging Levels Definition ---------------------
21
22/**
23 * @brief Enumeration of logging levels.
24 *
25 * Defines various severity levels for logging messages.
26 */
27typedef enum {
28 LOG_ERROR = 0, /**< Critical errors that may halt the program */
29 LOG_WARNING, /**< Non-critical issues that warrant attention */
30 LOG_INFO, /**< Informational messages about program execution */
31 LOG_DEBUG, /**< Detailed debugging information */
32 LOG_TRACE, /**< Very fine-grained tracing information for in-depth debugging */
33 LOG_VERBOSE /**< Extremely detailed logs, typically for development use only */
35
36// -------------------- Logging Scope Definitions ------------------
37
38/**
39 * @brief Logging scope definitions for controlling message output.
40 *
41 * - LOCAL: Logs on the current process using MPI_COMM_SELF.
42 * - GLOBAL: Logs across all processes using MPI_COMM_WORLD.
43 */
44#define LOCAL 0 ///< Scope for local logging on the current process.
45#define GLOBAL 1 ///< Scope for global logging across all processes.
46
47//----------------------- Custom KSP Monitor Struct ------------
48
49/**
50 * @brief Context for a dual-purpose KSP monitor.
51 *
52 * This struct holds a file viewer for unconditional logging and a boolean
53 * flag to enable/disable optional logging to the console.
54 */
55typedef struct {
56 FILE *file_handle; // C file handling for logging.
57 PetscBool log_to_console; // Flag to enable console output.
58 PetscReal bnorm; // Stores the norm of the initial RHS vector.
59 PetscInt step; // Timestep
60 PetscInt block_id; // the ID of the block this monitor is for.
62
63// --------------------- Logging Macros ---------------------
64
65/**
66 * @brief Logging macro for PETSc-based applications with scope control.
67 *
68 * This macro provides a convenient way to log messages with different scopes
69 * (LOCAL or GLOBAL) and severity levels. It utilizes PETSc's `PetscPrintf`
70 * function for message output.
71 *
72 * @param scope Specifies the logging scope:
73 * - LOCAL: Logs on the current process using MPI_COMM_SELF.
74 * - GLOBAL: Logs on all processes using MPI_COMM_WORLD.
75 * @param level The severity level of the message (e.g., LOG_INFO, LOG_ERROR).
76 * @param fmt The format string for the message (similar to printf).
77 * @param ... Additional arguments for the format string (optional).
78 *
79 * Example usage:
80 * LOG(LOCAL, LOG_ERROR, "An error occurred at index %ld.\n", idx);
81 * LOG(GLOBAL, LOG_INFO, "Grid size: %ld x %ld x %ld.\n", nx, ny, nz);
82 */
83#define LOG(scope, level, fmt, ...) \
84 do { \
85 /* Determine the MPI communicator based on the scope */ \
86 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
87 /* Check if the log level is within the allowed range */ \
88 if ((int)(level) <= (int)get_log_level()) { \
89 /* Print the message to the specified communicator */ \
90 PetscPrintf(comm, fmt, ##__VA_ARGS__); \
91 } \
92 } while (0)
93
94/**
95 * @brief Default logging macro for PETSc-based applications.
96 *
97 * This macro simplifies logging by defaulting the scope to GLOBAL
98 * (i.e., `MPI_COMM_WORLD`) and providing a convenient interface for
99 * common logging needs.
100 *
101 * @param level The severity level of the message (e.g., LOG_ERROR, LOG_INFO).
102 * @param fmt The format string for the log message (similar to printf).
103 * @param ... Additional arguments for the format string (optional).
104 *
105 * Example usage:
106 * LOG_DEFAULT(LOG_ERROR, "Error occurred at index %ld.\n", idx);
107 * LOG_DEFAULT(LOG_INFO, "Grid size: %ld x %ld x %ld.\n", nx, ny, nz);
108 *
109 * @note
110 * - By default, this macro logs across all MPI processes using `MPI_COMM_WORLD`.
111 * - If finer control (e.g., local logging) is required, use the more general `LOG` macro.
112 * - The log level is filtered based on the value returned by `get_log_level()`.
113 */
114#define LOG_DEFAULT(level, fmt, ...) \
115 do { \
116 /* Set the communicator to global (MPI_COMM_WORLD) by default */ \
117 MPI_Comm comm = MPI_COMM_WORLD; \
118 /* Check if the log level is within the allowed range */ \
119 if ((int)(level) <= (int)get_log_level()) { \
120 /* Print the message using PetscPrintf with the global communicator */ \
121 PetscPrintf(comm, fmt, ##__VA_ARGS__); \
122 } \
123 } while (0)
124
125/**
126 * @brief Logging macro for PETSc-based applications with scope control,
127 * using synchronized output across processes.
128 *
129 * This macro uses `PetscSynchronizedPrintf` and `PetscSynchronizedFlush` to
130 * ensure messages from different ranks are printed in a synchronized (rank-by-rank)
131 * manner, preventing interleaved outputs.
132 *
133 * @param scope Specifies the logging scope:
134 * - LOCAL: Logs on the current process using MPI_COMM_SELF.
135 * - GLOBAL: Logs on all processes using MPI_COMM_WORLD.
136 * @param level The severity level of the message (e.g., LOG_INFO, LOG_ERROR).
137 * @param fmt The format string for the message (similar to printf).
138 * @param ... Additional arguments for the format string (optional).
139 *
140 * Example usage:
141 * LOG_SYNC(LOCAL, LOG_ERROR, "An error occurred at index %ld.\n", idx);
142 * LOG_SYNC(GLOBAL, LOG_INFO, "Synchronized info: rank = %ld.\n", rank);
143 */
144#define LOG_SYNC(scope, level, fmt, ...) \
145 do { \
146 /* Determine the MPI communicator based on the scope */ \
147 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
148 /* Check if the log level is within the allowed range */ \
149 if ((int)(level) <= (int)get_log_level()) { \
150 /* Synchronized print (collective) on the specified communicator */ \
151 PetscSynchronizedPrintf(comm, fmt, ##__VA_ARGS__); \
152 /* Ensure all ranks have finished printing before continuing */ \
153 PetscSynchronizedFlush(comm, PETSC_STDOUT); \
154 } \
155 } while (0)
156
157/**
158 * @brief Default synchronized logging macro for PETSc-based applications.
159 *
160 * This macro simplifies logging by defaulting the scope to GLOBAL
161 * (i.e., `MPI_COMM_WORLD`) and provides synchronized output across
162 * all processes.
163 *
164 * @param level The severity level of the message (e.g., LOG_ERROR, LOG_INFO).
165 * @param fmt The format string for the log message (similar to printf).
166 * @param ... Additional arguments for the format string (optional).
167 *
168 * Example usage:
169 * LOG_SYNC_DEFAULT(LOG_ERROR, "Error at index %ld.\n", idx);
170 * LOG_SYNC_DEFAULT(LOG_INFO, "Process rank: %ld.\n", rank);
171 *
172 * @note
173 * - By default, this macro logs across all MPI processes using `MPI_COMM_WORLD`.
174 * - If local (per-process) logging is required, use the more general `LOG_SYNC` macro.
175 * - The log level is filtered based on the value returned by `get_log_level()`.
176 */
177#define LOG_SYNC_DEFAULT(level, fmt, ...) \
178 do { \
179 if ((int)(level) <= (int)get_log_level()) { \
180 PetscSynchronizedPrintf(MPI_COMM_WORLD, fmt, ##__VA_ARGS__); \
181 PetscSynchronizedFlush(MPI_COMM_WORLD, PETSC_STDOUT); \
182 } \
183 } while (0)
184
185
186
187/**
188 * @brief Logging macro that checks both the log level and whether the calling function
189 * is in the allowed-function list before printing. Useful for selective, per-function logging.
190 *
191 * @param scope Specifies the logging scope (LOCAL or GLOBAL).
192 * @param level The severity level of the message (e.g., LOG_INFO, LOG_ERROR).
193 * @param fmt The format string for the message (similar to printf).
194 * @param ... Additional arguments for the format string (optional).
195 *
196 * Example usage:
197 * LOG_ALLOW(LOCAL, LOG_DEBUG, "Debugging info in function: %s\n", __func__);
198 */
199#define LOG_ALLOW(scope, level, fmt, ...) \
200 do { \
201 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
202 if ((int)(level) <= (int)get_log_level() && is_function_allowed(__func__)) { \
203 PetscPrintf(comm, "[%s] " fmt, __func__, ##__VA_ARGS__); \
204 } \
205 } while (0)
206
207
208/* ------- DEBUG ------------------------------------------
209#define LOG_ALLOW(scope, level, fmt, ...) \
210 do { \
211 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
212 PetscInt __current_level_val = get_log_level(); \
213 PetscBool __allowed_func_val = is_function_allowed(__func__); \
214 // Print BEFORE the check \
215 if (strcmp(__func__, "LocateAllParticlesInGrid") == 0) { \
216 printf("[DEBUG LOG_ALLOW in %s] Checking: level=%d, get_log_level() returned %d, func_allowed=%d\n", \
217 __func__, (int)level, (int)__current_level_val, (int)__allowed_func_val); \
218 } \
219 if ((int)(level) <= (int)__current_level_val && __allowed_func_val) { \
220 // Print AFTER passing the check // \
221 if (strcmp(__func__, "LocateAllParticlesInGrid") == 0) { \
222 printf("[DEBUG LOG_ALLOW in %s] Check PASSED. Printing log.\n", __func__); \
223 } \
224 PetscPrintf(comm, "[%s] " fmt, __func__, ##__VA_ARGS__); \
225 } \
226 } while (0)
227-------------------------------------------------------------------------------
228*/
229
230/**
231 * @brief Synchronized logging macro that checks both the log level
232 * and whether the calling function is in the allow-list.
233 *
234 * This macro uses `PetscSynchronizedPrintf` and `PetscSynchronizedFlush` to
235 * ensure messages from different ranks are printed in a rank-ordered fashion
236 * (i.e., to avoid interleaving). It also filters out messages if the current
237 * function is not in the allow-list (`is_function_allowed(__func__)`) or the
238 * requested log level is higher than `get_log_level()`.
239 *
240 * @param scope Either LOCAL (MPI_COMM_SELF) or GLOBAL (MPI_COMM_WORLD).
241 * @param level One of LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG.
242 * @param fmt A `printf`-style format string (e.g., "Message: %ld\n").
243 * @param ... Variadic arguments to fill in `fmt`.
244 *
245 * Example usage:
246 *
247 * \code{.c}
248 * LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Debug info: rank = %ld\n", rank);
249 * LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "Synchronized info in %s\n", __func__);
250 * \endcode
251 */
252#define LOG_ALLOW_SYNC(scope, level, fmt, ...) \
253do { \
254 /* ------------------------------------------------------------------ */ \
255 /* Validate scope and pick communicator *before* any early exits. */ \
256 /* ------------------------------------------------------------------ */ \
257 MPI_Comm _comm; \
258 if ((scope) == LOCAL) _comm = MPI_COMM_SELF; \
259 else if ((scope) == GLOBAL) _comm = MPI_COMM_WORLD; \
260 else { \
261 fprintf(stderr, "LOG_ALLOW_SYNC ERROR: invalid scope (%d) at %s:%d\n", \
262 (scope), __FILE__, __LINE__); \
263 MPI_Abort(MPI_COMM_WORLD, 1); \
264 } \
265 \
266 /* ------------------------------------------------------------------ */ \
267 /* Decide whether *this* rank should actually print. */ \
268 /* ------------------------------------------------------------------ */ \
269 PetscBool _doPrint = \
270 is_function_allowed(__func__) && ((int)(level) <= (int)get_log_level()); \
271 \
272 if (_doPrint) { \
273 PetscSynchronizedPrintf(_comm, "[%s] " fmt, __func__, ##__VA_ARGS__); \
274 } \
275 \
276 /* ------------------------------------------------------------------ */ \
277 /* ALL ranks call the flush, even if they printed nothing. */ \
278 /* ------------------------------------------------------------------ */ \
279 PetscSynchronizedFlush(_comm, PETSC_STDOUT); \
280} while (0)
281
282/**
283 * @brief Logs a message inside a loop, but only every `interval` iterations.
284 *
285 * @param scope LOCAL or GLOBAL.
286 * @param level LOG_* level.
287 * @param iterVar The loop variable (e.g., i).
288 * @param interval Only log when (iterVar % interval == 0).
289 * @param fmt printf-style format string.
290 * @param ... Variadic arguments to include in the formatted message.
291 *
292 * Example:
293 * for (int i = 0; i < 100; i++) {
294 * LOG_LOOP_ALLOW(LOCAL, LOG_DEBUG, i, 10, "Value of i=%d\n", i);
295 * }
296 */
297#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt, ...) \
298 do { \
299 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
300 if ((iterVar) % (interval) == 0) { \
301 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
302 PetscPrintf(comm, "[%s] [%s=%d] " fmt, \
303 __func__, #iterVar, (iterVar), ##__VA_ARGS__); \
304 } \
305 } \
306 } while (0)
307/*
308#define LOG_LOOP_ALLOW(scope,level, iterVar, interval, fmt, ...) \
309 do { \
310 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
311 if ((iterVar) % (interval) == 0) { \
312 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
313 PetscPrintf(comm, "[%s] [Iter=%d] " fmt, \
314 __func__, (iterVar), ##__VA_ARGS__); \
315 } \
316 } \
317 } while (0)
318*/
319
320/**
321 * @brief Logs a custom message if a variable equals a specific value.
322 *
323 * This is a variadic macro for logging a single event when a condition is met.
324 * It is extremely useful for printing debug information at a specific iteration
325 * of a loop or when a state variable reaches a certain value.
326 *
327 * @param scope Either LOCAL or GLOBAL.
328 * @param level The logging level.
329 * @param var The variable to check (e.g., a loop counter 'k').
330 * @param val The value that triggers the log (e.g., 6). The log prints if var == val.
331 * @param fmt A printf-style format string.
332 * @param ... A printf-style format string and its corresponding arguments.
333 */
334#define LOG_LOOP_ALLOW_EXACT(scope, level, var, val, fmt, ...) \
335 do { \
336 /* First, perform the cheap, standard gatekeeper checks. */ \
337 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
338 /* Only if those pass, check the user's specific condition. */ \
339 if ((var) == (val)) { \
340 MPI_Comm comm = ((scope) == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
341 /* Print the standard prefix, then the user's custom message. */ \
342 PetscPrintf(comm, "[%s] [%s=%d] " fmt, \
343 __func__, #var, (var), ##__VA_ARGS__); \
344 } \
345 } \
346 } while (0)
347
348/**
349 * @brief Logs a single element of an array, given an index.
350 *
351 * @param scope Either LOCAL or GLOBAL.
352 * @param level LOG_ERROR, LOG_WARNING, LOG_INFO, or LOG_DEBUG.
353 * @param arr Pointer to the array to log from.
354 * @param length The length of the array (to prevent out-of-bounds).
355 * @param idx The index of the element to print.
356 * @param fmt The printf-style format specifier (e.g. "%g", "%f", etc.).
357 *
358 * This macro only logs if:
359 * 1) The current function is in the allow-list (`is_function_allowed(__func__)`).
360 * 2) The requested logging `level` <= the current global `get_log_level()`.
361 * 3) The index `idx` is valid (0 <= idx < length).
362 */
363#define LOG_ARRAY_ELEMENT_ALLOW(scope,level, arr, length, idx, fmt) \
364 do { \
365 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
366 if ((idx) >= 0 && (idx) < (length)) { \
367 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
368 PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", \
369 __func__, (idx), (arr)[idx]); \
370 } \
371 } \
372 } while (0)
373
374/**
375 * @brief Logs a consecutive subrange of an array.
376 *
377 * @param scope Either LOCAL or GLOBAL.
378 * @param level LOG_ERROR, LOG_WARNING, LOG_INFO, or LOG_DEBUG.
379 * @param arr Pointer to the array to log from.
380 * @param length Total length of the array.
381 * @param start Starting index of the subrange.
382 * @param end Ending index of the subrange (inclusive).
383 * @param fmt The printf-style format specifier (e.g., "%g", "%f").
384 *
385 * This macro prints each element arr[i] for i in [start, end], bounded by [0, length-1].
386 */
387#define LOG_ARRAY_SUBRANGE_ALLOW(scope,level, arr, length, start, end, fmt) \
388 do { \
389 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
390 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
391 PetscInt _start = (start) < 0 ? 0 : (start); \
392 PetscInt _end = (end) >= (length) ? (length) - 1 : (end); \
393 for (PetscInt i = _start; i <= _end; i++) { \
394 PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", __func__, i, (arr)[i]); \
395 } \
396 } \
397 } while (0)
398
399// --------------------- Function Declarations ---------------------
400
401/**
402 * @brief Retrieves the current logging level from the environment variable `LOG_LEVEL`.
403 *
404 * The function checks the `LOG_LEVEL` environment variable and sets the logging level accordingly.
405 * Supported levels are "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", and "VERBOSE".
406 * Unset or unrecognized values default to "ERROR".
407 *
408 * @return LogLevel The current logging level.
409 */
411
412/**
413 * @brief Prints the current logging level to the console.
414 *
415 * This function retrieves the log level using `get_log_level()` and prints
416 * the corresponding log level name. It helps verify the logging configuration
417 * at runtime.
418 * The log levels supported are:
419 * - `LOG_ERROR` (0) : Logs only critical errors.
420 * - `LOG_WARNING` (1) : Logs warnings and errors.
421 * - `LOG_INFO` (2) : Logs general information, warnings, and errors.
422 * - `LOG_DEBUG` (3) : Logs debugging information, info, warnings, and errors.
423 * - `LOG_TRACE` (4) : Logs fine-grained trace information.
424 * - `LOG_VERBOSE` (5) : Logs very detailed developer output.
425 * If `LOG_LEVEL` is not set, it defaults to `LOG_ERROR`.
426 * @return PetscErrorCode 0 on success.
427 */
428PetscErrorCode print_log_level(void);
429
430/**
431 * @brief Sets the global list of function names that are allowed to log.
432 *
433 * You can replace the entire list of allowed function names at runtime.
434 *
435 * @param functionList Parameter `functionList` passed to `set_allowed_functions()`.
436 * @param count Parameter `count` passed to `set_allowed_functions()`.
437 */
438void set_allowed_functions(const char** functionList, int count);
439
440/**
441 * @brief Checks if a given function is in the allow-list.
442 *
443 * This helper is used internally by the LOG_ALLOW macro.
444 *
445 * @param functionName Parameter `functionName` passed to `is_function_allowed()`.
446 * @return PetscBool indicating the result of `is_function_allowed()`.
447 */
448PetscBool is_function_allowed(const char* functionName);
449
450/**
451 * @brief Prints the coordinates of a cell's vertices.
452 *
453 * This function iterates through the eight vertices of a given cell and prints their
454 * coordinates. It is primarily used for debugging purposes to verify the correctness
455 * of cell vertex assignments.
456 *
457 * @param[in] cell Pointer to a `Cell` structure representing the cell, containing its vertices.
458 * @param[in] rank MPI rank for identification (useful in parallel environments).
459 * @return PetscErrorCode Returns 0 to indicate successful execution. Non-zero on failure.
460 *
461 * @note
462 * - Ensure that the `cell` pointer is not `NULL` before calling this function..
463 */
464PetscErrorCode LOG_CELL_VERTICES(const Cell *cell, PetscMPIInt rank);
465
466/**
467 * @brief Prints the signed distances to each face of the cell.
468 *
469 * This function iterates through the six signed distances from a point to each face of a given cell
470 * and prints their values. It is primarily used for debugging purposes to verify the correctness
471 * of distance calculations.
472 *
473 * @param[in] d An array of six `PetscReal` values representing the signed distances.
474 * The indices correspond to:
475 * - d[LEFT]: Left Face
476 * - d[RIGHT]: Right Face
477 * - d[BOTTOM]: Bottom Face
478 * - d[TOP]: Top Face
479 * - d[FRONT]: Front Face
480 * - d[BACK]: Back Face
481 *
482 * @return PetscErrorCode Returns 0 to indicate successful execution. Non-zero on failure.
483 *
484 * @note
485 * - Ensure that the `d` array is correctly populated with signed distances before calling this function.
486 */
487PetscErrorCode LOG_FACE_DISTANCES(PetscReal* d);
488
489/**
490 * @brief Prints particle fields in a table that automatically adjusts its column widths.
491 *
492 * This function retrieves data from the particle swarm and prints a table where the
493 * width of each column is determined by the maximum width needed to display the data.
494 * Only every 'printInterval'-th particle is printed.
495 *
496 * @param[in] user Pointer to the UserCtx structure.
497 * @param[in] printInterval Only every printInterval‑th particle is printed.
498 *
499 * @return PetscErrorCode Returns 0 on success.
500 */
501PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx* user, PetscInt printInterval);
502
503/**
504 * @brief Returns whether periodic particle console snapshots are enabled.
505 *
506 * This checks only the reporting contract (particles exist, cadence is enabled,
507 * and the global log level is at least INFO).
508 *
509 * @param simCtx Simulation context controlling the operation.
510 * @return PetscBool indicating the result of `IsParticleConsoleSnapshotEnabled()`.
511 */
512PetscBool IsParticleConsoleSnapshotEnabled(const SimCtx *simCtx);
513
514/**
515 * @brief Returns whether a particle console snapshot should be emitted for the
516 *
517 * completed timestep.
518 *
519 * @param simCtx Simulation context controlling the operation.
520 * @param completed_step Completed step index used by the decision helper.
521 * @return PetscBool indicating the result of `ShouldEmitPeriodicParticleConsoleSnapshot()`.
522 */
523PetscBool ShouldEmitPeriodicParticleConsoleSnapshot(const SimCtx *simCtx, PetscInt completed_step);
524
525/**
526 * @brief Emits one particle console snapshot into the main solver log.
527 *
528 * @param user Primary `UserCtx` input for the operation.
529 * @param simCtx Simulation context controlling the operation.
530 * @param step Step index associated with the operation.
531 * @return PetscErrorCode 0 on success.
532 */
533PetscErrorCode EmitParticleConsoleSnapshot(UserCtx *user, SimCtx *simCtx, PetscInt step);
534
535/* ------------------------------------------------------------------------- */
536/**
537 * @brief Free an array previously returned by LoadAllowedFunctionsFromFile().
538 *
539 * @param[in,out] funcs Array of strings to release (may be @c NULL).
540 * @param[in] n Number of entries in @p funcs. Ignored if @p funcs is
541 * @c NULL.
542 *
543 * @return 0 on success or a PETSc error code.
544 */
545PetscErrorCode FreeAllowedFunctions(char **funcs, PetscInt n);
546
547/**
548 * @brief Load function names from a text file.
549 *
550 * The file is expected to contain **one identifier per line**. Blank lines and
551 * lines whose first non‑blank character is a <tt>#</tt> are silently skipped so
552 * the file can include comments. Example:
553 *
554 * @code{.txt}
555 * # Allowed function list
556 * main
557 * InitializeSimulation
558 * InterpolateAllFieldsToSwarm # inline comments are OK, too
559 * @endcode
560 *
561 * The routine allocates memory as needed (growing an internal buffer with
562 * @c PetscRealloc()) and returns the resulting array and its length to the
563 * caller. Use FreeAllowedFunctions() to clean up when done.
564 *
565 * @param[in] filename Path of the configuration file to read.
566 * @param[out] funcsOut On success, points to a freshly‑allocated array of
567 * <tt>char*</tt> (size @p nOut).
568 * @param[out] nOut Number of valid entries in @p funcsOut.
569 *
570 * @return 0 on success, or a PETSc error code on failure (e.g. I/O error, OOM).
571 */
572PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[],
573 char ***funcsOut,
574 PetscInt *nOut);
575
576
577/**
578 * @brief Helper function to convert BCFace enum to a string representation.
579 * @param[in] face The BCFace enum value.
580 * @return Pointer to a constant string representing the face.
581 */
582const char* BCFaceToString(BCFace face);
583
584/**
585 * @brief Helper function to convert FieldInitialization to a string representation.
586 * @param[in] FieldInitialization The FieldInitialization value.
587 * @return Pointer to a constant string representing the FieldInitialization.
588 */
589const char* FieldInitializationToString(PetscInt FieldInitialization);
590
591/**
592 * @brief Helper function to convert ParticleInitialization to a string representation.
593 * @param[in] ParticleInitialization The ParticleInitialization enum value.
594 * @return Pointer to a constant string representing the FieldInitialization.
595 */
596const char* ParticleInitializationToString(ParticleInitializationType ParticleInitialization);
597
598/**
599 * @brief Helper function to convert LES Flag to a string representation.
600 * @param[in] LESFlag The LES flag value.
601 * @return Pointer to a constant string representing the LES Flag.
602 */
603const char* LESModelToString(LESModelType LESFlag);
604
605/**
606 * @brief Helper function to convert Momentum Solver flag to a string representation.
607 * @param[in] SolverFlag The Momentum Solver flag value.
608 * @return Pointer to a constant string representing the MomentumSolverType.
609 */
610const char* MomentumSolverTypeToString(MomentumSolverType SolverFlag);
611
612/**
613 * @brief Helper function to convert BCType enum to a string representation.
614 * @param[in] type The BCType enum value.
615 * @return Pointer to a constant string representing the BC type.
616 */
617const char* BCTypeToString(BCType type);
618
619/**
620 * @brief Converts a BCHandlerType enum to its string representation.
621 *
622 * Provides a descriptive string for a specific boundary condition implementation strategy.
623 * This is crucial for logging the exact behavior configured for a face.
624 *
625 * @param handler_type The BCHandlerType enum value (e.g., BC_HANDLER_WALL_NOSLIP).
626 * @return A constant character string corresponding to the enum. Returns
627 * "UNKNOWN_HANDLER" if the enum value is not recognized.
628 */
629const char* BCHandlerTypeToString(BCHandlerType handler_type);
630
631/**
632 * @brief A custom KSP monitor that logs to a file and optionally to the console.
633 *
634 * This function unconditionally calls the standard true residual monitor to log to a
635 * file viewer provided in the context. It also checks a flag in the context
636* and, if true, calls the monitor again to log to standard output.
637 *
638 * @param ksp The Krylov subspace context.
639 * @param it The current iteration number.
640 * @param rnorm The preconditioned residual norm.
641 * @param ctx A pointer to the DualMonitorCtx structure.
642 * @return PetscErrorCode 0 on success.
643 */
644PetscErrorCode DualKSPMonitor(KSP ksp, PetscInt it, PetscReal rnorm, void *ctx);
645
646/**
647 * @brief Destroys the DualMonitorCtx.
648 *
649 * This function is passed to KSPMonitorSet to ensure the viewer is
650 * properly destroyed and the context memory is freed when the KSP is destroyed.
651 * @param ctx a pointer to the context pointer to be destroyed
652 * @return PetscErrorCode
653 */
654PetscErrorCode DualMonitorDestroy(void **ctx);
655
656/**
657 * @brief Logs continuity metrics for a single block to a file.
658 *
659 * This function should be called for each block, once per timestep. It opens a
660 * central log file in append mode. To ensure the header is written only once,
661 * it checks if it is processing block 0 on the simulation's start step.
662 *
663 * @param user A pointer to the UserCtx for the specific block whose metrics
664 * are to be logged. The function accesses both global (SimCtx)
665 * and local (user->...) data.
666 * @return PetscErrorCode 0 on success.
667 */
668PetscErrorCode LOG_CONTINUITY_METRICS(UserCtx *user);
669
670/**
671 * @brief A function that outputs the name of the current level in the ParticleLocation enum.
672 * @param level The ParticleLocation enum value.
673 * @return A constant character string corresponding to the enum. Returns
674 * "UNKNOWN_LEVEL" if the enum value is not recognized.
675 */
677
678/*================================================================================*
679 * PROGRESS BAR UTILITY *
680 *================================================================================*/
681
682/**
683 * @brief Prints a progress bar to the console.
684 *
685 * This function should only be called by the root process (rank 0). It uses
686 * a carriage return `\r` to overwrite the same line in the terminal, creating
687 * a dynamic progress bar.
688 *
689 * @param step The current step index from the loop (e.g., from 0 to N-1).
690 * @param startStep The global starting step number of the simulation.
691 * @param totalSteps The total number of steps to be run in this simulation instance.
692 * @param currentTime The current simulation time to display.
693 */
694void PrintProgressBar(PetscInt step, PetscInt startStep, PetscInt totalSteps, PetscReal currentTime);
695
696/**
697 * @brief Initializes the custom profiling system using configuration from SimCtx.
698 *
699 * This function sets up the internal data structures for tracking function
700 * performance. It reads the list of "critical functions" from the provided
701 * SimCtx and marks them for per-step logging at LOG_INFO level.
702 *
703 * It should be called once at the beginning of the application, after
704 * CreateSimulationContext() but before the main time loop.
705 *
706 * @param simCtx The master simulation context, which contains the list of
707 * critical function names to always log.
708 * @return PetscErrorCode
709 */
710PetscErrorCode ProfilingInitialize(SimCtx *simCtx);
711
712/**
713 * @brief Resets per-timestep profiling counters for the next solver step.
714 *
715 * This clears transient counters without discarding cumulative totals used by
716 * final profiling summaries.
717 *
718 * @return PetscErrorCode 0 on success.
719 */
720PetscErrorCode ProfilingResetTimestepCounters(void);
721
722/**
723 * @brief Logs the performance summary for the current timestep and resets timers.
724 *
725 * Depending on the configured profiling timestep mode, this function writes
726 * per-step profiling rows to the configured profiling log file:
727 * - `off`: writes nothing
728 * - `selected`: writes only functions marked for per-step reporting
729 * - `all`: writes every instrumented function that ran in the timestep
730 *
731 * It must be called once per timestep, typically at the end of the main loop.
732 * After logging, it resets the per-step counters and timers.
733 *
734 * @param simCtx The simulation context holding profiling output settings.
735 * @param step The current simulation step number, for logging context.
736 * @return PetscErrorCode
737 */
738PetscErrorCode ProfilingLogTimestepSummary(SimCtx *simCtx, PetscInt step);
739
740
741/**
742 * @brief the profiling excercise and build a profiling summary which is then printed to a log file.
743 *
744 * @param simCtx The Simulation Context Structure that can contains all the data regarding the simulation.
745 *
746 * @return PetscErrorCode 0 on success.
747 */
748PetscErrorCode ProfilingFinalize(SimCtx *simCtx);
749
750// --- Internal functions, do not call directly ---
751// These are called by the macros below.
752/**
753 * @brief Internal profiling hook invoked by `PROFILE_FUNCTION_BEGIN`.
754 * @param func_name Function name used by the profiling helper.
755 */
756void _ProfilingStart(const char *func_name);
757/**
758 * @brief Internal profiling hook invoked by `PROFILE_FUNCTION_END`.
759 * @param func_name Function name used by the profiling helper.
760 */
761void _ProfilingEnd(const char *func_name);
762
763
764/**
765 * @brief Marks the beginning of a profiled code block (typically a function).
766 *
767 * Place this macro at the very beginning of a function you wish to profile.
768 * It automatically captures the function's name and starts a wall-clock timer.
769 */
770#define PROFILE_FUNCTION_BEGIN \
771 _ProfilingStart(__FUNCT__)
772
773/**
774 * @brief Marks the end of a profiled code block.
775 *
776 * Place this macro just before every return point in a function that starts
777 * with PROFILE_FUNCTION_BEGIN. It stops the timer and accumulates the results.
778 */
779#define PROFILE_FUNCTION_END \
780 _ProfilingEnd(__FUNCT__)
781
782
783/**
784 * @brief Computes and logs the local and global min/max values of a 3-component vector field.
785 *
786 * This utility function inspects a PETSc Vec associated with a DMDA and calculates the
787 * minimum and maximum values for each of its three components (e.g., x, y, z) both for the
788 * local data on the current MPI rank and for the entire global domain.
789 *
790 * It uses the same "smart" logic as the flow solver, ignoring the padding nodes at the
791 * IM, JM, and KM boundaries of the grid. The results are printed to the standard output
792 * in a formatted, easy-to-read table.
793 *
794 * @param[in] user Pointer to the user-defined context. Used for grid information (IM, JM, KM)
795 * and MPI rank.
796 * @param[in] fieldName A string descriptor for the field being analyzed (e.g., "Velocity",
797 * "Coordinates"). This is used for clear log output.
798 *
799 * @return PetscErrorCode Returns 0 on success, non-zero on failure.
800 */
801PetscErrorCode LOG_FIELD_MIN_MAX(UserCtx *user, const char *fieldName);
802
803/**
804 * @brief Logs the anatomy of a specified field at key boundary locations,
805 * respecting the solver's specific grid and variable architecture.
806 *
807 * This intelligent diagnostic function inspects a PETSc Vec and prints its values
808 * at critical boundary locations (-Xi/+Xi, -Eta/+Eta, -Zeta/+Zeta). It is "architecture-aware":
809 *
810 * - **Cell-Centered Fields ("Ucat", "P"):** It correctly applies the "Shifted Index Architecture,"
811 * where the value for geometric `Cell i` is stored at array index `i+1`. It labels
812 * the output to clearly distinguish between true physical values and ghost values.
813 * - **Face-Centered Fields ("Ucont"):** It uses a direct index mapping, where the value for
814 * the face at `Node i` is stored at index `i`.
815 * - **Node-Centered Fields ("Coordinates"):** It uses a direct index mapping, where the value for
816 * `Node i` is stored at index `i`.
817 *
818 * The output is synchronized across MPI ranks to ensure readability and focuses on a
819 * slice through the center of the domain to be concise.
820 *
821 * @param user A pointer to the UserCtx structure containing the DMs and Vecs.
822 * @param field_name A string identifier for the field to log (e.g., "Ucat", "P", "Ucont", "Coordinates").
823 * @param stage_name A string identifier for the current simulation stage (e.g., "After Advection").
824 * @return PetscErrorCode Returns 0 on success, non-zero on failure.
825 */
826PetscErrorCode LOG_FIELD_ANATOMY(UserCtx *user, const char *field_name, const char *stage_name);
827
828/**
829 * @brief Logs the interpolation error between the analytical and computed solutions.
830 *
831 * @param user Primary `UserCtx` input for the operation.
832 * @return PetscErrorCode 0 on success.
833 */
834PetscErrorCode LOG_INTERPOLATION_ERROR(UserCtx *user);
835
836/**
837 * @brief Logs particle-to-grid scatter verification metrics for the prescribed scalar truth path.
838 *
839 * @param user Primary `UserCtx` input for the operation.
840 * @return PetscErrorCode 0 on success.
841 */
842PetscErrorCode LOG_SCATTER_METRICS(UserCtx *user);
843
844/**
845 * @brief Resets the aggregate per-timestep search instrumentation counters.
846 *
847 * @param simCtx Simulation context whose search metrics should be zeroed.
848 * @return PetscErrorCode 0 on success.
849 */
850PetscErrorCode ResetSearchMetrics(SimCtx *simCtx);
851
852/**
853 * @brief Computes advanced particle statistics and stores them in SimCtx.
854 *
855 * This function calculates:
856 * - Particle load imbalance across MPI ranks.
857 * - The total number of grid cells occupied by at least one particle.
858 *
859 * It requires that CalculateParticleCountPerCell() has been called prior to its
860 * execution. It uses collective MPI operations and must be called by all ranks.
861 *
862 * @param user Pointer to the UserCtx.
863 * @return PetscErrorCode 0 on success.
864 */
865PetscErrorCode CalculateAdvancedParticleMetrics(UserCtx *user);
866
867/**
868 * @brief Writes compact runtime search metrics to CSV and optionally to console.
869 *
870 * The CSV artifact is always written for particle-enabled runs. Console output
871 * remains gated by normal logging level and function allow-listing.
872 *
873 * @param user Pointer to the UserCtx.
874 * @return PetscErrorCode 0 on success.
875 */
876PetscErrorCode LOG_SEARCH_METRICS(UserCtx *user);
877
878/**
879 * @brief Logs particle swarm metrics, adapting its behavior based on a boolean flag in SimCtx.
880 *
881 * This function serves a dual purpose:
882 * 1. If simCtx->isInitializationPhase is PETSC_TRUE, it logs settlement
883 * diagnostics to "Initialization_Metrics.log", using the provided stageName.
884 * 2. If simCtx->isInitializationPhase is PETSC_FALSE, it logs regular
885 * timestep metrics to "Particle_Metrics.log".
886 *
887 * @param user A pointer to the UserCtx.
888 * @param stageName A descriptive label recorded in the metrics log (for example,
889 * initialization stage name or "Timestep Metrics").
890 * @return PetscErrorCode 0 on success.
891 */
892PetscErrorCode LOG_PARTICLE_METRICS(UserCtx *user, const char *stageName);
893#endif // LOGGING_H
void set_allowed_functions(const char **functionList, int count)
Sets the global list of function names that are allowed to log.
Definition logging.c:152
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:2248
const char * BCHandlerTypeToString(BCHandlerType handler_type)
Converts a BCHandlerType enum to its string representation.
Definition logging.c:771
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:183
const char * FieldInitializationToString(PetscInt FieldInitialization)
Helper function to convert FieldInitialization to a string representation.
Definition logging.c:687
PetscErrorCode DualMonitorDestroy(void **ctx)
Destroys the DualMonitorCtx.
Definition logging.c:808
PetscBool log_to_console
Definition logging.h:57
PetscErrorCode LOG_INTERPOLATION_ERROR(UserCtx *user)
Logs the interpolation error between the analytical and computed solutions.
Definition logging.c:1785
PetscBool ShouldEmitPeriodicParticleConsoleSnapshot(const SimCtx *simCtx, PetscInt completed_step)
Returns whether a particle console snapshot should be emitted for the.
Definition logging.c:542
const char * BCFaceToString(BCFace face)
Helper function to convert BCFace enum to a string representation.
Definition logging.c:669
PetscErrorCode FreeAllowedFunctions(char **funcs, PetscInt n)
Free an array previously returned by LoadAllowedFunctionsFromFile().
Definition logging.c:650
PetscBool IsParticleConsoleSnapshotEnabled(const SimCtx *simCtx)
Returns whether periodic particle console snapshots are enabled.
Definition logging.c:525
PetscErrorCode print_log_level(void)
Prints the current logging level to the console.
Definition logging.c:116
PetscErrorCode EmitParticleConsoleSnapshot(UserCtx *user, SimCtx *simCtx, PetscInt step)
Emits one particle console snapshot into the main solver log.
Definition logging.c:556
PetscReal bnorm
Definition logging.h:58
PetscErrorCode ProfilingFinalize(SimCtx *simCtx)
the profiling excercise and build a profiling summary which is then printed to a log file.
Definition logging.c:1214
PetscInt step
Definition logging.h:59
PetscErrorCode LoadAllowedFunctionsFromFile(const char filename[], char ***funcsOut, PetscInt *nOut)
Load function names from a text file.
Definition logging.c:596
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:1367
void PrintProgressBar(PetscInt step, PetscInt startStep, PetscInt totalSteps, PetscReal currentTime)
Prints a progress bar to the console.
Definition logging.c:1320
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:1515
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:84
PetscErrorCode ProfilingLogTimestepSummary(SimCtx *simCtx, PetscInt step)
Logs the performance summary for the current timestep and resets timers.
Definition logging.c:1121
PetscErrorCode LOG_FACE_DISTANCES(PetscReal *d)
Prints the signed distances to each face of the cell.
Definition logging.c:230
PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx *user, PetscInt printInterval)
Prints particle fields in a table that automatically adjusts its column widths.
Definition logging.c:397
void _ProfilingEnd(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_END.
Definition logging.c:1082
const char * BCTypeToString(BCType type)
Helper function to convert BCType enum to a string representation.
Definition logging.c:751
PetscErrorCode CalculateAdvancedParticleMetrics(UserCtx *user)
Computes advanced particle statistics and stores them in SimCtx.
Definition logging.c:2194
const char * ParticleLocationStatusToString(ParticleLocationStatus level)
A function that outputs the name of the current level in the ParticleLocation enum.
Definition logging.c:973
PetscErrorCode LOG_SCATTER_METRICS(UserCtx *user)
Logs particle-to-grid scatter verification metrics for the prescribed scalar truth path.
Definition logging.c:1861
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:847
PetscErrorCode LOG_CONTINUITY_METRICS(UserCtx *user)
Logs continuity metrics for a single block to a file.
Definition logging.c:914
PetscErrorCode LOG_SEARCH_METRICS(UserCtx *user)
Writes compact runtime search metrics to CSV and optionally to console.
Definition logging.c:2043
PetscErrorCode ProfilingInitialize(SimCtx *simCtx)
Initializes the custom profiling system using configuration from SimCtx.
Definition logging.c:1044
LogLevel
Enumeration of logging levels.
Definition logging.h:27
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:28
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:32
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:31
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:33
const char * LESModelToString(LESModelType LESFlag)
Helper function to convert LES Flag to a string representation.
Definition logging.c:720
PetscErrorCode LOG_CELL_VERTICES(const Cell *cell, PetscMPIInt rank)
Prints the coordinates of a cell's vertices.
Definition logging.c:205
PetscErrorCode ProfilingResetTimestepCounters(void)
Resets per-timestep profiling counters for the next solver step.
Definition logging.c:1104
PetscErrorCode ResetSearchMetrics(SimCtx *simCtx)
Resets the aggregate per-timestep search instrumentation counters.
Definition logging.c:2012
const char * MomentumSolverTypeToString(MomentumSolverType SolverFlag)
Helper function to convert Momentum Solver flag to a string representation.
Definition logging.c:736
FILE * file_handle
Definition logging.h:56
PetscInt block_id
Definition logging.h:60
const char * ParticleInitializationToString(ParticleInitializationType ParticleInitialization)
Helper function to convert ParticleInitialization to a string representation.
Definition logging.c:703
void _ProfilingStart(const char *func_name)
Internal profiling hook invoked by PROFILE_FUNCTION_BEGIN.
Definition logging.c:1068
Context for a dual-purpose KSP monitor.
Definition logging.h:55
Main header file for a complex fluid dynamics solver.
LESModelType
Identifies the six logical faces of a structured computational block.
Definition variables.h:488
BCType
Defines the general mathematical/physical Category of a boundary.
Definition variables.h:251
ParticleInitializationType
Enumerator to identify the particle initialization strategy.
Definition variables.h:508
ParticleLocationStatus
Defines the state of a particle with respect to its location and migration status during the iterativ...
Definition variables.h:135
BCHandlerType
Defines the specific computational "strategy" for a boundary handler.
Definition variables.h:271
MomentumSolverType
Enumerator to identify the implemented momentum solver strategies.
Definition variables.h:502
BCFace
Identifies the six logical faces of a structured computational block.
Definition variables.h:244
Defines the vertices of a single hexahedral grid cell.
Definition variables.h:160
The master context for the entire simulation.
Definition variables.h:643
User-defined context containing data specific to a single computational grid level.
Definition variables.h:811