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