PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions
logging.h File Reference

Logging utilities and macros for PETSc-based applications. More...

#include <petsc.h>
#include <stdlib.h>
#include <string.h>
#include <petscsys.h>
#include <ctype.h>
#include "variables.h"
#include "Boundaries.h"
Include dependency graph for logging.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  DualMonitorCtx
 Context for a dual-purpose KSP monitor. More...
 

Macros

#define LOCAL   0
 Logging scope definitions for controlling message output.
 
#define GLOBAL   1
 Scope for global logging across all processes.
 
#define LOG(scope, level, fmt, ...)
 Logging macro for PETSc-based applications with scope control.
 
#define LOG_DEFAULT(level, fmt, ...)
 Default logging macro for PETSc-based applications.
 
#define LOG_SYNC(scope, level, fmt, ...)
 Logging macro for PETSc-based applications with scope control, using synchronized output across processes.
 
#define LOG_SYNC_DEFAULT(level, fmt, ...)
 Default synchronized logging macro for PETSc-based applications.
 
#define LOG_ALLOW(scope, level, fmt, ...)
 Logging macro that checks both the log level and whether the calling function is in the allowed-function list before printing.
 
#define LOG_ALLOW_SYNC(scope, level, fmt, ...)
 Synchronized logging macro that checks both the log level and whether the calling function is in the allow-list.
 
#define LOG_LOOP_ALLOW(scope, level, iterVar, interval, fmt, ...)
 Logs a message inside a loop, but only every interval iterations.
 
#define LOG_LOOP_ALLOW_EXACT(scope, level, var, val, fmt, ...)
 Logs a custom message if a variable equals a specific value.
 
#define LOG_ARRAY_ELEMENT_ALLOW(scope, level, arr, length, idx, fmt)
 Logs a single element of an array, given an index.
 
#define LOG_ARRAY_SUBRANGE_ALLOW(scope, level, arr, length, start, end, fmt)
 Logs a consecutive subrange of an array.
 
#define PROFILE_FUNCTION_BEGIN    _ProfilingStart(__FUNCT__)
 Marks the beginning of a profiled code block (typically a function).
 
#define PROFILE_FUNCTION_END    _ProfilingEnd(__FUNCT__)
 Marks the end of a profiled code block.
 

Enumerations

enum  LogLevel {
  LOG_ERROR = 0 , LOG_WARNING , LOG_INFO , LOG_DEBUG ,
  LOG_TRACE , LOG_VERBOSE
}
 Enumeration of logging levels. More...
 

Functions

LogLevel get_log_level ()
 Retrieves the current logging level from the environment variable LOG_LEVEL.
 
PetscErrorCode print_log_level (void)
 Prints the current logging level to the console.
 
void set_allowed_functions (const char **functionList, int count)
 Sets the global list of function names that are allowed to log.
 
PetscBool is_function_allowed (const char *functionName)
 Checks if a given function is in the allow-list.
 
PetscErrorCode LOG_CELL_VERTICES (const Cell *cell, PetscMPIInt rank)
 Prints the coordinates of a cell's vertices.
 
PetscErrorCode LOG_FACE_DISTANCES (PetscReal *d)
 Prints the signed distances to each face of the cell.
 
PetscErrorCode LOG_PARTICLE_FIELDS (UserCtx *user, PetscInt printInterval)
 Prints particle fields in a table that automatically adjusts its column widths.
 
PetscBool IsParticleConsoleSnapshotEnabled (const SimCtx *simCtx)
 Returns whether periodic particle console snapshots are enabled.
 
PetscBool ShouldEmitPeriodicParticleConsoleSnapshot (const SimCtx *simCtx, PetscInt completed_step)
 Returns whether a particle console snapshot should be emitted for the.
 
PetscErrorCode EmitParticleConsoleSnapshot (UserCtx *user, SimCtx *simCtx, PetscInt step)
 Emits one particle console snapshot into the main solver log.
 
PetscErrorCode FreeAllowedFunctions (char **funcs, PetscInt n)
 Free an array previously returned by LoadAllowedFunctionsFromFile().
 
PetscErrorCode LoadAllowedFunctionsFromFile (const char filename[], char ***funcsOut, PetscInt *nOut)
 Load function names from a text file.
 
const char * BCFaceToString (BCFace face)
 Helper function to convert BCFace enum to a string representation.
 
const char * FieldInitializationToString (PetscInt FieldInitialization)
 Helper function to convert FieldInitialization to a string representation.
 
const char * ParticleInitializationToString (ParticleInitializationType ParticleInitialization)
 Helper function to convert ParticleInitialization to a string representation.
 
const char * LESModelToString (LESModelType LESFlag)
 Helper function to convert LES Flag to a string representation.
 
const char * MomentumSolverTypeToString (MomentumSolverType SolverFlag)
 Helper function to convert Momentum Solver flag to a string representation.
 
const char * BCTypeToString (BCType type)
 Helper function to convert BCType enum to a string representation.
 
const char * BCHandlerTypeToString (BCHandlerType handler_type)
 Converts a BCHandlerType enum to its string representation.
 
PetscErrorCode DualKSPMonitor (KSP ksp, PetscInt it, PetscReal rnorm, void *ctx)
 A custom KSP monitor that logs to a file and optionally to the console.
 
PetscErrorCode DualMonitorDestroy (void **ctx)
 Destroys the DualMonitorCtx.
 
PetscErrorCode LOG_CONTINUITY_METRICS (UserCtx *user)
 Logs continuity metrics for a single block to a file.
 
PetscErrorCode LOG_SOLUTION_CONVERGENCE (SimCtx *simCtx)
 Logs physical solution-convergence metrics once per completed timestep.
 
const char * ParticleLocationStatusToString (ParticleLocationStatus level)
 A function that outputs the name of the current level in the ParticleLocation enum.
 
void PrintProgressBar (PetscInt step, PetscInt startStep, PetscInt totalSteps, PetscReal currentTime)
 Prints a progress bar to the console.
 
PetscErrorCode ProfilingInitialize (SimCtx *simCtx)
 Initializes the custom profiling system using configuration from SimCtx.
 
PetscErrorCode ProfilingResetTimestepCounters (void)
 Resets per-timestep profiling counters for the next solver step.
 
PetscErrorCode ProfilingLogTimestepSummary (SimCtx *simCtx, PetscInt step)
 Logs the performance summary for the current timestep and resets timers.
 
PetscErrorCode RuntimeMemoryLogSample (SimCtx *simCtx, PetscInt step, const char *event, const char *reason)
 Append a reduced runtime memory sample to the configured memory log.
 
PetscErrorCode ProfilingFinalize (SimCtx *simCtx)
 the profiling excercise and build a profiling summary which is then printed to a log file.
 
void _ProfilingStart (const char *func_name)
 Internal profiling hook invoked by PROFILE_FUNCTION_BEGIN.
 
void _ProfilingEnd (const char *func_name)
 Internal profiling hook invoked by PROFILE_FUNCTION_END.
 
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.
 
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 grid and variable architecture.
 
PetscErrorCode LOG_INTERPOLATION_ERROR (UserCtx *user)
 Logs the interpolation error between the analytical and computed solutions.
 
PetscErrorCode LOG_SCATTER_METRICS (UserCtx *user)
 Logs particle-to-grid scatter verification metrics for the prescribed scalar truth path.
 
PetscErrorCode ResetSearchMetrics (SimCtx *simCtx)
 Resets the aggregate per-timestep search instrumentation counters.
 
PetscErrorCode CalculateAdvancedParticleMetrics (UserCtx *user)
 Computes advanced particle statistics and stores them in SimCtx.
 
PetscErrorCode LOG_SEARCH_METRICS (UserCtx *user)
 Writes compact runtime search metrics to CSV and optionally to console.
 
PetscErrorCode LOG_PARTICLE_METRICS (UserCtx *user, const char *stageName)
 Logs particle swarm metrics, adapting its behavior based on a boolean flag in SimCtx.
 

Detailed Description

Logging utilities and macros for PETSc-based applications.

This header defines logging levels, scopes, and macros for consistent logging throughout the application. It provides functions to retrieve the current logging level and macros to simplify logging with scope control.

Definition in file logging.h.


Data Structure Documentation

◆ DualMonitorCtx

struct DualMonitorCtx

Context for a dual-purpose KSP monitor.

This struct holds a file viewer for unconditional logging and a boolean flag to enable/disable optional logging to the console.

Definition at line 55 of file logging.h.

Data Fields
FILE * file_handle
PetscBool log_to_console
PetscReal bnorm
PetscInt step
PetscInt block_id

Macro Definition Documentation

◆ LOCAL

#define LOCAL   0

Logging scope definitions for controlling message output.

  • LOCAL: Logs on the current process using MPI_COMM_SELF.
  • GLOBAL: Logs across all processes using MPI_COMM_WORLD. Scope for local logging on the current process.

Definition at line 44 of file logging.h.

◆ GLOBAL

#define GLOBAL   1

Scope for global logging across all processes.

Definition at line 45 of file logging.h.

◆ LOG

#define LOG (   scope,
  level,
  fmt,
  ... 
)
Value:
do { \
/* Determine the MPI communicator based on the scope */ \
MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
/* Check if the log level is within the allowed range */ \
if ((int)(level) <= (int)get_log_level()) { \
/* Print the message to the specified communicator */ \
PetscPrintf(comm, fmt, ##__VA_ARGS__); \
} \
} while (0)
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:84

Logging macro for PETSc-based applications with scope control.

This macro provides a convenient way to log messages with different scopes (LOCAL or GLOBAL) and severity levels. It utilizes PETSc's PetscPrintf function for message output.

Parameters
scopeSpecifies the logging scope:
  • LOCAL: Logs on the current process using MPI_COMM_SELF.
  • GLOBAL: Logs on all processes using MPI_COMM_WORLD.
levelThe severity level of the message (e.g., LOG_INFO, LOG_ERROR).
fmtThe format string for the message (similar to printf).
...Additional arguments for the format string (optional).

Example usage: LOG(LOCAL, LOG_ERROR, "An error occurred at index %ld.\n", idx); LOG(GLOBAL, LOG_INFO, "Grid size: %ld x %ld x %ld.\n", nx, ny, nz);

Definition at line 83 of file logging.h.

84 { \
85 /* Determine the MPI communicator based on the scope */ \
86 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
87 /* Check if the log level is within the allowed range */ \
88 if ((int)(level) <= (int)get_log_level()) { \
89 /* Print the message to the specified communicator */ \
90 PetscPrintf(comm, fmt, ##__VA_ARGS__); \
91 } \
92 } while (0)

◆ LOG_DEFAULT

#define LOG_DEFAULT (   level,
  fmt,
  ... 
)
Value:
do { \
/* Set the communicator to global (MPI_COMM_WORLD) by default */ \
MPI_Comm comm = MPI_COMM_WORLD; \
/* Check if the log level is within the allowed range */ \
if ((int)(level) <= (int)get_log_level()) { \
/* Print the message using PetscPrintf with the global communicator */ \
PetscPrintf(comm, fmt, ##__VA_ARGS__); \
} \
} while (0)

Default logging macro for PETSc-based applications.

This macro simplifies logging by defaulting the scope to GLOBAL (i.e., MPI_COMM_WORLD) and providing a convenient interface for common logging needs.

Parameters
levelThe severity level of the message (e.g., LOG_ERROR, LOG_INFO).
fmtThe format string for the log message (similar to printf).
...Additional arguments for the format string (optional).

Example usage: LOG_DEFAULT(LOG_ERROR, "Error occurred at index %ld.\n", idx); LOG_DEFAULT(LOG_INFO, "Grid size: %ld x %ld x %ld.\n", nx, ny, nz);

Note
  • By default, this macro logs across all MPI processes using MPI_COMM_WORLD.
  • If finer control (e.g., local logging) is required, use the more general LOG macro.
  • The log level is filtered based on the value returned by get_log_level().

Definition at line 114 of file logging.h.

115 { \
116 /* Set the communicator to global (MPI_COMM_WORLD) by default */ \
117 MPI_Comm comm = MPI_COMM_WORLD; \
118 /* Check if the log level is within the allowed range */ \
119 if ((int)(level) <= (int)get_log_level()) { \
120 /* Print the message using PetscPrintf with the global communicator */ \
121 PetscPrintf(comm, fmt, ##__VA_ARGS__); \
122 } \
123 } while (0)

◆ LOG_SYNC

#define LOG_SYNC (   scope,
  level,
  fmt,
  ... 
)
Value:
do { \
/* Determine the MPI communicator based on the scope */ \
MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
/* Check if the log level is within the allowed range */ \
if ((int)(level) <= (int)get_log_level()) { \
/* Synchronized print (collective) on the specified communicator */ \
PetscSynchronizedPrintf(comm, fmt, ##__VA_ARGS__); \
/* Ensure all ranks have finished printing before continuing */ \
PetscSynchronizedFlush(comm, PETSC_STDOUT); \
} \
} while (0)

Logging macro for PETSc-based applications with scope control, using synchronized output across processes.

This macro uses PetscSynchronizedPrintf and PetscSynchronizedFlush to ensure messages from different ranks are printed in a synchronized (rank-by-rank) manner, preventing interleaved outputs.

Parameters
scopeSpecifies the logging scope:
  • LOCAL: Logs on the current process using MPI_COMM_SELF.
  • GLOBAL: Logs on all processes using MPI_COMM_WORLD.
levelThe severity level of the message (e.g., LOG_INFO, LOG_ERROR).
fmtThe format string for the message (similar to printf).
...Additional arguments for the format string (optional).

Example usage: LOG_SYNC(LOCAL, LOG_ERROR, "An error occurred at index %ld.\n", idx); LOG_SYNC(GLOBAL, LOG_INFO, "Synchronized info: rank = %ld.\n", rank);

Definition at line 144 of file logging.h.

145 { \
146 /* Determine the MPI communicator based on the scope */ \
147 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
148 /* Check if the log level is within the allowed range */ \
149 if ((int)(level) <= (int)get_log_level()) { \
150 /* Synchronized print (collective) on the specified communicator */ \
151 PetscSynchronizedPrintf(comm, fmt, ##__VA_ARGS__); \
152 /* Ensure all ranks have finished printing before continuing */ \
153 PetscSynchronizedFlush(comm, PETSC_STDOUT); \
154 } \
155 } while (0)

◆ LOG_SYNC_DEFAULT

#define LOG_SYNC_DEFAULT (   level,
  fmt,
  ... 
)
Value:
do { \
if ((int)(level) <= (int)get_log_level()) { \
PetscSynchronizedPrintf(MPI_COMM_WORLD, fmt, ##__VA_ARGS__); \
PetscSynchronizedFlush(MPI_COMM_WORLD, PETSC_STDOUT); \
} \
} while (0)

Default synchronized logging macro for PETSc-based applications.

This macro simplifies logging by defaulting the scope to GLOBAL (i.e., MPI_COMM_WORLD) and provides synchronized output across all processes.

Parameters
levelThe severity level of the message (e.g., LOG_ERROR, LOG_INFO).
fmtThe format string for the log message (similar to printf).
...Additional arguments for the format string (optional).

Example usage: LOG_SYNC_DEFAULT(LOG_ERROR, "Error at index %ld.\n", idx); LOG_SYNC_DEFAULT(LOG_INFO, "Process rank: %ld.\n", rank);

Note
  • By default, this macro logs across all MPI processes using MPI_COMM_WORLD.
  • If local (per-process) logging is required, use the more general LOG_SYNC macro.
  • The log level is filtered based on the value returned by get_log_level().

Definition at line 177 of file logging.h.

178 { \
179 if ((int)(level) <= (int)get_log_level()) { \
180 PetscSynchronizedPrintf(MPI_COMM_WORLD, fmt, ##__VA_ARGS__); \
181 PetscSynchronizedFlush(MPI_COMM_WORLD, PETSC_STDOUT); \
182 } \
183 } while (0)

◆ LOG_ALLOW

#define LOG_ALLOW (   scope,
  level,
  fmt,
  ... 
)
Value:
do { \
MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
if ((int)(level) <= (int)get_log_level() && is_function_allowed(__func__)) { \
PetscPrintf(comm, "[%s] " fmt, __func__, ##__VA_ARGS__); \
} \
} while (0)
PetscBool is_function_allowed(const char *functionName)
Checks if a given function is in the allow-list.
Definition logging.c:183

Logging macro that checks both the log level and whether the calling function is in the allowed-function list before printing.

Useful for selective, per-function logging.

Parameters
scopeSpecifies the logging scope (LOCAL or GLOBAL).
levelThe severity level of the message (e.g., LOG_INFO, LOG_ERROR).
fmtThe format string for the message (similar to printf).
...Additional arguments for the format string (optional).

Example usage: LOG_ALLOW(LOCAL, LOG_DEBUG, "Debugging info in function: %s\n", func);

Definition at line 199 of file logging.h.

200 { \
201 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
202 if ((int)(level) <= (int)get_log_level() && is_function_allowed(__func__)) { \
203 PetscPrintf(comm, "[%s] " fmt, __func__, ##__VA_ARGS__); \
204 } \
205 } while (0)

◆ LOG_ALLOW_SYNC

#define LOG_ALLOW_SYNC (   scope,
  level,
  fmt,
  ... 
)
Value:
do { \
/* ------------------------------------------------------------------ */ \
/* Validate scope and pick communicator *before* any early exits. */ \
/* ------------------------------------------------------------------ */ \
MPI_Comm _comm; \
if ((scope) == LOCAL) _comm = MPI_COMM_SELF; \
else if ((scope) == GLOBAL) _comm = MPI_COMM_WORLD; \
else { \
fprintf(stderr, "LOG_ALLOW_SYNC ERROR: invalid scope (%d) at %s:%d\n", \
(scope), __FILE__, __LINE__); \
MPI_Abort(MPI_COMM_WORLD, 1); \
} \
\
/* ------------------------------------------------------------------ */ \
/* Decide whether *this* rank should actually print. */ \
/* ------------------------------------------------------------------ */ \
PetscBool _doPrint = \
is_function_allowed(__func__) && ((int)(level) <= (int)get_log_level()); \
\
if (_doPrint) { \
PetscSynchronizedPrintf(_comm, "[%s] " fmt, __func__, ##__VA_ARGS__); \
} \
\
/* ------------------------------------------------------------------ */ \
/* ALL ranks call the flush, even if they printed nothing. */ \
/* ------------------------------------------------------------------ */ \
PetscSynchronizedFlush(_comm, PETSC_STDOUT); \
} while (0)
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:45

Synchronized logging macro that checks both the log level and whether the calling function is in the allow-list.

This macro uses PetscSynchronizedPrintf and PetscSynchronizedFlush to ensure messages from different ranks are printed in a rank-ordered fashion (i.e., to avoid interleaving). It also filters out messages if the current function is not in the allow-list (is_function_allowed(__func__)) or the requested log level is higher than get_log_level().

Parameters
scopeEither LOCAL (MPI_COMM_SELF) or GLOBAL (MPI_COMM_WORLD).
levelOne of LOG_ERROR, LOG_WARNING, LOG_INFO, LOG_DEBUG.
fmtA printf-style format string (e.g., "Message: %ld\n").
...Variadic arguments to fill in fmt.

Example usage:

LOG_ALLOW_SYNC(LOCAL, LOG_DEBUG, "Debug info: rank = %ld\n", rank);
LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "Synchronized info in %s\n", __func__);
#define LOG_ALLOW_SYNC(scope, level, fmt,...)
Synchronized logging macro that checks both the log level and whether the calling function is in the ...
Definition logging.h:252
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:31

Definition at line 252 of file logging.h.

253 { \
254 /* ------------------------------------------------------------------ */ \
255 /* Validate scope and pick communicator *before* any early exits. */ \
256 /* ------------------------------------------------------------------ */ \
257 MPI_Comm _comm; \
258 if ((scope) == LOCAL) _comm = MPI_COMM_SELF; \
259 else if ((scope) == GLOBAL) _comm = MPI_COMM_WORLD; \
260 else { \
261 fprintf(stderr, "LOG_ALLOW_SYNC ERROR: invalid scope (%d) at %s:%d\n", \
262 (scope), __FILE__, __LINE__); \
263 MPI_Abort(MPI_COMM_WORLD, 1); \
264 } \
265 \
266 /* ------------------------------------------------------------------ */ \
267 /* Decide whether *this* rank should actually print. */ \
268 /* ------------------------------------------------------------------ */ \
269 PetscBool _doPrint = \
270 is_function_allowed(__func__) && ((int)(level) <= (int)get_log_level()); \
271 \
272 if (_doPrint) { \
273 PetscSynchronizedPrintf(_comm, "[%s] " fmt, __func__, ##__VA_ARGS__); \
274 } \
275 \
276 /* ------------------------------------------------------------------ */ \
277 /* ALL ranks call the flush, even if they printed nothing. */ \
278 /* ------------------------------------------------------------------ */ \
279 PetscSynchronizedFlush(_comm, PETSC_STDOUT); \
280} while (0)

◆ LOG_LOOP_ALLOW

#define LOG_LOOP_ALLOW (   scope,
  level,
  iterVar,
  interval,
  fmt,
  ... 
)
Value:
do { \
if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
if ((iterVar) % (interval) == 0) { \
MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
PetscPrintf(comm, "[%s] [%s=%d] " fmt, \
__func__, #iterVar, (iterVar), ##__VA_ARGS__); \
} \
} \
} while (0)

Logs a message inside a loop, but only every interval iterations.

Parameters
scopeLOCAL or GLOBAL.
levelLOG_* level.
iterVarThe loop variable (e.g., i).
intervalOnly log when (iterVar % interval == 0).
fmtprintf-style format string.
...Variadic arguments to include in the formatted message.

Example: for (int i = 0; i < 100; i++) { LOG_LOOP_ALLOW(LOCAL, LOG_DEBUG, i, 10, "Value of i=%d\n", i); }

Definition at line 297 of file logging.h.

298 { \
299 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
300 if ((iterVar) % (interval) == 0) { \
301 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
302 PetscPrintf(comm, "[%s] [%s=%d] " fmt, \
303 __func__, #iterVar, (iterVar), ##__VA_ARGS__); \
304 } \
305 } \
306 } while (0)

◆ LOG_LOOP_ALLOW_EXACT

#define LOG_LOOP_ALLOW_EXACT (   scope,
  level,
  var,
  val,
  fmt,
  ... 
)
Value:
do { \
/* First, perform the cheap, standard gatekeeper checks. */ \
if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
/* Only if those pass, check the user's specific condition. */ \
if ((var) == (val)) { \
MPI_Comm comm = ((scope) == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
/* Print the standard prefix, then the user's custom message. */ \
PetscPrintf(comm, "[%s] [%s=%d] " fmt, \
__func__, #var, (var), ##__VA_ARGS__); \
} \
} \
} while (0)

Logs a custom message if a variable equals a specific value.

This is a variadic macro for logging a single event when a condition is met. It is extremely useful for printing debug information at a specific iteration of a loop or when a state variable reaches a certain value.

Parameters
scopeEither LOCAL or GLOBAL.
levelThe logging level.
varThe variable to check (e.g., a loop counter 'k').
valThe value that triggers the log (e.g., 6). The log prints if var == val.
fmtA printf-style format string.
...A printf-style format string and its corresponding arguments.

Definition at line 334 of file logging.h.

335 { \
336 /* First, perform the cheap, standard gatekeeper checks. */ \
337 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
338 /* Only if those pass, check the user's specific condition. */ \
339 if ((var) == (val)) { \
340 MPI_Comm comm = ((scope) == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
341 /* Print the standard prefix, then the user's custom message. */ \
342 PetscPrintf(comm, "[%s] [%s=%d] " fmt, \
343 __func__, #var, (var), ##__VA_ARGS__); \
344 } \
345 } \
346 } while (0)

◆ LOG_ARRAY_ELEMENT_ALLOW

#define LOG_ARRAY_ELEMENT_ALLOW (   scope,
  level,
  arr,
  length,
  idx,
  fmt 
)
Value:
do { \
if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
if ((idx) >= 0 && (idx) < (length)) { \
MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", \
__func__, (idx), (arr)[idx]); \
} \
} \
} while (0)

Logs a single element of an array, given an index.

Parameters
scopeEither LOCAL or GLOBAL.
levelLOG_ERROR, LOG_WARNING, LOG_INFO, or LOG_DEBUG.
arrPointer to the array to log from.
lengthThe length of the array (to prevent out-of-bounds).
idxThe index of the element to print.
fmtThe printf-style format specifier (e.g. "%g", "%f", etc.).

This macro only logs if: 1) The current function is in the allow-list (is_function_allowed(__func__)). 2) The requested logging level <= the current global get_log_level(). 3) The index idx is valid (0 <= idx < length).

Definition at line 363 of file logging.h.

364 { \
365 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
366 if ((idx) >= 0 && (idx) < (length)) { \
367 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
368 PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", \
369 __func__, (idx), (arr)[idx]); \
370 } \
371 } \
372 } while (0)

◆ LOG_ARRAY_SUBRANGE_ALLOW

#define LOG_ARRAY_SUBRANGE_ALLOW (   scope,
  level,
  arr,
  length,
  start,
  end,
  fmt 
)
Value:
do { \
if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
PetscInt _start = (start) < 0 ? 0 : (start); \
PetscInt _end = (end) >= (length) ? (length) - 1 : (end); \
for (PetscInt i = _start; i <= _end; i++) { \
PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", __func__, i, (arr)[i]); \
} \
} \
} while (0)

Logs a consecutive subrange of an array.

Parameters
scopeEither LOCAL or GLOBAL.
levelLOG_ERROR, LOG_WARNING, LOG_INFO, or LOG_DEBUG.
arrPointer to the array to log from.
lengthTotal length of the array.
startStarting index of the subrange.
endEnding index of the subrange (inclusive).
fmtThe printf-style format specifier (e.g., "%g", "%f").

This macro prints each element arr[i] for i in [start, end], bounded by [0, length-1].

Definition at line 387 of file logging.h.

388 { \
389 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
390 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
391 PetscInt _start = (start) < 0 ? 0 : (start); \
392 PetscInt _end = (end) >= (length) ? (length) - 1 : (end); \
393 for (PetscInt i = _start; i <= _end; i++) { \
394 PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", __func__, i, (arr)[i]); \
395 } \
396 } \
397 } while (0)

◆ PROFILE_FUNCTION_BEGIN

#define PROFILE_FUNCTION_BEGIN    _ProfilingStart(__FUNCT__)

Marks the beginning of a profiled code block (typically a function).

Place this macro at the very beginning of a function you wish to profile. It automatically captures the function's name and starts a wall-clock timer.

Definition at line 811 of file logging.h.

◆ PROFILE_FUNCTION_END

#define PROFILE_FUNCTION_END    _ProfilingEnd(__FUNCT__)

Marks the end of a profiled code block.

Place this macro just before every return point in a function that starts with PROFILE_FUNCTION_BEGIN. It stops the timer and accumulates the results.

Definition at line 820 of file logging.h.

Enumeration Type Documentation

◆ LogLevel

enum LogLevel

Enumeration of logging levels.

Defines various severity levels for logging messages.

Enumerator
LOG_ERROR 

Critical errors that may halt the program.

LOG_WARNING 

Non-critical issues that warrant attention.

LOG_INFO 

Informational messages about program execution.

LOG_DEBUG 

Detailed debugging information.

LOG_TRACE 

Very fine-grained tracing information for in-depth debugging.

LOG_VERBOSE 

Extremely detailed logs, typically for development use only.

Definition at line 27 of file logging.h.

27 {
28 LOG_ERROR = 0, /**< Critical errors that may halt the program */
29 LOG_WARNING, /**< Non-critical issues that warrant attention */
30 LOG_INFO, /**< Informational messages about program execution */
31 LOG_DEBUG, /**< Detailed debugging information */
32 LOG_TRACE, /**< Very fine-grained tracing information for in-depth debugging */
33 LOG_VERBOSE /**< Extremely detailed logs, typically for development use only */
34} LogLevel;
LogLevel
Enumeration of logging levels.
Definition logging.h:27
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:28
@ LOG_TRACE
Very fine-grained tracing information for in-depth debugging.
Definition logging.h:32
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:29
@ LOG_VERBOSE
Extremely detailed logs, typically for development use only.
Definition logging.h:33

Function Documentation

◆ get_log_level()

LogLevel get_log_level ( )

Retrieves the current logging level from the environment variable LOG_LEVEL.

The function checks the LOG_LEVEL environment variable and sets the logging level accordingly. Supported levels are "ERROR", "WARNING", "INFO", "DEBUG", "TRACE", and "VERBOSE". Unset or unrecognized values default to "ERROR".

Returns
LogLevel The current logging level.

Retrieves the current logging level from the environment variable LOG_LEVEL.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
get_log_level()

Definition at line 84 of file logging.c.

84 {
85 if (current_log_level == -1) { // Log level not set yet
86 const char *env = getenv("LOG_LEVEL");
87 if (!env) {
88 current_log_level = LOG_ERROR; // Default level
89 }
90 else if (strcmp(env, "DEBUG") == 0) {
92 }
93 else if (strcmp(env, "INFO") == 0) {
95 }
96 else if (strcmp(env, "WARNING") == 0) {
98 }
99 else if (strcmp(env, "VERBOSE") == 0) {
101 }
102 else if (strcmp(env, "TRACE") == 0) {
104 }
105 else {
106 current_log_level = LOG_ERROR; // Default if unrecognized
107 }
108 }
109 return current_log_level;
110}
static LogLevel current_log_level
Static variable to cache the current logging level.
Definition logging.c:16
Here is the caller graph for this function:

◆ print_log_level()

PetscErrorCode print_log_level ( void  )

Prints the current logging level to the console.

This function retrieves the log level using get_log_level() and prints the corresponding log level name. It helps verify the logging configuration at runtime. The log levels supported are:

  • LOG_ERROR (0) : Logs only critical errors.
  • LOG_WARNING (1) : Logs warnings and errors.
  • LOG_INFO (2) : Logs general information, warnings, and errors.
  • LOG_DEBUG (3) : Logs debugging information, info, warnings, and errors.
  • LOG_TRACE (4) : Logs fine-grained trace information.
  • LOG_VERBOSE (5) : Logs very detailed developer output. If LOG_LEVEL is not set, it defaults to LOG_ERROR.

    Returns
    PetscErrorCode 0 on success.

    Prints the current logging level to the console.

    Local to this translation unit.

Definition at line 116 of file logging.c.

117{
118 PetscMPIInt rank;
119 PetscErrorCode ierr;
120 int level;
121 const char *level_name;
122
123 PetscFunctionBeginUser;
124 /* get MPI rank */
125 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRMPI(ierr);
126
127 /* decide level name */
128 level = get_log_level();
129 level_name = (level == LOG_ERROR) ? "ERROR" :
130 (level == LOG_WARNING) ? "WARNING" :
131 (level == LOG_INFO) ? "INFO" :
132 (level == LOG_DEBUG) ? "DEBUG" :
133 (level == LOG_VERBOSE) ? "VERBOSE" :
134 (level == LOG_TRACE) ? "TRACE" :
135 "UNKNOWN";
136
137 /* print it out */
138 ierr = PetscPrintf(PETSC_COMM_SELF,
139 "Current log level: %s (%d) | rank: %d\n",
140 level_name, level, (int)rank);
141 CHKERRMPI(ierr);
142
143 PetscFunctionReturn(PETSC_SUCCESS);
144}
LogLevel get_log_level()
Implementation of get_log_level().
Definition logging.c:84
Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_allowed_functions()

void set_allowed_functions ( const char **  functionList,
int  count 
)

Sets the global list of function names that are allowed to log.

You can replace the entire list of allowed function names at runtime.

Parameters
functionListParameter functionList passed to set_allowed_functions().
countParameter count passed to set_allowed_functions().

Sets the global list of function names that are allowed to log.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
set_allowed_functions()

Definition at line 152 of file logging.c.

153{
154 // 1. Free any existing entries
155 if (gAllowedFunctions) {
156 for (int i = 0; i < gNumAllowed; ++i) {
157 free(gAllowedFunctions[i]); // each was strdup'ed
158 }
159 free(gAllowedFunctions);
160 gAllowedFunctions = NULL;
161 gNumAllowed = 0;
162 }
163
164 // 2. Allocate new array
165 if (count > 0) {
166 gAllowedFunctions = (char**)malloc(sizeof(char*) * count);
167 }
168
169 // 3. Copy the new entries
170 for (int i = 0; i < count; ++i) {
171 // strdup is a POSIX function. If not available, implement your own string copy.
172 gAllowedFunctions[i] = strdup(functionList[i]);
173 }
174 gNumAllowed = count;
175}
static char ** gAllowedFunctions
Global/static array of function names allowed to log.
Definition logging.c:23
static int gNumAllowed
Number of entries in the gAllowedFunctions array.
Definition logging.c:28
Here is the caller graph for this function:

◆ is_function_allowed()

PetscBool is_function_allowed ( const char *  functionName)

Checks if a given function is in the allow-list.

This helper is used internally by the LOG_ALLOW macro.

Parameters
functionNameParameter functionName passed to is_function_allowed().
Returns
PetscBool indicating the result of is_function_allowed().

Checks if a given function is in the allow-list.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
is_function_allowed()

Definition at line 183 of file logging.c.

184{
185 /* no list ⇒ allow all */
186 if (gNumAllowed == 0) {
187 return PETSC_TRUE;
188 }
189
190 /* otherwise only the listed functions are allowed */
191 for (int i = 0; i < gNumAllowed; ++i) {
192 if (strcmp(gAllowedFunctions[i], functionName) == 0) {
193 return PETSC_TRUE;
194 }
195 }
196 return PETSC_FALSE;
197}
Here is the caller graph for this function:

◆ LOG_CELL_VERTICES()

PetscErrorCode LOG_CELL_VERTICES ( const Cell cell,
PetscMPIInt  rank 
)

Prints the coordinates of a cell's vertices.

This function iterates through the eight vertices of a given cell and prints their coordinates. It is primarily used for debugging purposes to verify the correctness of cell vertex assignments.

Parameters
[in]cellPointer to a Cell structure representing the cell, containing its vertices.
[in]rankMPI rank for identification (useful in parallel environments).
Returns
PetscErrorCode Returns 0 to indicate successful execution. Non-zero on failure.
Note
  • Ensure that the cell pointer is not NULL before calling this function..

Prints the coordinates of a cell's vertices.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_CELL_VERTICES()

Definition at line 205 of file logging.c.

206{
207
208 // Validate input pointers
209 if (cell == NULL) {
210 LOG_ALLOW(LOCAL,LOG_ERROR, "'cell' is NULL.\n");
211 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "LOG_CELL_VERTICES - Input parameter 'cell' is NULL.");
212 }
213
214 LOG_ALLOW(LOCAL,LOG_VERBOSE, "Rank %d, Cell Vertices:\n", rank);
215 for(int i = 0; i < 8; i++){
216 LOG_ALLOW(LOCAL,LOG_VERBOSE, " Vertex[%d]: (%.2f, %.2f, %.2f)\n",
217 i, cell->vertices[i].x, cell->vertices[i].y, cell->vertices[i].z);
218 }
219
220 return 0; // Indicate successful execution
221}
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:199
PetscScalar x
Definition variables.h:101
PetscScalar z
Definition variables.h:101
PetscScalar y
Definition variables.h:101
Cmpnts vertices[8]
Coordinates of the eight vertices of the cell.
Definition variables.h:161
Here is the caller graph for this function:

◆ LOG_FACE_DISTANCES()

PetscErrorCode LOG_FACE_DISTANCES ( PetscReal *  d)

Prints the signed distances to each face of the cell.

This function iterates through the six signed distances from a point to each face of a given cell and prints their values. It is primarily used for debugging purposes to verify the correctness of distance calculations.

Parameters
[in]dAn array of six PetscReal values representing the signed distances. The indices correspond to:
  • d[LEFT]: Left Face
  • d[RIGHT]: Right Face
  • d[BOTTOM]: Bottom Face
  • d[TOP]: Top Face
  • d[FRONT]: Front Face
  • d[BACK]: Back Face
Returns
PetscErrorCode Returns 0 to indicate successful execution. Non-zero on failure.
Note
  • Ensure that the d array is correctly populated with signed distances before calling this function.

Prints the signed distances to each face of the cell.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_FACE_DISTANCES()

Definition at line 230 of file logging.c.

231{
232
233 // Validate input array
234 if (d == NULL) {
235 LOG_ALLOW(LOCAL,LOG_ERROR, " 'd' is NULL.\n");
236 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, " Input array 'd' is NULL.");
237 }
238
239 PetscPrintf(PETSC_COMM_SELF, " Face Distances:\n");
240 PetscPrintf(PETSC_COMM_SELF, " LEFT(%d): %.15f\n", LEFT, d[LEFT]);
241 PetscPrintf(PETSC_COMM_SELF, " RIGHT(%d): %.15f\n", RIGHT, d[RIGHT]);
242 PetscPrintf(PETSC_COMM_SELF, " BOTTOM(%d): %.15f\n", BOTTOM, d[BOTTOM]);
243 PetscPrintf(PETSC_COMM_SELF, " TOP(%d): %.15f\n", TOP, d[TOP]);
244 PetscPrintf(PETSC_COMM_SELF, " FRONT(%d): %.15f\n", FRONT, d[FRONT]);
245 PetscPrintf(PETSC_COMM_SELF, " BACK(%d): %.15f\n", BACK, d[BACK]);
246
247 return 0; // Indicate successful execution
248}
@ TOP
Definition variables.h:145
@ FRONT
Definition variables.h:145
@ BOTTOM
Definition variables.h:145
@ BACK
Definition variables.h:145
@ LEFT
Definition variables.h:145
@ RIGHT
Definition variables.h:145
Here is the caller graph for this function:

◆ LOG_PARTICLE_FIELDS()

PetscErrorCode LOG_PARTICLE_FIELDS ( UserCtx user,
PetscInt  printInterval 
)

Prints particle fields in a table that automatically adjusts its column widths.

This function retrieves data from the particle swarm and prints a table where the width of each column is determined by the maximum width needed to display the data. Only every 'printInterval'-th particle is printed.

Parameters
[in]userPointer to the UserCtx structure.
[in]printIntervalOnly every printInterval‑th particle is printed.
Returns
PetscErrorCode Returns 0 on success.

Prints particle fields in a table that automatically adjusts its column widths.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_PARTICLE_FIELDS()

Definition at line 397 of file logging.c.

398{
399 DM swarm = user->swarm;
400 PetscErrorCode ierr;
401 PetscInt localNumParticles;
402 PetscReal *positions = NULL;
403 PetscInt64 *particleIDs = NULL;
404 PetscMPIInt *particleRanks = NULL;
405 PetscInt *cellIDs = NULL;
406 PetscReal *weights = NULL;
407 PetscReal *velocities = NULL;
408 PetscMPIInt rank;
409
410 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
411 LOG_ALLOW(LOCAL,LOG_INFO, "Rank %d is retrieving particle data.\n", rank);
412
413 ierr = DMSwarmGetLocalSize(swarm, &localNumParticles); CHKERRQ(ierr);
414 LOG_ALLOW(LOCAL,LOG_DEBUG,"Rank %d has %d particles.\n", rank, localNumParticles);
415
416 ierr = DMSwarmGetField(swarm, "position", NULL, NULL, (void**)&positions); CHKERRQ(ierr);
417 ierr = DMSwarmGetField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
418 ierr = DMSwarmGetField(swarm, "DMSwarm_rank", NULL, NULL, (void**)&particleRanks); CHKERRQ(ierr);
419 ierr = DMSwarmGetField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
420 ierr = DMSwarmGetField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
421 ierr = DMSwarmGetField(swarm, "velocity", NULL, NULL, (void**)&velocities); CHKERRQ(ierr);
422
423 /* Compute maximum column widths. */
424 int wRank, wPID, wCell, wPos, wVel, wWt;
425 wRank = wPID = wCell = wPos = wVel = wWt = 0;
426 ierr = ComputeMaxColumnWidths(localNumParticles, particleRanks, particleIDs, cellIDs,
427 positions, velocities, weights,
428 &wRank, &wPID, &wCell, &wPos, &wVel, &wWt); CHKERRQ(ierr);
429
430 /* Build a header string and a row format string. */
431 char headerFmt[256];
432 char rowFmt[256];
433 BuildHeaderString(headerFmt, sizeof(headerFmt), wRank, wPID, wCell, wPos, wVel, wWt);
434 BuildRowFormatString(wRank, wPID, wCell, wPos, wVel, wWt, rowFmt, sizeof(rowFmt));
435
436 /* Print header (using synchronized printing for parallel output). */
437 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--------------------------------------------------------------------------------------------------------------\n"); CHKERRQ(ierr);
438 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", headerFmt); CHKERRQ(ierr);
439 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--------------------------------------------------------------------------------------------------------------\n"); CHKERRQ(ierr);
440
441 /* Loop over particles and print every printInterval-th row. */
442 char rowStr[256];
443 for (PetscInt i = 0; i < localNumParticles; i++) {
444 if (i % printInterval == 0) {
445 // ------- DEBUG
446 //char cellStr[TMP_BUF_SIZE], posStr[TMP_BUF_SIZE], velStr[TMP_BUF_SIZE], wtStr[TMP_BUF_SIZE];
447 //CellToStr(&cellIDs[3*i], cellStr, TMP_BUF_SIZE);
448 //TripleRealToStr(&positions[3*i], posStr, TMP_BUF_SIZE);
449 //TripleRealToStr(&velocities[3*i], velStr, TMP_BUF_SIZE);
450 // TripleRealToStr(&weights[3*i], wtStr, TMP_BUF_SIZE);
451
452 // if (rank == 0) { // Or whatever rank is Rank 0
453 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Particle %lld: PID=%lld, Rank=%d\n", (long long)i, (long long)particleIDs[i], particleRanks[i]);
454 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Raw Pos: (%.10e, %.10e, %.10e)\n", positions[3*i+0], positions[3*i+1], positions[3*i+2]);
455 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Str Pos: %s\n", posStr);
456 //PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Raw Vel: (%.10e, %.10e, %.10e)\n", velocities[3*i+0], velocities[3*i+1], velocities[3*i+2]);
457 // PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] Str Vel: %s\n", velStr);
458 // Add similar for cell, weights
459 // PetscPrintf(PETSC_COMM_SELF, "[Rank 0 DEBUG LPF] About to build rowStr for particle %lld\n", (long long)i);
460 // fflush(stdout);
461 // }
462
463 // snprintf(rowStr, sizeof(rowStr), rowFmt,
464 // particleRanks[i],
465 // particleIDs[i],
466 // cellStr,
467 // posStr,
468 // velStr,
469 // wtStr);
470
471
472 // ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", rowStr); CHKERRQ(ierr);
473
474 // ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", rowStr); CHKERRQ(ierr);
475
476 // -------- DEBUG
477 /* Format the row by converting each field to a string first.
478 * We use temporary buffers and then build the row string.
479 */
480
481 char cellStr[TMP_BUF_SIZE], posStr[TMP_BUF_SIZE], velStr[TMP_BUF_SIZE], wtStr[TMP_BUF_SIZE];
482 CellToStr(&cellIDs[3*i], cellStr, TMP_BUF_SIZE);
483 TripleRealToStr(&positions[3*i], posStr, TMP_BUF_SIZE);
484 TripleRealToStr(&velocities[3*i], velStr, TMP_BUF_SIZE);
485 TripleRealToStr(&weights[3*i], wtStr, TMP_BUF_SIZE);
486
487 /* Build the row string. Note that for the integer fields we can use the row format string. */
488 snprintf(rowStr, sizeof(rowStr), rowFmt,
489 particleRanks[i],
490 particleIDs[i],
491 cellStr,
492 posStr,
493 velStr,
494 wtStr);
495 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "%s", rowStr); CHKERRQ(ierr);
496 }
497 }
498
499
500 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "--------------------------------------------------------------------------------------------------------------\n"); CHKERRQ(ierr);
501 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, "\n"); CHKERRQ(ierr);
502 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
503
504 LOG_ALLOW_SYNC(GLOBAL,LOG_DEBUG,"Completed printing on Rank %d.\n", rank);
505
506 /* Restore fields */
507 ierr = DMSwarmRestoreField(swarm, "position", NULL, NULL, (void**)&positions); CHKERRQ(ierr);
508 ierr = DMSwarmRestoreField(swarm, "DMSwarm_pid", NULL, NULL, (void**)&particleIDs); CHKERRQ(ierr);
509 ierr = DMSwarmRestoreField(swarm, "DMSwarm_rank", NULL, NULL, (void**)&particleRanks); CHKERRQ(ierr);
510 ierr = DMSwarmRestoreField(swarm, "DMSwarm_CellID", NULL, NULL, (void**)&cellIDs); CHKERRQ(ierr);
511 ierr = DMSwarmRestoreField(swarm, "weight", NULL, NULL, (void**)&weights); CHKERRQ(ierr);
512 ierr = DMSwarmRestoreField(swarm, "velocity", NULL, NULL, (void**)&velocities); CHKERRQ(ierr);
513
514 LOG_ALLOW(LOCAL,LOG_DEBUG, "Restored all particle fields.\n");
515 return 0;
516}
#define TMP_BUF_SIZE
Definition logging.c:7
static void BuildRowFormatString(PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt, char *fmtStr, size_t bufSize)
Definition logging.c:366
static void BuildHeaderString(char *headerStr, size_t bufSize, PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt)
Definition logging.c:379
static void CellToStr(const PetscInt *cell, char *buf, size_t bufsize)
Definition logging.c:269
static void TripleRealToStr(const PetscReal *arr, char *buf, size_t bufsize)
Definition logging.c:277
static PetscErrorCode ComputeMaxColumnWidths(PetscInt nParticles, const PetscMPIInt *ranks, const PetscInt64 *pids, const PetscInt *cellIDs, const PetscReal *positions, const PetscReal *velocities, const PetscReal *weights, int *wRank, int *wPID, int *wCell, int *wPos, int *wVel, int *wWt)
Definition logging.c:302
Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsParticleConsoleSnapshotEnabled()

PetscBool IsParticleConsoleSnapshotEnabled ( const SimCtx simCtx)

Returns whether periodic particle console snapshots are enabled.

This checks only the reporting contract (particles exist, cadence is enabled, and the global log level is at least INFO).

Parameters
simCtxSimulation context controlling the operation.
Returns
PetscBool indicating the result of IsParticleConsoleSnapshotEnabled().

Returns whether periodic particle console snapshots are enabled.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
IsParticleConsoleSnapshotEnabled()

Definition at line 525 of file logging.c.

526{
527 if (!simCtx) {
528 return PETSC_FALSE;
529 }
530 return (PetscBool)(simCtx->np > 0 &&
531 simCtx->particleConsoleOutputFreq > 0 &&
533}
PetscInt np
Definition variables.h:753
PetscInt particleConsoleOutputFreq
Definition variables.h:664
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ShouldEmitPeriodicParticleConsoleSnapshot()

PetscBool ShouldEmitPeriodicParticleConsoleSnapshot ( const SimCtx simCtx,
PetscInt  completed_step 
)

Returns whether a particle console snapshot should be emitted for the.

completed timestep.

Parameters
simCtxSimulation context controlling the operation.
completed_stepCompleted step index used by the decision helper.
Returns
PetscBool indicating the result of ShouldEmitPeriodicParticleConsoleSnapshot().

Returns whether a particle console snapshot should be emitted for the.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
ShouldEmitPeriodicParticleConsoleSnapshot()

Definition at line 542 of file logging.c.

543{
544 return (PetscBool)(IsParticleConsoleSnapshotEnabled(simCtx) &&
545 completed_step > 0 &&
546 completed_step % simCtx->particleConsoleOutputFreq == 0);
547}
PetscBool IsParticleConsoleSnapshotEnabled(const SimCtx *simCtx)
Implementation of IsParticleConsoleSnapshotEnabled().
Definition logging.c:525
Here is the call graph for this function:
Here is the caller graph for this function:

◆ EmitParticleConsoleSnapshot()

PetscErrorCode EmitParticleConsoleSnapshot ( UserCtx user,
SimCtx simCtx,
PetscInt  step 
)

Emits one particle console snapshot into the main solver log.

Parameters
userPrimary UserCtx input for the operation.
simCtxSimulation context controlling the operation.
stepStep index associated with the operation.
Returns
PetscErrorCode 0 on success.

Emits one particle console snapshot into the main solver log.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
EmitParticleConsoleSnapshot()

Definition at line 556 of file logging.c.

557{
558 PetscErrorCode ierr;
559
560 PetscFunctionBeginUser;
561 LOG(GLOBAL, LOG_INFO, "Particle states at step %d:\n", step);
562 ierr = LOG_PARTICLE_FIELDS(user, simCtx->LoggingFrequency); CHKERRQ(ierr);
563 PetscFunctionReturn(0);
564}
PetscErrorCode LOG_PARTICLE_FIELDS(UserCtx *user, PetscInt printInterval)
Implementation of LOG_PARTICLE_FIELDS().
Definition logging.c:397
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
Definition logging.h:83
PetscInt LoggingFrequency
Definition variables.h:783
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FreeAllowedFunctions()

PetscErrorCode FreeAllowedFunctions ( char **  funcs,
PetscInt  n 
)

Free an array previously returned by LoadAllowedFunctionsFromFile().

Parameters
[in,out]funcsArray of strings to release (may be NULL).
[in]nNumber of entries in funcs. Ignored if funcs is NULL.
Returns
0 on success or a PETSc error code.

Free an array previously returned by LoadAllowedFunctionsFromFile().

Local to this translation unit.

Definition at line 650 of file logging.c.

651{
652 PetscErrorCode ierr;
653 PetscFunctionBegin;
654 if (funcs) {
655 for (PetscInt i = 0; i < n; ++i) {
656 ierr = PetscFree(funcs[i]); CHKERRQ(ierr);
657 }
658 ierr = PetscFree(funcs); CHKERRQ(ierr);
659 }
660 PetscFunctionReturn(0);
661}
Here is the caller graph for this function:

◆ LoadAllowedFunctionsFromFile()

PetscErrorCode LoadAllowedFunctionsFromFile ( const char  filename[],
char ***  funcsOut,
PetscInt *  nOut 
)

Load function names from a text file.

The file is expected to contain one identifier per line. Blank lines and lines whose first non‑blank character is a # are silently skipped so the file can include comments. Example:

# Allowed function list
InitializeSimulation
InterpolateAllFieldsToSwarm # inline comments are OK, too
PetscErrorCode InterpolateAllFieldsToSwarm(UserCtx *user)
Interpolates all relevant fields from the DMDA to the DMSwarm.
int main(int argc, char **argv)
Entry point for the postprocessor executable.

The routine allocates memory as needed (growing an internal buffer with PetscRealloc()) and returns the resulting array and its length to the caller. Use FreeAllowedFunctions() to clean up when done.

Parameters
[in]filenamePath of the configuration file to read.
[out]funcsOutOn success, points to a freshly‑allocated array of char* (size nOut).
[out]nOutNumber of valid entries in funcsOut.
Returns
0 on success, or a PETSc error code on failure (e.g. I/O error, OOM).

Load function names from a text file.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LoadAllowedFunctionsFromFile()

Definition at line 596 of file logging.c.

599{
600 FILE *fp = NULL;
601 char **funcs = NULL;
602 size_t cap = 16; /* initial capacity */
603 size_t n = 0; /* number of names */
604 char line[PETSC_MAX_PATH_LEN];
605 PetscErrorCode ierr;
606
607 PetscFunctionBegin;
608
609 /* ---------------------------------------------------------------------- */
610 /* 1. Open file */
611 fp = fopen(filename, "r");
612 if (!fp) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
613 "Cannot open %s", filename);
614
615 /* 2. Allocate initial pointer array */
616 ierr = PetscMalloc1(cap, &funcs); CHKERRQ(ierr);
617
618 /* 3. Read file line by line */
619 while (fgets(line, sizeof line, fp)) {
620 /* Strip everything after a comment character '#'. */
621 char *hash = strchr(line, '#');
622 if (hash) *hash = '\0';
623
624 trim(line); /* remove leading/trailing blanks */
625 if (!*line) continue; /* skip if empty */
626
627 /* Grow the array if necessary */
628 if (n == cap) {
629 cap *= 2;
630 ierr = PetscRealloc(cap * sizeof(*funcs), (void **)&funcs); CHKERRQ(ierr);
631 }
632
633 /* Deep‑copy the cleaned identifier */
634 ierr = PetscStrallocpy(line, &funcs[n++]); CHKERRQ(ierr);
635 }
636 fclose(fp);
637
638 /* 4. Return results to caller */
639 *funcsOut = funcs;
640 *nOut = (PetscInt)n;
641
642 PetscFunctionReturn(0);
643}
static void trim(char *s)
Internal helper implementation: trim().
Definition logging.c:571
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BCFaceToString()

const char * BCFaceToString ( BCFace  face)

Helper function to convert BCFace enum to a string representation.

Parameters
[in]faceThe BCFace enum value.
Returns
Pointer to a constant string representing the face.

Helper function to convert BCFace enum to a string representation.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
BCFaceToString()

Definition at line 669 of file logging.c.

669 {
670 switch (face) {
671 case BC_FACE_NEG_X: return "-Xi (I-Min)";
672 case BC_FACE_POS_X: return "+Xi (I-Max)";
673 case BC_FACE_NEG_Y: return "-Eta (J-Min)";
674 case BC_FACE_POS_Y: return "+Eta (J-Max)";
675 case BC_FACE_NEG_Z: return "-Zeta (K-Min)";
676 case BC_FACE_POS_Z: return "+Zeta (K-Max)";
677 default: return "Unknown Face";
678 }
679}
@ BC_FACE_NEG_X
Definition variables.h:245
@ BC_FACE_POS_Z
Definition variables.h:247
@ BC_FACE_POS_Y
Definition variables.h:246
@ BC_FACE_NEG_Z
Definition variables.h:247
@ BC_FACE_POS_X
Definition variables.h:245
@ BC_FACE_NEG_Y
Definition variables.h:246
Here is the caller graph for this function:

◆ FieldInitializationToString()

const char * FieldInitializationToString ( PetscInt  FieldInitialization)

Helper function to convert FieldInitialization to a string representation.

Parameters
[in]FieldInitializationThe FieldInitialization value.
Returns
Pointer to a constant string representing the FieldInitialization.

Helper function to convert FieldInitialization to a string representation.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
FieldInitializationToString()

Definition at line 687 of file logging.c.

688{
689 switch(FieldInitialization){
690 case 0: return "Zero";
691 case 1: return "Constant Normal velocity";
692 case 2: return "Poiseuille Normal velocity";
693 default: return "Unknown Field Initialization";
694 }
695}
Here is the caller graph for this function:

◆ ParticleInitializationToString()

const char * ParticleInitializationToString ( ParticleInitializationType  ParticleInitialization)

Helper function to convert ParticleInitialization to a string representation.

Parameters
[in]ParticleInitializationThe ParticleInitialization enum value.
Returns
Pointer to a constant string representing the FieldInitialization.

Helper function to convert ParticleInitialization to a string representation.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
ParticleInitializationToString()

Definition at line 703 of file logging.c.

704{
705 switch(ParticleInitialization){
706 case PARTICLE_INIT_SURFACE_RANDOM: return "Surface: Random";
707 case PARTICLE_INIT_VOLUME: return "Volume";
708 case PARTICLE_INIT_POINT_SOURCE: return "Point Source";
709 case PARTICLE_INIT_SURFACE_EDGES: return "Surface: At edges";
710 default: return "Unknown Particle Initialization";
711 }
712}
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:517
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
Definition variables.h:520
@ PARTICLE_INIT_POINT_SOURCE
All particles at a fixed (psrc_x,psrc_y,psrc_z) — for validation.
Definition variables.h:519
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
Definition variables.h:518
Here is the caller graph for this function:

◆ LESModelToString()

const char * LESModelToString ( LESModelType  LESFlag)

Helper function to convert LES Flag to a string representation.

Parameters
[in]LESFlagThe LES flag value.
Returns
Pointer to a constant string representing the LES Flag.

Helper function to convert LES Flag to a string representation.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LESModelToString()

Definition at line 720 of file logging.c.

721{
722 switch(LESFlag){
723 case NO_LES_MODEL: return "No LES";
724 case CONSTANT_SMAGORINSKY: return "Constant Smagorinsky";
725 case DYNAMIC_SMAGORINSKY: return "Dynamic Smagorinsky";
726 default: return "Unknown LES Flag";
727 }
728}
@ DYNAMIC_SMAGORINSKY
Definition variables.h:491
@ NO_LES_MODEL
Definition variables.h:489
@ CONSTANT_SMAGORINSKY
Definition variables.h:490
Here is the caller graph for this function:

◆ MomentumSolverTypeToString()

const char * MomentumSolverTypeToString ( MomentumSolverType  SolverFlag)

Helper function to convert Momentum Solver flag to a string representation.

Parameters
[in]SolverFlagThe Momentum Solver flag value.
Returns
Pointer to a constant string representing the MomentumSolverType.

Helper function to convert Momentum Solver flag to a string representation.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
MomentumSolverTypeToString()

Definition at line 736 of file logging.c.

737{
738 switch(SolverFlag){
739 case MOMENTUM_SOLVER_EXPLICIT_RK: return "Explicit 4 stage Runge-Kutta ";
740 case MOMENTUM_SOLVER_DUALTIME_PICARD_RK4: return "Dual Time Stepping with Picard Iterations and 4 stage Runge-Kutta Smoothing";
741 default: return "Unknown Momentum Solver Type";
742 }
743}
@ MOMENTUM_SOLVER_EXPLICIT_RK
Definition variables.h:503
@ MOMENTUM_SOLVER_DUALTIME_PICARD_RK4
Definition variables.h:504
Here is the caller graph for this function:

◆ BCTypeToString()

const char * BCTypeToString ( BCType  type)

Helper function to convert BCType enum to a string representation.

Parameters
[in]typeThe BCType enum value.
Returns
Pointer to a constant string representing the BC type.

Helper function to convert BCType enum to a string representation.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
BCTypeToString()

Definition at line 751 of file logging.c.

751 {
752 switch (type) {
753 // case DIRICHLET: return "DIRICHLET";
754 // case NEUMANN: return "NEUMANN";
755 case WALL: return "WALL";
756 case INLET: return "INLET";
757 case OUTLET: return "OUTLET";
758 case FARFIELD: return "FARFIELD";
759 case PERIODIC: return "PERIODIC";
760 case INTERFACE: return "INTERFACE";
761
762 // case CUSTOM: return "CUSTOM";
763 default: return "Unknown BC Type";
764 }
765}
@ INLET
Definition variables.h:258
@ INTERFACE
Definition variables.h:253
@ FARFIELD
Definition variables.h:259
@ OUTLET
Definition variables.h:257
@ PERIODIC
Definition variables.h:260
@ WALL
Definition variables.h:254
Here is the caller graph for this function:

◆ BCHandlerTypeToString()

const char * BCHandlerTypeToString ( BCHandlerType  handler_type)

Converts a BCHandlerType enum to its string representation.

Provides a descriptive string for a specific boundary condition implementation strategy. This is crucial for logging the exact behavior configured for a face.

Parameters
handler_typeThe BCHandlerType enum value (e.g., BC_HANDLER_WALL_NOSLIP).
Returns
A constant character string corresponding to the enum. Returns "UNKNOWN_HANDLER" if the enum value is not recognized.

Converts a BCHandlerType enum to its string representation.

Local to this translation unit.

Definition at line 771 of file logging.c.

771 {
772 switch (handler_type) {
773 // Wall & Symmetry Handlers
774 case BC_HANDLER_WALL_NOSLIP: return "noslip";
775 case BC_HANDLER_WALL_MOVING: return "moving";
776 case BC_HANDLER_SYMMETRY_PLANE: return "symmetry_plane";
777
778 // Inlet Handlers
779 case BC_HANDLER_INLET_CONSTANT_VELOCITY: return "constant_velocity";
780 case BC_HANDLER_INLET_PULSATILE_FLUX: return "pulsatile_flux";
781 case BC_HANDLER_INLET_PARABOLIC: return "parabolic";
782 case BC_HANDLER_INLET_PROFILE_FROM_FILE: return "prescribed_flow";
783
784 // Outlet Handlers
785 case BC_HANDLER_OUTLET_CONSERVATION: return "conservation";
786 case BC_HANDLER_OUTLET_PRESSURE: return "pressure";
787
788 // Other Physical Handlers
789 case BC_HANDLER_FARFIELD_NONREFLECTING: return "nonreflecting";
790
791 // Multi-Block / Interface Handlers
792 case BC_HANDLER_PERIODIC_GEOMETRIC: return "geometric";
793 case BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX: return "constant flux";
794 case BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX: return "initial flux";
795 case BC_HANDLER_INTERFACE_OVERSET: return "overset";
796
797 // Default case
799 default: return "UNKNOWN_HANDLER";
800 }
801}
@ BC_HANDLER_INLET_PULSATILE_FLUX
Definition variables.h:280
@ BC_HANDLER_PERIODIC_GEOMETRIC
Definition variables.h:284
@ BC_HANDLER_INLET_PARABOLIC
Definition variables.h:277
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
Definition variables.h:276
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:287
@ BC_HANDLER_INTERFACE_OVERSET
Definition variables.h:285
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:286
@ BC_HANDLER_WALL_MOVING
Definition variables.h:274
@ BC_HANDLER_INLET_PROFILE_FROM_FILE
Definition variables.h:278
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:273
@ BC_HANDLER_OUTLET_CONSERVATION
Definition variables.h:282
@ BC_HANDLER_FARFIELD_NONREFLECTING
Definition variables.h:281
@ BC_HANDLER_OUTLET_PRESSURE
Definition variables.h:283
@ BC_HANDLER_SYMMETRY_PLANE
Definition variables.h:275
@ BC_HANDLER_UNDEFINED
Definition variables.h:272
Here is the caller graph for this function:

◆ DualKSPMonitor()

PetscErrorCode DualKSPMonitor ( KSP  ksp,
PetscInt  it,
PetscReal  rnorm,
void *  ctx 
)

A custom KSP monitor that logs to a file and optionally to the console.

This function unconditionally calls the standard true residual monitor to log to a file viewer provided in the context. It also checks a flag in the context and, if true, calls the monitor again to log to standard output.

Parameters
kspThe Krylov subspace context.
itThe current iteration number.
rnormThe preconditioned residual norm.
ctxA pointer to the DualMonitorCtx structure.
Returns
PetscErrorCode 0 on success.

A custom KSP monitor that logs to a file and optionally to the console.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
DualKSPMonitor()

Definition at line 848 of file logging.c.

849{
850 DualMonitorCtx *monctx = (DualMonitorCtx*)ctx;
851 PetscErrorCode ierr;
852 PetscReal trnorm, relnorm;
853 Vec r;
854 char norm_buf[256];
855 PetscMPIInt rank;
856
857 PetscFunctionBeginUser;
858 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
859
860 // 1. Calculate the true residual norm.
861 ierr = KSPBuildResidual(ksp, NULL, NULL, &r); CHKERRQ(ierr);
862 ierr = VecNorm(r, NORM_2, &trnorm); CHKERRQ(ierr);
863 ierr = VecDestroy(&r); CHKERRQ(ierr);
864
865 // 2. On the first iteration, compute and store the norm of the RHS vector `b`.
866 if (it == 0) {
867 Vec b;
868 ierr = KSPGetRhs(ksp, &b); CHKERRQ(ierr);
869 ierr = VecNorm(b, NORM_2, &monctx->bnorm); CHKERRQ(ierr);
870 }
871
872 if(!rank){
873 // 3. Compute the relative norm and format the output string.
874 if (monctx->bnorm > 1.e-15) {
875 relnorm = trnorm / monctx->bnorm;
876 sprintf(norm_buf, "ts: %-5d | block: %-2d | iter: %-3d | Unprecond Norm: %12.5e | True Norm: %12.5e | Rel Norm: %12.5e",(int)monctx->step, (int)monctx->block_id, (int)it, (double)rnorm, (double)trnorm, (double)relnorm);
877 } else {
878 sprintf(norm_buf,"ts: %-5d | block: %-2d | iter: %-3d | Unprecond Norm: %12.5e | True Norm: %12.5e",(int)monctx->step, (int)monctx->block_id, (int)it, (double)rnorm, (double)trnorm);
879 }
880
881 // 4. Log to the file viewer (unconditionally).
882 if(monctx->file_handle){
883 ierr = PetscFPrintf(PETSC_COMM_SELF,monctx->file_handle,"%s\n", norm_buf); CHKERRQ(ierr);
884 }
885 // 5. Log to the console (conditionally).
886 if (monctx->log_to_console) {
887 PetscFPrintf(PETSC_COMM_SELF,stdout, "%s\n", norm_buf); CHKERRQ(ierr);
888 }
889
890 } //rank
891
892 PetscFunctionReturn(0);
893}
PetscBool log_to_console
Definition logging.h:57
PetscReal bnorm
Definition logging.h:58
PetscInt step
Definition logging.h:59
FILE * file_handle
Definition logging.h:56
PetscInt block_id
Definition logging.h:60
Context for a dual-purpose KSP monitor.
Definition logging.h:55
Here is the caller graph for this function:

◆ DualMonitorDestroy()

PetscErrorCode DualMonitorDestroy ( void **  ctx)

Destroys the DualMonitorCtx.

This function is passed to KSPMonitorSet to ensure the viewer is properly destroyed and the context memory is freed when the KSP is destroyed.

Parameters
ctxa pointer to the context pointer to be destroyed
Returns
PetscErrorCode

Destroys the DualMonitorCtx.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
DualMonitorDestroy()

Definition at line 809 of file logging.c.

810{
811 DualMonitorCtx *monctx = (DualMonitorCtx*)*ctx;
812 PetscErrorCode ierr;
813 PetscMPIInt rank;
814
815 PetscFunctionBeginUser;
816 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
817 if(!rank && monctx->file_handle){
818 fclose(monctx->file_handle);
819 }
820
821 ierr = PetscFree(monctx); CHKERRQ(ierr);
822 *ctx = NULL;
823 PetscFunctionReturn(0);
824}
Here is the caller graph for this function:

◆ LOG_CONTINUITY_METRICS()

PetscErrorCode LOG_CONTINUITY_METRICS ( UserCtx user)

Logs continuity metrics for a single block to a file.

This function should be called for each block, once per timestep. It opens a central log file in append mode. To ensure the header is written only once, it checks if it is processing block 0 on the simulation's start step.

Parameters
userA pointer to the UserCtx for the specific block whose metrics are to be logged. The function accesses both global (SimCtx) and local (user->...) data.
Returns
PetscErrorCode 0 on success.

Logs continuity metrics for a single block to a file.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_CONTINUITY_METRICS()

Definition at line 1752 of file logging.c.

1753{
1754 PetscErrorCode ierr;
1755 PetscMPIInt rank;
1756 SimCtx *simCtx = user->simCtx; // Get the shared SimCtx
1757 const PetscInt bi = user->_this; // Get this block's specific ID
1758 const PetscInt ti = simCtx->step; // Get the current timestep
1759
1760 PetscFunctionBeginUser;
1761 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1762
1763 // Only rank 0 performs file I/O.
1764 if (!rank) {
1765 FILE *f;
1766 char filen[PETSC_MAX_PATH_LEN + 64];
1767 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/Continuity_Metrics.log", simCtx->log_dir); CHKERRQ(ierr);
1768
1769 // Open the log file in append mode.
1770 f = fopen(filen, "a");
1771 if (!f) {
1772 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
1773 }
1774
1775 // Write a header only when the file is empty and it's the first block (bi=0).
1776 // Using ftell() instead of step comparison ensures correctness across continuations.
1777 if (ftell(f) == 0 && bi == 0) {
1778 PetscFPrintf(PETSC_COMM_SELF, f, "%-10s | %-6s | %-18s | %-30s | %-18s | %-18s | %-18s | %-18s\n",
1779 "Timestep", "Block", "Max Divergence", "Max Divergence Location ([k][j][i]=idx)", "Sum(RHS)","Total Flux In", "Total Flux Out", "Net Flux");
1780 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------------------------------\n");
1781 }
1782
1783 // Prepare the data strings and values for the current block.
1784 PetscReal net_flux = simCtx->FluxInSum - simCtx->FluxOutSum;
1785 char location_str[64];
1786 sprintf(location_str, "([%d][%d][%d] = %d)", (int)simCtx->MaxDivz, (int)simCtx->MaxDivy, (int)simCtx->MaxDivx, (int)simCtx->MaxDivFlatArg);
1787
1788 // Write the formatted line for the current block.
1789 PetscFPrintf(PETSC_COMM_SELF, f, "%-10d | %-6d | %-18.10e | %-39s | %-18.10e | %-18.10e | %-18.10e | %-18.10e\n",
1790 (int)ti,
1791 (int)bi,
1792 (double)simCtx->MaxDiv,
1793 location_str,
1794 (double)simCtx->summationRHS,
1795 (double)simCtx->FluxInSum,
1796 (double)simCtx->FluxOutSum,
1797 (double)net_flux);
1798
1799 fclose(f);
1800 }
1801
1802 PetscFunctionReturn(0);
1803}
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:833
PetscReal FluxOutSum
Definition variables.h:735
PetscInt _this
Definition variables.h:843
PetscReal MaxDiv
Definition variables.h:785
PetscInt MaxDivx
Definition variables.h:786
PetscInt MaxDivy
Definition variables.h:786
PetscInt MaxDivz
Definition variables.h:786
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:676
PetscInt MaxDivFlatArg
Definition variables.h:786
PetscReal FluxInSum
Definition variables.h:735
PetscInt step
Definition variables.h:659
PetscReal summationRHS
Definition variables.h:784
The master context for the entire simulation.
Definition variables.h:651
Here is the caller graph for this function:

◆ LOG_SOLUTION_CONVERGENCE()

PetscErrorCode LOG_SOLUTION_CONVERGENCE ( SimCtx simCtx)

Logs physical solution-convergence metrics once per completed timestep.

This logger is intentionally separate from the detailed inner solver-health logs. Depending on the configured mode, it records deterministic step drift, periodic phase-aligned drift, or statistical window drift into logs/solution_convergence.log.

The logger is solver-mode only and is intended to run after a completed flow-solve / projection step but before history vectors are shifted forward. Warmup rows are handled internally:

  • steady/transient mode: the first logged step has has_reference = 0
  • periodic mode: the first cycle fills the phase reference ring
  • statistical mode: window-drift fields remain zero until enough samples exist to form the requested windows

Existing detailed inner logs remain the authoritative source for momentum, Poisson, and continuity health. This logger only summarizes physical solution-drift metrics.

Parameters
[in,out]simCtxMaster simulation context controlling the logging mode and owning any supporting runtime buffers.
Returns
PetscErrorCode 0 on success.

Logs physical solution-convergence metrics once per completed timestep.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_SOLUTION_CONVERGENCE()

Definition at line 1560 of file logging.c.

1561{
1562 PetscMPIInt rank = 0;
1563 PetscBool has_reference = PETSC_FALSE;
1564 PetscInt phase_step = -1;
1565 PetscInt samples_before = 0;
1566 PetscReal u_abs_l2 = 0.0, u_rel_l2 = 0.0, p_abs_l2 = 0.0, p_rel_l2 = 0.0;
1567 PetscReal mean_speed = 0.0, mean_speed_reference = 0.0, mean_speed_abs_drift = 0.0, mean_speed_rel_drift = 0.0;
1568 PetscReal mean_ke = 0.0, mean_ke_reference = 0.0, mean_ke_abs_drift = 0.0, mean_ke_rel_drift = 0.0;
1569 PetscReal mean_speed_window = 0.0, mean_speed_window_prev = 0.0, mean_speed_window_abs_drift = 0.0, mean_speed_window_rel_drift = 0.0;
1570 PetscReal mean_speed_rms_window = 0.0, mean_speed_rms_window_prev = 0.0, mean_speed_rms_window_abs_drift = 0.0, mean_speed_rms_window_rel_drift = 0.0;
1571 PetscReal mean_ke_window = 0.0, mean_ke_window_prev = 0.0, mean_ke_window_abs_drift = 0.0, mean_ke_window_rel_drift = 0.0;
1572 PetscReal mean_ke_rms_window = 0.0, mean_ke_rms_window_prev = 0.0, mean_ke_rms_window_abs_drift = 0.0, mean_ke_rms_window_rel_drift = 0.0;
1573
1574 PetscFunctionBeginUser;
1575 if (!simCtx) PetscFunctionReturn(0);
1576 if (simCtx->exec_mode != EXEC_MODE_SOLVER) PetscFunctionReturn(0);
1577
1578 samples_before = simCtx->solutionConvergenceSamplesRecorded;
1579
1580 switch (simCtx->solutionConvergenceMode) {
1583 PetscCall(ComputeDeterministicSolutionMetrics(simCtx, PETSC_FALSE, -1, samples_before,
1584 &has_reference,
1585 &u_abs_l2, &u_rel_l2,
1586 &p_abs_l2, &p_rel_l2,
1587 &mean_speed, &mean_speed_reference,
1588 &mean_speed_abs_drift, &mean_speed_rel_drift,
1589 &mean_ke, &mean_ke_reference,
1590 &mean_ke_abs_drift, &mean_ke_rel_drift));
1591 break;
1593 phase_step = simCtx->solutionConvergencePeriodSteps > 0 ? (simCtx->step % simCtx->solutionConvergencePeriodSteps) : -1;
1594 PetscCall(ComputeDeterministicSolutionMetrics(simCtx, PETSC_TRUE, phase_step, samples_before,
1595 &has_reference,
1596 &u_abs_l2, &u_rel_l2,
1597 &p_abs_l2, &p_rel_l2,
1598 &mean_speed, &mean_speed_reference,
1599 &mean_speed_abs_drift, &mean_speed_rel_drift,
1600 &mean_ke, &mean_ke_reference,
1601 &mean_ke_abs_drift, &mean_ke_rel_drift));
1602 break;
1604 PetscCall(ComputeCurrentFlowObservables(simCtx, &mean_speed, &mean_ke));
1605 PetscCall(AppendStatisticalObservableSample(simCtx, samples_before, mean_speed, mean_ke));
1606 PetscCall(ComputeStatisticalWindowMetrics(simCtx, samples_before + 1,
1607 &has_reference,
1608 &mean_speed_window, &mean_speed_window_prev,
1609 &mean_speed_window_abs_drift, &mean_speed_window_rel_drift,
1610 &mean_speed_rms_window, &mean_speed_rms_window_prev,
1611 &mean_speed_rms_window_abs_drift, &mean_speed_rms_window_rel_drift,
1612 &mean_ke_window, &mean_ke_window_prev,
1613 &mean_ke_window_abs_drift, &mean_ke_window_rel_drift,
1614 &mean_ke_rms_window, &mean_ke_rms_window_prev,
1615 &mean_ke_rms_window_abs_drift, &mean_ke_rms_window_rel_drift));
1616 break;
1617 default:
1618 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown solution convergence mode %d.", (int)simCtx->solutionConvergenceMode);
1619 }
1620
1621 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1622 if (rank == 0) {
1623 char log_path[PETSC_MAX_PATH_LEN + 32];
1624 FILE *f = NULL;
1625 const char *mode_str = SolutionConvergenceModeToString(simCtx->solutionConvergenceMode);
1626
1627 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1628 f = fopen(log_path, "a");
1629 if (!f) {
1630 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open solution convergence log: %s", log_path);
1631 }
1632
1633 if (ftell(f) == 0) {
1634 switch (simCtx->solutionConvergenceMode) {
1637 fprintf(f, "==================== Solution Convergence Log [mode: %s] ====================\n", mode_str);
1638 /* 16 columns; header width = 314 chars */
1639 fprintf(f, "%-10s | %-18s | %-22s | %-3s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s\n",
1640 "step", "time", "mode", "ref",
1641 "u_abs_l2", "u_rel_l2", "p_abs_l2", "p_rel_l2",
1642 "mean_speed", "spd_ref", "spd_abs", "spd_rel",
1643 "mean_ke", "ke_ref", "ke_abs", "ke_rel");
1644 fprintf(f, "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
1645 break;
1647 fprintf(f, "==================== Solution Convergence Log [mode: %s | period_steps: %d] ====================\n",
1648 mode_str, (int)simCtx->solutionConvergencePeriodSteps);
1649 /* 18 columns; header width = 330 chars */
1650 fprintf(f, "%-10s | %-18s | %-22s | %-3s | %-5s | %-5s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s\n",
1651 "step", "time", "mode", "ref", "ph", "per",
1652 "u_abs_l2", "u_rel_l2", "p_abs_l2", "p_rel_l2",
1653 "mean_speed", "spd_ref", "spd_abs", "spd_rel",
1654 "mean_ke", "ke_ref", "ke_abs", "ke_rel");
1655 fprintf(f, "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
1656 break;
1658 fprintf(f, "==================== Solution Convergence Log [mode: %s | window_steps: %d] ====================\n",
1659 mode_str, (int)simCtx->solutionConvergenceWindowSteps);
1660 /* 21 columns; header width = 406 chars */
1661 fprintf(f, "%-10s | %-18s | %-22s | %-3s | %-5s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s\n",
1662 "step", "time", "mode", "ref", "win",
1663 "mean_speed", "mean_ke",
1664 "spd_win", "spd_win_prev", "spd_win_abs", "spd_win_rel",
1665 "spd_rms_win", "spd_rms_abs", "spd_rms_rel",
1666 "ke_win", "ke_win_prev", "ke_win_abs", "ke_win_rel",
1667 "ke_rms_win", "ke_rms_abs", "ke_rms_rel");
1668 fprintf(f, "------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
1669 break;
1670 default: break;
1671 }
1672 }
1673
1674 switch (simCtx->solutionConvergenceMode) {
1677 fprintf(f,
1678 "%-10d | %-18.10e | %-22s | %-3d | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e\n",
1679 (int)simCtx->step, (double)simCtx->ti, mode_str, has_reference ? 1 : 0,
1680 (double)u_abs_l2, (double)u_rel_l2, (double)p_abs_l2, (double)p_rel_l2,
1681 (double)mean_speed, (double)mean_speed_reference,
1682 (double)mean_speed_abs_drift, (double)mean_speed_rel_drift,
1683 (double)mean_ke, (double)mean_ke_reference,
1684 (double)mean_ke_abs_drift, (double)mean_ke_rel_drift);
1685 break;
1687 fprintf(f,
1688 "%-10d | %-18.10e | %-22s | %-3d | %-5d | %-5d | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e\n",
1689 (int)simCtx->step, (double)simCtx->ti, mode_str, has_reference ? 1 : 0,
1690 (int)phase_step, (int)simCtx->solutionConvergencePeriodSteps,
1691 (double)u_abs_l2, (double)u_rel_l2, (double)p_abs_l2, (double)p_rel_l2,
1692 (double)mean_speed, (double)mean_speed_reference,
1693 (double)mean_speed_abs_drift, (double)mean_speed_rel_drift,
1694 (double)mean_ke, (double)mean_ke_reference,
1695 (double)mean_ke_abs_drift, (double)mean_ke_rel_drift);
1696 break;
1698 fprintf(f,
1699 "%-10d | %-18.10e | %-22s | %-3d | %-5d | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e | %-18.10e\n",
1700 (int)simCtx->step, (double)simCtx->ti, mode_str, has_reference ? 1 : 0,
1701 (int)simCtx->solutionConvergenceWindowSteps,
1702 (double)mean_speed, (double)mean_ke,
1703 (double)mean_speed_window, (double)mean_speed_window_prev,
1704 (double)mean_speed_window_abs_drift, (double)mean_speed_window_rel_drift,
1705 (double)mean_speed_rms_window,
1706 (double)mean_speed_rms_window_abs_drift, (double)mean_speed_rms_window_rel_drift,
1707 (double)mean_ke_window, (double)mean_ke_window_prev,
1708 (double)mean_ke_window_abs_drift, (double)mean_ke_window_rel_drift,
1709 (double)mean_ke_rms_window,
1710 (double)mean_ke_rms_window_abs_drift, (double)mean_ke_rms_window_rel_drift);
1711 break;
1712 default: break;
1713 }
1714 fclose(f);
1715 }
1716
1718 phase_step >= 0 && phase_step < simCtx->solutionConvergencePeriodSteps) {
1719 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
1720 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
1721 PetscCall(VecCopy(user[bi].Ucat, user[bi].solutionConvergencePeriodicUcatRef[phase_step]));
1722 PetscCall(VecCopy(user[bi].P, user[bi].solutionConvergencePeriodicPRef[phase_step]));
1723 }
1724 }
1725
1726 simCtx->solutionConvergenceSamplesRecorded = samples_before + 1;
1727
1728 PetscFunctionReturn(0);
1729}
static PetscErrorCode AppendStatisticalObservableSample(SimCtx *simCtx, PetscInt samples_before, PetscReal mean_speed, PetscReal mean_ke)
Appends one timestep's scalar observables to the statistical history.
Definition logging.c:1330
static const char * SolutionConvergenceModeToString(SolutionConvergenceMode mode)
Maps the internal solution-convergence mode enum to its log label.
Definition logging.c:1543
static PetscErrorCode ComputeStatisticalWindowMetrics(const SimCtx *simCtx, PetscInt samples_available, PetscBool *has_reference_out, PetscReal *mean_speed_window_out, PetscReal *mean_speed_window_prev_out, PetscReal *mean_speed_window_abs_out, PetscReal *mean_speed_window_rel_out, PetscReal *mean_speed_rms_window_out, PetscReal *mean_speed_rms_window_prev_out, PetscReal *mean_speed_rms_window_abs_out, PetscReal *mean_speed_rms_window_rel_out, PetscReal *mean_ke_window_out, PetscReal *mean_ke_window_prev_out, PetscReal *mean_ke_window_abs_out, PetscReal *mean_ke_window_rel_out, PetscReal *mean_ke_rms_window_out, PetscReal *mean_ke_rms_window_prev_out, PetscReal *mean_ke_rms_window_abs_out, PetscReal *mean_ke_rms_window_rel_out)
Computes adjacent-window drift metrics for statistical steady mode.
Definition logging.c:1410
static PetscErrorCode ComputeDeterministicSolutionMetrics(SimCtx *simCtx, PetscBool periodic_mode, PetscInt phase_step, PetscInt samples_before, PetscBool *has_reference_out, PetscReal *u_abs_l2_out, PetscReal *u_rel_l2_out, PetscReal *p_abs_l2_out, PetscReal *p_rel_l2_out, PetscReal *mean_speed_out, PetscReal *mean_speed_ref_out, PetscReal *mean_speed_abs_out, PetscReal *mean_speed_rel_out, PetscReal *mean_ke_out, PetscReal *mean_ke_ref_out, PetscReal *mean_ke_abs_out, PetscReal *mean_ke_rel_out)
Computes deterministic solution-drift metrics for the current step.
Definition logging.c:1064
static PetscErrorCode ComputeCurrentFlowObservables(SimCtx *simCtx, PetscReal *mean_speed_out, PetscReal *mean_ke_out)
Computes instantaneous global flow observables for statistical mode.
Definition logging.c:954
UserCtx * user
Definition variables.h:536
PetscInt block_number
Definition variables.h:726
UserMG usermg
Definition variables.h:778
PetscInt solutionConvergenceSamplesRecorded
Definition variables.h:710
PetscInt solutionConvergencePeriodSteps
Definition variables.h:708
PetscInt mglevels
Definition variables.h:543
PetscInt solutionConvergenceWindowSteps
Definition variables.h:709
@ EXEC_MODE_SOLVER
Definition variables.h:624
MGCtx * mgctx
Definition variables.h:546
@ SOLUTION_CONVERGENCE_TRANSIENT
Definition variables.h:512
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:510
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
Definition variables.h:511
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:509
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:707
ExecutionMode exec_mode
Definition variables.h:670
PetscReal ti
Definition variables.h:660
User-defined context containing data specific to a single computational grid level.
Definition variables.h:830
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ParticleLocationStatusToString()

const char * ParticleLocationStatusToString ( ParticleLocationStatus  level)

A function that outputs the name of the current level in the ParticleLocation enum.

Parameters
levelThe ParticleLocation enum value.
Returns
A constant character string corresponding to the enum. Returns "UNKNOWN_LEVEL" if the enum value is not recognized.

A function that outputs the name of the current level in the ParticleLocation enum.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
ParticleLocationStatusToString()

Definition at line 1811 of file logging.c.

1812{
1813 switch (level) {
1814 case NEEDS_LOCATION: return "NEEDS_LOCATION";
1815 case ACTIVE_AND_LOCATED: return "ACTIVE_AND_LOCATED";
1816 case MIGRATING_OUT: return "MIGRATING_OUT";
1817 case LOST: return "LOST";
1818 case UNINITIALIZED: return "UNINITIALIZED";
1819 default: return "UNKNOWN_LEVEL";
1820 }
1821}
@ LOST
Definition variables.h:139
@ NEEDS_LOCATION
Definition variables.h:136
@ ACTIVE_AND_LOCATED
Definition variables.h:137
@ UNINITIALIZED
Definition variables.h:140
@ MIGRATING_OUT
Definition variables.h:138
Here is the caller graph for this function:

◆ PrintProgressBar()

void PrintProgressBar ( PetscInt  step,
PetscInt  startStep,
PetscInt  totalSteps,
PetscReal  currentTime 
)

Prints a progress bar to the console.

This function should only be called by the root process (rank 0). It uses a carriage return \r to overwrite the same line in the terminal, creating a dynamic progress bar.

Parameters
stepThe current step index from the loop (e.g., from 0 to N-1).
startStepThe global starting step number of the simulation.
totalStepsThe total number of steps to be run in this simulation instance.
currentTimeThe current simulation time to display.

Prints a progress bar to the console.

Local to this translation unit.

Definition at line 2254 of file logging.c.

2255{
2256 if (totalSteps <= 0) return;
2257
2258 // --- Configuration ---
2259 const int barWidth = 50;
2260
2261 // --- Calculation ---
2262 // Calculate progress as a fraction from 0.0 to 1.0
2263 PetscReal progress = (PetscReal)(step - startStep + 1) / totalSteps;
2264 // Ensure progress doesn't exceed 1.0 due to floating point inaccuracies
2265 if (progress > 1.0) progress = 1.0;
2266
2267 int pos = (int)(barWidth * progress);
2268
2269 // --- Printing ---
2270 // Carriage return moves cursor to the beginning of the line
2271 PetscPrintf(PETSC_COMM_SELF, "\rProgress: [");
2272
2273 for (int i = 0; i < barWidth; ++i) {
2274 if (i < pos) {
2275 PetscPrintf(PETSC_COMM_SELF, "=");
2276 } else if (i == pos) {
2277 PetscPrintf(PETSC_COMM_SELF, ">");
2278 } else {
2279 PetscPrintf(PETSC_COMM_SELF, " ");
2280 }
2281 }
2282
2283 // Print percentage, step count, and current time
2284 PetscPrintf(PETSC_COMM_SELF, "] %3d%% (Step %" PetscInt_FMT "/%" PetscInt_FMT ", t=%.4f)",
2285 (int)(progress * 100.0),
2286 step + 1,
2287 startStep + totalSteps,
2288 currentTime);
2289
2290 // Flush the output buffer to ensure the bar is displayed immediately
2291 fflush(stdout);
2292}
Here is the caller graph for this function:

◆ ProfilingInitialize()

PetscErrorCode ProfilingInitialize ( SimCtx simCtx)

Initializes the custom profiling system using configuration from SimCtx.

This function sets up the internal data structures for tracking function performance. It reads the list of "critical functions" from the provided SimCtx and marks them for per-step logging at LOG_INFO level.

It should be called once at the beginning of the application, after CreateSimulationContext() but before the main time loop.

Parameters
simCtxThe master simulation context, which contains the list of critical function names to always log.
Returns
PetscErrorCode

Initializes the custom profiling system using configuration from SimCtx.

Local to this translation unit.

Definition at line 1882 of file logging.c.

1883{
1884 PetscFunctionBeginUser;
1885 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingInitialize");
1886
1887 // Iterate through the list of critical functions provided in SimCtx
1888 for (PetscInt i = 0; i < simCtx->nProfilingSelectedFuncs; ++i) {
1889 PetscInt idx;
1890 const char *func_name = simCtx->profilingSelectedFuncs[i];
1891 PetscErrorCode ierr = _FindOrCreateEntry(func_name, &idx); CHKERRQ(ierr);
1892 g_profiler_registry[idx].always_log = PETSC_TRUE;
1893
1894 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Marked '%s' as a critical function for profiling.\n", func_name);
1895 }
1896 PetscFunctionReturn(0);
1897}
PetscBool always_log
Definition logging.c:1833
static PetscErrorCode _FindOrCreateEntry(const char *func_name, PetscInt *idx)
Internal helper implementation: _FindOrCreateEntry().
Definition logging.c:1846
static ProfiledFunction * g_profiler_registry
Definition logging.c:1837
char ** profilingSelectedFuncs
Definition variables.h:790
PetscInt nProfilingSelectedFuncs
Definition variables.h:791
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ProfilingResetTimestepCounters()

PetscErrorCode ProfilingResetTimestepCounters ( void  )

Resets per-timestep profiling counters for the next solver step.

This clears transient counters without discarding cumulative totals used by final profiling summaries.

Returns
PetscErrorCode 0 on success.

Resets per-timestep profiling counters for the next solver step.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
ProfilingResetTimestepCounters()

Definition at line 1942 of file logging.c.

1943{
1944 PetscFunctionBeginUser;
1945 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1948 }
1949 PetscFunctionReturn(0);
1950}
static PetscInt g_profiler_count
Definition logging.c:1838
double current_step_time
Definition logging.c:1829
long long current_step_call_count
Definition logging.c:1831
Here is the caller graph for this function:

◆ ProfilingLogTimestepSummary()

PetscErrorCode ProfilingLogTimestepSummary ( SimCtx simCtx,
PetscInt  step 
)

Logs the performance summary for the current timestep and resets timers.

Depending on the configured profiling timestep mode, this function writes per-step profiling rows to the configured profiling log file:

  • off: writes nothing
  • selected: writes only functions marked for per-step reporting
  • all: writes every instrumented function that ran in the timestep

It must be called once per timestep, typically at the end of the main loop. After logging, it resets the per-step counters and timers.

Parameters
simCtxThe simulation context holding profiling output settings.
stepThe current simulation step number, for logging context.
Returns
PetscErrorCode

Logs the performance summary for the current timestep and resets timers.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
ProfilingLogTimestepSummary()

Definition at line 1959 of file logging.c.

1960{
1961 PetscBool should_write = PETSC_FALSE;
1962 FILE *f = NULL;
1963 char filen[(2 * PETSC_MAX_PATH_LEN) + 16];
1964
1965 PetscFunctionBeginUser;
1966 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingLogTimestepSummary");
1967
1968 if (strcmp(simCtx->profilingTimestepMode, "off") == 0) {
1969 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1972 }
1973 PetscFunctionReturn(0);
1974 }
1975
1976 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1977 if (g_profiler_registry[i].current_step_call_count <= 0) {
1978 continue;
1979 }
1980 if (strcmp(simCtx->profilingTimestepMode, "all") == 0 || g_profiler_registry[i].always_log) {
1981 should_write = PETSC_TRUE;
1982 break;
1983 }
1984 }
1985
1986 if (should_write && simCtx->rank == 0) {
1987 snprintf(filen, sizeof(filen), "%s/%s", simCtx->log_dir, simCtx->profilingTimestepFile);
1988 if (step == simCtx->StartStep + 1 && !simCtx->continueMode) {
1989 f = fopen(filen, "w");
1990 if (!f) {
1991 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open profiling timestep log file: %s", filen);
1992 }
1993 PetscFPrintf(PETSC_COMM_SELF, f, "step,function,calls,step_time_s\n");
1994 } else {
1995 f = fopen(filen, "a");
1996 if (!f) {
1997 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open profiling timestep log file: %s", filen);
1998 }
1999 if (step == simCtx->StartStep + 1 && ftell(f) == 0) {
2000 PetscFPrintf(PETSC_COMM_SELF, f, "step,function,calls,step_time_s\n");
2001 }
2002 }
2003
2004 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2005 if (g_profiler_registry[i].current_step_call_count <= 0) {
2006 continue;
2007 }
2008 if (strcmp(simCtx->profilingTimestepMode, "all") == 0 || g_profiler_registry[i].always_log) {
2009 PetscFPrintf(
2010 PETSC_COMM_SELF,
2011 f,
2012 "%d,%s,%lld,%.6f\n",
2013 (int)step,
2014 g_profiler_registry[i].name,
2015 g_profiler_registry[i].current_step_call_count,
2016 g_profiler_registry[i].current_step_time
2017 );
2018 }
2019 }
2020 fclose(f);
2021 }
2022
2023 // Reset per-step counters for the next iteration
2024 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2027 }
2028 PetscFunctionReturn(0);
2029}
PetscBool continueMode
Definition variables.h:668
PetscMPIInt rank
Definition variables.h:654
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
Definition variables.h:793
char profilingTimestepMode[32]
Definition variables.h:792
PetscInt StartStep
Definition variables.h:661
Here is the caller graph for this function:

◆ RuntimeMemoryLogSample()

PetscErrorCode RuntimeMemoryLogSample ( SimCtx simCtx,
PetscInt  step,
const char *  event,
const char *  reason 
)

Append a reduced runtime memory sample to the configured memory log.

The log is intentionally compact: every rank samples process/PETSc allocator memory, one max reduction summarizes the job, and rank 0 appends one terminal-readable row.

Parameters
simCtxThe simulation context holding log directory and memory log settings.
stepThe solver/post step associated with the sample.
eventHuman-readable event label such as "Step", "Post", "Shutdown", or "Final".
reasonHuman-readable reason, or NULL/"-" when not applicable.
Returns
PetscErrorCode

Append a reduced runtime memory sample to the configured memory log.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
RuntimeMemoryLogSample()

Definition at line 2037 of file logging.c.

2038{
2039 PetscErrorCode ierr;
2040 PetscLogDouble process_current_bytes = 0.0;
2041 PetscLogDouble process_peak_bytes = 0.0;
2042 PetscLogDouble petsc_current_bytes = 0.0;
2043 PetscLogDouble petsc_peak_bytes = 0.0;
2044 PetscReal local_values[5];
2045 PetscReal global_values[5];
2046 PetscReal process_current_mb = 0.0;
2047 PetscReal process_peak_mb = 0.0;
2048 PetscReal petsc_current_mb = 0.0;
2049 PetscReal petsc_peak_mb = 0.0;
2050 PetscReal process_change_mb = 0.0;
2051 char path[(2 * PETSC_MAX_PATH_LEN) + 16];
2052 FILE *f = NULL;
2053
2054 PetscFunctionBeginUser;
2055 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for RuntimeMemoryLogSample");
2056 if (!simCtx->runtimeMemoryLogEnabled) PetscFunctionReturn(0);
2057
2058 ierr = PetscMemoryGetCurrentUsage(&process_current_bytes); CHKERRQ(ierr);
2059 ierr = PetscMemoryGetMaximumUsage(&process_peak_bytes); CHKERRQ(ierr);
2060 ierr = PetscMallocGetCurrentUsage(&petsc_current_bytes); CHKERRQ(ierr);
2061 ierr = PetscMallocGetMaximumUsage(&petsc_peak_bytes); CHKERRQ(ierr);
2062
2063 process_current_mb = (PetscReal)(process_current_bytes / (1024.0 * 1024.0));
2064 process_peak_mb = (PetscReal)(process_peak_bytes / (1024.0 * 1024.0));
2065 petsc_current_mb = (PetscReal)(petsc_current_bytes / (1024.0 * 1024.0));
2066 petsc_peak_mb = (PetscReal)(petsc_peak_bytes / (1024.0 * 1024.0));
2067 if (simCtx->runtimeMemoryLogHasPrevious) {
2068 process_change_mb = process_current_mb - simCtx->runtimeMemoryLogPreviousProcessMB;
2069 }
2070
2071 local_values[0] = process_current_mb;
2072 local_values[1] = process_peak_mb;
2073 local_values[2] = petsc_current_mb;
2074 local_values[3] = petsc_peak_mb;
2075 local_values[4] = process_change_mb;
2076 ierr = MPI_Allreduce(local_values, global_values, 5, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2077
2078 simCtx->runtimeMemoryLogPreviousProcessMB = process_current_mb;
2079 simCtx->runtimeMemoryLogHasPrevious = PETSC_TRUE;
2080
2081 if (simCtx->rank == 0) {
2082 ierr = PetscSNPrintf(path, sizeof(path), "%s/%s", simCtx->log_dir, simCtx->runtimeMemoryLogFile); CHKERRQ(ierr);
2083 f = fopen(path, "a");
2084 if (!f) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open runtime memory log file: %s", path);
2085
2086 if (!simCtx->runtimeMemoryLogStarted) {
2087 fprintf(f, "# PICurv runtime memory log\n");
2088 if (simCtx->continueMode) {
2089 fprintf(f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
2090 }
2091 fprintf(
2092 f,
2093 "%-8s %-10s %22s %20s %22s %28s %22s %-18s\n",
2094 "Step",
2095 "Event",
2096 "Process Current MB Max",
2097 "Process Peak MB Max",
2098 "PETSc Allocated MB Max",
2099 "PETSc Peak Allocated MB Max",
2100 "Process Change MB Max",
2101 "Reason"
2102 );
2103 simCtx->runtimeMemoryLogStarted = PETSC_TRUE;
2104 }
2105
2106 fprintf(
2107 f,
2108 "%-8" PetscInt_FMT " %-10s %22.3f %20.3f %22.3f %28.3f %22.3f %-18s\n",
2109 step,
2110 event ? event : "-",
2111 (double)global_values[0],
2112 (double)global_values[1],
2113 (double)global_values[2],
2114 (double)global_values[3],
2115 (double)global_values[4],
2116 (reason && reason[0]) ? reason : "-"
2117 );
2118 if ((event && (strcmp(event, "Shutdown") == 0 || strcmp(event, "Final") == 0))) {
2119 fflush(f);
2120 }
2121 fclose(f);
2122 }
2123
2124 PetscFunctionReturn(0);
2125}
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
Definition variables.h:809
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
Definition variables.h:810
PetscBool runtimeMemoryLogStarted
True after rank 0 writes the log header.
Definition variables.h:811
PetscBool runtimeMemoryLogHasPrevious
True after the first process-memory sample.
Definition variables.h:812
PetscReal runtimeMemoryLogPreviousProcessMB
Previous local process memory sample in MB.
Definition variables.h:813
Here is the caller graph for this function:

◆ ProfilingFinalize()

PetscErrorCode ProfilingFinalize ( SimCtx simCtx)

the profiling excercise and build a profiling summary which is then printed to a log file.

Parameters
simCtxThe Simulation Context Structure that can contains all the data regarding the simulation.
Returns
PetscErrorCode 0 on success.

the profiling excercise and build a profiling summary which is then printed to a log file.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
ProfilingFinalize()

Definition at line 2148 of file logging.c.

2149{
2150 PetscErrorCode ierr;
2151 PetscInt rank = simCtx->rank;
2152 PetscFunctionBeginUser;
2153 if (!simCtx->profilingFinalSummary) PetscFunctionReturn(0);
2154 if (!rank) {
2155
2156 char exec_mode_modifier[32] = "Unknown";
2157 if(simCtx->exec_mode == EXEC_MODE_SOLVER) PetscCall(PetscStrncpy(exec_mode_modifier, "Solver", sizeof(exec_mode_modifier)));
2158 else if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) PetscCall(PetscStrncpy(exec_mode_modifier, "PostProcessor", sizeof(exec_mode_modifier)));
2159 //--- Step 0: Create a file viewer for log file
2160 FILE *f;
2161 char filen[PETSC_MAX_PATH_LEN + 128];
2162 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/ProfilingSummary_%s.log",simCtx->log_dir,exec_mode_modifier); CHKERRQ(ierr);
2163
2164 // Open the log file: append with section label in continue mode, truncate otherwise.
2165 if (simCtx->continueMode) {
2166 f = fopen(filen, "a");
2167 if (!f) {
2168 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
2169 }
2170 fprintf(f, "\n=== Continuation from step %" PetscInt_FMT " ===\n", simCtx->StartStep);
2171 } else {
2172 f = fopen(filen, "w");
2173 if (!f) {
2174 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
2175 }
2176 }
2177
2178 // --- Step 1: Sort the data for readability ---
2180
2181 // --- Step 2: Dynamically determine the width for the function name column ---
2182 PetscInt max_name_len = strlen("Function"); // Start with the header's length
2183 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2184 if (g_profiler_registry[i].total_call_count > 0) {
2185 PetscInt len = strlen(g_profiler_registry[i].name);
2186 if (len > max_name_len) {
2187 max_name_len = len;
2188 }
2189 }
2190 }
2191 // Add a little padding
2192 max_name_len += 2;
2193
2194 // --- Step 3: Define fixed widths for numeric columns for consistent alignment ---
2195 const int time_width = 18;
2196 const int count_width = 15;
2197 const int avg_width = 22;
2198
2199 // --- Step 4: Print the formatted table ---
2200 PetscFPrintf(PETSC_COMM_SELF, f, "=================================================================================================================\n");
2201 PetscFPrintf(PETSC_COMM_SELF, f, " FINAL PROFILING SUMMARY (Sorted by Total Time)\n");
2202 PetscFPrintf(PETSC_COMM_SELF, f, "=================================================================================================================\n");
2203
2204 // Header Row
2205 PetscFPrintf(PETSC_COMM_SELF, f, "%-*s | %-*s | %-*s | %-*s\n",
2206 max_name_len, "Function",
2207 time_width, "Total Time (s)",
2208 count_width, "Call Count",
2209 avg_width, "Avg. Time/Call (ms)");
2210
2211 // Separator Line (dynamically sized)
2212 for (int i = 0; i < max_name_len; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2213 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
2214 for (int i = 0; i < time_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2215 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
2216 for (int i = 0; i < count_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2217 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
2218 for (int i = 0; i < avg_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2219 PetscFPrintf(PETSC_COMM_SELF, f, "\n");
2220
2221 // Data Rows
2222 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2223 if (g_profiler_registry[i].total_call_count > 0) {
2224 double avg_time_ms = (g_profiler_registry[i].total_time / g_profiler_registry[i].total_call_count) * 1000.0;
2225 PetscFPrintf(PETSC_COMM_SELF, f, "%-*s | %*.*f | %*lld | %*.*f\n",
2226 max_name_len, g_profiler_registry[i].name,
2227 time_width, 6, g_profiler_registry[i].total_time,
2228 count_width, g_profiler_registry[i].total_call_count,
2229 avg_width, 6, avg_time_ms);
2230 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------\n");
2231 }
2232 }
2233 PetscFPrintf(PETSC_COMM_SELF, f, "==================================================================================================================\n");
2234
2235 fclose(f);
2236 }
2237
2238 // --- Final Cleanup ---
2239 PetscFree(g_profiler_registry);
2240 g_profiler_registry = NULL;
2241 g_profiler_count = 0;
2243 PetscFunctionReturn(0);
2244}
long long total_call_count
Definition logging.c:1830
static PetscInt g_profiler_capacity
Definition logging.c:1839
double total_time
Definition logging.c:1828
static int _CompareProfiledFunctions(const void *a, const void *b)
Internal helper implementation: _CompareProfiledFunctions().
Definition logging.c:2132
PetscBool profilingFinalSummary
Definition variables.h:794
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:625
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _ProfilingStart()

void _ProfilingStart ( const char *  func_name)

Internal profiling hook invoked by PROFILE_FUNCTION_BEGIN.

Parameters
func_nameFunction name used by the profiling helper.

Internal profiling hook invoked by PROFILE_FUNCTION_BEGIN.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
_ProfilingStart()

Definition at line 1906 of file logging.c.

1907{
1908 PetscInt idx;
1909 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
1910 PetscTime(&g_profiler_registry[idx].start_time);
1911}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _ProfilingEnd()

void _ProfilingEnd ( const char *  func_name)

Internal profiling hook invoked by PROFILE_FUNCTION_END.

Parameters
func_nameFunction name used by the profiling helper.

Internal profiling hook invoked by PROFILE_FUNCTION_END.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
_ProfilingEnd()

Definition at line 1920 of file logging.c.

1921{
1922 double end_time;
1923 PetscTime(&end_time);
1924
1925 PetscInt idx;
1926 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
1927
1928 double elapsed = end_time - g_profiler_registry[idx].start_time;
1929 g_profiler_registry[idx].total_time += elapsed;
1930 g_profiler_registry[idx].current_step_time += elapsed;
1933}
double start_time
Definition logging.c:1832
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LOG_FIELD_MIN_MAX()

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.

This utility function inspects a PETSc Vec associated with a DMDA and calculates the minimum and maximum values for each of its three components (e.g., x, y, z) both for the local data on the current MPI rank and for the entire global domain.

It uses the same "smart" logic as the flow solver, ignoring the padding nodes at the IM, JM, and KM boundaries of the grid. The results are printed to the standard output in a formatted, easy-to-read table.

Parameters
[in]userPointer to the user-defined context. Used for grid information (IM, JM, KM) and MPI rank.
[in]fieldNameA string descriptor for the field being analyzed (e.g., "Velocity", "Coordinates"). This is used for clear log output.
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Computes and logs the local and global min/max values of a 3-component vector field.

Full API contract is documented with the header declaration in include/logging.h.

See also
LOG_FIELD_MIN_MAX()

Definition at line 2301 of file logging.c.

2302{
2303 PetscErrorCode ierr;
2304 PetscInt i, j, k;
2305 DMDALocalInfo info;
2306
2307 Vec fieldVec = NULL;
2308 DM dm = NULL;
2309 PetscInt dof;
2310 char data_layout[20];
2311
2312 PetscFunctionBeginUser;
2313
2314 // --- 1. Map string name to PETSc objects and determine data layout ---
2315 if (strcasecmp(fieldName, "Ucat") == 0) {
2316 fieldVec = user->Ucat; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
2317 } else if (strcasecmp(fieldName, "P") == 0) {
2318 fieldVec = user->P; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
2319 } else if (strcasecmp(fieldName, "Diffusivity") == 0) {
2320 fieldVec = user->Diffusivity; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
2321 } else if (strcasecmp(fieldName, "DiffusivityGradient") == 0) {
2322 fieldVec = user->DiffusivityGradient; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
2323 } else if (strcasecmp(fieldName, "Ucont") == 0) {
2324 fieldVec = user->lUcont; dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered");
2325 } else if (strcasecmp(fieldName, "Coordinates") == 0) {
2326 ierr = DMGetCoordinates(user->da, &fieldVec); CHKERRQ(ierr);
2327 dm = user->fda; dof = 3; strcpy(data_layout, "Node-Centered");
2328 } else if (strcasecmp(fieldName,"Psi") == 0) {
2329 fieldVec = user->Psi; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered"); // Assuming Psi is cell-centered
2330 } else {
2331 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Field %s not recognized.", fieldName);
2332 }
2333
2334 if (!fieldVec) {
2335 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Vector for field '%s' is NULL.", fieldName);
2336 }
2337 if (!dm) {
2338 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM for field '%s' is NULL.", fieldName);
2339 }
2340
2341 ierr = DMDAGetLocalInfo(dm, &info); CHKERRQ(ierr);
2342
2343 // --- 2. Define Architecture-Aware Loop Bounds ---
2344 PetscInt i_start, i_end, j_start, j_end, k_start, k_end;
2345
2346 if (strcmp(data_layout, "Cell-Centered") == 0) {
2347 // For cell-centered data, the physical values are stored from index 1 to N-1.
2348 // We find the intersection of the rank's owned range [xs, xe) with the
2349 // physical data range [1, IM-1).
2350 i_start = PetscMax(info.xs, 1); i_end = PetscMin(info.xs + info.xm, user->IM);
2351 j_start = PetscMax(info.ys, 1); j_end = PetscMin(info.ys + info.ym, user->JM);
2352 k_start = PetscMax(info.zs, 1); k_end = PetscMin(info.zs + info.zm, user->KM);
2353 } else { // For Node- or Face-Centered data
2354 // The physical values are stored from index 0 to N-1.
2355 // We find the intersection of the rank's owned range [xs, xe) with the
2356 // physical data range [0, IM-1].
2357 i_start = PetscMax(info.xs, 0); i_end = PetscMin(info.xs + info.xm, user->IM);
2358 j_start = PetscMax(info.ys, 0); j_end = PetscMin(info.ys + info.ym, user->JM);
2359 k_start = PetscMax(info.zs, 0); k_end = PetscMin(info.zs + info.zm, user->KM);
2360 }
2361
2362 // --- 3. Barrier for clean, grouped output ---
2363 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
2364 if (user->simCtx->rank == 0) {
2365 PetscPrintf(PETSC_COMM_SELF, "\n--- Field Ranges: [%s] (Layout: %s) ---\n", fieldName, data_layout);
2366 }
2367
2368 // --- 4. Branch on DoF and perform calculation with correct bounds ---
2369 if (dof == 1) {
2370 PetscReal localMin = PETSC_MAX_REAL, localMax = PETSC_MIN_REAL;
2371 PetscReal globalMin, globalMax;
2372 const PetscScalar ***array;
2373
2374 ierr = DMDAVecGetArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2375 for (k = k_start; k < k_end; k++) {
2376 for (j = j_start; j < j_end; j++) {
2377 for (i = i_start; i < i_end; i++) {
2378 localMin = PetscMin(localMin, array[k][j][i]);
2379 localMax = PetscMax(localMax, array[k][j][i]);
2380 }
2381 }
2382 }
2383 ierr = DMDAVecRestoreArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2384
2385 ierr = MPI_Allreduce(&localMin, &globalMin, 1, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
2386 ierr = MPI_Allreduce(&localMax, &globalMax, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
2387
2388 PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin, localMax);
2389 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
2390 if (user->simCtx->rank == 0) {
2391 PetscPrintf(PETSC_COMM_SELF, " Global Range: [ %11.4e , %11.4e ]\n", globalMin, globalMax);
2392 }
2393
2394 } else if (dof == 3) {
2395 Cmpnts localMin = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
2396 Cmpnts localMax = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
2397 Cmpnts globalMin, globalMax;
2398 const Cmpnts ***array;
2399
2400 ierr = DMDAVecGetArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2401 for (k = k_start; k < k_end; k++) {
2402 for (j = j_start; j < j_end; j++) {
2403 for (i = i_start; i < i_end; i++) {
2404 localMin.x = PetscMin(localMin.x, array[k][j][i].x);
2405 localMin.y = PetscMin(localMin.y, array[k][j][i].y);
2406 localMin.z = PetscMin(localMin.z, array[k][j][i].z);
2407 localMax.x = PetscMax(localMax.x, array[k][j][i].x);
2408 localMax.y = PetscMax(localMax.y, array[k][j][i].y);
2409 localMax.z = PetscMax(localMax.z, array[k][j][i].z);
2410 }
2411 }
2412 }
2413 ierr = DMDAVecRestoreArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2414
2415 ierr = MPI_Allreduce(&localMin, &globalMin, 3, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
2416 ierr = MPI_Allreduce(&localMax, &globalMax, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
2417
2418 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local X-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.x, localMax.x);
2419 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Y-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.y, localMax.y);
2420 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Z-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.z, localMax.z);
2421 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
2422
2423 if (user->simCtx->rank == 0) {
2424 PetscPrintf(PETSC_COMM_SELF, " [Global] X-Range: [ %11.4e , %11.4e ]\n", globalMin.x, globalMax.x);
2425 PetscPrintf(PETSC_COMM_SELF, " [Global] Y-Range: [ %11.4e , %11.4e ]\n", globalMin.y, globalMax.y);
2426 PetscPrintf(PETSC_COMM_SELF, " [Global] Z-Range: [ %11.4e , %11.4e ]\n", globalMin.z, globalMax.z);
2427 }
2428
2429 } else {
2430 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "LogFieldStatistics only supports fields with 1 or 3 components, but field '%s' has %" PetscInt_FMT ".", fieldName, dof);
2431 }
2432
2433 // --- 5. Final barrier for clean output ordering ---
2434 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
2435 if (user->simCtx->rank == 0) {
2436 PetscPrintf(PETSC_COMM_SELF, "--------------------------------------------\n\n");
2437 }
2438
2439 PetscFunctionReturn(0);
2440}
PetscInt KM
Definition variables.h:839
Vec DiffusivityGradient
Definition variables.h:860
Vec Ucat
Definition variables.h:856
PetscInt JM
Definition variables.h:839
Vec lUcont
Definition variables.h:856
Vec Diffusivity
Definition variables.h:859
PetscInt IM
Definition variables.h:839
Vec Psi
Definition variables.h:904
A 3D point or vector with PetscScalar components.
Definition variables.h:100
Here is the caller graph for this function:

◆ LOG_FIELD_ANATOMY()

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 grid and variable architecture.

This intelligent diagnostic function inspects a PETSc Vec and prints its values at critical boundary locations (-Xi/+Xi, -Eta/+Eta, -Zeta/+Zeta). It is "architecture-aware":

  • Cell-Centered Fields ("Ucat", "P"): It correctly applies the "Shifted Index Architecture," where the value for geometric Cell i is stored at array index i+1. It labels the output to clearly distinguish between true physical values and ghost values.
  • Face-Centered Fields ("Ucont"): It uses a direct index mapping, where the value for the face at Node i is stored at index i.
  • Node-Centered Fields ("Coordinates"): It uses a direct index mapping, where the value for Node i is stored at index i.

The output is synchronized across MPI ranks to ensure readability and focuses on a slice through the center of the domain to be concise.

Parameters
userA pointer to the UserCtx structure containing the DMs and Vecs.
field_nameA string identifier for the field to log (e.g., "Ucat", "P", "Ucont", "Coordinates").
stage_nameA string identifier for the current simulation stage (e.g., "After Advection").
Returns
PetscErrorCode Returns 0 on success, non-zero on failure.

Logs the anatomy of a specified field at key boundary locations, respecting the solver's specific grid and variable architecture.

Full API contract is documented with the header declaration in include/logging.h.

See also
LOG_FIELD_ANATOMY()

Definition at line 2449 of file logging.c.

2450{
2451 PetscErrorCode ierr;
2452 DMDALocalInfo info;
2453 PetscMPIInt rank;
2454
2455 Vec vec_local = NULL;
2456 DM dm = NULL;
2457 PetscInt dof = 0;
2458 char data_layout[20];
2459 char dominant_dir = '\0'; // 'x', 'y', 'z' for face-centered, 'm' for mixed (Ucont)
2460
2461 PetscFunctionBeginUser;
2462 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2463
2464 // --- 1. Map string name to PETSc objects and determine data layout ---
2465 if (strcasecmp(field_name, "Ucat") == 0) {
2466 vec_local = user->lUcat; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
2467 } else if (strcasecmp(field_name, "P") == 0) {
2468 vec_local = user->lP; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
2469 } else if (strcasecmp(field_name, "Diffusivity") == 0) {
2470 vec_local = user->lDiffusivity; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
2471 } else if (strcasecmp(field_name, "DiffusivityGradient") == 0) {
2472 vec_local = user->lDiffusivityGradient; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
2473 } else if (strcasecmp(field_name, "Psi") == 0) {
2474 vec_local = user->lPsi; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
2475 } else if (strcasecmp(field_name, "Center-Coordinates") == 0) {
2476 vec_local = user->lCent; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
2477 } else if (strcasecmp(field_name, "Ucont") == 0) {
2478 vec_local = user->lUcont; dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'm'; // Mixed
2479 } else if (strcasecmp(field_name, "Csi") == 0 || strcasecmp(field_name, "X-Face-Centers") == 0) {
2480 vec_local = (strcasecmp(field_name, "Csi") == 0) ? user->lCsi : user->Centx;
2481 dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'x';
2482 } else if (strcasecmp(field_name, "Eta") == 0 || strcasecmp(field_name, "Y-Face-Centers") == 0) {
2483 vec_local = (strcasecmp(field_name, "Eta") == 0) ? user->lEta : user->Centy;
2484 dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'y';
2485 } else if (strcasecmp(field_name, "Zet") == 0 || strcasecmp(field_name, "Z-Face-Centers") == 0) {
2486 vec_local = (strcasecmp(field_name, "Zet") == 0) ? user->lZet : user->Centz;
2487 dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'z';
2488 } else if (strcasecmp(field_name, "Coordinates") == 0) {
2489 ierr = DMGetCoordinatesLocal(user->da, &vec_local); CHKERRQ(ierr);
2490 dm = user->fda; dof = 3; strcpy(data_layout, "Node-Centered");
2491 } else if (strcasecmp(field_name, "CornerField")== 0){
2492 vec_local = user->lCellFieldAtCorner; strcpy(data_layout, "Node-Centered");
2493 PetscInt bs = 1;
2494 ierr = VecGetBlockSize(user->CellFieldAtCorner, &bs); CHKERRQ(ierr);
2495 dof = bs;
2496 if(dof == 1) dm = user->da;
2497 else dm = user->fda;
2498 } else {
2499 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown field name for LOG_FIELD_ANATOMY: %s", field_name);
2500 }
2501
2502 // --- 2. Get Grid Info and Array Pointers ---
2503 ierr = DMDAGetLocalInfo(dm, &info); CHKERRQ(ierr);
2504
2505 ierr = PetscBarrier(NULL);
2506 PetscPrintf(PETSC_COMM_WORLD, "\n--- Field Anatomy Log: [%s] | Stage: [%s] | Layout: [%s] ---\n", field_name, stage_name, data_layout);
2507
2508 // Global physical dimensions (number of cells)
2509 PetscInt im_phys = user->IM;
2510 PetscInt jm_phys = user->JM;
2511 PetscInt km_phys = user->KM;
2512
2513 // Slice through the center of the local domain
2514 PetscInt i_mid = (PetscInt)(info.xs + 0.5 * info.xm) - 1;
2515 PetscInt j_mid = (PetscInt)(info.ys + 0.5 * info.ym) - 1;
2516 PetscInt k_mid = (PetscInt)(info.zs + 0.5 * info.zm) - 1;
2517
2518 // --- 3. Print Boundary Information based on Data Layout ---
2519
2520 // ======================================================================
2521 // === CASE 1: Cell-Centered Fields (Ucat, P) - USES SHIFTED INDEX ===
2522 // ======================================================================
2523 if (strcmp(data_layout, "Cell-Centered") == 0) {
2524 const void *l_arr;
2525 ierr = DMDAVecGetArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
2526
2527
2528 // --- I-Direction Boundaries ---
2529 if (info.xs == 0) { // Rank on -Xi boundary
2530 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][0]) = ", rank, 0);
2531 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][0]);
2532 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][0].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][0].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][0].z);
2533
2534 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][0]) = ", rank, 1);
2535 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][1]);
2536 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][1].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][1].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][1].z);
2537 }
2538 if (info.xs + info.xm == info.mx) { // Rank on +Xi boundary
2539 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][%d]) = ", rank, im_phys - 1, im_phys - 2);
2540 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][im_phys - 1]);
2541 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys - 1].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys - 1].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys - 1].z);
2542
2543 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][%d]) = ", rank, im_phys, im_phys - 2);
2544 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][im_phys]);
2545 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys].z);
2546 }
2547
2548 // --- J-Direction Boundaries ---
2549 if (info.ys == 0) { // Rank on -Eta boundary
2550 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][0][i]) = ", rank, 0);
2551 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][0][i_mid]);
2552 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][0][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][0][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][0][i_mid].z);
2553
2554 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][0][i]) = ", rank, 1);
2555 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][1][i_mid]);
2556 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][1][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][1][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][1][i_mid].z);
2557 }
2558
2559 if (info.ys + info.ym == info.my) { // Rank on +Eta boundary
2560 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][%d][i]) = ", rank, jm_phys - 1, jm_phys - 2);
2561 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][jm_phys - 1][i_mid]);
2562 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][jm_phys - 1][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][jm_phys - 1][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][jm_phys - 1][i_mid].z);
2563
2564 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][%d][i]) = ", rank, jm_phys, jm_phys - 2);
2565 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][jm_phys][i_mid]);
2566 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][jm_phys][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][jm_phys][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][jm_phys][i_mid].z);
2567 }
2568
2569 // --- K-Direction Boundaries ---
2570 if (info.zs == 0) { // Rank on -Zeta boundary
2571 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Ghost for Cell[0][j][i]) = ", rank, 0);
2572 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[0][j_mid][i_mid]);
2573 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[0][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[0][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[0][j_mid][i_mid].z);
2574 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Value for Cell[0][j][i]) = ", rank, 1);
2575 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[1][j_mid][i_mid]);
2576 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[1][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[1][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[1][j_mid][i_mid].z);
2577 }
2578 if (info.zs + info.zm == info.mz) { // Rank on +Zeta boundary
2579 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Value for Cell[%d][j][i]) = ", rank, km_phys - 1, km_phys - 2);
2580 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[km_phys - 1][j_mid][i_mid]);
2581 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[km_phys - 1][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[km_phys - 1][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[km_phys - 1][j_mid][i_mid].z);
2582 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Ghost for Cell[%d][j][i]) = ", rank, km_phys, km_phys - 2);
2583 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[km_phys][j_mid][i_mid]);
2584 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[km_phys][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[km_phys][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[km_phys][j_mid][i_mid].z);
2585 }
2586 ierr = DMDAVecRestoreArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
2587 }
2588 // ======================================================================
2589 // === CASE 2: Face-Centered Fields - NUANCED DIRECTIONAL LOGIC ===
2590 // ======================================================================
2591 else if (strcmp(data_layout, "Face-Centered") == 0) {
2592 const Cmpnts ***l_arr;
2593 ierr = DMDAVecGetArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
2594
2595 // --- I-Direction Boundaries ---
2596 if (info.xs == 0) { // Rank on -Xi boundary
2597 if (dominant_dir == 'x') { // Node-like in I-dir
2598 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (First Phys. X-Face) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][j_mid][0].x, l_arr[k_mid][j_mid][0].y, l_arr[k_mid][j_mid][0].z);
2599 } else if (dominant_dir == 'y' || dominant_dir == 'z') { // Cell-like in I-dir
2600 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][0]) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][j_mid][0].x, l_arr[k_mid][j_mid][0].y, l_arr[k_mid][j_mid][0].z);
2601 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][0]) = (%.5f, %.5f, %.5f)\n", rank, 1, l_arr[k_mid][j_mid][1].x, l_arr[k_mid][j_mid][1].y, l_arr[k_mid][j_mid][1].z);
2602 } else if (dominant_dir == 'm') { // Ucont: Mixed
2603 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: u-comp @ Idx %2d (1st X-Face) = %.5f\n", rank, 0, l_arr[k_mid][j_mid][0].x);
2604 }
2605 }
2606 if (info.xs + info.xm == info.mx) { // Rank on +Xi boundary
2607 if (dominant_dir == 'x') { // Node-like in I-dir
2608 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Last Phys. X-Face) = (%.5f, %.5f, %.5f)\n", rank, im_phys - 1, l_arr[k_mid][j_mid][im_phys - 1].x, l_arr[k_mid][j_mid][im_phys-1].y, l_arr[k_mid][j_mid][im_phys - 1].z);
2609 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost Location) = (%.5f, %.5f, %.5f)\n", rank, im_phys, l_arr[k_mid][j_mid][im_phys].x, l_arr[k_mid][j_mid][im_phys].y, l_arr[k_mid][j_mid][im_phys].z);
2610 } else if (dominant_dir == 'y' || dominant_dir == 'z') { // Cell-like in I-dir
2611 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][%d]) = (%.5f, %.5f, %.5f)\n", rank, im_phys - 1, im_phys - 2, l_arr[k_mid][j_mid][im_phys - 1].x, l_arr[k_mid][j_mid][im_phys - 1].y, l_arr[k_mid][j_mid][im_phys-1].z);
2612 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][%d]) = (%.5f, %.5f, %.5f)\n", rank, im_phys, im_phys - 2, l_arr[k_mid][j_mid][im_phys].x, l_arr[k_mid][j_mid][im_phys].y, l_arr[k_mid][j_mid][im_phys].z);
2613 } else if (dominant_dir == 'm') { // Ucont: Mixed
2614 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: u-comp @ Idx %2d (Last X-Face) = %.5f\n", rank, im_phys - 1, l_arr[k_mid][j_mid][im_phys - 1].x);
2615 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: u-comp @ Idx %2d (Ghost Location) = %.5f\n", rank, im_phys, l_arr[k_mid][j_mid][im_phys].x);
2616 }
2617 }
2618
2619 // --- J-Direction Boundaries ---
2620 if (info.ys == 0) { // Rank on -Eta boundary
2621 if (dominant_dir == 'y') { // Node-like in J-dir
2622 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (First Phys. Y-Face) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][0][i_mid].x, l_arr[k_mid][0][i_mid].y, l_arr[k_mid][0][i_mid].z);
2623 } else if (dominant_dir == 'x' || dominant_dir == 'z') { // Cell-like in J-dir
2624 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][0][i]) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][0][i_mid].x, l_arr[k_mid][0][i_mid].y, l_arr[k_mid][0][i_mid].z);
2625 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][0][i]) = (%.5f, %.5f, %.5f)\n", rank, 1, l_arr[k_mid][1][i_mid].x, l_arr[k_mid][1][i_mid].y, l_arr[k_mid][1][i_mid].z);
2626 } else if (dominant_dir == 'm') { // Ucont: Mixed
2627 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: v-comp @ Jdx %2d (1st Y-Face) = %.5f\n", rank, 0, l_arr[k_mid][0][i_mid].y);
2628 }
2629 }
2630 if (info.ys + info.ym == info.my) { // Rank on +Eta boundary
2631 if (dominant_dir == 'y') { // Node-like in J-dir
2632 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Last Phys. Y-Face) = (%.5f, %.5f, %.5f)\n", rank, jm_phys - 1, l_arr[k_mid][jm_phys - 1][i_mid].x, l_arr[k_mid][jm_phys - 1][i_mid].y, l_arr[k_mid][jm_phys - 1][i_mid].z);
2633 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost Location) = (%.5f, %.5f, %.5f)\n", rank, jm_phys, l_arr[k_mid][jm_phys][i_mid].x, l_arr[k_mid][jm_phys][i_mid].y, l_arr[k_mid][jm_phys][i_mid].z);
2634 } else if (dominant_dir == 'x' || dominant_dir == 'z') { // Cell-like in J-dir
2635 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][%d][i]) = (%.5f, %.5f, %.5f)\n", rank, jm_phys-1, jm_phys-2, l_arr[k_mid][jm_phys - 1][i_mid].x, l_arr[k_mid][jm_phys - 1][i_mid].y, l_arr[k_mid][jm_phys - 1][i_mid].z);
2636 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][%d][i]) = (%.5f, %.5f, %.5f)\n", rank, jm_phys, jm_phys-2, l_arr[k_mid][jm_phys][i_mid].x, l_arr[k_mid][jm_phys][i_mid].y, l_arr[k_mid][jm_phys][i_mid].z);
2637 } else if (dominant_dir == 'm') { // Ucont: Mixed
2638 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: v-comp @ Jdx %2d (Last Y-Face) = %.5f\n", rank, jm_phys - 1, l_arr[k_mid][jm_phys - 1][i_mid].y);
2639 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: v-comp @ Jdx %2d (Ghost Location) = %.5f\n", rank, jm_phys, l_arr[k_mid][jm_phys][i_mid].y);
2640 }
2641 }
2642
2643 // --- K-Direction Boundaries ---
2644 if (info.zs == 0) { // Rank on -Zeta boundary
2645 if (dominant_dir == 'z') { // Node-like in K-dir
2646 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (First Phys. Z-Face) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[0][j_mid][i_mid].x, l_arr[0][j_mid][i_mid].y, l_arr[0][j_mid][i_mid].z);
2647 } else if (dominant_dir == 'x' || dominant_dir == 'y') { // Cell-like in K-dir
2648 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Ghost for Cell[0][j][i]) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[0][j_mid][i_mid].x, l_arr[0][j_mid][i_mid].y, l_arr[0][j_mid][i_mid].z);
2649 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Value for Cell[0][j][i]) = (%.5f, %.5f, %.5f)\n", rank, 1, l_arr[1][j_mid][i_mid].x, l_arr[1][j_mid][i_mid].y, l_arr[1][j_mid][i_mid].z);
2650 } else if (dominant_dir == 'm') { // Ucont: Mixed
2651 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: w-comp @ Idx %2d (1st Z-Face) = %.5f\n", rank, 0, l_arr[0][j_mid][i_mid].z);
2652 }
2653 }
2654 if (info.zs + info.zm == info.mz) { // Rank on +Zeta boundary
2655 if (dominant_dir == 'z') { // Node-like in K-dir
2656 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Last Phys. Z-Face) = (%.5f, %.5f, %.5f)\n", rank, km_phys - 1, l_arr[km_phys - 1][j_mid][i_mid].x, l_arr[km_phys - 1][j_mid][i_mid].y, l_arr[km_phys - 1][j_mid][i_mid].z);
2657 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Ghost Location) = (%.5f, %.5f, %.5f)\n", rank, km_phys, l_arr[km_phys][j_mid][i_mid].x, l_arr[km_phys][j_mid][i_mid].y, l_arr[km_phys][j_mid][i_mid].z);
2658 } else if (dominant_dir == 'x' || dominant_dir == 'y') { // Cell-like in K-dir
2659 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Value for Cell[%d][j][i]) = (%.5f, %.5f, %.5f)\n", rank, km_phys-1, km_phys-2, l_arr[km_phys-1][j_mid][i_mid].x, l_arr[km_phys-1][j_mid][i_mid].y, l_arr[km_phys - 1][j_mid][i_mid].z);
2660 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Ghost for Cell[%d][j][i]) = (%.5f, %.5f, %.5f)\n", rank, km_phys, km_phys-2, l_arr[km_phys][j_mid][i_mid].x, l_arr[km_phys][j_mid][i_mid].y, l_arr[km_phys][j_mid][i_mid].z);
2661 } else if (dominant_dir == 'm') { // Ucont: Mixed
2662 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: w-comp @ Idx %2d (Last Z-Face) = %.5f\n", rank, km_phys - 1, l_arr[km_phys - 1][j_mid][i_mid].z);
2663 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: w-comp @ Idx %2d (Ghost Loc.) = %.5f\n", rank, km_phys, l_arr[km_phys][j_mid][i_mid].z);
2664
2665 }
2666 }
2667 ierr = DMDAVecRestoreArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
2668 }
2669 // ======================================================================
2670 // === CASE 3: Node-Centered Fields - USES DIRECT INDEX ===
2671 // ======================================================================
2672 else if (strcmp(data_layout, "Node-Centered") == 0) {
2673 const Cmpnts ***l_arr;
2674 ierr = DMDAVecGetArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
2675
2676 // --- I-Direction Boundaries ---
2677 if (info.xs == 0) {
2678 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (First Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][j_mid][0].x, l_arr[k_mid][j_mid][0].y, l_arr[k_mid][j_mid][0].z);
2679 }
2680 if (info.xs + info.xm == info.mx) {
2681 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Last Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, im_phys - 1, l_arr[k_mid][j_mid][im_phys - 1].x, l_arr[k_mid][j_mid][im_phys - 1].y, l_arr[k_mid][j_mid][im_phys - 1].z);
2682 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Unused/Ghost Loc) = (%.5f, %.5f, %.5f)\n", rank, im_phys, l_arr[k_mid][j_mid][im_phys].x, l_arr[k_mid][j_mid][im_phys].y, l_arr[k_mid][j_mid][im_phys].z);
2683 }
2684 // --- J-Direction Boundaries ---
2685 if (info.ys == 0) {
2686 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (First Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][0][i_mid].x, l_arr[k_mid][0][i_mid].y, l_arr[k_mid][0][i_mid].z);
2687 }
2688 if (info.ys + info.ym == info.my) {
2689 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Last Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, jm_phys - 1, l_arr[k_mid][jm_phys - 1][i_mid].x, l_arr[k_mid][jm_phys - 1][i_mid].y, l_arr[k_mid][jm_phys - 1][i_mid].z);
2690 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Unused/Ghost Loc) = (%.5f, %.5f, %.5f)\n", rank, jm_phys, l_arr[k_mid][jm_phys][i_mid].x, l_arr[k_mid][jm_phys][i_mid].y, l_arr[k_mid][jm_phys][i_mid].z);
2691 }
2692 // --- K-Direction Boundaries ---
2693 if (info.zs == 0) {
2694 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (First Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[0][j_mid][i_mid].x, l_arr[0][j_mid][i_mid].y, l_arr[0][j_mid][i_mid].z);
2695 }
2696 if(info.zs + info.zm == info.mz) {
2697 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Last Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, km_phys - 1, l_arr[km_phys - 1][j_mid][i_mid].x, l_arr[km_phys - 1][j_mid][i_mid].y, l_arr[km_phys - 1][j_mid][i_mid].z);
2698 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Unused/Ghost Loc) = (%.5f, %.5f, %.5f)\n", rank, km_phys, l_arr[km_phys][j_mid][i_mid].x, l_arr[km_phys][j_mid][i_mid].y, l_arr[km_phys][j_mid][i_mid].z);
2699 }
2700 ierr = DMDAVecRestoreArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
2701 }
2702 else {
2703 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "LOG_FIELD_ANATOMY encountered an unknown data layout: %s", data_layout);
2704 }
2705
2706 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
2707 ierr = PetscBarrier(NULL);
2708 PetscFunctionReturn(0);
2709}
Vec lDiffusivityGradient
Definition variables.h:860
Vec lCent
Definition variables.h:879
Vec lZet
Definition variables.h:879
Vec lCellFieldAtCorner
Definition variables.h:867
Vec lPsi
Definition variables.h:904
Vec lCsi
Definition variables.h:879
Vec CellFieldAtCorner
Definition variables.h:867
Vec lUcat
Definition variables.h:856
Vec lEta
Definition variables.h:879
Vec lDiffusivity
Definition variables.h:859
Here is the caller graph for this function:

◆ LOG_INTERPOLATION_ERROR()

PetscErrorCode LOG_INTERPOLATION_ERROR ( UserCtx user)

Logs the interpolation error between the analytical and computed solutions.

Parameters
userPrimary UserCtx input for the operation.
Returns
PetscErrorCode 0 on success.

Logs the interpolation error between the analytical and computed solutions.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_INTERPOLATION_ERROR()

Definition at line 2719 of file logging.c.

2720{
2721 SimCtx *simCtx = user->simCtx;
2722 PetscErrorCode ierr;
2723 DM swarm = user->swarm;
2724 Vec positionVec, analyticalvelocityVec, velocityVec, errorVec;
2725 PetscReal Interpolation_error = 0.0;
2726 PetscReal Maximum_Interpolation_error = 0.0;
2727 PetscReal AnalyticalSolution_magnitude = 0.0;
2728 PetscReal ErrorPercentage = 0.0;
2729
2730 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating global vectors.\n");
2731 ierr = DMSwarmCreateGlobalVectorFromField(swarm, "position", &positionVec); CHKERRQ(ierr);
2732 ierr = DMSwarmCreateGlobalVectorFromField(swarm, "velocity", &velocityVec); CHKERRQ(ierr);
2733
2734 ierr = VecDuplicate(positionVec, &analyticalvelocityVec); CHKERRQ(ierr);
2735 ierr = VecCopy(positionVec, analyticalvelocityVec); CHKERRQ(ierr);
2736
2737 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Computing analytical solution.\n");
2738 ierr = SetAnalyticalSolutionForParticles(analyticalvelocityVec, simCtx); CHKERRQ(ierr);
2739
2740 ierr = VecDuplicate(analyticalvelocityVec, &errorVec); CHKERRQ(ierr);
2741 ierr = VecCopy(analyticalvelocityVec, errorVec); CHKERRQ(ierr);
2742
2743 ierr = VecNorm(analyticalvelocityVec, NORM_2, &AnalyticalSolution_magnitude); CHKERRQ(ierr);
2744
2745 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Computing error.\n");
2746 ierr = VecAXPY(errorVec, -1.0, velocityVec); CHKERRQ(ierr);
2747 ierr = VecNorm(errorVec, NORM_2, &Interpolation_error); CHKERRQ(ierr);
2748 ierr = VecNorm(errorVec,NORM_INFINITY,&Maximum_Interpolation_error); CHKERRQ(ierr);
2749
2750 ErrorPercentage = (AnalyticalSolution_magnitude > 0) ?
2751 (Interpolation_error / AnalyticalSolution_magnitude * 100.0) : 0.0;
2752
2753 /* --- CSV output (always, rank 0 only) --- */
2754 if (simCtx->rank == 0) {
2755 char csv_path[PETSC_MAX_PATH_LEN + 32];
2756 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/interpolation_error.csv", simCtx->log_dir); CHKERRQ(ierr);
2757 FILE *f = fopen(csv_path, "a");
2758 if (f) {
2759 if (ftell(f) == 0) {
2760 fprintf(f, "step,time,L2_error,Linf_error,L2_analytical,error_pct\n");
2761 }
2762 PetscReal t = (PetscReal)simCtx->ti * simCtx->dt;
2763 fprintf(f, "%d,%.6e,%.6e,%.6e,%.6e,%.4f\n",
2764 (int)simCtx->step, t,
2765 Interpolation_error, Maximum_Interpolation_error,
2766 AnalyticalSolution_magnitude, ErrorPercentage);
2767 fclose(f);
2768 }
2769 }
2770
2771 /* --- Console output (only at INFO level or above) --- */
2772 if (get_log_level() >= LOG_INFO) {
2773 LOG_ALLOW(GLOBAL, LOG_INFO, "Interpolation error (%%): %g\n", ErrorPercentage);
2774 PetscPrintf(PETSC_COMM_WORLD, "Interpolation error (%%): %g\n", ErrorPercentage);
2775 LOG_ALLOW(GLOBAL, LOG_INFO, "Maximum Interpolation error: %g\n", Maximum_Interpolation_error);
2776 PetscPrintf(PETSC_COMM_WORLD, "Maximum Interpolation error: %g\n", Maximum_Interpolation_error);
2777 }
2778
2779 ierr = VecDestroy(&analyticalvelocityVec); CHKERRQ(ierr);
2780 ierr = VecDestroy(&errorVec); CHKERRQ(ierr);
2781 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, "position", &positionVec); CHKERRQ(ierr);
2782 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, "velocity", &velocityVec); CHKERRQ(ierr);
2783
2784 return 0;
2785}
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Applies the analytical solution to particle velocity vector.
PetscReal dt
Definition variables.h:666
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LOG_SCATTER_METRICS()

PetscErrorCode LOG_SCATTER_METRICS ( UserCtx user)

Logs particle-to-grid scatter verification metrics for the prescribed scalar truth path.

Parameters
userPrimary UserCtx input for the operation.
Returns
PetscErrorCode 0 on success.

Logs particle-to-grid scatter verification metrics for the prescribed scalar truth path.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_SCATTER_METRICS()

Definition at line 2795 of file logging.c.

2796{
2797 PetscErrorCode ierr;
2798 SimCtx *simCtx = NULL;
2799 DMDALocalInfo info;
2800 PetscInt xs, xe, ys, ye, zs, ze, mx, my, mz;
2801 PetscInt lxs, lxe, lys, lye, lzs, lze;
2802 Vec reference_vec = NULL;
2803 PetscReal ***psi = NULL;
2804 PetscReal ***psi_ref = NULL;
2805 PetscReal ***aj = NULL;
2806 PetscReal ***count = NULL;
2807 PetscReal *particle_psi = NULL;
2808 PetscInt nlocal = 0;
2809 PetscReal local_l1 = 0.0, global_l1 = 0.0;
2810 PetscReal local_l2_sq = 0.0, global_l2_sq = 0.0;
2811 PetscReal local_linf = 0.0, global_linf = 0.0;
2812 PetscReal local_ref_l2_sq = 0.0, global_ref_l2_sq = 0.0;
2813 PetscReal local_grid_integral = 0.0, global_grid_integral = 0.0;
2814 PetscReal local_domain_volume = 0.0, global_domain_volume = 0.0;
2815 PetscReal local_particle_sum = 0.0, global_particle_sum = 0.0;
2816 PetscInt64 local_particle_count = 0, global_particle_count = 0;
2817 PetscInt64 local_cell_count = 0, global_cell_count = 0;
2818 PetscInt64 local_occupied_count = 0, global_occupied_count = 0;
2819 PetscReal particle_integral = 0.0;
2820 PetscReal occupancy_fraction = 0.0;
2821 PetscReal mean_particles_per_occupied_cell = 0.0;
2822 PetscReal l2_error = 0.0;
2823 PetscReal relative_l2_error = 0.0;
2824
2825 PetscFunctionBeginUser;
2826 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
2827 simCtx = user->simCtx;
2828 if (!VerificationScalarOverrideActive(simCtx) || !user->swarm || !user->Psi || !user->ParticleCount) {
2829 PetscFunctionReturn(0);
2830 }
2831
2832 info = user->info;
2833 xs = info.xs; xe = info.xs + info.xm;
2834 ys = info.ys; ye = info.ys + info.ym;
2835 zs = info.zs; ze = info.zs + info.zm;
2836 mx = info.mx; my = info.my; mz = info.mz;
2837 lxs = (xs == 0) ? xs + 1 : xs; lxe = (xe == mx) ? xe - 1 : xe;
2838 lys = (ys == 0) ? ys + 1 : ys; lye = (ye == my) ? ye - 1 : ye;
2839 lzs = (zs == 0) ? zs + 1 : zs; lze = (ze == mz) ? ze - 1 : ze;
2840
2841 ierr = VecDuplicate(user->Psi, &reference_vec); CHKERRQ(ierr);
2842 ierr = SetAnalyticalScalarFieldAtCellCenters(user, reference_vec); CHKERRQ(ierr);
2843
2844 ierr = DMDAVecGetArrayRead(user->da, user->Psi, &psi); CHKERRQ(ierr);
2845 ierr = DMDAVecGetArrayRead(user->da, reference_vec, &psi_ref); CHKERRQ(ierr);
2846 ierr = DMDAVecGetArrayRead(user->da, user->Aj, &aj); CHKERRQ(ierr);
2847 ierr = DMDAVecGetArrayRead(user->da, user->ParticleCount, &count); CHKERRQ(ierr);
2848
2849 for (PetscInt k = lzs; k < lze; ++k) {
2850 for (PetscInt j = lys; j < lye; ++j) {
2851 for (PetscInt i = lxs; i < lxe; ++i) {
2852 const PetscReal cell_volume = (PetscAbsReal(aj[k][j][i]) > 1.0e-14) ? (1.0 / aj[k][j][i]) : 0.0;
2853 const PetscReal err = psi[k][j][i] - psi_ref[k][j][i];
2854 local_cell_count += 1;
2855 local_domain_volume += cell_volume;
2856 local_grid_integral += psi[k][j][i] * cell_volume;
2857 local_l1 += PetscAbsReal(err) * cell_volume;
2858 local_l2_sq += err * err * cell_volume;
2859 local_ref_l2_sq += psi_ref[k][j][i] * psi_ref[k][j][i] * cell_volume;
2860 local_linf = PetscMax(local_linf, PetscAbsReal(err));
2861 if (count[k][j][i] > 0.0) local_occupied_count += 1;
2862 }
2863 }
2864 }
2865
2866 ierr = DMDAVecRestoreArrayRead(user->da, user->ParticleCount, &count); CHKERRQ(ierr);
2867 ierr = DMDAVecRestoreArrayRead(user->da, user->Aj, &aj); CHKERRQ(ierr);
2868 ierr = DMDAVecRestoreArrayRead(user->da, reference_vec, &psi_ref); CHKERRQ(ierr);
2869 ierr = DMDAVecRestoreArrayRead(user->da, user->Psi, &psi); CHKERRQ(ierr);
2870 ierr = VecDestroy(&reference_vec); CHKERRQ(ierr);
2871
2872 ierr = DMSwarmGetLocalSize(user->swarm, &nlocal); CHKERRQ(ierr);
2873 local_particle_count = (PetscInt64)nlocal;
2874 if (nlocal > 0) {
2875 ierr = DMSwarmGetField(user->swarm, "Psi", NULL, NULL, (void **)&particle_psi); CHKERRQ(ierr);
2876 for (PetscInt p = 0; p < nlocal; ++p) local_particle_sum += particle_psi[p];
2877 ierr = DMSwarmRestoreField(user->swarm, "Psi", NULL, NULL, (void **)&particle_psi); CHKERRQ(ierr);
2878 }
2879
2880 ierr = MPI_Allreduce(&local_l1, &global_l1, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2881 ierr = MPI_Allreduce(&local_l2_sq, &global_l2_sq, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2882 ierr = MPI_Allreduce(&local_linf, &global_linf, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2883 ierr = MPI_Allreduce(&local_ref_l2_sq, &global_ref_l2_sq, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2884 ierr = MPI_Allreduce(&local_grid_integral, &global_grid_integral, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2885 ierr = MPI_Allreduce(&local_domain_volume, &global_domain_volume, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2886 ierr = MPI_Allreduce(&local_particle_sum, &global_particle_sum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2887 ierr = MPI_Allreduce(&local_particle_count, &global_particle_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2888 ierr = MPI_Allreduce(&local_cell_count, &global_cell_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2889 ierr = MPI_Allreduce(&local_occupied_count, &global_occupied_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2890
2891 l2_error = PetscSqrtReal(global_l2_sq);
2892 relative_l2_error = (global_ref_l2_sq > 0.0) ? (l2_error / PetscSqrtReal(global_ref_l2_sq)) : 0.0;
2893 occupancy_fraction = (global_cell_count > 0) ? ((PetscReal)global_occupied_count / (PetscReal)global_cell_count) : 0.0;
2894 mean_particles_per_occupied_cell =
2895 (global_occupied_count > 0) ? ((PetscReal)global_particle_count / (PetscReal)global_occupied_count) : 0.0;
2896 particle_integral =
2897 (global_particle_count > 0) ? (global_domain_volume * global_particle_sum / (PetscReal)global_particle_count) : 0.0;
2898
2899 if (simCtx->rank == 0) {
2900 char csv_path[PETSC_MAX_PATH_LEN + 32];
2901 FILE *f = NULL;
2902 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/scatter_metrics.csv", simCtx->log_dir); CHKERRQ(ierr);
2903 f = fopen(csv_path, "a");
2904 if (f) {
2905 if (ftell(f) == 0) {
2906 fprintf(f,
2907 "step,time,total_particles,total_cells,occupied_cells,occupancy_fraction,"
2908 "mean_particles_per_occupied_cell,particle_integral,grid_integral,"
2909 "conservation_error_abs,L1_error,L2_error,Linf_error,relative_L2_error\n");
2910 }
2911 fprintf(f, "%d,%.6e,%lld,%lld,%lld,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e\n",
2912 (int)simCtx->step,
2913 (double)simCtx->ti,
2914 (long long)global_particle_count,
2915 (long long)global_cell_count,
2916 (long long)global_occupied_count,
2917 (double)occupancy_fraction,
2918 (double)mean_particles_per_occupied_cell,
2919 (double)particle_integral,
2920 (double)global_grid_integral,
2921 (double)PetscAbsReal(global_grid_integral - particle_integral),
2922 (double)global_l1,
2923 (double)l2_error,
2924 (double)global_linf,
2925 (double)relative_l2_error);
2926 fclose(f);
2927 }
2928 }
2929
2930 if (get_log_level() >= LOG_INFO) {
2931 LOG_ALLOW(GLOBAL, LOG_INFO, "Scatter relative L2 error: %.6e\n", (double)relative_l2_error);
2932 LOG_ALLOW(GLOBAL, LOG_INFO, "Scatter occupancy fraction: %.6e\n", (double)occupancy_fraction);
2933 }
2934
2935 PetscFunctionReturn(0);
2936}
PetscErrorCode SetAnalyticalScalarFieldAtCellCenters(UserCtx *user, Vec targetVec)
Writes the configured verification scalar profile at physical cell centers into a scalar Vec.
Vec ParticleCount
Definition variables.h:903
DMDALocalInfo info
Definition variables.h:837
PetscBool VerificationScalarOverrideActive(const SimCtx *simCtx)
Reports whether a verification-only scalar override is active.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ ResetSearchMetrics()

PetscErrorCode ResetSearchMetrics ( SimCtx simCtx)

Resets the aggregate per-timestep search instrumentation counters.

Parameters
simCtxSimulation context whose search metrics should be zeroed.
Returns
PetscErrorCode 0 on success.

Resets the aggregate per-timestep search instrumentation counters.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
ResetSearchMetrics()

Definition at line 2946 of file logging.c.

2947{
2948 PetscFunctionBeginUser;
2949 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL for ResetSearchMetrics.");
2950
2951 simCtx->searchMetrics.searchAttempts = 0;
2952 simCtx->searchMetrics.searchPopulation = 0;
2954 simCtx->searchMetrics.searchLostCount = 0;
2955 simCtx->searchMetrics.traversalStepsSum = 0;
2956 simCtx->searchMetrics.reSearchCount = 0;
2957 simCtx->searchMetrics.maxTraversalSteps = 0;
2959 simCtx->searchMetrics.tieBreakCount = 0;
2965
2966 PetscFunctionReturn(0);
2967}
PetscInt64 searchLocatedCount
Definition variables.h:224
PetscInt64 searchLostCount
Definition variables.h:225
PetscInt64 boundaryClampCount
Definition variables.h:231
PetscInt64 traversalStepsSum
Definition variables.h:226
PetscInt64 searchPopulation
Definition variables.h:223
PetscInt currentSettlementPass
Definition variables.h:235
PetscInt64 reSearchCount
Definition variables.h:227
PetscInt64 bboxGuessFallbackCount
Definition variables.h:233
PetscInt64 bboxGuessSuccessCount
Definition variables.h:232
PetscInt64 maxParticlePassDepth
Definition variables.h:234
PetscInt64 maxTraversalSteps
Definition variables.h:228
SearchMetricsState searchMetrics
Definition variables.h:766
PetscInt64 searchAttempts
Definition variables.h:222
PetscInt64 tieBreakCount
Definition variables.h:230
PetscInt64 maxTraversalFailCount
Definition variables.h:229
Here is the caller graph for this function:

◆ CalculateAdvancedParticleMetrics()

PetscErrorCode CalculateAdvancedParticleMetrics ( UserCtx user)

Computes advanced particle statistics and stores them in SimCtx.

This function calculates:

  • Particle load imbalance across MPI ranks.
  • The total number of grid cells occupied by at least one particle.

It requires that CalculateParticleCountPerCell() has been called prior to its execution. It uses collective MPI operations and must be called by all ranks.

Parameters
userPointer to the UserCtx.
Returns
PetscErrorCode 0 on success.

Computes advanced particle statistics and stores them in SimCtx.

Local to this translation unit.

Definition at line 3128 of file logging.c.

3129{
3130 PetscErrorCode ierr;
3131 SimCtx *simCtx = user->simCtx;
3132 PetscMPIInt size, rank;
3133
3134 PetscFunctionBeginUser;
3135 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
3136 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3137
3138 // --- 1. Particle Load Imbalance ---
3139 PetscInt nLocal, nGlobal, nLocalMax;
3140 ierr = DMSwarmGetLocalSize(user->swarm, &nLocal); CHKERRQ(ierr);
3141 ierr = DMSwarmGetSize(user->swarm, &nGlobal); CHKERRQ(ierr);
3142 ierr = MPI_Allreduce(&nLocal, &nLocalMax, 1, MPIU_INT, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
3143
3144 PetscReal avg_per_rank = (size > 0) ? ((PetscReal)nGlobal / size) : 0.0;
3145 // Handle division by zero if there are no particles
3146 simCtx->particleLoadImbalance = (avg_per_rank > 1e-9) ? (nLocalMax / avg_per_rank) : 1.0;
3147
3148
3149 // --- 2. Number of Occupied Cells ---
3150 // This part requires access to the user->ParticleCount vector.
3151 PetscInt local_occupied_cells = 0;
3152 PetscInt global_occupied_cells;
3153 const PetscScalar *count_array;
3154 PetscInt vec_local_size;
3155
3156 ierr = VecGetLocalSize(user->ParticleCount, &vec_local_size); CHKERRQ(ierr);
3157 ierr = VecGetArrayRead(user->ParticleCount, &count_array); CHKERRQ(ierr);
3158
3159 for (PetscInt i = 0; i < vec_local_size; ++i) {
3160 if (count_array[i] > 0.5) { // Use 0.5 to be safe with floating point
3161 local_occupied_cells++;
3162 }
3163 }
3164 ierr = VecRestoreArrayRead(user->ParticleCount, &count_array); CHKERRQ(ierr);
3165
3166 ierr = MPI_Allreduce(&local_occupied_cells, &global_occupied_cells, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
3167 simCtx->occupiedCellCount = global_occupied_cells;
3168
3169 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "[Rank %d] Advanced Metrics: Imbalance=%.2f, OccupiedCells=%d\n", rank, simCtx->particleLoadImbalance, simCtx->occupiedCellCount);
3170
3171 PetscFunctionReturn(0);
3172}
PetscInt occupiedCellCount
Definition variables.h:764
PetscReal particleLoadImbalance
Definition variables.h:765
Here is the caller graph for this function:

◆ LOG_SEARCH_METRICS()

PetscErrorCode LOG_SEARCH_METRICS ( UserCtx user)

Writes compact runtime search metrics to CSV and optionally to console.

The CSV artifact is always written for particle-enabled runs. Console output remains gated by normal logging level and function allow-listing.

Parameters
userPointer to the UserCtx.
Returns
PetscErrorCode 0 on success.

Writes compact runtime search metrics to CSV and optionally to console.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_SEARCH_METRICS()

Definition at line 2977 of file logging.c.

2978{
2979 PetscErrorCode ierr;
2980 SimCtx *simCtx = NULL;
2981 PetscInt totalParticles = 0;
2982 PetscReal local_metrics[SEARCH_METRIC_REDUCTION_LEN] = {0.0};
2983 PetscReal global_metrics[SEARCH_METRIC_REDUCTION_LEN] = {0.0};
2984 PetscReal meanTraversalSteps = 0.0;
2985 PetscReal searchFailureFraction = 0.0;
2986 PetscReal searchWorkIndex = 0.0;
2987 PetscReal reSearchFraction = 0.0;
2988 long long searchAttempts = 0;
2989 long long searchPopulation = 0;
2990 long long searchLocatedCount = 0;
2991 long long searchLostCount = 0;
2992 long long traversalStepsSum = 0;
2993 long long reSearchCount = 0;
2994 long long tieBreakCount = 0;
2995 long long boundaryClampCount = 0;
2996 long long bboxGuessSuccessCount = 0;
2997 long long bboxGuessFallbackCount = 0;
2998 long long maxTraversalFailCount = 0;
2999 long long maxTraversalSteps = 0;
3000 long long maxPassDepth = 0;
3001 MPI_Op reduction_op = MPI_OP_NULL;
3002
3003 PetscFunctionBeginUser;
3004 if (!user || !user->simCtx) {
3005 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx and SimCtx are required for LOG_SEARCH_METRICS.");
3006 }
3007 simCtx = user->simCtx;
3008
3009 if (simCtx->np <= 0) {
3010 PetscFunctionReturn(0);
3011 }
3012
3013 ierr = DMSwarmGetSize(user->swarm, &totalParticles); CHKERRQ(ierr);
3014
3015 local_metrics[SEARCH_METRIC_SUM_SEARCH_ATTEMPTS] = (PetscReal)simCtx->searchMetrics.searchAttempts;
3016 local_metrics[SEARCH_METRIC_SUM_SEARCH_POPULATION] = (PetscReal)simCtx->searchMetrics.searchPopulation;
3017 local_metrics[SEARCH_METRIC_SUM_SEARCH_LOCATED] = (PetscReal)simCtx->searchMetrics.searchLocatedCount;
3018 local_metrics[SEARCH_METRIC_SUM_SEARCH_LOST] = (PetscReal)simCtx->searchMetrics.searchLostCount;
3019 local_metrics[SEARCH_METRIC_SUM_TRAVERSAL_STEPS] = (PetscReal)simCtx->searchMetrics.traversalStepsSum;
3020 local_metrics[SEARCH_METRIC_SUM_RESEARCH] = (PetscReal)simCtx->searchMetrics.reSearchCount;
3021 local_metrics[SEARCH_METRIC_SUM_TIE_BREAKS] = (PetscReal)simCtx->searchMetrics.tieBreakCount;
3022 local_metrics[SEARCH_METRIC_SUM_BOUNDARY_CLAMPS] = (PetscReal)simCtx->searchMetrics.boundaryClampCount;
3023 local_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS] = (PetscReal)simCtx->searchMetrics.bboxGuessSuccessCount;
3024 local_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK] = (PetscReal)simCtx->searchMetrics.bboxGuessFallbackCount;
3025 local_metrics[SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS] = (PetscReal)simCtx->searchMetrics.maxTraversalFailCount;
3026 local_metrics[SEARCH_METRIC_MAX_TRAVERSAL_STEPS] = (PetscReal)simCtx->searchMetrics.maxTraversalSteps;
3027 local_metrics[SEARCH_METRIC_MAX_PASS_DEPTH] = (PetscReal)simCtx->searchMetrics.maxParticlePassDepth;
3028
3029 ierr = MPI_Op_create(SearchMetricsReduceOp, PETSC_TRUE, &reduction_op); CHKERRMPI(ierr);
3030 ierr = MPI_Allreduce(local_metrics, global_metrics, SEARCH_METRIC_REDUCTION_LEN, MPIU_REAL, reduction_op, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3031 ierr = MPI_Op_free(&reduction_op); CHKERRMPI(ierr);
3032 reduction_op = MPI_OP_NULL;
3033
3034 searchAttempts = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_ATTEMPTS] + 0.5);
3035 searchPopulation = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_POPULATION] + 0.5);
3036 searchLocatedCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_LOCATED] + 0.5);
3037 searchLostCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_LOST] + 0.5);
3038 traversalStepsSum = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_TRAVERSAL_STEPS] + 0.5);
3039 reSearchCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_RESEARCH] + 0.5);
3040 tieBreakCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_TIE_BREAKS] + 0.5);
3041 boundaryClampCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BOUNDARY_CLAMPS] + 0.5);
3042 bboxGuessSuccessCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS] + 0.5);
3043 bboxGuessFallbackCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK] + 0.5);
3044 maxTraversalFailCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS] + 0.5);
3045 maxTraversalSteps = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_MAX_TRAVERSAL_STEPS] + 0.5);
3046 maxPassDepth = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_MAX_PASS_DEPTH] + 0.5);
3047
3048 if (searchAttempts > 0) {
3049 meanTraversalSteps = (PetscReal)traversalStepsSum / (PetscReal)searchAttempts;
3050 }
3051 if (searchPopulation > 0) {
3052 searchFailureFraction = (PetscReal)searchLostCount / (PetscReal)searchPopulation;
3053 searchWorkIndex = (PetscReal)traversalStepsSum / (PetscReal)searchPopulation;
3054 reSearchFraction = (PetscReal)reSearchCount / (PetscReal)searchPopulation;
3055 }
3056
3057 if (simCtx->rank == 0) {
3058 char csv_path[PETSC_MAX_PATH_LEN + 32];
3059 FILE *f = NULL;
3060
3061 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/search_metrics.csv", simCtx->log_dir); CHKERRQ(ierr);
3062 f = fopen(csv_path, "a");
3063 if (!f) {
3064 LOG_ALLOW(GLOBAL, LOG_WARNING, "LOG_SEARCH_METRICS: could not open '%s' for writing.\n", csv_path);
3065 } else {
3066 if (ftell(f) == 0) {
3067 fprintf(f,
3068 "step,time,total_particles,lost,lost_cumulative,migrated,migration_passes,search_attempts,"
3069 "mean_traversal_steps,max_traversal_steps,tie_break_count,boundary_clamp_count,"
3070 "bbox_guess_success_count,bbox_guess_fallback_count,max_particle_pass_depth,load_imbalance,"
3071 "search_population,search_located_count,search_lost_count,traversal_steps_sum,re_search_count,"
3072 "max_traversal_fail_count,search_failure_fraction,search_work_index,re_search_fraction\n");
3073 }
3074 fprintf(f,
3075 "%d,%.6e,%d,%d,%d,%d,%d,%lld,%.6e,%lld,%lld,%lld,%lld,%lld,%lld,%.6e,%lld,%lld,%lld,%lld,%lld,%lld,%.6e,%.6e,%.6e\n",
3076 (int)simCtx->step,
3077 (double)simCtx->ti,
3078 (int)totalParticles,
3079 (int)simCtx->particlesLostLastStep,
3080 (int)simCtx->particlesLostCumulative,
3081 (int)simCtx->particlesMigratedLastStep,
3082 (int)simCtx->migrationPassesLastStep,
3083 searchAttempts,
3084 (double)meanTraversalSteps,
3085 maxTraversalSteps,
3086 tieBreakCount,
3087 boundaryClampCount,
3088 bboxGuessSuccessCount,
3089 bboxGuessFallbackCount,
3090 maxPassDepth,
3091 (double)simCtx->particleLoadImbalance,
3092 searchPopulation,
3093 searchLocatedCount,
3094 searchLostCount,
3095 traversalStepsSum,
3096 reSearchCount,
3097 maxTraversalFailCount,
3098 (double)searchFailureFraction,
3099 (double)searchWorkIndex,
3100 (double)reSearchFraction);
3101 fclose(f);
3102 }
3103 }
3104
3106 "Search metrics: sff=%.3e swi=%.3e re_search=%.3e lost(step/total)=%d/%d migrated=%d passes=%d traversal(mean/max)=%.2f/%lld tie_breaks=%lld max_pass_depth=%lld\n",
3107 (double)searchFailureFraction,
3108 (double)searchWorkIndex,
3109 (double)reSearchFraction,
3110 (int)simCtx->particlesLostLastStep,
3111 (int)simCtx->particlesLostCumulative,
3112 (int)simCtx->particlesMigratedLastStep,
3113 (int)simCtx->migrationPassesLastStep,
3114 (double)meanTraversalSteps,
3115 maxTraversalSteps,
3116 tieBreakCount,
3117 maxPassDepth);
3118
3119 PetscFunctionReturn(0);
3120}
@ SEARCH_METRIC_SUM_SEARCH_LOCATED
Definition logging.c:33
@ SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS
Definition logging.c:41
@ SEARCH_METRIC_REDUCTION_LEN
Definition logging.c:44
@ SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK
Definition logging.c:40
@ SEARCH_METRIC_SUM_RESEARCH
Definition logging.c:36
@ SEARCH_METRIC_SUM_TRAVERSAL_STEPS
Definition logging.c:35
@ SEARCH_METRIC_MAX_TRAVERSAL_STEPS
Definition logging.c:42
@ SEARCH_METRIC_SUM_BOUNDARY_CLAMPS
Definition logging.c:38
@ SEARCH_METRIC_SUM_SEARCH_POPULATION
Definition logging.c:32
@ SEARCH_METRIC_MAX_PASS_DEPTH
Definition logging.c:43
@ SEARCH_METRIC_SUM_TIE_BREAKS
Definition logging.c:37
@ SEARCH_METRIC_SUM_SEARCH_LOST
Definition logging.c:34
@ SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS
Definition logging.c:39
@ SEARCH_METRIC_SUM_SEARCH_ATTEMPTS
Definition logging.c:31
static void SearchMetricsReduceOp(void *invec, void *inoutvec, int *len, MPI_Datatype *datatype)
Internal reduction callback for packed search metrics.
Definition logging.c:51
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LOG_PARTICLE_METRICS()

PetscErrorCode LOG_PARTICLE_METRICS ( UserCtx user,
const char *  stageName 
)

Logs particle swarm metrics, adapting its behavior based on a boolean flag in SimCtx.

This function serves a dual purpose:

  1. If simCtx->isInitializationPhase is PETSC_TRUE, it logs settlement diagnostics to "Initialization_Metrics.log", using the provided stageName.
  2. If simCtx->isInitializationPhase is PETSC_FALSE, it logs regular timestep metrics to "Particle_Metrics.log".
Parameters
userA pointer to the UserCtx.
stageNameA descriptive label recorded in the metrics log (for example, initialization stage name or "Timestep Metrics").
Returns
PetscErrorCode 0 on success.

Logs particle swarm metrics, adapting its behavior based on a boolean flag in SimCtx.

Full API contract (arguments, ownership, side effects) is documented with the header declaration in include/logging.h.

See also
LOG_PARTICLE_METRICS()

Definition at line 3182 of file logging.c.

3183{
3184 PetscErrorCode ierr;
3185 PetscMPIInt rank;
3186 SimCtx *simCtx = user->simCtx;
3187 const char *stage_label = (stageName && stageName[0] != '\0') ? stageName : "N/A";
3188
3189 PetscFunctionBeginUser;
3190 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3191
3192 PetscInt totalParticles;
3193 ierr = DMSwarmGetSize(user->swarm, &totalParticles); CHKERRQ(ierr);
3194
3195 if (!rank) {
3196 FILE *f;
3197 char filen[PETSC_MAX_PATH_LEN + 64];
3198 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/Particle_Metrics.log", simCtx->log_dir); CHKERRQ(ierr);
3199 f = fopen(filen, "a");
3200 if (!f) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open particle log file: %s", filen);
3201
3202 if (ftell(f) == 0) {
3203 PetscFPrintf(PETSC_COMM_SELF, f, "%-18s | %-10s | %-12s | %-10s | %-10s | %-10s | %-15s | %-10s | %-10s\n",
3204 "Stage", "Timestep", "Total Ptls", "Lost", "Lost Total", "Migrated", "Occupied Cells", "Imbalance", "Mig Passes");
3205 PetscFPrintf(PETSC_COMM_SELF, f, "-------------------------------------------------------------------------------------------------------------------------------------------\n");
3206 }
3207
3208 PetscFPrintf(PETSC_COMM_SELF, f, "%-18s | %-10d | %-12d | %-10d | %-10d | %-10d | %-15d | %-10.2f | %-10d\n",
3209 stage_label, (int)simCtx->step, (int)totalParticles, (int)simCtx->particlesLostLastStep,
3210 (int)simCtx->particlesLostCumulative, (int)simCtx->particlesMigratedLastStep, (int)simCtx->occupiedCellCount,
3211 (double)simCtx->particleLoadImbalance, (int)simCtx->migrationPassesLastStep);
3212 fclose(f);
3213 }
3214 PetscFunctionReturn(0);
3215}
PetscInt particlesLostLastStep
Definition variables.h:760
PetscInt particlesLostCumulative
Definition variables.h:761
PetscInt particlesMigratedLastStep
Definition variables.h:763
PetscInt migrationPassesLastStep
Definition variables.h:762
Here is the caller graph for this function: