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