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 "statistics_window.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.
 
PetscBool IsStatisticsConsoleSnapshotEnabled (const struct SimCtx *simCtx)
 Reports whether the periodic statistics console snapshot is enabled.
 
PetscBool ShouldEmitPeriodicStatisticsConsoleSnapshot (const struct SimCtx *simCtx, PetscInt completed_step)
 Reports whether a completed step falls on the console snapshot cadence.
 
PetscErrorCode EmitStatisticsConsoleSnapshot (UserCtx *user, const struct SimCtx *simCtx, PetscInt step)
 Emits one console snapshot of window progress.
 
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)
 Returns the canonical log token for a boundary-face enum value.
 
const char * InitialConditionModeToString (InitialConditionMode mode)
 Convert an initial-condition mode to a string representation.
 
const char * FlowDirectionToString (FlowDirection fd)
 Convert a FlowDirection enum value to its YAML token string.
 
const char * ParticleInitializationToString (ParticleInitializationType ParticleInitialization)
 Returns the canonical log token for a particle-initialization mode.
 
const char * LESModelToString (LESModelType LESFlag)
 Returns the canonical log token for an LES model selector.
 
const char * LESFilterWidthModelToString (LESFilterWidthModel model)
 Returns the user-facing name of an LES grid-filter-width model.
 
const char * LESTestFilterKernelToString (LESTestFilterKernel kernel)
 Returns the user-facing name of an LES test-filter kernel.
 
const char * LESAveragingModeToString (LESAveragingMode mode)
 Returns the user-facing name of an LES coefficient-averaging mode.
 
const char * LESClipModeToString (LESClipMode mode)
 Returns the user-facing name of an LES coefficient-limiting mode.
 
const char * WallFunctionModelToString (WallFunctionModel model)
 Returns the user-facing name of a wall-function model.
 
const char * MomentumSolverTypeToString (MomentumSolverType SolverFlag)
 Returns the canonical log token for a momentum-solver selector.
 
const char * BCTypeToString (BCType type)
 Returns the canonical log token for a boundary mathematical type.
 
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, FieldId field_id)
 Computes and logs the local and global min/max values of a 3-component vector field.
 
PetscErrorCode LOG_FIELD_ANATOMY (UserCtx *user, FieldId field_id, 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_CORNER_FIELD_ANATOMY (UserCtx *user, FieldId corner_field_id, const char *stage_name)
 Logs the node-layout anatomy of the transient center-to-corner interpolation field.
 
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.
 
PetscErrorCode PicurvOpenDiagnosticsCsv (const SimCtx *simCtx, const char *filename, const char *header, FILE **file)
 Opens a per-run diagnostics CSV in the run's analysis directory for appending.
 

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 56 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 45 of file logging.h.

◆ GLOBAL

#define GLOBAL   1

Scope for global logging across all processes.

Definition at line 46 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:45
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:87

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 84 of file logging.h.

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

◆ 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 115 of file logging.h.

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

◆ 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 145 of file logging.h.

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

◆ 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 178 of file logging.h.

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

◆ 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:186

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 200 of file logging.h.

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

◆ 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:46

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:253
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32

Definition at line 253 of file logging.h.

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

299 { \
300 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
301 if ((iterVar) % (interval) == 0) { \
302 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
303 PetscPrintf(comm, "[%s] [%s=%d] " fmt, \
304 __func__, #iterVar, (iterVar), ##__VA_ARGS__); \
305 } \
306 } \
307 } 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 335 of file logging.h.

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

365 { \
366 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
367 if ((idx) >= 0 && (idx) < (length)) { \
368 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
369 PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", \
370 __func__, (idx), (arr)[idx]); \
371 } \
372 } \
373 } 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 388 of file logging.h.

389 { \
390 if (is_function_allowed(__func__) && (int)(level) <= (int)get_log_level()) { \
391 MPI_Comm comm = (scope == LOCAL) ? MPI_COMM_SELF : MPI_COMM_WORLD; \
392 PetscInt _start = (start) < 0 ? 0 : (start); \
393 PetscInt _end = (end) >= (length) ? (length) - 1 : (end); \
394 for (PetscInt i = _start; i <= _end; i++) { \
395 PetscPrintf(comm, "[%s] arr[%d] = " fmt "\n", __func__, i, (arr)[i]); \
396 } \
397 } \
398 } 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 885 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 894 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 28 of file logging.h.

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

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 87 of file logging.c.

87 {
88 if (current_log_level == -1) { // Log level not set yet
89 const char *env = getenv("LOG_LEVEL");
90 if (!env) {
91 current_log_level = LOG_ERROR; // Default level
92 }
93 else if (strcmp(env, "DEBUG") == 0) {
95 }
96 else if (strcmp(env, "INFO") == 0) {
98 }
99 else if (strcmp(env, "WARNING") == 0) {
101 }
102 else if (strcmp(env, "VERBOSE") == 0) {
104 }
105 else if (strcmp(env, "TRACE") == 0) {
107 }
108 else {
109 current_log_level = LOG_ERROR; // Default if unrecognized
110 }
111 }
112 return current_log_level;
113}
static LogLevel current_log_level
Static variable to cache the current logging level.
Definition logging.c:19
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 119 of file logging.c.

120{
121 PetscMPIInt rank;
122 PetscErrorCode ierr;
123 int level;
124 const char *level_name;
125
126 PetscFunctionBeginUser;
127 /* get MPI rank */
128 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRMPI(ierr);
129
130 /* decide level name */
131 level = get_log_level();
132 level_name = (level == LOG_ERROR) ? "ERROR" :
133 (level == LOG_WARNING) ? "WARNING" :
134 (level == LOG_INFO) ? "INFO" :
135 (level == LOG_DEBUG) ? "DEBUG" :
136 (level == LOG_VERBOSE) ? "VERBOSE" :
137 (level == LOG_TRACE) ? "TRACE" :
138 "UNKNOWN";
139
140 /* print it out */
141 ierr = PetscPrintf(PETSC_COMM_SELF,
142 "Current log level: %s (%d) | rank: %d\n",
143 level_name, level, (int)rank);
144 CHKERRMPI(ierr);
145
146 PetscFunctionReturn(PETSC_SUCCESS);
147}
LogLevel get_log_level()
Implementation of get_log_level().
Definition logging.c:87
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
functionListReplacement array of permitted function names.
countNumber of entries in functionList.

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 155 of file logging.c.

156{
157 // 1. Free any existing entries
158 if (gAllowedFunctions) {
159 for (int i = 0; i < gNumAllowed; ++i) {
160 free(gAllowedFunctions[i]); // each was strdup'ed
161 }
162 free(gAllowedFunctions);
163 gAllowedFunctions = NULL;
164 gNumAllowed = 0;
165 }
166
167 // 2. Allocate new array
168 if (count > 0) {
169 gAllowedFunctions = (char**)malloc(sizeof(char*) * count);
170 }
171
172 // 3. Copy the new entries
173 for (int i = 0; i < count; ++i) {
174 // strdup is a POSIX function. If not available, implement your own string copy.
175 gAllowedFunctions[i] = strdup(functionList[i]);
176 }
177 gNumAllowed = count;
178}
static char ** gAllowedFunctions
Global/static array of function names allowed to log.
Definition logging.c:26
static int gNumAllowed
Number of entries in the gAllowedFunctions array.
Definition logging.c:31
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
functionNameFunction name to query.
Returns
PETSC_TRUE when the name is enabled by the allow-list.

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 186 of file logging.c.

187{
188 /* no list ⇒ allow all */
189 if (gNumAllowed == 0) {
190 return PETSC_TRUE;
191 }
192
193 /* otherwise only the listed functions are allowed */
194 for (int i = 0; i < gNumAllowed; ++i) {
195 if (strcmp(gAllowedFunctions[i], functionName) == 0) {
196 return PETSC_TRUE;
197 }
198 }
199 return PETSC_FALSE;
200}
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 208 of file logging.c.

209{
210
211 // Validate input pointers
212 if (cell == NULL) {
213 LOG_ALLOW(LOCAL,LOG_ERROR, "'cell' is NULL.\n");
214 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "LOG_CELL_VERTICES - Input parameter 'cell' is NULL.");
215 }
216
217 LOG_ALLOW(LOCAL,LOG_VERBOSE, "Rank %d, Cell Vertices:\n", rank);
218 for(int i = 0; i < 8; i++){
219 LOG_ALLOW(LOCAL,LOG_VERBOSE, " Vertex[%d]: (%.2f, %.2f, %.2f)\n",
220 i, cell->vertices[i].x, cell->vertices[i].y, cell->vertices[i].z);
221 }
222
223 return 0; // Indicate successful execution
224}
#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:200
PetscScalar x
Definition variables.h:122
PetscScalar z
Definition variables.h:122
PetscScalar y
Definition variables.h:122
Cmpnts vertices[8]
Coordinates of the eight vertices of the cell.
Definition variables.h:204
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 233 of file logging.c.

234{
235
236 // Validate input array
237 if (d == NULL) {
238 LOG_ALLOW(LOCAL,LOG_ERROR, " 'd' is NULL.\n");
239 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, " Input array 'd' is NULL.");
240 }
241
242 PetscPrintf(PETSC_COMM_SELF, " Face Distances:\n");
243 PetscPrintf(PETSC_COMM_SELF, " LEFT(%d): %.15f\n", LEFT, d[LEFT]);
244 PetscPrintf(PETSC_COMM_SELF, " RIGHT(%d): %.15f\n", RIGHT, d[RIGHT]);
245 PetscPrintf(PETSC_COMM_SELF, " BOTTOM(%d): %.15f\n", BOTTOM, d[BOTTOM]);
246 PetscPrintf(PETSC_COMM_SELF, " TOP(%d): %.15f\n", TOP, d[TOP]);
247 PetscPrintf(PETSC_COMM_SELF, " FRONT(%d): %.15f\n", FRONT, d[FRONT]);
248 PetscPrintf(PETSC_COMM_SELF, " BACK(%d): %.15f\n", BACK, d[BACK]);
249
250 return 0; // Indicate successful execution
251}
@ TOP
Definition variables.h:173
@ FRONT
Definition variables.h:173
@ BOTTOM
Definition variables.h:173
@ BACK
Definition variables.h:173
@ LEFT
Definition variables.h:173
@ RIGHT
Definition variables.h:173
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 400 of file logging.c.

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

529{
530 if (!simCtx) {
531 return PETSC_FALSE;
532 }
533 return (PetscBool)(simCtx->np > 0 &&
534 simCtx->particleConsoleOutputFreq > 0 &&
536}
PetscInt np
Definition variables.h:990
PetscInt particleConsoleOutputFreq
Definition variables.h:872
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 545 of file logging.c.

546{
547 return (PetscBool)(IsParticleConsoleSnapshotEnabled(simCtx) &&
548 completed_step > 0 &&
549 completed_step % simCtx->particleConsoleOutputFreq == 0);
550}
PetscBool IsParticleConsoleSnapshotEnabled(const SimCtx *simCtx)
Implementation of IsParticleConsoleSnapshotEnabled().
Definition logging.c:528
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 559 of file logging.c.

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

◆ IsStatisticsConsoleSnapshotEnabled()

PetscBool IsStatisticsConsoleSnapshotEnabled ( const struct SimCtx *  simCtx)

Reports whether the periodic statistics console snapshot is enabled.

Mirrors the particle console gate: the subsystem must be active, the configured cadence positive, and the effective log level at least LOG_INFO.

Parameters
[in]simCtxSimulation context to inspect.
Returns
PETSC_TRUE when snapshots should be emitted.
Here is the caller graph for this function:

◆ ShouldEmitPeriodicStatisticsConsoleSnapshot()

PetscBool ShouldEmitPeriodicStatisticsConsoleSnapshot ( const struct SimCtx *  simCtx,
PetscInt  completed_step 
)

Reports whether a completed step falls on the console snapshot cadence.

Parameters
[in]simCtxSimulation context to inspect.
[in]completed_stepStep that has just completed.
Returns
PETSC_TRUE when a snapshot is due for this step.
Here is the caller graph for this function:

◆ EmitStatisticsConsoleSnapshot()

PetscErrorCode EmitStatisticsConsoleSnapshot ( UserCtx *  user,
const struct SimCtx *  simCtx,
PetscInt  step 
)

Emits one console snapshot of window progress.

Reports window-level scalars only; it never dumps field data.

Parameters
[in]userFinest-level block array supplying accumulator state.
[in]simCtxSimulation context carrying the window array.
[in]stepStep the snapshot describes.
Returns
Zero on success.
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 652 of file logging.c.

653{
654 PetscErrorCode ierr;
655 PetscFunctionBegin;
656 if (funcs) {
657 for (PetscInt i = 0; i < n; ++i) {
658 ierr = PetscFree(funcs[i]); CHKERRQ(ierr);
659 }
660 ierr = PetscFree(funcs); CHKERRQ(ierr);
661 }
662 PetscFunctionReturn(0);
663}
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 598 of file logging.c.

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

◆ BCFaceToString()

const char * BCFaceToString ( BCFace  face)

Returns the canonical log token for a boundary-face enum value.

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

Returns the canonical log token for a boundary-face enum value.

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

See also
BCFaceToString()

Definition at line 671 of file logging.c.

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

◆ InitialConditionModeToString()

const char * InitialConditionModeToString ( InitialConditionMode  mode)

Convert an initial-condition mode to a string representation.

Parameters
[in]modeInitial-condition mode value.
Returns
Pointer to a constant string representing the initial-condition mode.

Convert an initial-condition mode to a string representation.

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

See also
InitialConditionModeToString()

Definition at line 689 of file logging.c.

690{
691 switch(mode){
692 case IC_MODE_ZERO: return "Zero";
693 case IC_MODE_CONSTANT_CARTESIAN: return "Cartesian Constant";
694 case IC_MODE_POISEUILLE: return "Poiseuille";
695 case IC_MODE_CONSTANT_STREAMWISE: return "Streamwise Constant";
696 case IC_MODE_FILE: return "File";
697 default: return "Unknown Initial Condition";
698 }
699}
@ IC_MODE_CONSTANT_CARTESIAN
Definition variables.h:179
@ IC_MODE_POISEUILLE
Definition variables.h:180
@ IC_MODE_CONSTANT_STREAMWISE
Definition variables.h:181
@ IC_MODE_FILE
Definition variables.h:182
@ IC_MODE_ZERO
Definition variables.h:178
Here is the caller graph for this function:

◆ FlowDirectionToString()

const char * FlowDirectionToString ( FlowDirection  fd)

Convert a FlowDirection enum value to its YAML token string.

Parameters
[in]fdFlowDirection value.
Returns
Token string such as "+Zeta", or "from INLET" when FLOW_DIR_UNSET.

Definition at line 705 of file logging.c.

706{
707 switch ((int)fd) {
708 case FLOW_DIR_POS_XI: return "+Xi";
709 case FLOW_DIR_NEG_XI: return "-Xi";
710 case FLOW_DIR_POS_ETA: return "+Eta";
711 case FLOW_DIR_NEG_ETA: return "-Eta";
712 case FLOW_DIR_POS_ZETA: return "+Zeta";
713 case FLOW_DIR_NEG_ZETA: return "-Zeta";
714 default: return "from INLET";
715 }
716}
@ FLOW_DIR_NEG_ZETA
Definition variables.h:304
@ FLOW_DIR_NEG_ETA
Definition variables.h:302
@ FLOW_DIR_POS_ZETA
Definition variables.h:303
@ FLOW_DIR_POS_XI
Definition variables.h:299
@ FLOW_DIR_NEG_XI
Definition variables.h:300
@ FLOW_DIR_POS_ETA
Definition variables.h:301
Here is the caller graph for this function:

◆ ParticleInitializationToString()

const char * ParticleInitializationToString ( ParticleInitializationType  ParticleInitialization)

Returns the canonical log token for a particle-initialization mode.

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

Returns the canonical log token for a particle-initialization mode.

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

See also
ParticleInitializationToString()

Definition at line 724 of file logging.c.

725{
726 switch(ParticleInitialization){
727 case PARTICLE_INIT_SURFACE_RANDOM: return "Surface: Random";
728 case PARTICLE_INIT_VOLUME: return "Volume";
729 case PARTICLE_INIT_POINT_SOURCE: return "Point Source";
730 case PARTICLE_INIT_SURFACE_EDGES: return "Surface: At edges";
731 default: return "Unknown Particle Initialization";
732 }
733}
@ PARTICLE_INIT_SURFACE_RANDOM
Random placement on the inlet face.
Definition variables.h:710
@ PARTICLE_INIT_SURFACE_EDGES
Deterministic placement at inlet face edges.
Definition variables.h:713
@ PARTICLE_INIT_POINT_SOURCE
All particles at a fixed (psrc_x,psrc_y,psrc_z) — for validation.
Definition variables.h:712
@ PARTICLE_INIT_VOLUME
Random volumetric distribution across the domain.
Definition variables.h:711
Here is the caller graph for this function:

◆ LESModelToString()

const char * LESModelToString ( LESModelType  LESFlag)

Returns the canonical log token for an LES model selector.

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

Returns the canonical log token for an LES model selector.

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

See also
LESModelToString()

Definition at line 741 of file logging.c.

742{
743 switch(LESFlag){
744 case NO_LES_MODEL: return "No LES";
745 case CONSTANT_SMAGORINSKY: return "Constant Smagorinsky";
746 case DYNAMIC_SMAGORINSKY: return "Dynamic Smagorinsky";
747 case VREMAN: return "Vreman";
748 case WALE: return "WALE";
749 default: return "Unknown LES Flag";
750 }
751}
@ DYNAMIC_SMAGORINSKY
Definition variables.h:551
@ VREMAN
Definition variables.h:552
@ NO_LES_MODEL
Definition variables.h:549
@ WALE
Definition variables.h:553
@ CONSTANT_SMAGORINSKY
Definition variables.h:550
Here is the caller graph for this function:

◆ LESFilterWidthModelToString()

const char * LESFilterWidthModelToString ( LESFilterWidthModel  model)

Returns the user-facing name of an LES grid-filter-width model.

Parameters
[in]modelThe filter-width model selector.
Returns
Pointer to a constant string naming the model.

Returns the user-facing name of an LES grid-filter-width model.

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

See also
LESFilterWidthModelToString()

Definition at line 761 of file logging.c.

762{
763 /* These spellings are the user-facing YAML values, so a banner line can be pasted
764 back into a case file without translation. */
765 switch(model){
766 case LES_FILTER_WIDTH_CUBE_ROOT_VOLUME: return "cube_root_volume";
767 case LES_FILTER_WIDTH_GEOMETRIC_MEAN: return "geometric_mean";
768 case LES_FILTER_WIDTH_MAX_EDGE: return "max_edge";
769 case LES_FILTER_WIDTH_SCOTTI: return "scotti";
770 default: return "unknown";
771 }
772}
@ LES_FILTER_WIDTH_SCOTTI
Definition variables.h:583
@ LES_FILTER_WIDTH_GEOMETRIC_MEAN
Definition variables.h:581
@ LES_FILTER_WIDTH_CUBE_ROOT_VOLUME
Definition variables.h:580
@ LES_FILTER_WIDTH_MAX_EDGE
Definition variables.h:582
Here is the caller graph for this function:

◆ LESTestFilterKernelToString()

const char * LESTestFilterKernelToString ( LESTestFilterKernel  kernel)

Returns the user-facing name of an LES test-filter kernel.

Parameters
[in]kernelThe test-filter kernel selector.
Returns
Pointer to a constant string naming the kernel.

Returns the user-facing name of an LES test-filter kernel.

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

See also
LESTestFilterKernelToString()

Definition at line 782 of file logging.c.

783{
784 switch(kernel){
785 case LES_TEST_FILTER_VOLUME_WEIGHTED_BOX: return "volume_weighted_box";
786 case LES_TEST_FILTER_SIMPSON_IK: return "simpson_ik";
787 default: return "unknown";
788 }
789}
@ LES_TEST_FILTER_SIMPSON_IK
Definition variables.h:593
@ LES_TEST_FILTER_VOLUME_WEIGHTED_BOX
Definition variables.h:592
Here is the caller graph for this function:

◆ LESAveragingModeToString()

const char * LESAveragingModeToString ( LESAveragingMode  mode)

Returns the user-facing name of an LES coefficient-averaging mode.

Parameters
[in]modeThe averaging mode selector.
Returns
Pointer to a constant string naming the mode.

Returns the user-facing name of an LES coefficient-averaging mode.

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

See also
LESAveragingModeToString()

Definition at line 799 of file logging.c.

800{
801 switch(mode){
802 case LES_AVERAGING_LOCAL: return "local";
803 case LES_AVERAGING_HOMOGENEOUS: return "homogeneous";
804 case LES_AVERAGING_GLOBAL: return "global";
805 default: return "unknown";
806 }
807}
@ LES_AVERAGING_LOCAL
Definition variables.h:605
@ LES_AVERAGING_GLOBAL
Definition variables.h:607
@ LES_AVERAGING_HOMOGENEOUS
Definition variables.h:606
Here is the caller graph for this function:

◆ LESClipModeToString()

const char * LESClipModeToString ( LESClipMode  mode)

Returns the user-facing name of an LES coefficient-limiting mode.

Parameters
[in]modeThe limiting mode selector.
Returns
Pointer to a constant string naming the mode.

Returns the user-facing name of an LES coefficient-limiting mode.

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

See also
LESClipModeToString()

Definition at line 817 of file logging.c.

818{
819 switch(mode){
820 case LES_CLIP_CLAMP: return "clamp";
821 case LES_CLIP_CLIP_NEGATIVE: return "clip_negative";
822 case LES_CLIP_NONE: return "none";
823 default: return "unknown";
824 }
825}
@ LES_CLIP_CLIP_NEGATIVE
Definition variables.h:619
@ LES_CLIP_CLAMP
Definition variables.h:618
@ LES_CLIP_NONE
Definition variables.h:620
Here is the caller graph for this function:

◆ WallFunctionModelToString()

const char * WallFunctionModelToString ( WallFunctionModel  model)

Returns the user-facing name of a wall-function model.

Parameters
[in]modelThe wall-model selector.
Returns
Pointer to a constant string naming the model, or "none" when disabled.

Returns the user-facing name of a wall-function model.

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

See also
WallFunctionModelToString()

Definition at line 835 of file logging.c.

836{
837 /* User-facing YAML spellings, so a banner line can be pasted back into a case. */
838 switch(model){
839 case WALL_FUNCTION_NONE: return "none";
840 case WALL_FUNCTION_LOG_LAW: return "log_law";
841 case WALL_FUNCTION_WERNER: return "werner";
842 case WALL_FUNCTION_CABOT: return "cabot";
843 default: return "unknown";
844 }
845}
@ WALL_FUNCTION_CABOT
Definition variables.h:569
@ WALL_FUNCTION_LOG_LAW
Definition variables.h:567
@ WALL_FUNCTION_WERNER
Definition variables.h:568
@ WALL_FUNCTION_NONE
Definition variables.h:566
Here is the caller graph for this function:

◆ MomentumSolverTypeToString()

const char * MomentumSolverTypeToString ( MomentumSolverType  SolverFlag)

Returns the canonical log token for a momentum-solver selector.

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

Returns the canonical log token for a momentum-solver selector.

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

See also
MomentumSolverTypeToString()

Definition at line 853 of file logging.c.

854{
855 switch(SolverFlag){
856 case MOMENTUM_SOLVER_EXPLICIT_RK: return "Explicit 4 stage Runge-Kutta ";
857 case MOMENTUM_SOLVER_DUALTIME_PICARD_JAMESON_RK: return "Dual Time Picard with 4-stage Jameson RK Smoothing";
858 case MOMENTUM_SOLVER_NEWTON_KRYLOV: return "Newton Krylov";
859 default: return "Unknown Momentum Solver Type";
860 }
861}
@ MOMENTUM_SOLVER_DUALTIME_PICARD_JAMESON_RK
Definition variables.h:694
@ MOMENTUM_SOLVER_EXPLICIT_RK
Definition variables.h:693
@ MOMENTUM_SOLVER_NEWTON_KRYLOV
Definition variables.h:695
Here is the caller graph for this function:

◆ BCTypeToString()

const char * BCTypeToString ( BCType  type)

Returns the canonical log token for a boundary mathematical type.

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

Returns the canonical log token for a boundary mathematical type.

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

See also
BCTypeToString()

Definition at line 869 of file logging.c.

869 {
870 switch (type) {
871 // case DIRICHLET: return "DIRICHLET";
872 // case NEUMANN: return "NEUMANN";
873 case WALL: return "WALL";
874 case INLET: return "INLET";
875 case OUTLET: return "OUTLET";
876 case FARFIELD: return "FARFIELD";
877 case PERIODIC: return "PERIODIC";
878 case INTERFACE: return "INTERFACE";
879
880 // case CUSTOM: return "CUSTOM";
881 default: return "Unknown BC Type";
882 }
883}
@ INLET
Definition variables.h:316
@ INTERFACE
Definition variables.h:311
@ FARFIELD
Definition variables.h:317
@ OUTLET
Definition variables.h:315
@ PERIODIC
Definition variables.h:318
@ WALL
Definition variables.h:312
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 889 of file logging.c.

889 {
890 switch (handler_type) {
891 // Wall & Symmetry Handlers
892 case BC_HANDLER_WALL_NOSLIP: return "noslip";
893 case BC_HANDLER_WALL_MOVING: return "moving";
894 case BC_HANDLER_SYMMETRY_PLANE: return "symmetry_plane";
895
896 // Inlet Handlers
897 case BC_HANDLER_INLET_CONSTANT_VELOCITY: return "constant_velocity";
898 case BC_HANDLER_INLET_PARABOLIC: return "parabolic";
899 case BC_HANDLER_INLET_PROFILE_FROM_FILE: return "prescribed_flow";
900
901 // Outlet Handlers
902 case BC_HANDLER_OUTLET_CONSERVATION: return "conservation";
903 case BC_HANDLER_OUTLET_PRESSURE: return "pressure";
904
905 // Other Physical Handlers
906 case BC_HANDLER_FARFIELD_NONREFLECTING: return "nonreflecting";
907
908 // Multi-Block / Interface Handlers
909 case BC_HANDLER_PERIODIC_GEOMETRIC: return "geometric";
910 case BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX: return "constant flux";
911 case BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX: return "initial flux";
912 case BC_HANDLER_INTERFACE_OVERSET: return "overset";
913
914 // Default case
916 default: return "UNKNOWN_HANDLER";
917 }
918}
@ BC_HANDLER_PERIODIC_GEOMETRIC
Definition variables.h:340
@ BC_HANDLER_INLET_PARABOLIC
Definition variables.h:335
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
Definition variables.h:334
@ BC_HANDLER_PERIODIC_DRIVEN_INITIAL_FLUX
Definition variables.h:343
@ BC_HANDLER_INTERFACE_OVERSET
Definition variables.h:341
@ BC_HANDLER_PERIODIC_DRIVEN_CONSTANT_FLUX
Definition variables.h:342
@ BC_HANDLER_WALL_MOVING
Definition variables.h:332
@ BC_HANDLER_INLET_PROFILE_FROM_FILE
Definition variables.h:336
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:331
@ BC_HANDLER_OUTLET_CONSERVATION
Definition variables.h:338
@ BC_HANDLER_FARFIELD_NONREFLECTING
Definition variables.h:337
@ BC_HANDLER_OUTLET_PRESSURE
Definition variables.h:339
@ BC_HANDLER_SYMMETRY_PLANE
Definition variables.h:333
@ BC_HANDLER_UNDEFINED
Definition variables.h:330
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 965 of file logging.c.

966{
967 DualMonitorCtx *monctx = (DualMonitorCtx*)ctx;
968 PetscErrorCode ierr;
969 PetscReal trnorm, relnorm;
970 Vec r;
971 char norm_buf[256];
972 PetscMPIInt rank;
973
974 PetscFunctionBeginUser;
975 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
976
977 // 1. Calculate the true residual norm.
978 ierr = KSPBuildResidual(ksp, NULL, NULL, &r); CHKERRQ(ierr);
979 ierr = VecNorm(r, NORM_2, &trnorm); CHKERRQ(ierr);
980 ierr = VecDestroy(&r); CHKERRQ(ierr);
981
982 // 2. On the first iteration, compute and store the norm of the RHS vector `b`.
983 if (it == 0) {
984 Vec b;
985 ierr = KSPGetRhs(ksp, &b); CHKERRQ(ierr);
986 ierr = VecNorm(b, NORM_2, &monctx->bnorm); CHKERRQ(ierr);
987 }
988
989 if(!rank){
990 // 3. Compute the relative norm and format the output string.
991 if (monctx->bnorm > 1.e-15) {
992 relnorm = trnorm / monctx->bnorm;
993 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);
994 } else {
995 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);
996 }
997
998 // 4. Log to the file viewer (unconditionally).
999 if(monctx->file_handle){
1000 ierr = PetscFPrintf(PETSC_COMM_SELF,monctx->file_handle,"%s\n", norm_buf); CHKERRQ(ierr);
1001 }
1002 // 5. Log to the console (conditionally).
1003 if (monctx->log_to_console) {
1004 PetscFPrintf(PETSC_COMM_SELF,stdout, "%s\n", norm_buf); CHKERRQ(ierr);
1005 }
1006
1007 } //rank
1008
1009 PetscFunctionReturn(0);
1010}
PetscBool log_to_console
Definition logging.h:58
PetscReal bnorm
Definition logging.h:59
PetscInt step
Definition logging.h:60
FILE * file_handle
Definition logging.h:57
PetscInt block_id
Definition logging.h:61
Context for a dual-purpose KSP monitor.
Definition logging.h:56
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 926 of file logging.c.

927{
928 DualMonitorCtx *monctx = (DualMonitorCtx*)*ctx;
929 PetscErrorCode ierr;
930 PetscMPIInt rank;
931
932 PetscFunctionBeginUser;
933 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
934 if(!rank && monctx->file_handle){
935 fclose(monctx->file_handle);
936 }
937
938 ierr = PetscFree(monctx); CHKERRQ(ierr);
939 *ctx = NULL;
940 PetscFunctionReturn(0);
941}
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 1891 of file logging.c.

1892{
1893 PetscErrorCode ierr;
1894 PetscMPIInt rank;
1895 SimCtx *simCtx = user->simCtx; // Get the shared SimCtx
1896 const PetscInt bi = user->_this; // Get this block's specific ID
1897 const PetscInt ti = simCtx->step; // Get the current timestep
1898
1899 PetscFunctionBeginUser;
1900 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1901
1902 // Only rank 0 performs file I/O.
1903 if (!rank) {
1904 FILE *f;
1905 char filen[PETSC_MAX_PATH_LEN + 64];
1906 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/Continuity_Metrics.log", simCtx->log_dir); CHKERRQ(ierr);
1907
1908 // Open the log file in append mode.
1909 f = fopen(filen, "a");
1910 if (!f) {
1911 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
1912 }
1913
1914 // Write a header only when the file is empty and it's the first block (bi=0).
1915 // Using ftell() instead of step comparison ensures correctness across continuations.
1916 if (ftell(f) == 0 && bi == 0) {
1917 PetscFPrintf(PETSC_COMM_SELF, f, "%-10s | %-6s | %-18s | %-30s | %-24s | %-18s | %-18s | %-18s\n",
1918 "Timestep", "Block", "Max Divergence", "Max Divergence Location ([k][j][i]=idx)", "Poisson Source Imbalance","Total Flux In", "Total Flux Out", "Net Flux");
1919 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------------------------------\n");
1920 }
1921 if (simCtx->continueMode && ti == simCtx->StartStep + 1 && bi == 0) {
1922 PetscFPrintf(PETSC_COMM_SELF, f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
1923 }
1924
1925 // Prepare the data strings and values for the current block.
1926 PetscReal net_flux = simCtx->FluxInSum - simCtx->FluxOutSum;
1927 char location_str[64];
1928 sprintf(location_str, "([%d][%d][%d] = %d)", (int)simCtx->MaxDivz, (int)simCtx->MaxDivy, (int)simCtx->MaxDivx, (int)simCtx->MaxDivFlatArg);
1929
1930 // Write the formatted line for the current block.
1931 PetscFPrintf(PETSC_COMM_SELF, f, "%-10d | %-6d | %-18.10e | %-39s | %-24.10e | %-18.10e | %-18.10e | %-18.10e\n",
1932 (int)ti,
1933 (int)bi,
1934 (double)simCtx->MaxDiv,
1935 location_str,
1936 (double)simCtx->poissonSourceImbalance,
1937 (double)simCtx->FluxInSum,
1938 (double)simCtx->FluxOutSum,
1939 (double)net_flux);
1940
1941 fclose(f);
1942 }
1943
1944 PetscFunctionReturn(0);
1945}
PetscBool continueMode
Definition variables.h:876
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:1077
PetscReal FluxOutSum
Definition variables.h:959
PetscReal poissonSourceImbalance
Definition variables.h:1026
PetscInt _this
Definition variables.h:1092
PetscInt StartStep
Definition variables.h:869
PetscReal MaxDiv
Definition variables.h:1027
PetscInt MaxDivx
Definition variables.h:1028
PetscInt MaxDivy
Definition variables.h:1028
PetscInt MaxDivz
Definition variables.h:1028
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:882
PetscInt MaxDivFlatArg
Definition variables.h:1028
PetscReal FluxInSum
Definition variables.h:959
PetscInt step
Definition variables.h:867
The master context for the entire simulation.
Definition variables.h:859
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 1695 of file logging.c.

1696{
1697 PetscMPIInt rank = 0;
1698 PetscBool has_reference = PETSC_FALSE;
1699 PetscInt phase_step = -1;
1700 PetscInt samples_before = 0;
1701 PetscReal u_abs_l2 = 0.0, u_rel_l2 = 0.0, p_abs_l2 = 0.0, p_rel_l2 = 0.0;
1702 PetscReal mean_speed = 0.0, mean_speed_reference = 0.0, mean_speed_abs_drift = 0.0, mean_speed_rel_drift = 0.0;
1703 PetscReal mean_ke = 0.0, mean_ke_reference = 0.0, mean_ke_abs_drift = 0.0, mean_ke_rel_drift = 0.0;
1704 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;
1705 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;
1706 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;
1707 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;
1708
1709 PetscFunctionBeginUser;
1710 if (!simCtx) PetscFunctionReturn(0);
1711 if (simCtx->exec_mode != EXEC_MODE_SOLVER) PetscFunctionReturn(0);
1712 if (!simCtx->solutionConvergenceEnabled) PetscFunctionReturn(0);
1713
1714 samples_before = simCtx->solutionConvergenceSamplesRecorded;
1715
1716 switch (simCtx->solutionConvergenceMode) {
1719 PetscCall(ComputeDeterministicSolutionMetrics(simCtx, PETSC_FALSE, -1, samples_before,
1720 &has_reference,
1721 &u_abs_l2, &u_rel_l2,
1722 &p_abs_l2, &p_rel_l2,
1723 &mean_speed, &mean_speed_reference,
1724 &mean_speed_abs_drift, &mean_speed_rel_drift,
1725 &mean_ke, &mean_ke_reference,
1726 &mean_ke_abs_drift, &mean_ke_rel_drift));
1727 break;
1729 phase_step = simCtx->solutionConvergencePeriodSteps > 0 ? (simCtx->step % simCtx->solutionConvergencePeriodSteps) : -1;
1730 PetscCall(ComputeDeterministicSolutionMetrics(simCtx, PETSC_TRUE, phase_step, samples_before,
1731 &has_reference,
1732 &u_abs_l2, &u_rel_l2,
1733 &p_abs_l2, &p_rel_l2,
1734 &mean_speed, &mean_speed_reference,
1735 &mean_speed_abs_drift, &mean_speed_rel_drift,
1736 &mean_ke, &mean_ke_reference,
1737 &mean_ke_abs_drift, &mean_ke_rel_drift));
1738 break;
1740 PetscCall(ComputeCurrentFlowObservables(simCtx, &mean_speed, &mean_ke));
1741 PetscCall(AppendStatisticalObservableSample(simCtx, samples_before, mean_speed, mean_ke));
1742 PetscCall(ComputeStatisticalWindowMetrics(simCtx, samples_before + 1,
1743 &has_reference,
1744 &mean_speed_window, &mean_speed_window_prev,
1745 &mean_speed_window_abs_drift, &mean_speed_window_rel_drift,
1746 &mean_speed_rms_window, &mean_speed_rms_window_prev,
1747 &mean_speed_rms_window_abs_drift, &mean_speed_rms_window_rel_drift,
1748 &mean_ke_window, &mean_ke_window_prev,
1749 &mean_ke_window_abs_drift, &mean_ke_window_rel_drift,
1750 &mean_ke_rms_window, &mean_ke_rms_window_prev,
1751 &mean_ke_rms_window_abs_drift, &mean_ke_rms_window_rel_drift));
1752 break;
1753 default:
1754 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown solution convergence mode %d.", (int)simCtx->solutionConvergenceMode);
1755 }
1756
1757 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
1758 if (rank == 0) {
1759 char log_path[PETSC_MAX_PATH_LEN + 32];
1760 FILE *f = NULL;
1761 const char *mode_str = SolutionConvergenceModeToString(simCtx->solutionConvergenceMode);
1762
1763 PetscCall(PetscSNPrintf(log_path, sizeof(log_path), "%s/solution_convergence.log", simCtx->log_dir));
1764 f = fopen(log_path, "a");
1765 if (!f) {
1766 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open solution convergence log: %s", log_path);
1767 }
1768
1769 if (ftell(f) == 0) {
1770 switch (simCtx->solutionConvergenceMode) {
1773 fprintf(f, "==================== Solution Convergence Log [mode: %s] ====================\n", mode_str);
1774 /* 16 columns; header width = 314 chars */
1775 fprintf(f, "%-10s | %-18s | %-22s | %-3s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s\n",
1776 "step", "time", "mode", "ref",
1777 "u_abs_l2", "u_rel_l2", "p_abs_l2", "p_rel_l2",
1778 "mean_speed", "spd_ref", "spd_abs", "spd_rel",
1779 "mean_ke", "ke_ref", "ke_abs", "ke_rel");
1780 fprintf(f, "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
1781 break;
1783 fprintf(f, "==================== Solution Convergence Log [mode: %s | period_steps: %d] ====================\n",
1784 mode_str, (int)simCtx->solutionConvergencePeriodSteps);
1785 /* 18 columns; header width = 330 chars */
1786 fprintf(f, "%-10s | %-18s | %-22s | %-3s | %-5s | %-5s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s\n",
1787 "step", "time", "mode", "ref", "ph", "per",
1788 "u_abs_l2", "u_rel_l2", "p_abs_l2", "p_rel_l2",
1789 "mean_speed", "spd_ref", "spd_abs", "spd_rel",
1790 "mean_ke", "ke_ref", "ke_abs", "ke_rel");
1791 fprintf(f, "----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
1792 break;
1794 fprintf(f, "==================== Solution Convergence Log [mode: %s | window_steps: %d] ====================\n",
1795 mode_str, (int)simCtx->solutionConvergenceWindowSteps);
1796 /* 21 columns; header width = 406 chars */
1797 fprintf(f, "%-10s | %-18s | %-22s | %-3s | %-5s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s | %-18s\n",
1798 "step", "time", "mode", "ref", "win",
1799 "mean_speed", "mean_ke",
1800 "spd_win", "spd_win_prev", "spd_win_abs", "spd_win_rel",
1801 "spd_rms_win", "spd_rms_abs", "spd_rms_rel",
1802 "ke_win", "ke_win_prev", "ke_win_abs", "ke_win_rel",
1803 "ke_rms_win", "ke_rms_abs", "ke_rms_rel");
1804 fprintf(f, "------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n");
1805 break;
1806 default: break;
1807 }
1808 }
1809 if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
1810 fprintf(f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
1811 }
1812
1813 switch (simCtx->solutionConvergenceMode) {
1816 fprintf(f,
1817 "%-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",
1818 (int)simCtx->step, (double)simCtx->ti, mode_str, has_reference ? 1 : 0,
1819 (double)u_abs_l2, (double)u_rel_l2, (double)p_abs_l2, (double)p_rel_l2,
1820 (double)mean_speed, (double)mean_speed_reference,
1821 (double)mean_speed_abs_drift, (double)mean_speed_rel_drift,
1822 (double)mean_ke, (double)mean_ke_reference,
1823 (double)mean_ke_abs_drift, (double)mean_ke_rel_drift);
1824 break;
1826 fprintf(f,
1827 "%-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",
1828 (int)simCtx->step, (double)simCtx->ti, mode_str, has_reference ? 1 : 0,
1829 (int)phase_step, (int)simCtx->solutionConvergencePeriodSteps,
1830 (double)u_abs_l2, (double)u_rel_l2, (double)p_abs_l2, (double)p_rel_l2,
1831 (double)mean_speed, (double)mean_speed_reference,
1832 (double)mean_speed_abs_drift, (double)mean_speed_rel_drift,
1833 (double)mean_ke, (double)mean_ke_reference,
1834 (double)mean_ke_abs_drift, (double)mean_ke_rel_drift);
1835 break;
1837 fprintf(f,
1838 "%-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",
1839 (int)simCtx->step, (double)simCtx->ti, mode_str, has_reference ? 1 : 0,
1840 (int)simCtx->solutionConvergenceWindowSteps,
1841 (double)mean_speed, (double)mean_ke,
1842 (double)mean_speed_window, (double)mean_speed_window_prev,
1843 (double)mean_speed_window_abs_drift, (double)mean_speed_window_rel_drift,
1844 (double)mean_speed_rms_window,
1845 (double)mean_speed_rms_window_abs_drift, (double)mean_speed_rms_window_rel_drift,
1846 (double)mean_ke_window, (double)mean_ke_window_prev,
1847 (double)mean_ke_window_abs_drift, (double)mean_ke_window_rel_drift,
1848 (double)mean_ke_rms_window,
1849 (double)mean_ke_rms_window_abs_drift, (double)mean_ke_rms_window_rel_drift);
1850 break;
1851 default: break;
1852 }
1853 fclose(f);
1854 }
1855
1857 phase_step >= 0 && phase_step < simCtx->solutionConvergencePeriodSteps) {
1858 UserCtx *user = simCtx->usermg.mgctx[simCtx->usermg.mglevels - 1].user;
1859 for (PetscInt bi = 0; bi < simCtx->block_number; ++bi) {
1860 PetscCall(VecCopy(user[bi].Ucat, user[bi].solutionConvergencePeriodicUcatRef[phase_step]));
1861 PetscCall(VecCopy(user[bi].P, user[bi].solutionConvergencePeriodicPRef[phase_step]));
1862 }
1863 }
1864
1865 simCtx->solutionConvergenceSamplesRecorded = samples_before + 1;
1866
1867 PetscFunctionReturn(0);
1868}
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:1465
static const char * SolutionConvergenceModeToString(SolutionConvergenceMode mode)
Maps the internal solution-convergence mode enum to its log label.
Definition logging.c:1678
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:1545
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:1187
static PetscErrorCode ComputeCurrentFlowObservables(SimCtx *simCtx, PetscReal *mean_speed_out, PetscReal *mean_ke_out)
Computes instantaneous global flow observables for statistical mode.
Definition logging.c:1071
UserCtx * user
Definition variables.h:729
PetscInt block_number
Definition variables.h:952
UserMG usermg
Definition variables.h:1015
PetscInt solutionConvergenceSamplesRecorded
Definition variables.h:927
PetscBool solutionConvergenceEnabled
Definition variables.h:923
PetscInt solutionConvergencePeriodSteps
Definition variables.h:925
PetscInt mglevels
Definition variables.h:736
PetscInt solutionConvergenceWindowSteps
Definition variables.h:926
@ EXEC_MODE_SOLVER
Definition variables.h:832
MGCtx * mgctx
Definition variables.h:739
@ SOLUTION_CONVERGENCE_TRANSIENT
Definition variables.h:705
@ SOLUTION_CONVERGENCE_PERIODIC_DETERMINISTIC
Definition variables.h:703
@ SOLUTION_CONVERGENCE_STATISTICAL_STEADY
Definition variables.h:704
@ SOLUTION_CONVERGENCE_STEADY_DETERMINISTIC
Definition variables.h:702
SolutionConvergenceMode solutionConvergenceMode
Definition variables.h:924
ExecutionMode exec_mode
Definition variables.h:878
PetscReal ti
Definition variables.h:868
User-defined context containing data specific to a single computational grid level.
Definition variables.h:1074
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 1953 of file logging.c.

1954{
1955 switch (level) {
1956 case NEEDS_LOCATION: return "NEEDS_LOCATION";
1957 case ACTIVE_AND_LOCATED: return "ACTIVE_AND_LOCATED";
1958 case MIGRATING_OUT: return "MIGRATING_OUT";
1959 case LOST: return "LOST";
1960 case UNINITIALIZED: return "UNINITIALIZED";
1961 default: return "UNKNOWN_LEVEL";
1962 }
1963}
@ LOST
Definition variables.h:167
@ NEEDS_LOCATION
Definition variables.h:164
@ ACTIVE_AND_LOCATED
Definition variables.h:165
@ UNINITIALIZED
Definition variables.h:168
@ MIGRATING_OUT
Definition variables.h:166
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 2411 of file logging.c.

2412{
2413 if (totalSteps <= 0) return;
2414
2415 // --- Configuration ---
2416 const int barWidth = 50;
2417
2418 // --- Calculation ---
2419 // Calculate progress as a fraction from 0.0 to 1.0
2420 PetscReal progress = (PetscReal)(step - startStep + 1) / totalSteps;
2421 // Ensure progress doesn't exceed 1.0 due to floating point inaccuracies
2422 if (progress > 1.0) progress = 1.0;
2423
2424 int pos = (int)(barWidth * progress);
2425
2426 // --- Printing ---
2427 // Carriage return moves cursor to the beginning of the line
2428 PetscPrintf(PETSC_COMM_SELF, "\rProgress: [");
2429
2430 for (int i = 0; i < barWidth; ++i) {
2431 if (i < pos) {
2432 PetscPrintf(PETSC_COMM_SELF, "=");
2433 } else if (i == pos) {
2434 PetscPrintf(PETSC_COMM_SELF, ">");
2435 } else {
2436 PetscPrintf(PETSC_COMM_SELF, " ");
2437 }
2438 }
2439
2440 // Print percentage, step count, and current time
2441 PetscPrintf(PETSC_COMM_SELF, "] %3d%% (Step %" PetscInt_FMT "/%" PetscInt_FMT ", t=%.4f)",
2442 (int)(progress * 100.0),
2443 step + 1,
2444 startStep + totalSteps,
2445 currentTime);
2446
2447 // Flush the output buffer to ensure the bar is displayed immediately
2448 fflush(stdout);
2449}
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 2023 of file logging.c.

2024{
2025 PetscFunctionBeginUser;
2026 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingInitialize");
2027
2028 // Iterate through the list of critical functions provided in SimCtx
2029 for (PetscInt i = 0; i < simCtx->nProfilingSelectedFuncs; ++i) {
2030 PetscInt idx;
2031 const char *func_name = simCtx->profilingSelectedFuncs[i];
2032 PetscErrorCode ierr = _FindOrCreateEntry(func_name, &idx); CHKERRQ(ierr);
2033 g_profiler_registry[idx].always_log = PETSC_TRUE;
2034
2035 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Marked '%s' as a critical function for profiling.\n", func_name);
2036 }
2037 PetscFunctionReturn(0);
2038}
PetscBool always_log
Definition logging.c:1975
static PetscErrorCode _FindOrCreateEntry(const char *func_name, PetscInt *idx)
Find a profiling record by name or allocate and register a new record.
Definition logging.c:1987
static ProfiledFunction * g_profiler_registry
Definition logging.c:1979
char ** profilingSelectedFuncs
Definition variables.h:1032
PetscInt nProfilingSelectedFuncs
Definition variables.h:1033
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 2083 of file logging.c.

2084{
2085 PetscFunctionBeginUser;
2086 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2089 }
2090 PetscFunctionReturn(0);
2091}
static PetscInt g_profiler_count
Definition logging.c:1980
double current_step_time
Definition logging.c:1971
long long current_step_call_count
Definition logging.c:1973
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 2100 of file logging.c.

2101{
2102 PetscBool should_write = PETSC_FALSE;
2103 FILE *f = NULL;
2104 char filen[(2 * PETSC_MAX_PATH_LEN) + 16];
2105
2106 PetscFunctionBeginUser;
2107 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingLogTimestepSummary");
2108
2109 if (strcmp(simCtx->profilingTimestepMode, "off") == 0) {
2110 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2113 }
2114 PetscFunctionReturn(0);
2115 }
2116
2117 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2118 if (g_profiler_registry[i].current_step_call_count <= 0) {
2119 continue;
2120 }
2121 if (strcmp(simCtx->profilingTimestepMode, "all") == 0 || g_profiler_registry[i].always_log) {
2122 should_write = PETSC_TRUE;
2123 break;
2124 }
2125 }
2126
2127 /* A selected name that matches no instrumented function records nothing, and a
2128 list made only of such names writes no file at all. Say so once, on the first
2129 step, rather than leave an absent file to be discovered after the run. */
2130 if (step == simCtx->StartStep + 1 && strcmp(simCtx->profilingTimestepMode, "selected") == 0) {
2131 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2132 if (g_profiler_registry[i].always_log && g_profiler_registry[i].total_call_count == 0) {
2134 "profiling.timestep_output.functions lists '%s', which recorded no call in the first "
2135 "step. It is not an instrumented function; the final summary lists the names that are.\n",
2136 g_profiler_registry[i].name);
2137 }
2138 }
2139 }
2140
2141 if (should_write && simCtx->rank == 0) {
2142 snprintf(filen, sizeof(filen), "%s/%s", simCtx->log_dir, simCtx->profilingTimestepFile);
2143 if (step == simCtx->StartStep + 1 && !simCtx->continueMode) {
2144 f = fopen(filen, "w");
2145 if (!f) {
2146 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open profiling timestep log file: %s", filen);
2147 }
2148 PetscFPrintf(PETSC_COMM_SELF, f, "step,function,calls,step_time_s\n");
2149 } else {
2150 f = fopen(filen, "a");
2151 if (!f) {
2152 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open profiling timestep log file: %s", filen);
2153 }
2154 if (step == simCtx->StartStep + 1 && ftell(f) == 0) {
2155 PetscFPrintf(PETSC_COMM_SELF, f, "step,function,calls,step_time_s\n");
2156 }
2157 }
2158 if (simCtx->continueMode && step == simCtx->StartStep + 1) {
2159 PetscFPrintf(PETSC_COMM_SELF, f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
2160 }
2161
2162 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2163 if (g_profiler_registry[i].current_step_call_count <= 0) {
2164 continue;
2165 }
2166 if (strcmp(simCtx->profilingTimestepMode, "all") == 0 || g_profiler_registry[i].always_log) {
2167 PetscFPrintf(
2168 PETSC_COMM_SELF,
2169 f,
2170 "%d,%s,%lld,%.6f\n",
2171 (int)step,
2172 g_profiler_registry[i].name,
2173 g_profiler_registry[i].current_step_call_count,
2174 g_profiler_registry[i].current_step_time
2175 );
2176 }
2177 }
2178 fclose(f);
2179 }
2180
2181 // Reset per-step counters for the next iteration
2182 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2185 }
2186 PetscFunctionReturn(0);
2187}
PetscMPIInt rank
Definition variables.h:862
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
Definition variables.h:1035
char profilingTimestepMode[32]
Definition variables.h:1034
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 2195 of file logging.c.

2196{
2197 PetscErrorCode ierr;
2198 PetscLogDouble process_current_bytes = 0.0;
2199 PetscLogDouble process_peak_bytes = 0.0;
2200 PetscLogDouble petsc_current_bytes = 0.0;
2201 PetscLogDouble petsc_peak_bytes = 0.0;
2202 PetscReal local_values[5];
2203 PetscReal global_values[5];
2204 PetscReal process_current_mb = 0.0;
2205 PetscReal process_peak_mb = 0.0;
2206 PetscReal petsc_current_mb = 0.0;
2207 PetscReal petsc_peak_mb = 0.0;
2208 PetscReal process_change_mb = 0.0;
2209 char path[(2 * PETSC_MAX_PATH_LEN) + 16];
2210 FILE *f = NULL;
2211
2212 PetscFunctionBeginUser;
2213 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for RuntimeMemoryLogSample");
2214 if (!simCtx->runtimeMemoryLogEnabled) PetscFunctionReturn(0);
2215
2216 ierr = PetscMemoryGetCurrentUsage(&process_current_bytes); CHKERRQ(ierr);
2217 ierr = PetscMemoryGetMaximumUsage(&process_peak_bytes); CHKERRQ(ierr);
2218 ierr = PetscMallocGetCurrentUsage(&petsc_current_bytes); CHKERRQ(ierr);
2219 ierr = PetscMallocGetMaximumUsage(&petsc_peak_bytes); CHKERRQ(ierr);
2220
2221 process_current_mb = (PetscReal)(process_current_bytes / (1024.0 * 1024.0));
2222 process_peak_mb = (PetscReal)(process_peak_bytes / (1024.0 * 1024.0));
2223 petsc_current_mb = (PetscReal)(petsc_current_bytes / (1024.0 * 1024.0));
2224 petsc_peak_mb = (PetscReal)(petsc_peak_bytes / (1024.0 * 1024.0));
2225 if (simCtx->runtimeMemoryLogHasPrevious) {
2226 process_change_mb = process_current_mb - simCtx->runtimeMemoryLogPreviousProcessMB;
2227 }
2228
2229 local_values[0] = process_current_mb;
2230 local_values[1] = process_peak_mb;
2231 local_values[2] = petsc_current_mb;
2232 local_values[3] = petsc_peak_mb;
2233 local_values[4] = process_change_mb;
2234 ierr = MPI_Allreduce(local_values, global_values, 5, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2235
2236 simCtx->runtimeMemoryLogPreviousProcessMB = process_current_mb;
2237 simCtx->runtimeMemoryLogHasPrevious = PETSC_TRUE;
2238
2239 if (simCtx->rank == 0) {
2240 ierr = PetscSNPrintf(path, sizeof(path), "%s/%s", simCtx->log_dir, simCtx->runtimeMemoryLogFile); CHKERRQ(ierr);
2241 f = fopen(path, "a");
2242 if (!f) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open runtime memory log file: %s", path);
2243
2244 if (!simCtx->runtimeMemoryLogStarted) {
2245 fprintf(f, "# PICurv runtime memory log\n");
2246 if (simCtx->continueMode) {
2247 fprintf(f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
2248 }
2249 fprintf(
2250 f,
2251 "%-8s %-10s %22s %20s %22s %28s %22s %-18s\n",
2252 "Step",
2253 "Event",
2254 "Process Current MB Max",
2255 "Process Peak MB Max",
2256 "PETSc Allocated MB Max",
2257 "PETSc Peak Allocated MB Max",
2258 "Process Change MB Max",
2259 "Reason"
2260 );
2261 simCtx->runtimeMemoryLogStarted = PETSC_TRUE;
2262 }
2263
2264 fprintf(
2265 f,
2266 "%-8" PetscInt_FMT " %-10s %22.3f %20.3f %22.3f %28.3f %22.3f %-18s\n",
2267 step,
2268 event ? event : "-",
2269 (double)global_values[0],
2270 (double)global_values[1],
2271 (double)global_values[2],
2272 (double)global_values[3],
2273 (double)global_values[4],
2274 (reason && reason[0]) ? reason : "-"
2275 );
2276 if ((event && (strcmp(event, "Shutdown") == 0 || strcmp(event, "Final") == 0))) {
2277 fflush(f);
2278 }
2279 fclose(f);
2280 }
2281
2282 PetscFunctionReturn(0);
2283}
PetscBool runtimeMemoryLogEnabled
Enable the rank-reduced runtime memory log.
Definition variables.h:1051
char runtimeMemoryLogFile[PETSC_MAX_PATH_LEN]
File name written under log_dir.
Definition variables.h:1052
PetscBool runtimeMemoryLogStarted
True after rank 0 writes the log header.
Definition variables.h:1053
PetscBool runtimeMemoryLogHasPrevious
True after the first process-memory sample.
Definition variables.h:1054
PetscReal runtimeMemoryLogPreviousProcessMB
Previous local process memory sample in MB.
Definition variables.h:1055
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 2305 of file logging.c.

2306{
2307 PetscErrorCode ierr;
2308 PetscInt rank = simCtx->rank;
2309 PetscFunctionBeginUser;
2310 if (!simCtx->profilingFinalSummary) PetscFunctionReturn(0);
2311 if (!rank) {
2312
2313 char exec_mode_modifier[32] = "Unknown";
2314 if(simCtx->exec_mode == EXEC_MODE_SOLVER) PetscCall(PetscStrncpy(exec_mode_modifier, "Solver", sizeof(exec_mode_modifier)));
2315 else if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) PetscCall(PetscStrncpy(exec_mode_modifier, "PostProcessor", sizeof(exec_mode_modifier)));
2316 //--- Step 0: Create a file viewer for log file
2317 FILE *f;
2318 char filen[PETSC_MAX_PATH_LEN + 128];
2319 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/ProfilingSummary_%s.log",simCtx->log_dir,exec_mode_modifier); CHKERRQ(ierr);
2320
2321 // Open the log file: append with section label in continue mode, truncate otherwise.
2322 if (simCtx->continueMode) {
2323 f = fopen(filen, "a");
2324 if (!f) {
2325 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
2326 }
2327 fprintf(f, "\n=== Continuation from step %" PetscInt_FMT " ===\n", simCtx->StartStep);
2328 } else {
2329 f = fopen(filen, "w");
2330 if (!f) {
2331 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
2332 }
2333 }
2334
2335 // --- Step 1: Sort the data for readability ---
2337
2338 // --- Step 2: Dynamically determine the width for the function name column ---
2339 PetscInt max_name_len = strlen("Function"); // Start with the header's length
2340 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2341 if (g_profiler_registry[i].total_call_count > 0) {
2342 PetscInt len = strlen(g_profiler_registry[i].name);
2343 if (len > max_name_len) {
2344 max_name_len = len;
2345 }
2346 }
2347 }
2348 // Add a little padding
2349 max_name_len += 2;
2350
2351 // --- Step 3: Define fixed widths for numeric columns for consistent alignment ---
2352 const int time_width = 18;
2353 const int count_width = 15;
2354 const int avg_width = 22;
2355
2356 // --- Step 4: Print the formatted table ---
2357 PetscFPrintf(PETSC_COMM_SELF, f, "=================================================================================================================\n");
2358 PetscFPrintf(PETSC_COMM_SELF, f, " FINAL PROFILING SUMMARY (Sorted by Total Time)\n");
2359 PetscFPrintf(PETSC_COMM_SELF, f, "=================================================================================================================\n");
2360
2361 // Header Row
2362 PetscFPrintf(PETSC_COMM_SELF, f, "%-*s | %-*s | %-*s | %-*s\n",
2363 max_name_len, "Function",
2364 time_width, "Total Time (s)",
2365 count_width, "Call Count",
2366 avg_width, "Avg. Time/Call (ms)");
2367
2368 // Separator Line (dynamically sized)
2369 for (int i = 0; i < max_name_len; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2370 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
2371 for (int i = 0; i < time_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2372 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
2373 for (int i = 0; i < count_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2374 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
2375 for (int i = 0; i < avg_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
2376 PetscFPrintf(PETSC_COMM_SELF, f, "\n");
2377
2378 // Data Rows
2379 for (PetscInt i = 0; i < g_profiler_count; ++i) {
2380 if (g_profiler_registry[i].total_call_count > 0) {
2381 double avg_time_ms = (g_profiler_registry[i].total_time / g_profiler_registry[i].total_call_count) * 1000.0;
2382 PetscFPrintf(PETSC_COMM_SELF, f, "%-*s | %*.*f | %*lld | %*.*f\n",
2383 max_name_len, g_profiler_registry[i].name,
2384 time_width, 6, g_profiler_registry[i].total_time,
2385 count_width, g_profiler_registry[i].total_call_count,
2386 avg_width, 6, avg_time_ms);
2387 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------\n");
2388 }
2389 }
2390 PetscFPrintf(PETSC_COMM_SELF, f, "==================================================================================================================\n");
2391
2392 fclose(f);
2393 }
2394
2395 // --- Final Cleanup ---
2396 PetscFree(g_profiler_registry);
2397 g_profiler_registry = NULL;
2398 g_profiler_count = 0;
2400 PetscFunctionReturn(0);
2401}
long long total_call_count
Definition logging.c:1972
static PetscInt g_profiler_capacity
Definition logging.c:1981
double total_time
Definition logging.c:1970
static int _CompareProfiledFunctions(const void *a, const void *b)
Order profiling records by their accumulated execution time.
Definition logging.c:2289
PetscBool profilingFinalSummary
Definition variables.h:1036
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:833
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 2047 of file logging.c.

2048{
2049 PetscInt idx;
2050 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
2051 PetscTime(&g_profiler_registry[idx].start_time);
2052}
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 2061 of file logging.c.

2062{
2063 double end_time;
2064 PetscTime(&end_time);
2065
2066 PetscInt idx;
2067 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
2068
2069 double elapsed = end_time - g_profiler_registry[idx].start_time;
2070 g_profiler_registry[idx].total_time += elapsed;
2071 g_profiler_registry[idx].current_step_time += elapsed;
2074}
double start_time
Definition logging.c:1974
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,
FieldId  field_id 
)

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]field_idTyped identity of the field being analyzed.
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 2458 of file logging.c.

2459{
2460 PetscErrorCode ierr;
2461 PetscInt i, j, k;
2462 DMDALocalInfo info;
2463
2464 FieldView view;
2465 Vec fieldVec = NULL;
2466 DM dm = NULL;
2467 PetscInt dof;
2468 FieldLayout layout;
2469 const char *fieldName = NULL;
2470 const char *data_layout = NULL;
2471
2472 PetscFunctionBeginUser;
2473
2474 ierr = FieldGetView(user, field_id, &view); CHKERRQ(ierr);
2475 fieldName = view.descriptor->canonical_name;
2476 dm = view.dm;
2477 dof = view.descriptor->dof;
2478 layout = view.descriptor->layout;
2479 data_layout = FieldLayoutName(layout);
2480 fieldVec = (layout == FIELD_LAYOUT_COMPONENT_STAGGERED) ? view.local_vec : view.global_vec;
2481
2482 ierr = DMDAGetLocalInfo(dm, &info); CHKERRQ(ierr);
2483
2484 // --- 2. Define Architecture-Aware Loop Bounds ---
2485 PetscInt i_start, i_end, j_start, j_end, k_start, k_end;
2486
2487 if (layout == FIELD_LAYOUT_CELL_CENTERED) {
2488 // For cell-centered data, the physical values are stored from index 1 to N-1.
2489 // We find the intersection of the rank's owned range [xs, xe) with the
2490 // physical data range [1, IM-1).
2491 i_start = PetscMax(info.xs, 1); i_end = PetscMin(info.xs + info.xm, user->IM);
2492 j_start = PetscMax(info.ys, 1); j_end = PetscMin(info.ys + info.ym, user->JM);
2493 k_start = PetscMax(info.zs, 1); k_end = PetscMin(info.zs + info.zm, user->KM);
2494 } else { // For Node- or Face-Centered data
2495 // The physical values are stored from index 0 to N-1.
2496 // We find the intersection of the rank's owned range [xs, xe) with the
2497 // physical data range [0, IM-1].
2498 i_start = PetscMax(info.xs, 0); i_end = PetscMin(info.xs + info.xm, user->IM);
2499 j_start = PetscMax(info.ys, 0); j_end = PetscMin(info.ys + info.ym, user->JM);
2500 k_start = PetscMax(info.zs, 0); k_end = PetscMin(info.zs + info.zm, user->KM);
2501 }
2502
2503 // --- 3. Barrier for clean, grouped output ---
2504 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
2505 if (user->simCtx->rank == 0) {
2506 PetscPrintf(PETSC_COMM_SELF, "\n--- Field Ranges: [%s] (Layout: %s) ---\n", fieldName, data_layout);
2507 }
2508
2509 // --- 4. Branch on DoF and perform calculation with correct bounds ---
2510 if (dof == 1) {
2511 PetscReal localMin = PETSC_MAX_REAL, localMax = PETSC_MIN_REAL;
2512 PetscReal globalMin, globalMax;
2513 const PetscScalar ***array;
2514
2515 ierr = DMDAVecGetArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2516 for (k = k_start; k < k_end; k++) {
2517 for (j = j_start; j < j_end; j++) {
2518 for (i = i_start; i < i_end; i++) {
2519 localMin = PetscMin(localMin, array[k][j][i]);
2520 localMax = PetscMax(localMax, array[k][j][i]);
2521 }
2522 }
2523 }
2524 ierr = DMDAVecRestoreArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2525
2526 ierr = MPI_Allreduce(&localMin, &globalMin, 1, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
2527 ierr = MPI_Allreduce(&localMax, &globalMax, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
2528
2529 PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin, localMax);
2530 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
2531 if (user->simCtx->rank == 0) {
2532 PetscPrintf(PETSC_COMM_SELF, " Global Range: [ %11.4e , %11.4e ]\n", globalMin, globalMax);
2533 }
2534
2535 } else if (dof == 3) {
2536 Cmpnts localMin = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
2537 Cmpnts localMax = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
2538 Cmpnts globalMin, globalMax;
2539 const Cmpnts ***array;
2540
2541 ierr = DMDAVecGetArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2542 for (k = k_start; k < k_end; k++) {
2543 for (j = j_start; j < j_end; j++) {
2544 for (i = i_start; i < i_end; i++) {
2545 localMin.x = PetscMin(localMin.x, array[k][j][i].x);
2546 localMin.y = PetscMin(localMin.y, array[k][j][i].y);
2547 localMin.z = PetscMin(localMin.z, array[k][j][i].z);
2548 localMax.x = PetscMax(localMax.x, array[k][j][i].x);
2549 localMax.y = PetscMax(localMax.y, array[k][j][i].y);
2550 localMax.z = PetscMax(localMax.z, array[k][j][i].z);
2551 }
2552 }
2553 }
2554 ierr = DMDAVecRestoreArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
2555
2556 ierr = MPI_Allreduce(&localMin, &globalMin, 3, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
2557 ierr = MPI_Allreduce(&localMax, &globalMax, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
2558
2559 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local X-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.x, localMax.x);
2560 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Y-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.y, localMax.y);
2561 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Z-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.z, localMax.z);
2562 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
2563
2564 if (user->simCtx->rank == 0) {
2565 PetscPrintf(PETSC_COMM_SELF, " [Global] X-Range: [ %11.4e , %11.4e ]\n", globalMin.x, globalMax.x);
2566 PetscPrintf(PETSC_COMM_SELF, " [Global] Y-Range: [ %11.4e , %11.4e ]\n", globalMin.y, globalMax.y);
2567 PetscPrintf(PETSC_COMM_SELF, " [Global] Z-Range: [ %11.4e , %11.4e ]\n", globalMin.z, globalMax.z);
2568 }
2569
2570 } else {
2571 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);
2572 }
2573
2574 // --- 5. Final barrier for clean output ordering ---
2575 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
2576 if (user->simCtx->rank == 0) {
2577 PetscPrintf(PETSC_COMM_SELF, "--------------------------------------------\n\n");
2578 }
2579
2580 PetscFunctionReturn(0);
2581}
FieldLayout layout
const FieldDescriptor * descriptor
PetscErrorCode FieldGetView(UserCtx *user, FieldId field_id, FieldView *view)
Resolve the existing DM and global/local vectors for one field.
FieldLayout
Logical storage topology of a field.
@ FIELD_LAYOUT_CELL_CENTERED
@ FIELD_LAYOUT_COMPONENT_STAGGERED
const char * canonical_name
const char * FieldLayoutName(FieldLayout layout)
Return a stable printable label for a field layout.
Non-owning runtime objects resolved for one field and UserCtx.
PetscInt KM
Definition variables.h:1088
PetscInt JM
Definition variables.h:1088
PetscInt IM
Definition variables.h:1088
A 3D point or vector with PetscScalar components.
Definition variables.h:121
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LOG_FIELD_ANATOMY()

PetscErrorCode LOG_FIELD_ANATOMY ( UserCtx *  user,
FieldId  field_id,
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.
  • Single-Face-Family Fields: Csi/ICsi/IEta/IZet/Centx belong to the I-face family, with corresponding J- and K-face families.
  • Component-Staggered Fields ("Ucont" and histories): x/y/z components live on I/J/K faces respectively.
  • 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_idTyped identity of the persistent Eulerian field to log.
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.

See also
LOG_FIELD_ANATOMY()

Definition at line 2861 of file logging.c.

2862{
2863 FieldView view;
2864
2865 PetscFunctionBeginUser;
2866 PetscCall(FieldGetView(user, field_id, &view));
2867 PetscCall(LogFieldAnatomyView(user, view.descriptor->canonical_name, stage_name,
2868 view.dm, view.local_vec, view.descriptor->dof,
2869 view.descriptor->layout));
2870 PetscFunctionReturn(0);
2871}
static PetscErrorCode LogFieldAnatomyView(UserCtx *user, const char *field_name, const char *stage_name, DM dm, Vec vec_local, PetscInt dof, FieldLayout layout)
Shared architecture-aware anatomy logger for catalog and transient fields.
Definition logging.c:2588
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LOG_CORNER_FIELD_ANATOMY()

PetscErrorCode LOG_CORNER_FIELD_ANATOMY ( UserCtx *  user,
FieldId  corner_field_id,
const char *  stage_name 
)

Logs the node-layout anatomy of the transient center-to-corner interpolation field.

Parameters
userContext owning the corner-staging workspace.
corner_field_idWhich corner workspace the caller populated.
stage_namePrintable simulation stage.
Returns
Zero on success.

Logs the node-layout anatomy of the transient center-to-corner interpolation field.

See also
LOG_CORNER_FIELD_ANATOMY()

Definition at line 2947 of file logging.c.

2948{
2949 FieldView view;
2950
2951 PetscFunctionBeginUser;
2952 PetscCheck(user != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
2953 PetscCheck(corner_field_id == FIELD_ID_CELL_SCALAR_AT_CORNER ||
2954 corner_field_id == FIELD_ID_CELL_VECTOR_AT_CORNER,
2955 PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE,
2956 "Corner anatomy logging expects a corner-staging field identity.");
2957 /* The caller states which workspace it used, so the degree of freedom and DM
2958 * come from the catalog instead of being inferred from a cached vector. */
2959 PetscCall(FieldGetView(user, corner_field_id, &view));
2960 PetscCall(LogFieldAnatomyView(user, view.descriptor->canonical_name, stage_name, view.dm,
2961 view.local_vec, view.descriptor->dof,
2962 view.descriptor->layout));
2963 PetscFunctionReturn(0);
2964}
@ FIELD_ID_CELL_SCALAR_AT_CORNER
@ FIELD_ID_CELL_VECTOR_AT_CORNER
Here is the call graph for this function:
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 2974 of file logging.c.

2975{
2976 SimCtx *simCtx = user->simCtx;
2977 PetscErrorCode ierr;
2978 DM swarm = user->swarm;
2979 Vec positionVec, analyticalvelocityVec, velocityVec, errorVec;
2980 PetscReal Interpolation_error = 0.0;
2981 PetscReal Maximum_Interpolation_error = 0.0;
2982 PetscReal AnalyticalSolution_magnitude = 0.0;
2983 PetscReal ErrorPercentage = 0.0;
2984
2985 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating global vectors.\n");
2986 ierr = DMSwarmCreateGlobalVectorFromField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), &positionVec); CHKERRQ(ierr);
2987 ierr = DMSwarmCreateGlobalVectorFromField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_VELOCITY), &velocityVec); CHKERRQ(ierr);
2988
2989 ierr = VecDuplicate(positionVec, &analyticalvelocityVec); CHKERRQ(ierr);
2990 ierr = VecCopy(positionVec, analyticalvelocityVec); CHKERRQ(ierr);
2991
2992 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Computing analytical solution.\n");
2993 ierr = SetAnalyticalSolutionForParticles(analyticalvelocityVec, simCtx); CHKERRQ(ierr);
2994
2995 ierr = VecDuplicate(analyticalvelocityVec, &errorVec); CHKERRQ(ierr);
2996 ierr = VecCopy(analyticalvelocityVec, errorVec); CHKERRQ(ierr);
2997
2998 ierr = VecNorm(analyticalvelocityVec, NORM_2, &AnalyticalSolution_magnitude); CHKERRQ(ierr);
2999
3000 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Computing error.\n");
3001 ierr = VecAXPY(errorVec, -1.0, velocityVec); CHKERRQ(ierr);
3002 ierr = VecNorm(errorVec, NORM_2, &Interpolation_error); CHKERRQ(ierr);
3003 ierr = VecNorm(errorVec,NORM_INFINITY,&Maximum_Interpolation_error); CHKERRQ(ierr);
3004
3005 ErrorPercentage = (AnalyticalSolution_magnitude > 0) ?
3006 (Interpolation_error / AnalyticalSolution_magnitude * 100.0) : 0.0;
3007
3008 /* --- CSV output (always, rank 0 only) --- */
3009 if (simCtx->rank == 0) {
3010 char csv_path[PETSC_MAX_PATH_LEN + 32];
3011 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/interpolation_error.csv", simCtx->analysis_dir); CHKERRQ(ierr);
3012 FILE *f = fopen(csv_path, "a");
3013 if (f) {
3014 if (ftell(f) == 0) {
3015 fprintf(f, "step,time,L2_error,Linf_error,L2_analytical,error_pct,physical_time\n");
3016 }
3017 if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
3018 fprintf(f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
3019 }
3020 /* ti is solver time, not a step count; physical_time is it in seconds. */
3021 PetscReal t = simCtx->ti;
3022 PetscReal physical_time = 0.0;
3023 ierr = PicurvPhysicalTime(simCtx, t, &physical_time); CHKERRQ(ierr);
3024 fprintf(f, "%d,%.6e,%.6e,%.6e,%.6e,%.4f,%.6e\n",
3025 (int)simCtx->step, t,
3026 Interpolation_error, Maximum_Interpolation_error,
3027 AnalyticalSolution_magnitude, ErrorPercentage, physical_time);
3028 fclose(f);
3029 }
3030 }
3031
3032 /* --- Console output (only at INFO level or above) --- */
3033 if (get_log_level() >= LOG_INFO) {
3034 LOG_ALLOW(GLOBAL, LOG_INFO, "Interpolation error (%%): %g\n", ErrorPercentage);
3035 PetscPrintf(PETSC_COMM_WORLD, "Interpolation error (%%): %g\n", ErrorPercentage);
3036 LOG_ALLOW(GLOBAL, LOG_INFO, "Maximum Interpolation error: %g\n", Maximum_Interpolation_error);
3037 PetscPrintf(PETSC_COMM_WORLD, "Maximum Interpolation error: %g\n", Maximum_Interpolation_error);
3038 }
3039
3040 ierr = VecDestroy(&analyticalvelocityVec); CHKERRQ(ierr);
3041 ierr = VecDestroy(&errorVec); CHKERRQ(ierr);
3042 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_POSITION), &positionVec); CHKERRQ(ierr);
3043 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, ParticleFieldName(PARTICLE_FIELD_ID_VELOCITY), &velocityVec); CHKERRQ(ierr);
3044
3045 return 0;
3046}
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Applies the analytical solution to particle velocity vector.
PetscErrorCode PicurvPhysicalTime(const SimCtx *simCtx, PetscReal solver_time, PetscReal *physical)
Convert a solver time to physical seconds, t * L_ref / U_ref.
Definition io.c:3177
char analysis_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:883
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 3056 of file logging.c.

3057{
3058 PetscErrorCode ierr;
3059 SimCtx *simCtx = NULL;
3060 DMDALocalInfo info;
3061 PetscInt xs, xe, ys, ye, zs, ze, mx, my, mz;
3062 PetscInt lxs, lxe, lys, lye, lzs, lze;
3063 Vec reference_vec = NULL;
3064 PetscReal ***psi = NULL;
3065 PetscReal ***psi_ref = NULL;
3066 PetscReal ***aj = NULL;
3067 PetscReal ***count = NULL;
3068 PetscReal *particle_psi = NULL;
3069 PetscInt nlocal = 0;
3070 PetscReal local_l1 = 0.0, global_l1 = 0.0;
3071 PetscReal local_l2_sq = 0.0, global_l2_sq = 0.0;
3072 PetscReal local_linf = 0.0, global_linf = 0.0;
3073 PetscReal local_ref_l2_sq = 0.0, global_ref_l2_sq = 0.0;
3074 PetscReal local_grid_integral = 0.0, global_grid_integral = 0.0;
3075 PetscReal local_domain_volume = 0.0, global_domain_volume = 0.0;
3076 PetscReal local_particle_sum = 0.0, global_particle_sum = 0.0;
3077 PetscInt64 local_particle_count = 0, global_particle_count = 0;
3078 PetscInt64 local_cell_count = 0, global_cell_count = 0;
3079 PetscInt64 local_occupied_count = 0, global_occupied_count = 0;
3080 PetscReal particle_integral = 0.0;
3081 PetscReal occupancy_fraction = 0.0;
3082 PetscReal mean_particles_per_occupied_cell = 0.0;
3083 PetscReal l2_error = 0.0;
3084 PetscReal relative_l2_error = 0.0;
3085
3086 PetscFunctionBeginUser;
3087 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
3088 simCtx = user->simCtx;
3089 if (!VerificationScalarOverrideActive(simCtx) || !user->swarm || !user->Psi || !user->ParticleCount) {
3090 PetscFunctionReturn(0);
3091 }
3092
3093 info = user->info;
3094 xs = info.xs; xe = info.xs + info.xm;
3095 ys = info.ys; ye = info.ys + info.ym;
3096 zs = info.zs; ze = info.zs + info.zm;
3097 mx = info.mx; my = info.my; mz = info.mz;
3098 lxs = (xs == 0) ? xs + 1 : xs; lxe = (xe == mx) ? xe - 1 : xe;
3099 lys = (ys == 0) ? ys + 1 : ys; lye = (ye == my) ? ye - 1 : ye;
3100 lzs = (zs == 0) ? zs + 1 : zs; lze = (ze == mz) ? ze - 1 : ze;
3101
3102 ierr = VecDuplicate(user->Psi, &reference_vec); CHKERRQ(ierr);
3103 ierr = SetAnalyticalScalarFieldAtCellCenters(user, reference_vec); CHKERRQ(ierr);
3104
3105 ierr = DMDAVecGetArrayRead(user->da, user->Psi, &psi); CHKERRQ(ierr);
3106 ierr = DMDAVecGetArrayRead(user->da, reference_vec, &psi_ref); CHKERRQ(ierr);
3107 ierr = DMDAVecGetArrayRead(user->da, user->Aj, &aj); CHKERRQ(ierr);
3108 ierr = DMDAVecGetArrayRead(user->da, user->ParticleCount, &count); CHKERRQ(ierr);
3109
3110 for (PetscInt k = lzs; k < lze; ++k) {
3111 for (PetscInt j = lys; j < lye; ++j) {
3112 for (PetscInt i = lxs; i < lxe; ++i) {
3113 const PetscReal cell_volume = (PetscAbsReal(aj[k][j][i]) > 1.0e-14) ? (1.0 / aj[k][j][i]) : 0.0;
3114 const PetscReal err = psi[k][j][i] - psi_ref[k][j][i];
3115 local_cell_count += 1;
3116 local_domain_volume += cell_volume;
3117 local_grid_integral += psi[k][j][i] * cell_volume;
3118 local_l1 += PetscAbsReal(err) * cell_volume;
3119 local_l2_sq += err * err * cell_volume;
3120 local_ref_l2_sq += psi_ref[k][j][i] * psi_ref[k][j][i] * cell_volume;
3121 local_linf = PetscMax(local_linf, PetscAbsReal(err));
3122 if (count[k][j][i] > 0.0) local_occupied_count += 1;
3123 }
3124 }
3125 }
3126
3127 ierr = DMDAVecRestoreArrayRead(user->da, user->ParticleCount, &count); CHKERRQ(ierr);
3128 ierr = DMDAVecRestoreArrayRead(user->da, user->Aj, &aj); CHKERRQ(ierr);
3129 ierr = DMDAVecRestoreArrayRead(user->da, reference_vec, &psi_ref); CHKERRQ(ierr);
3130 ierr = DMDAVecRestoreArrayRead(user->da, user->Psi, &psi); CHKERRQ(ierr);
3131 ierr = VecDestroy(&reference_vec); CHKERRQ(ierr);
3132
3133 ierr = DMSwarmGetLocalSize(user->swarm, &nlocal); CHKERRQ(ierr);
3134 local_particle_count = (PetscInt64)nlocal;
3135 if (nlocal > 0) {
3136 ierr = DMSwarmGetField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_PSI), NULL, NULL, (void **)&particle_psi); CHKERRQ(ierr);
3137 for (PetscInt p = 0; p < nlocal; ++p) local_particle_sum += particle_psi[p];
3138 ierr = DMSwarmRestoreField(user->swarm, ParticleFieldName(PARTICLE_FIELD_ID_PSI), NULL, NULL, (void **)&particle_psi); CHKERRQ(ierr);
3139 }
3140
3141 ierr = MPI_Allreduce(&local_l1, &global_l1, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3142 ierr = MPI_Allreduce(&local_l2_sq, &global_l2_sq, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3143 ierr = MPI_Allreduce(&local_linf, &global_linf, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3144 ierr = MPI_Allreduce(&local_ref_l2_sq, &global_ref_l2_sq, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3145 ierr = MPI_Allreduce(&local_grid_integral, &global_grid_integral, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3146 ierr = MPI_Allreduce(&local_domain_volume, &global_domain_volume, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3147 ierr = MPI_Allreduce(&local_particle_sum, &global_particle_sum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3148 ierr = MPI_Allreduce(&local_particle_count, &global_particle_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3149 ierr = MPI_Allreduce(&local_cell_count, &global_cell_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3150 ierr = MPI_Allreduce(&local_occupied_count, &global_occupied_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3151
3152 l2_error = PetscSqrtReal(global_l2_sq);
3153 relative_l2_error = (global_ref_l2_sq > 0.0) ? (l2_error / PetscSqrtReal(global_ref_l2_sq)) : 0.0;
3154 occupancy_fraction = (global_cell_count > 0) ? ((PetscReal)global_occupied_count / (PetscReal)global_cell_count) : 0.0;
3155 mean_particles_per_occupied_cell =
3156 (global_occupied_count > 0) ? ((PetscReal)global_particle_count / (PetscReal)global_occupied_count) : 0.0;
3157 particle_integral =
3158 (global_particle_count > 0) ? (global_domain_volume * global_particle_sum / (PetscReal)global_particle_count) : 0.0;
3159
3160 if (simCtx->rank == 0) {
3161 char csv_path[PETSC_MAX_PATH_LEN + 32];
3162 FILE *f = NULL;
3163 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/scatter_metrics.csv", simCtx->analysis_dir); CHKERRQ(ierr);
3164 f = fopen(csv_path, "a");
3165 if (f) {
3166 if (ftell(f) == 0) {
3167 fprintf(f,
3168 "step,time,total_particles,total_cells,occupied_cells,occupancy_fraction,"
3169 "mean_particles_per_occupied_cell,particle_integral,grid_integral,"
3170 "conservation_error_abs,L1_error,L2_error,Linf_error,relative_L2_error,"
3171 "physical_time\n");
3172 }
3173 if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
3174 fprintf(f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
3175 }
3176 PetscReal physical_time = 0.0;
3177 ierr = PicurvPhysicalTime(simCtx, simCtx->ti, &physical_time); CHKERRQ(ierr);
3178 fprintf(f, "%d,%.6e,%lld,%lld,%lld,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e\n",
3179 (int)simCtx->step,
3180 (double)simCtx->ti,
3181 (long long)global_particle_count,
3182 (long long)global_cell_count,
3183 (long long)global_occupied_count,
3184 (double)occupancy_fraction,
3185 (double)mean_particles_per_occupied_cell,
3186 (double)particle_integral,
3187 (double)global_grid_integral,
3188 (double)PetscAbsReal(global_grid_integral - particle_integral),
3189 (double)global_l1,
3190 (double)l2_error,
3191 (double)global_linf,
3192 (double)relative_l2_error,
3193 (double)physical_time);
3194 fclose(f);
3195 }
3196 }
3197
3198 if (get_log_level() >= LOG_INFO) {
3199 LOG_ALLOW(GLOBAL, LOG_INFO, "Scatter relative L2 error: %.6e\n", (double)relative_l2_error);
3200 LOG_ALLOW(GLOBAL, LOG_INFO, "Scatter occupancy fraction: %.6e\n", (double)occupancy_fraction);
3201 }
3202
3203 PetscFunctionReturn(0);
3204}
PetscErrorCode SetAnalyticalScalarFieldAtCellCenters(UserCtx *user, Vec targetVec)
Writes the configured verification scalar profile at physical cell centers into a scalar Vec.
@ PARTICLE_FIELD_ID_PSI
Vec ParticleCount
Definition variables.h:1171
DMDALocalInfo info
Definition variables.h:1086
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 3214 of file logging.c.

3215{
3216 PetscFunctionBeginUser;
3217 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL for ResetSearchMetrics.");
3218
3219 simCtx->searchMetrics.searchAttempts = 0;
3220 simCtx->searchMetrics.searchPopulation = 0;
3222 simCtx->searchMetrics.searchLostCount = 0;
3223 simCtx->searchMetrics.traversalStepsSum = 0;
3224 simCtx->searchMetrics.reSearchCount = 0;
3225 simCtx->searchMetrics.maxTraversalSteps = 0;
3227 simCtx->searchMetrics.tieBreakCount = 0;
3233
3234 PetscFunctionReturn(0);
3235}
PetscInt64 searchLocatedCount
Definition variables.h:267
PetscInt64 searchLostCount
Definition variables.h:268
PetscInt64 boundaryClampCount
Definition variables.h:274
PetscInt64 traversalStepsSum
Definition variables.h:269
PetscInt64 searchPopulation
Definition variables.h:266
PetscInt currentSettlementPass
Definition variables.h:278
PetscInt64 reSearchCount
Definition variables.h:270
PetscInt64 bboxGuessFallbackCount
Definition variables.h:276
PetscInt64 bboxGuessSuccessCount
Definition variables.h:275
PetscInt64 maxParticlePassDepth
Definition variables.h:277
PetscInt64 maxTraversalSteps
Definition variables.h:271
SearchMetricsState searchMetrics
Definition variables.h:1005
PetscInt64 searchAttempts
Definition variables.h:265
PetscInt64 tieBreakCount
Definition variables.h:273
PetscInt64 maxTraversalFailCount
Definition variables.h:272
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 3404 of file logging.c.

3405{
3406 PetscErrorCode ierr;
3407 SimCtx *simCtx = user->simCtx;
3408 PetscMPIInt size, rank;
3409
3410 PetscFunctionBeginUser;
3411 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
3412 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3413
3414 // --- 1. Particle Load Imbalance ---
3415 PetscInt nLocal, nGlobal, nLocalMax;
3416 ierr = DMSwarmGetLocalSize(user->swarm, &nLocal); CHKERRQ(ierr);
3417 ierr = DMSwarmGetSize(user->swarm, &nGlobal); CHKERRQ(ierr);
3418 ierr = MPI_Allreduce(&nLocal, &nLocalMax, 1, MPIU_INT, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
3419
3420 PetscReal avg_per_rank = (size > 0) ? ((PetscReal)nGlobal / size) : 0.0;
3421 // Handle division by zero if there are no particles
3422 simCtx->particleLoadImbalance = (avg_per_rank > 1e-9) ? (nLocalMax / avg_per_rank) : 1.0;
3423
3424
3425 // --- 2. Number of Occupied Cells ---
3426 // This part requires access to the user->ParticleCount vector.
3427 PetscInt local_occupied_cells = 0;
3428 PetscInt global_occupied_cells;
3429 const PetscScalar *count_array;
3430 PetscInt vec_local_size;
3431
3432 ierr = VecGetLocalSize(user->ParticleCount, &vec_local_size); CHKERRQ(ierr);
3433 ierr = VecGetArrayRead(user->ParticleCount, &count_array); CHKERRQ(ierr);
3434
3435 for (PetscInt i = 0; i < vec_local_size; ++i) {
3436 if (count_array[i] > 0.5) { // Use 0.5 to be safe with floating point
3437 local_occupied_cells++;
3438 }
3439 }
3440 ierr = VecRestoreArrayRead(user->ParticleCount, &count_array); CHKERRQ(ierr);
3441
3442 ierr = MPI_Allreduce(&local_occupied_cells, &global_occupied_cells, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
3443 simCtx->occupiedCellCount = global_occupied_cells;
3444
3445 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "[Rank %d] Advanced Metrics: Imbalance=%.2f, OccupiedCells=%d\n", rank, simCtx->particleLoadImbalance, simCtx->occupiedCellCount);
3446
3447 PetscFunctionReturn(0);
3448}
PetscInt occupiedCellCount
Definition variables.h:1003
PetscReal particleLoadImbalance
Definition variables.h:1004
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 3245 of file logging.c.

3246{
3247 PetscErrorCode ierr;
3248 SimCtx *simCtx = NULL;
3249 PetscInt totalParticles = 0;
3250 PetscReal local_metrics[SEARCH_METRIC_REDUCTION_LEN] = {0.0};
3251 PetscReal global_metrics[SEARCH_METRIC_REDUCTION_LEN] = {0.0};
3252 PetscReal meanTraversalSteps = 0.0;
3253 PetscReal searchFailureFraction = 0.0;
3254 PetscReal searchWorkIndex = 0.0;
3255 PetscReal reSearchFraction = 0.0;
3256 long long searchAttempts = 0;
3257 long long searchPopulation = 0;
3258 long long searchLocatedCount = 0;
3259 long long searchLostCount = 0;
3260 long long traversalStepsSum = 0;
3261 long long reSearchCount = 0;
3262 long long tieBreakCount = 0;
3263 long long boundaryClampCount = 0;
3264 long long bboxGuessSuccessCount = 0;
3265 long long bboxGuessFallbackCount = 0;
3266 long long maxTraversalFailCount = 0;
3267 long long maxTraversalSteps = 0;
3268 long long maxPassDepth = 0;
3269 MPI_Op reduction_op = MPI_OP_NULL;
3270
3271 PetscFunctionBeginUser;
3272 if (!user || !user->simCtx) {
3273 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx and SimCtx are required for LOG_SEARCH_METRICS.");
3274 }
3275 simCtx = user->simCtx;
3276
3277 if (simCtx->np <= 0) {
3278 PetscFunctionReturn(0);
3279 }
3280
3281 ierr = DMSwarmGetSize(user->swarm, &totalParticles); CHKERRQ(ierr);
3282
3283 local_metrics[SEARCH_METRIC_SUM_SEARCH_ATTEMPTS] = (PetscReal)simCtx->searchMetrics.searchAttempts;
3284 local_metrics[SEARCH_METRIC_SUM_SEARCH_POPULATION] = (PetscReal)simCtx->searchMetrics.searchPopulation;
3285 local_metrics[SEARCH_METRIC_SUM_SEARCH_LOCATED] = (PetscReal)simCtx->searchMetrics.searchLocatedCount;
3286 local_metrics[SEARCH_METRIC_SUM_SEARCH_LOST] = (PetscReal)simCtx->searchMetrics.searchLostCount;
3287 local_metrics[SEARCH_METRIC_SUM_TRAVERSAL_STEPS] = (PetscReal)simCtx->searchMetrics.traversalStepsSum;
3288 local_metrics[SEARCH_METRIC_SUM_RESEARCH] = (PetscReal)simCtx->searchMetrics.reSearchCount;
3289 local_metrics[SEARCH_METRIC_SUM_TIE_BREAKS] = (PetscReal)simCtx->searchMetrics.tieBreakCount;
3290 local_metrics[SEARCH_METRIC_SUM_BOUNDARY_CLAMPS] = (PetscReal)simCtx->searchMetrics.boundaryClampCount;
3291 local_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS] = (PetscReal)simCtx->searchMetrics.bboxGuessSuccessCount;
3292 local_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK] = (PetscReal)simCtx->searchMetrics.bboxGuessFallbackCount;
3293 local_metrics[SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS] = (PetscReal)simCtx->searchMetrics.maxTraversalFailCount;
3294 local_metrics[SEARCH_METRIC_MAX_TRAVERSAL_STEPS] = (PetscReal)simCtx->searchMetrics.maxTraversalSteps;
3295 local_metrics[SEARCH_METRIC_MAX_PASS_DEPTH] = (PetscReal)simCtx->searchMetrics.maxParticlePassDepth;
3296
3297 ierr = MPI_Op_create(SearchMetricsReduceOp, PETSC_TRUE, &reduction_op); CHKERRMPI(ierr);
3298 ierr = MPI_Allreduce(local_metrics, global_metrics, SEARCH_METRIC_REDUCTION_LEN, MPIU_REAL, reduction_op, PETSC_COMM_WORLD); CHKERRMPI(ierr);
3299 ierr = MPI_Op_free(&reduction_op); CHKERRMPI(ierr);
3300 reduction_op = MPI_OP_NULL;
3301
3302 searchAttempts = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_ATTEMPTS] + 0.5);
3303 searchPopulation = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_POPULATION] + 0.5);
3304 searchLocatedCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_LOCATED] + 0.5);
3305 searchLostCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_LOST] + 0.5);
3306 traversalStepsSum = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_TRAVERSAL_STEPS] + 0.5);
3307 reSearchCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_RESEARCH] + 0.5);
3308 tieBreakCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_TIE_BREAKS] + 0.5);
3309 boundaryClampCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BOUNDARY_CLAMPS] + 0.5);
3310 bboxGuessSuccessCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS] + 0.5);
3311 bboxGuessFallbackCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK] + 0.5);
3312 maxTraversalFailCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS] + 0.5);
3313 maxTraversalSteps = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_MAX_TRAVERSAL_STEPS] + 0.5);
3314 maxPassDepth = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_MAX_PASS_DEPTH] + 0.5);
3315
3316 if (searchAttempts > 0) {
3317 meanTraversalSteps = (PetscReal)traversalStepsSum / (PetscReal)searchAttempts;
3318 }
3319 if (searchPopulation > 0) {
3320 searchFailureFraction = (PetscReal)searchLostCount / (PetscReal)searchPopulation;
3321 searchWorkIndex = (PetscReal)traversalStepsSum / (PetscReal)searchPopulation;
3322 reSearchFraction = (PetscReal)reSearchCount / (PetscReal)searchPopulation;
3323 }
3324
3325 if (simCtx->rank == 0) {
3326 char csv_path[PETSC_MAX_PATH_LEN + 32];
3327 FILE *f = NULL;
3328 PetscReal searchPhysicalTime = 0.0;
3329
3330 ierr = PicurvPhysicalTime(simCtx, simCtx->ti, &searchPhysicalTime); CHKERRQ(ierr);
3331 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/search_metrics.csv", simCtx->analysis_dir); CHKERRQ(ierr);
3332 f = fopen(csv_path, "a");
3333 if (!f) {
3334 LOG_ALLOW(GLOBAL, LOG_WARNING, "LOG_SEARCH_METRICS: could not open '%s' for writing.\n", csv_path);
3335 } else {
3336 if (ftell(f) == 0) {
3337 fprintf(f,
3338 "step,time,total_particles,lost,lost_cumulative,migrated,migration_passes,search_attempts,"
3339 "mean_traversal_steps,max_traversal_steps,tie_break_count,boundary_clamp_count,"
3340 "bbox_guess_success_count,bbox_guess_fallback_count,max_particle_pass_depth,load_imbalance,"
3341 "search_population,search_located_count,search_lost_count,traversal_steps_sum,re_search_count,"
3342 "max_traversal_fail_count,search_failure_fraction,search_work_index,re_search_fraction,"
3343 "physical_time,lost_psi_sum\n");
3344 }
3345 if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
3346 fprintf(f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
3347 }
3348 fprintf(f,
3349 "%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,%.6e,%.10e\n",
3350 (int)simCtx->step,
3351 (double)simCtx->ti,
3352 (int)totalParticles,
3353 (int)simCtx->particlesLostLastStep,
3354 (int)simCtx->particlesLostCumulative,
3355 (int)simCtx->particlesMigratedLastStep,
3356 (int)simCtx->migrationPassesLastStep,
3357 searchAttempts,
3358 (double)meanTraversalSteps,
3359 maxTraversalSteps,
3360 tieBreakCount,
3361 boundaryClampCount,
3362 bboxGuessSuccessCount,
3363 bboxGuessFallbackCount,
3364 maxPassDepth,
3365 (double)simCtx->particleLoadImbalance,
3366 searchPopulation,
3367 searchLocatedCount,
3368 searchLostCount,
3369 traversalStepsSum,
3370 reSearchCount,
3371 maxTraversalFailCount,
3372 (double)searchFailureFraction,
3373 (double)searchWorkIndex,
3374 (double)reSearchFraction,
3375 (double)searchPhysicalTime,
3376 (double)simCtx->particlesLostScalarLastStep);
3377 fclose(f);
3378 }
3379 }
3380
3382 "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",
3383 (double)searchFailureFraction,
3384 (double)searchWorkIndex,
3385 (double)reSearchFraction,
3386 (int)simCtx->particlesLostLastStep,
3387 (int)simCtx->particlesLostCumulative,
3388 (int)simCtx->particlesMigratedLastStep,
3389 (int)simCtx->migrationPassesLastStep,
3390 (double)meanTraversalSteps,
3391 maxTraversalSteps,
3392 tieBreakCount,
3393 maxPassDepth);
3394
3395 PetscFunctionReturn(0);
3396}
@ SEARCH_METRIC_SUM_SEARCH_LOCATED
Definition logging.c:36
@ SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS
Definition logging.c:44
@ SEARCH_METRIC_REDUCTION_LEN
Definition logging.c:47
@ SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK
Definition logging.c:43
@ SEARCH_METRIC_SUM_RESEARCH
Definition logging.c:39
@ SEARCH_METRIC_SUM_TRAVERSAL_STEPS
Definition logging.c:38
@ SEARCH_METRIC_MAX_TRAVERSAL_STEPS
Definition logging.c:45
@ SEARCH_METRIC_SUM_BOUNDARY_CLAMPS
Definition logging.c:41
@ SEARCH_METRIC_SUM_SEARCH_POPULATION
Definition logging.c:35
@ SEARCH_METRIC_MAX_PASS_DEPTH
Definition logging.c:46
@ SEARCH_METRIC_SUM_TIE_BREAKS
Definition logging.c:40
@ SEARCH_METRIC_SUM_SEARCH_LOST
Definition logging.c:37
@ SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS
Definition logging.c:42
@ SEARCH_METRIC_SUM_SEARCH_ATTEMPTS
Definition logging.c:34
static void SearchMetricsReduceOp(void *invec, void *inoutvec, int *len, MPI_Datatype *datatype)
Internal reduction callback for packed search metrics.
Definition logging.c:54
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 3458 of file logging.c.

3459{
3460 PetscErrorCode ierr;
3461 PetscMPIInt rank;
3462 SimCtx *simCtx = user->simCtx;
3463 const char *stage_label = (stageName && stageName[0] != '\0') ? stageName : "N/A";
3464
3465 PetscFunctionBeginUser;
3466 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
3467
3468 PetscInt totalParticles;
3469 ierr = DMSwarmGetSize(user->swarm, &totalParticles); CHKERRQ(ierr);
3470
3471 if (!rank) {
3472 FILE *f;
3473 char filen[PETSC_MAX_PATH_LEN + 64];
3474 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/Particle_Metrics.log", simCtx->log_dir); CHKERRQ(ierr);
3475 f = fopen(filen, "a");
3476 if (!f) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open particle log file: %s", filen);
3477
3478 if (ftell(f) == 0) {
3479 PetscFPrintf(PETSC_COMM_SELF, f, "%-18s | %-10s | %-12s | %-10s | %-10s | %-10s | %-15s | %-10s | %-10s\n",
3480 "Stage", "Timestep", "Total Ptls", "Lost", "Lost Total", "Migrated", "Occupied Cells", "Imbalance", "Mig Passes");
3481 PetscFPrintf(PETSC_COMM_SELF, f, "-------------------------------------------------------------------------------------------------------------------------------------------\n");
3482 }
3483 if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
3484 PetscFPrintf(PETSC_COMM_SELF, f, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
3485 }
3486
3487 PetscFPrintf(PETSC_COMM_SELF, f, "%-18s | %-10d | %-12d | %-10d | %-10d | %-10d | %-15d | %-10.2f | %-10d\n",
3488 stage_label, (int)simCtx->step, (int)totalParticles, (int)simCtx->particlesLostLastStep,
3489 (int)simCtx->particlesLostCumulative, (int)simCtx->particlesMigratedLastStep, (int)simCtx->occupiedCellCount,
3490 (double)simCtx->particleLoadImbalance, (int)simCtx->migrationPassesLastStep);
3491 fclose(f);
3492 }
3493 PetscFunctionReturn(0);
3494}
PetscInt particlesLostLastStep
Definition variables.h:997
PetscInt particlesLostCumulative
Definition variables.h:998
PetscInt particlesMigratedLastStep
Definition variables.h:1002
PetscInt migrationPassesLastStep
Definition variables.h:1001
Here is the caller graph for this function:

◆ PicurvOpenDiagnosticsCsv()

PetscErrorCode PicurvOpenDiagnosticsCsv ( const SimCtx *  simCtx,
const char *  filename,
const char *  header,
FILE **  file 
)

Opens a per-run diagnostics CSV in the run's analysis directory for appending.

The runtime diagnostics files share a lifecycle rather than a schema: they live in simCtx->analysis_dir, are appended to across a run, carry their column header only once, and mark the seam where a continuation resumed so a reader can tell a restart from a discontinuity in the data. This owns that lifecycle; the caller owns the columns.

Call on rank 0 only - the file is a serial artifact, and a collective write to it would interleave. The caller closes the handle.

Parameters
[in]simCtxSimulation context supplying the analysis directory, step, and continuation state.
[in]filenameBasename of the CSV, including the extension.
[in]headerColumn header written when the file is created, without a trailing newline.
[out]fileOpen append handle, never NULL on success.
Returns
PetscErrorCode 0 on success; PETSC_ERR_FILE_OPEN if the file cannot be opened.

Opens a per-run diagnostics CSV in the run's analysis directory for appending.

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

Definition at line 3503 of file logging.c.

3505{
3506 char path[PETSC_MAX_PATH_LEN + 64];
3507 FILE *handle = NULL;
3508
3509 PetscFunctionBeginUser;
3510 PetscCheck(simCtx && filename && header && file, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
3511 "A diagnostics CSV needs a context, a name, a header, and somewhere to "
3512 "return the handle.");
3513
3514 PetscCall(PetscSNPrintf(path, sizeof(path), "%s/%s", simCtx->analysis_dir, filename));
3515 handle = fopen(path, "a");
3516 PetscCheck(handle != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
3517 "Unable to open diagnostics file '%s'.", path);
3518
3519 if (ftell(handle) == 0) fprintf(handle, "%s\n", header);
3520 /* Written once, on the first step a continuation produces, so that a reader can tell
3521 a resumed run from a jump in the data itself. */
3522 if (simCtx->continueMode && simCtx->step == simCtx->StartStep + 1) {
3523 fprintf(handle, "# Continuation from step %" PetscInt_FMT "\n", simCtx->StartStep);
3524 }
3525
3526 *file = handle;
3527 PetscFunctionReturn(0);
3528}
Here is the caller graph for this function: