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