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

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

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

Go to the source code of this file.

Data Structures

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

Macros

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

Enumerations

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

Functions

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

Detailed Description

Logging utilities and macros for PETSc-based applications.

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

Definition in file logging.h.


Data Structure Documentation

◆ DualMonitorCtx

struct DualMonitorCtx

Context for a dual-purpose KSP monitor.

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

Definition at line 55 of file logging.h.

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

Macro Definition Documentation

◆ LOCAL

#define LOCAL   0

Logging scope definitions for controlling message output.

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

Definition at line 44 of file logging.h.

◆ GLOBAL

#define GLOBAL   1

Scope for global logging across all processes.

Definition at line 45 of file logging.h.

◆ LOG

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

Logging macro for PETSc-based applications with scope control.

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

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

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

Definition at line 83 of file logging.h.

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

◆ LOG_DEFAULT

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

Default logging macro for PETSc-based applications.

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

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

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

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

Definition at line 114 of file logging.h.

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

◆ LOG_SYNC

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

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

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

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

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

Definition at line 144 of file logging.h.

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

◆ LOG_SYNC_DEFAULT

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

Default synchronized logging macro for PETSc-based applications.

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

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

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

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

Definition at line 177 of file logging.h.

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

◆ LOG_ALLOW

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

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

Useful for selective, per-function logging.

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

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

Definition at line 199 of file logging.h.

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

◆ LOG_ALLOW_SYNC

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

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

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

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

Example usage:

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

Definition at line 252 of file logging.h.

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

◆ LOG_LOOP_ALLOW

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

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

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

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

Definition at line 297 of file logging.h.

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

◆ LOG_LOOP_ALLOW_EXACT

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

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

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

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

Definition at line 334 of file logging.h.

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

◆ LOG_ARRAY_ELEMENT_ALLOW

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

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

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

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

Definition at line 363 of file logging.h.

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

◆ LOG_ARRAY_SUBRANGE_ALLOW

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

Logs a consecutive subrange of an array.

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

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

Definition at line 387 of file logging.h.

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

◆ PROFILE_FUNCTION_BEGIN

#define PROFILE_FUNCTION_BEGIN    _ProfilingStart(__FUNCT__)

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

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

Definition at line 770 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 779 of file logging.h.

Enumeration Type Documentation

◆ LogLevel

enum LogLevel

Enumeration of logging levels.

Defines various severity levels for logging messages.

Enumerator
LOG_ERROR 

Critical errors that may halt the program.

LOG_WARNING 

Non-critical issues that warrant attention.

LOG_INFO 

Informational messages about program execution.

LOG_DEBUG 

Detailed debugging information.

LOG_TRACE 

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

LOG_VERBOSE 

Extremely detailed logs, typically for development use only.

Definition at line 27 of file logging.h.

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

Function Documentation

◆ get_log_level()

LogLevel get_log_level ( )

Retrieves the current logging level from the environment variable LOG_LEVEL.

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

Returns
LogLevel The current logging level.

Retrieves the current logging level from the environment variable LOG_LEVEL.

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

See also
get_log_level()

Definition at line 84 of file logging.c.

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

◆ print_log_level()

PetscErrorCode print_log_level ( void  )

Prints the current logging level to the console.

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

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

    Returns
    PetscErrorCode 0 on success.

    Prints the current logging level to the console.

    Local to this translation unit.

Definition at line 116 of file logging.c.

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

◆ set_allowed_functions()

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

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

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

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

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

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

See also
set_allowed_functions()

Definition at line 152 of file logging.c.

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

◆ is_function_allowed()

PetscBool is_function_allowed ( const char *  functionName)

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

This helper is used internally by the LOG_ALLOW macro.

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

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

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

See also
is_function_allowed()

Definition at line 183 of file logging.c.

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

◆ LOG_CELL_VERTICES()

PetscErrorCode LOG_CELL_VERTICES ( const Cell cell,
PetscMPIInt  rank 
)

Prints the coordinates of a cell's vertices.

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

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

Prints the coordinates of a cell's vertices.

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

See also
LOG_CELL_VERTICES()

Definition at line 205 of file logging.c.

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

◆ LOG_FACE_DISTANCES()

PetscErrorCode LOG_FACE_DISTANCES ( PetscReal *  d)

Prints the signed distances to each face of the cell.

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

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

Prints the signed distances to each face of the cell.

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

See also
LOG_FACE_DISTANCES()

Definition at line 230 of file logging.c.

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

◆ LOG_PARTICLE_FIELDS()

PetscErrorCode LOG_PARTICLE_FIELDS ( UserCtx user,
PetscInt  printInterval 
)

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

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

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

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

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

See also
LOG_PARTICLE_FIELDS()

Definition at line 397 of file logging.c.

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

◆ IsParticleConsoleSnapshotEnabled()

PetscBool IsParticleConsoleSnapshotEnabled ( const SimCtx simCtx)

Returns whether periodic particle console snapshots are enabled.

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

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

Returns whether periodic particle console snapshots are enabled.

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

See also
IsParticleConsoleSnapshotEnabled()

Definition at line 525 of file logging.c.

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

◆ ShouldEmitPeriodicParticleConsoleSnapshot()

PetscBool ShouldEmitPeriodicParticleConsoleSnapshot ( const SimCtx simCtx,
PetscInt  completed_step 
)

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

completed timestep.

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

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

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

See also
ShouldEmitPeriodicParticleConsoleSnapshot()

Definition at line 542 of file logging.c.

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

◆ EmitParticleConsoleSnapshot()

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

Emits one particle console snapshot into the main solver log.

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

Emits one particle console snapshot into the main solver log.

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

See also
EmitParticleConsoleSnapshot()

Definition at line 556 of file logging.c.

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

◆ FreeAllowedFunctions()

PetscErrorCode FreeAllowedFunctions ( char **  funcs,
PetscInt  n 
)

Free an array previously returned by LoadAllowedFunctionsFromFile().

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

Free an array previously returned by LoadAllowedFunctionsFromFile().

Local to this translation unit.

Definition at line 650 of file logging.c.

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

◆ LoadAllowedFunctionsFromFile()

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

Load function names from a text file.

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

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

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

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

Load function names from a text file.

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

See also
LoadAllowedFunctionsFromFile()

Definition at line 596 of file logging.c.

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

◆ BCFaceToString()

const char * BCFaceToString ( BCFace  face)

Helper function to convert BCFace enum to a string representation.

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

Helper function to convert BCFace enum to a string representation.

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

See also
BCFaceToString()

Definition at line 669 of file logging.c.

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

◆ FieldInitializationToString()

const char * FieldInitializationToString ( PetscInt  FieldInitialization)

Helper function to convert FieldInitialization to a string representation.

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

Helper function to convert FieldInitialization to a string representation.

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

See also
FieldInitializationToString()

Definition at line 687 of file logging.c.

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

◆ ParticleInitializationToString()

const char * ParticleInitializationToString ( ParticleInitializationType  ParticleInitialization)

Helper function to convert ParticleInitialization to a string representation.

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

Helper function to convert ParticleInitialization to a string representation.

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

See also
ParticleInitializationToString()

Definition at line 703 of file logging.c.

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

◆ LESModelToString()

const char * LESModelToString ( LESModelType  LESFlag)

Helper function to convert LES Flag to a string representation.

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

Helper function to convert LES Flag to a string representation.

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

See also
LESModelToString()

Definition at line 720 of file logging.c.

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

◆ MomentumSolverTypeToString()

const char * MomentumSolverTypeToString ( MomentumSolverType  SolverFlag)

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

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

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

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

See also
MomentumSolverTypeToString()

Definition at line 736 of file logging.c.

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

◆ BCTypeToString()

const char * BCTypeToString ( BCType  type)

Helper function to convert BCType enum to a string representation.

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

Helper function to convert BCType enum to a string representation.

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

See also
BCTypeToString()

Definition at line 751 of file logging.c.

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

◆ BCHandlerTypeToString()

const char * BCHandlerTypeToString ( BCHandlerType  handler_type)

Converts a BCHandlerType enum to its string representation.

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

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

Converts a BCHandlerType enum to its string representation.

Local to this translation unit.

Definition at line 771 of file logging.c.

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

◆ DualKSPMonitor()

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

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

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

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

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

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

See also
DualKSPMonitor()

Definition at line 847 of file logging.c.

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

◆ DualMonitorDestroy()

PetscErrorCode DualMonitorDestroy ( void **  ctx)

Destroys the DualMonitorCtx.

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

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

Destroys the DualMonitorCtx.

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

See also
DualMonitorDestroy()

Definition at line 808 of file logging.c.

809{
810 DualMonitorCtx *monctx = (DualMonitorCtx*)*ctx;
811 PetscErrorCode ierr;
812 PetscMPIInt rank;
813
814 PetscFunctionBeginUser;
815 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
816 if(!rank && monctx->file_handle){
817 fclose(monctx->file_handle);
818 }
819
820 ierr = PetscFree(monctx); CHKERRQ(ierr);
821 *ctx = NULL;
822 PetscFunctionReturn(0);
823}
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 914 of file logging.c.

915{
916 PetscErrorCode ierr;
917 PetscMPIInt rank;
918 SimCtx *simCtx = user->simCtx; // Get the shared SimCtx
919 const PetscInt bi = user->_this; // Get this block's specific ID
920 const PetscInt ti = simCtx->step; // Get the current timestep
921
922 PetscFunctionBeginUser;
923 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
924
925 // Only rank 0 performs file I/O.
926 if (!rank) {
927 FILE *f;
928 char filen[PETSC_MAX_PATH_LEN + 64];
929 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/Continuity_Metrics.log", simCtx->log_dir); CHKERRQ(ierr);
930
931 // Open the log file in append mode.
932 f = fopen(filen, "a");
933 if (!f) {
934 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
935 }
936
937 // Write a header only when the file is empty and it's the first block (bi=0).
938 // Using ftell() instead of step comparison ensures correctness across continuations.
939 if (ftell(f) == 0 && bi == 0) {
940 PetscFPrintf(PETSC_COMM_SELF, f, "%-10s | %-6s | %-18s | %-30s | %-18s | %-18s | %-18s | %-18s\n",
941 "Timestep", "Block", "Max Divergence", "Max Divergence Location ([k][j][i]=idx)", "Sum(RHS)","Total Flux In", "Total Flux Out", "Net Flux");
942 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------------------------------\n");
943 }
944
945 // Prepare the data strings and values for the current block.
946 PetscReal net_flux = simCtx->FluxInSum - simCtx->FluxOutSum;
947 char location_str[64];
948 sprintf(location_str, "([%d][%d][%d] = %d)", (int)simCtx->MaxDivz, (int)simCtx->MaxDivy, (int)simCtx->MaxDivx, (int)simCtx->MaxDivFlatArg);
949
950 // Write the formatted line for the current block.
951 PetscFPrintf(PETSC_COMM_SELF, f, "%-10d | %-6d | %-18.10e | %-39s | %-18.10e | %-18.10e | %-18.10e | %-18.10e\n",
952 (int)ti,
953 (int)bi,
954 (double)simCtx->MaxDiv,
955 location_str,
956 (double)simCtx->summationRHS,
957 (double)simCtx->FluxInSum,
958 (double)simCtx->FluxOutSum,
959 (double)net_flux);
960
961 fclose(f);
962 }
963
964 PetscFunctionReturn(0);
965}
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:814
PetscReal FluxOutSum
Definition variables.h:721
PetscInt _this
Definition variables.h:824
PetscReal MaxDiv
Definition variables.h:771
PetscInt MaxDivx
Definition variables.h:772
PetscInt MaxDivy
Definition variables.h:772
PetscInt MaxDivz
Definition variables.h:772
char log_dir[PETSC_MAX_PATH_LEN]
Definition variables.h:668
PetscInt MaxDivFlatArg
Definition variables.h:772
PetscReal FluxInSum
Definition variables.h:721
PetscInt step
Definition variables.h:651
PetscReal summationRHS
Definition variables.h:770
The master context for the entire simulation.
Definition variables.h:643
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 973 of file logging.c.

974{
975 switch (level) {
976 case NEEDS_LOCATION: return "NEEDS_LOCATION";
977 case ACTIVE_AND_LOCATED: return "ACTIVE_AND_LOCATED";
978 case MIGRATING_OUT: return "MIGRATING_OUT";
979 case LOST: return "LOST";
980 case UNINITIALIZED: return "UNINITIALIZED";
981 default: return "UNKNOWN_LEVEL";
982 }
983}
@ LOST
Definition variables.h:139
@ NEEDS_LOCATION
Definition variables.h:136
@ ACTIVE_AND_LOCATED
Definition variables.h:137
@ UNINITIALIZED
Definition variables.h:140
@ MIGRATING_OUT
Definition variables.h:138
Here is the caller graph for this function:

◆ PrintProgressBar()

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

Prints a progress bar to the console.

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

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

Prints a progress bar to the console.

Local to this translation unit.

Definition at line 1320 of file logging.c.

1321{
1322 if (totalSteps <= 0) return;
1323
1324 // --- Configuration ---
1325 const int barWidth = 50;
1326
1327 // --- Calculation ---
1328 // Calculate progress as a fraction from 0.0 to 1.0
1329 PetscReal progress = (PetscReal)(step - startStep + 1) / totalSteps;
1330 // Ensure progress doesn't exceed 1.0 due to floating point inaccuracies
1331 if (progress > 1.0) progress = 1.0;
1332
1333 int pos = (int)(barWidth * progress);
1334
1335 // --- Printing ---
1336 // Carriage return moves cursor to the beginning of the line
1337 PetscPrintf(PETSC_COMM_SELF, "\rProgress: [");
1338
1339 for (int i = 0; i < barWidth; ++i) {
1340 if (i < pos) {
1341 PetscPrintf(PETSC_COMM_SELF, "=");
1342 } else if (i == pos) {
1343 PetscPrintf(PETSC_COMM_SELF, ">");
1344 } else {
1345 PetscPrintf(PETSC_COMM_SELF, " ");
1346 }
1347 }
1348
1349 // Print percentage, step count, and current time
1350 PetscPrintf(PETSC_COMM_SELF, "] %3d%% (Step %" PetscInt_FMT "/%" PetscInt_FMT ", t=%.4f)",
1351 (int)(progress * 100.0),
1352 step + 1,
1353 startStep + totalSteps,
1354 currentTime);
1355
1356 // Flush the output buffer to ensure the bar is displayed immediately
1357 fflush(stdout);
1358}
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 1044 of file logging.c.

1045{
1046 PetscFunctionBeginUser;
1047 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingInitialize");
1048
1049 // Iterate through the list of critical functions provided in SimCtx
1050 for (PetscInt i = 0; i < simCtx->nProfilingSelectedFuncs; ++i) {
1051 PetscInt idx;
1052 const char *func_name = simCtx->profilingSelectedFuncs[i];
1053 PetscErrorCode ierr = _FindOrCreateEntry(func_name, &idx); CHKERRQ(ierr);
1054 g_profiler_registry[idx].always_log = PETSC_TRUE;
1055
1056 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Marked '%s' as a critical function for profiling.\n", func_name);
1057 }
1058 PetscFunctionReturn(0);
1059}
PetscBool always_log
Definition logging.c:995
static PetscErrorCode _FindOrCreateEntry(const char *func_name, PetscInt *idx)
Internal helper implementation: _FindOrCreateEntry().
Definition logging.c:1008
static ProfiledFunction * g_profiler_registry
Definition logging.c:999
char ** profilingSelectedFuncs
Definition variables.h:776
PetscInt nProfilingSelectedFuncs
Definition variables.h:777
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 1104 of file logging.c.

1105{
1106 PetscFunctionBeginUser;
1107 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1110 }
1111 PetscFunctionReturn(0);
1112}
static PetscInt g_profiler_count
Definition logging.c:1000
double current_step_time
Definition logging.c:991
long long current_step_call_count
Definition logging.c:993
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 1121 of file logging.c.

1122{
1123 PetscBool should_write = PETSC_FALSE;
1124 FILE *f = NULL;
1125 char filen[(2 * PETSC_MAX_PATH_LEN) + 16];
1126
1127 PetscFunctionBeginUser;
1128 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingLogTimestepSummary");
1129
1130 if (strcmp(simCtx->profilingTimestepMode, "off") == 0) {
1131 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1134 }
1135 PetscFunctionReturn(0);
1136 }
1137
1138 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1139 if (g_profiler_registry[i].current_step_call_count <= 0) {
1140 continue;
1141 }
1142 if (strcmp(simCtx->profilingTimestepMode, "all") == 0 || g_profiler_registry[i].always_log) {
1143 should_write = PETSC_TRUE;
1144 break;
1145 }
1146 }
1147
1148 if (should_write && simCtx->rank == 0) {
1149 snprintf(filen, sizeof(filen), "%s/%s", simCtx->log_dir, simCtx->profilingTimestepFile);
1150 if (step == simCtx->StartStep + 1 && !simCtx->continueMode) {
1151 f = fopen(filen, "w");
1152 if (!f) {
1153 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open profiling timestep log file: %s", filen);
1154 }
1155 PetscFPrintf(PETSC_COMM_SELF, f, "step,function,calls,step_time_s\n");
1156 } else {
1157 f = fopen(filen, "a");
1158 if (!f) {
1159 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open profiling timestep log file: %s", filen);
1160 }
1161 if (step == simCtx->StartStep + 1 && ftell(f) == 0) {
1162 PetscFPrintf(PETSC_COMM_SELF, f, "step,function,calls,step_time_s\n");
1163 }
1164 }
1165
1166 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1167 if (g_profiler_registry[i].current_step_call_count <= 0) {
1168 continue;
1169 }
1170 if (strcmp(simCtx->profilingTimestepMode, "all") == 0 || g_profiler_registry[i].always_log) {
1171 PetscFPrintf(
1172 PETSC_COMM_SELF,
1173 f,
1174 "%d,%s,%lld,%.6f\n",
1175 (int)step,
1176 g_profiler_registry[i].name,
1177 g_profiler_registry[i].current_step_call_count,
1178 g_profiler_registry[i].current_step_time
1179 );
1180 }
1181 }
1182 fclose(f);
1183 }
1184
1185 // Reset per-step counters for the next iteration
1186 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1189 }
1190 PetscFunctionReturn(0);
1191}
PetscBool continueMode
Definition variables.h:660
PetscMPIInt rank
Definition variables.h:646
char profilingTimestepFile[PETSC_MAX_PATH_LEN]
Definition variables.h:779
char profilingTimestepMode[32]
Definition variables.h:778
PetscInt StartStep
Definition variables.h:653
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 1214 of file logging.c.

1215{
1216 PetscErrorCode ierr;
1217 PetscInt rank = simCtx->rank;
1218 PetscFunctionBeginUser;
1219 if (!simCtx->profilingFinalSummary) PetscFunctionReturn(0);
1220 if (!rank) {
1221
1222 char exec_mode_modifier[32] = "Unknown";
1223 if(simCtx->exec_mode == EXEC_MODE_SOLVER) PetscCall(PetscStrncpy(exec_mode_modifier, "Solver", sizeof(exec_mode_modifier)));
1224 else if(simCtx->exec_mode == EXEC_MODE_POSTPROCESSOR) PetscCall(PetscStrncpy(exec_mode_modifier, "PostProcessor", sizeof(exec_mode_modifier)));
1225 //--- Step 0: Create a file viewer for log file
1226 FILE *f;
1227 char filen[PETSC_MAX_PATH_LEN + 128];
1228 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/ProfilingSummary_%s.log",simCtx->log_dir,exec_mode_modifier); CHKERRQ(ierr);
1229
1230 // Open the log file: append with section label in continue mode, truncate otherwise.
1231 if (simCtx->continueMode) {
1232 f = fopen(filen, "a");
1233 if (!f) {
1234 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
1235 }
1236 fprintf(f, "\n=== Continuation from step %" PetscInt_FMT " ===\n", simCtx->StartStep);
1237 } else {
1238 f = fopen(filen, "w");
1239 if (!f) {
1240 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
1241 }
1242 }
1243
1244 // --- Step 1: Sort the data for readability ---
1246
1247 // --- Step 2: Dynamically determine the width for the function name column ---
1248 PetscInt max_name_len = strlen("Function"); // Start with the header's length
1249 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1250 if (g_profiler_registry[i].total_call_count > 0) {
1251 PetscInt len = strlen(g_profiler_registry[i].name);
1252 if (len > max_name_len) {
1253 max_name_len = len;
1254 }
1255 }
1256 }
1257 // Add a little padding
1258 max_name_len += 2;
1259
1260 // --- Step 3: Define fixed widths for numeric columns for consistent alignment ---
1261 const int time_width = 18;
1262 const int count_width = 15;
1263 const int avg_width = 22;
1264
1265 // --- Step 4: Print the formatted table ---
1266 PetscFPrintf(PETSC_COMM_SELF, f, "=================================================================================================================\n");
1267 PetscFPrintf(PETSC_COMM_SELF, f, " FINAL PROFILING SUMMARY (Sorted by Total Time)\n");
1268 PetscFPrintf(PETSC_COMM_SELF, f, "=================================================================================================================\n");
1269
1270 // Header Row
1271 PetscFPrintf(PETSC_COMM_SELF, f, "%-*s | %-*s | %-*s | %-*s\n",
1272 max_name_len, "Function",
1273 time_width, "Total Time (s)",
1274 count_width, "Call Count",
1275 avg_width, "Avg. Time/Call (ms)");
1276
1277 // Separator Line (dynamically sized)
1278 for (int i = 0; i < max_name_len; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
1279 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
1280 for (int i = 0; i < time_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
1281 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
1282 for (int i = 0; i < count_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
1283 PetscFPrintf(PETSC_COMM_SELF, f, "-|-");
1284 for (int i = 0; i < avg_width; i++) PetscFPrintf(PETSC_COMM_SELF, f, "-");
1285 PetscFPrintf(PETSC_COMM_SELF, f, "\n");
1286
1287 // Data Rows
1288 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1289 if (g_profiler_registry[i].total_call_count > 0) {
1290 double avg_time_ms = (g_profiler_registry[i].total_time / g_profiler_registry[i].total_call_count) * 1000.0;
1291 PetscFPrintf(PETSC_COMM_SELF, f, "%-*s | %*.*f | %*lld | %*.*f\n",
1292 max_name_len, g_profiler_registry[i].name,
1293 time_width, 6, g_profiler_registry[i].total_time,
1294 count_width, g_profiler_registry[i].total_call_count,
1295 avg_width, 6, avg_time_ms);
1296 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------\n");
1297 }
1298 }
1299 PetscFPrintf(PETSC_COMM_SELF, f, "==================================================================================================================\n");
1300
1301 fclose(f);
1302 }
1303
1304 // --- Final Cleanup ---
1305 PetscFree(g_profiler_registry);
1306 g_profiler_registry = NULL;
1307 g_profiler_count = 0;
1309 PetscFunctionReturn(0);
1310}
long long total_call_count
Definition logging.c:992
static PetscInt g_profiler_capacity
Definition logging.c:1001
double total_time
Definition logging.c:990
static int _CompareProfiledFunctions(const void *a, const void *b)
Internal helper implementation: _CompareProfiledFunctions().
Definition logging.c:1198
PetscBool profilingFinalSummary
Definition variables.h:780
@ EXEC_MODE_SOLVER
Definition variables.h:616
@ EXEC_MODE_POSTPROCESSOR
Definition variables.h:617
ExecutionMode exec_mode
Definition variables.h:662
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 1068 of file logging.c.

1069{
1070 PetscInt idx;
1071 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
1072 PetscTime(&g_profiler_registry[idx].start_time);
1073}
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 1082 of file logging.c.

1083{
1084 double end_time;
1085 PetscTime(&end_time);
1086
1087 PetscInt idx;
1088 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
1089
1090 double elapsed = end_time - g_profiler_registry[idx].start_time;
1091 g_profiler_registry[idx].total_time += elapsed;
1092 g_profiler_registry[idx].current_step_time += elapsed;
1095}
double start_time
Definition logging.c:994
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LOG_FIELD_MIN_MAX()

PetscErrorCode LOG_FIELD_MIN_MAX ( UserCtx user,
const char *  fieldName 
)

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

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

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

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

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

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

See also
LOG_FIELD_MIN_MAX()

Definition at line 1367 of file logging.c.

1368{
1369 PetscErrorCode ierr;
1370 PetscInt i, j, k;
1371 DMDALocalInfo info;
1372
1373 Vec fieldVec = NULL;
1374 DM dm = NULL;
1375 PetscInt dof;
1376 char data_layout[20];
1377
1378 PetscFunctionBeginUser;
1379
1380 // --- 1. Map string name to PETSc objects and determine data layout ---
1381 if (strcasecmp(fieldName, "Ucat") == 0) {
1382 fieldVec = user->Ucat; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
1383 } else if (strcasecmp(fieldName, "P") == 0) {
1384 fieldVec = user->P; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
1385 } else if (strcasecmp(fieldName, "Diffusivity") == 0) {
1386 fieldVec = user->Diffusivity; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
1387 } else if (strcasecmp(fieldName, "DiffusivityGradient") == 0) {
1388 fieldVec = user->DiffusivityGradient; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
1389 } else if (strcasecmp(fieldName, "Ucont") == 0) {
1390 fieldVec = user->lUcont; dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered");
1391 } else if (strcasecmp(fieldName, "Coordinates") == 0) {
1392 ierr = DMGetCoordinates(user->da, &fieldVec); CHKERRQ(ierr);
1393 dm = user->fda; dof = 3; strcpy(data_layout, "Node-Centered");
1394 } else if (strcasecmp(fieldName,"Psi") == 0) {
1395 fieldVec = user->Psi; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered"); // Assuming Psi is cell-centered
1396 } else {
1397 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_UNKNOWN_TYPE, "Field %s not recognized.", fieldName);
1398 }
1399
1400 if (!fieldVec) {
1401 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Vector for field '%s' is NULL.", fieldName);
1402 }
1403 if (!dm) {
1404 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "DM for field '%s' is NULL.", fieldName);
1405 }
1406
1407 ierr = DMDAGetLocalInfo(dm, &info); CHKERRQ(ierr);
1408
1409 // --- 2. Define Architecture-Aware Loop Bounds ---
1410 PetscInt i_start, i_end, j_start, j_end, k_start, k_end;
1411
1412 if (strcmp(data_layout, "Cell-Centered") == 0) {
1413 // For cell-centered data, the physical values are stored from index 1 to N-1.
1414 // We find the intersection of the rank's owned range [xs, xe) with the
1415 // physical data range [1, IM-1).
1416 i_start = PetscMax(info.xs, 1); i_end = PetscMin(info.xs + info.xm, user->IM);
1417 j_start = PetscMax(info.ys, 1); j_end = PetscMin(info.ys + info.ym, user->JM);
1418 k_start = PetscMax(info.zs, 1); k_end = PetscMin(info.zs + info.zm, user->KM);
1419 } else { // For Node- or Face-Centered data
1420 // The physical values are stored from index 0 to N-1.
1421 // We find the intersection of the rank's owned range [xs, xe) with the
1422 // physical data range [0, IM-1].
1423 i_start = PetscMax(info.xs, 0); i_end = PetscMin(info.xs + info.xm, user->IM);
1424 j_start = PetscMax(info.ys, 0); j_end = PetscMin(info.ys + info.ym, user->JM);
1425 k_start = PetscMax(info.zs, 0); k_end = PetscMin(info.zs + info.zm, user->KM);
1426 }
1427
1428 // --- 3. Barrier for clean, grouped output ---
1429 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
1430 if (user->simCtx->rank == 0) {
1431 PetscPrintf(PETSC_COMM_SELF, "\n--- Field Ranges: [%s] (Layout: %s) ---\n", fieldName, data_layout);
1432 }
1433
1434 // --- 4. Branch on DoF and perform calculation with correct bounds ---
1435 if (dof == 1) {
1436 PetscReal localMin = PETSC_MAX_REAL, localMax = PETSC_MIN_REAL;
1437 PetscReal globalMin, globalMax;
1438 const PetscScalar ***array;
1439
1440 ierr = DMDAVecGetArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
1441 for (k = k_start; k < k_end; k++) {
1442 for (j = j_start; j < j_end; j++) {
1443 for (i = i_start; i < i_end; i++) {
1444 localMin = PetscMin(localMin, array[k][j][i]);
1445 localMax = PetscMax(localMax, array[k][j][i]);
1446 }
1447 }
1448 }
1449 ierr = DMDAVecRestoreArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
1450
1451 ierr = MPI_Allreduce(&localMin, &globalMin, 1, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
1452 ierr = MPI_Allreduce(&localMax, &globalMax, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
1453
1454 PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin, localMax);
1455 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
1456 if (user->simCtx->rank == 0) {
1457 PetscPrintf(PETSC_COMM_SELF, " Global Range: [ %11.4e , %11.4e ]\n", globalMin, globalMax);
1458 }
1459
1460 } else if (dof == 3) {
1461 Cmpnts localMin = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL};
1462 Cmpnts localMax = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL};
1463 Cmpnts globalMin, globalMax;
1464 const Cmpnts ***array;
1465
1466 ierr = DMDAVecGetArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
1467 for (k = k_start; k < k_end; k++) {
1468 for (j = j_start; j < j_end; j++) {
1469 for (i = i_start; i < i_end; i++) {
1470 localMin.x = PetscMin(localMin.x, array[k][j][i].x);
1471 localMin.y = PetscMin(localMin.y, array[k][j][i].y);
1472 localMin.z = PetscMin(localMin.z, array[k][j][i].z);
1473 localMax.x = PetscMax(localMax.x, array[k][j][i].x);
1474 localMax.y = PetscMax(localMax.y, array[k][j][i].y);
1475 localMax.z = PetscMax(localMax.z, array[k][j][i].z);
1476 }
1477 }
1478 }
1479 ierr = DMDAVecRestoreArrayRead(dm, fieldVec, &array); CHKERRQ(ierr);
1480
1481 ierr = MPI_Allreduce(&localMin, &globalMin, 3, MPIU_REAL, MPI_MIN, PETSC_COMM_WORLD); CHKERRQ(ierr);
1482 ierr = MPI_Allreduce(&localMax, &globalMax, 3, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
1483
1484 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local X-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.x, localMax.x);
1485 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Y-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.y, localMax.y);
1486 ierr = PetscSynchronizedPrintf(PETSC_COMM_WORLD, " [Rank %d] Local Z-Range: [ %11.4e , %11.4e ]\n", user->simCtx->rank, localMin.z, localMax.z);
1487 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
1488
1489 if (user->simCtx->rank == 0) {
1490 PetscPrintf(PETSC_COMM_SELF, " [Global] X-Range: [ %11.4e , %11.4e ]\n", globalMin.x, globalMax.x);
1491 PetscPrintf(PETSC_COMM_SELF, " [Global] Y-Range: [ %11.4e , %11.4e ]\n", globalMin.y, globalMax.y);
1492 PetscPrintf(PETSC_COMM_SELF, " [Global] Z-Range: [ %11.4e , %11.4e ]\n", globalMin.z, globalMax.z);
1493 }
1494
1495 } else {
1496 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);
1497 }
1498
1499 // --- 5. Final barrier for clean output ordering ---
1500 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
1501 if (user->simCtx->rank == 0) {
1502 PetscPrintf(PETSC_COMM_SELF, "--------------------------------------------\n\n");
1503 }
1504
1505 PetscFunctionReturn(0);
1506}
PetscInt KM
Definition variables.h:820
Vec DiffusivityGradient
Definition variables.h:841
Vec Ucat
Definition variables.h:837
PetscInt JM
Definition variables.h:820
Vec lUcont
Definition variables.h:837
Vec Diffusivity
Definition variables.h:840
PetscInt IM
Definition variables.h:820
Vec Psi
Definition variables.h:883
A 3D point or vector with PetscScalar components.
Definition variables.h:100
Here is the caller graph for this function:

◆ LOG_FIELD_ANATOMY()

PetscErrorCode LOG_FIELD_ANATOMY ( UserCtx user,
const char *  field_name,
const char *  stage_name 
)

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

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

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

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

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

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

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

See also
LOG_FIELD_ANATOMY()

Definition at line 1515 of file logging.c.

1516{
1517 PetscErrorCode ierr;
1518 DMDALocalInfo info;
1519 PetscMPIInt rank;
1520
1521 Vec vec_local = NULL;
1522 DM dm = NULL;
1523 PetscInt dof = 0;
1524 char data_layout[20];
1525 char dominant_dir = '\0'; // 'x', 'y', 'z' for face-centered, 'm' for mixed (Ucont)
1526
1527 PetscFunctionBeginUser;
1528 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
1529
1530 // --- 1. Map string name to PETSc objects and determine data layout ---
1531 if (strcasecmp(field_name, "Ucat") == 0) {
1532 vec_local = user->lUcat; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
1533 } else if (strcasecmp(field_name, "P") == 0) {
1534 vec_local = user->lP; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
1535 } else if (strcasecmp(field_name, "Diffusivity") == 0) {
1536 vec_local = user->lDiffusivity; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
1537 } else if (strcasecmp(field_name, "DiffusivityGradient") == 0) {
1538 vec_local = user->lDiffusivityGradient; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
1539 } else if (strcasecmp(field_name, "Psi") == 0) {
1540 vec_local = user->lPsi; dm = user->da; dof = 1; strcpy(data_layout, "Cell-Centered");
1541 } else if (strcasecmp(field_name, "Center-Coordinates") == 0) {
1542 vec_local = user->lCent; dm = user->fda; dof = 3; strcpy(data_layout, "Cell-Centered");
1543 } else if (strcasecmp(field_name, "Ucont") == 0) {
1544 vec_local = user->lUcont; dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'm'; // Mixed
1545 } else if (strcasecmp(field_name, "Csi") == 0 || strcasecmp(field_name, "X-Face-Centers") == 0) {
1546 vec_local = (strcasecmp(field_name, "Csi") == 0) ? user->lCsi : user->Centx;
1547 dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'x';
1548 } else if (strcasecmp(field_name, "Eta") == 0 || strcasecmp(field_name, "Y-Face-Centers") == 0) {
1549 vec_local = (strcasecmp(field_name, "Eta") == 0) ? user->lEta : user->Centy;
1550 dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'y';
1551 } else if (strcasecmp(field_name, "Zet") == 0 || strcasecmp(field_name, "Z-Face-Centers") == 0) {
1552 vec_local = (strcasecmp(field_name, "Zet") == 0) ? user->lZet : user->Centz;
1553 dm = user->fda; dof = 3; strcpy(data_layout, "Face-Centered"); dominant_dir = 'z';
1554 } else if (strcasecmp(field_name, "Coordinates") == 0) {
1555 ierr = DMGetCoordinatesLocal(user->da, &vec_local); CHKERRQ(ierr);
1556 dm = user->fda; dof = 3; strcpy(data_layout, "Node-Centered");
1557 } else if (strcasecmp(field_name, "CornerField")== 0){
1558 vec_local = user->lCellFieldAtCorner; strcpy(data_layout, "Node-Centered");
1559 PetscInt bs = 1;
1560 ierr = VecGetBlockSize(user->CellFieldAtCorner, &bs); CHKERRQ(ierr);
1561 dof = bs;
1562 if(dof == 1) dm = user->da;
1563 else dm = user->fda;
1564 } else {
1565 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Unknown field name for LOG_FIELD_ANATOMY: %s", field_name);
1566 }
1567
1568 // --- 2. Get Grid Info and Array Pointers ---
1569 ierr = DMDAGetLocalInfo(dm, &info); CHKERRQ(ierr);
1570
1571 ierr = PetscBarrier(NULL);
1572 PetscPrintf(PETSC_COMM_WORLD, "\n--- Field Anatomy Log: [%s] | Stage: [%s] | Layout: [%s] ---\n", field_name, stage_name, data_layout);
1573
1574 // Global physical dimensions (number of cells)
1575 PetscInt im_phys = user->IM;
1576 PetscInt jm_phys = user->JM;
1577 PetscInt km_phys = user->KM;
1578
1579 // Slice through the center of the local domain
1580 PetscInt i_mid = (PetscInt)(info.xs + 0.5 * info.xm) - 1;
1581 PetscInt j_mid = (PetscInt)(info.ys + 0.5 * info.ym) - 1;
1582 PetscInt k_mid = (PetscInt)(info.zs + 0.5 * info.zm) - 1;
1583
1584 // --- 3. Print Boundary Information based on Data Layout ---
1585
1586 // ======================================================================
1587 // === CASE 1: Cell-Centered Fields (Ucat, P) - USES SHIFTED INDEX ===
1588 // ======================================================================
1589 if (strcmp(data_layout, "Cell-Centered") == 0) {
1590 const void *l_arr;
1591 ierr = DMDAVecGetArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
1592
1593
1594 // --- I-Direction Boundaries ---
1595 if (info.xs == 0) { // Rank on -Xi boundary
1596 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][0]) = ", rank, 0);
1597 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][0]);
1598 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][0].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][0].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][0].z);
1599
1600 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][0]) = ", rank, 1);
1601 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][1]);
1602 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][1].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][1].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][1].z);
1603 }
1604 if (info.xs + info.xm == info.mx) { // Rank on +Xi boundary
1605 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][%d]) = ", rank, im_phys - 1, im_phys - 2);
1606 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][im_phys - 1]);
1607 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys - 1].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys - 1].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys - 1].z);
1608
1609 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][%d]) = ", rank, im_phys, im_phys - 2);
1610 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][j_mid][im_phys]);
1611 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys].x, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys].y, ((const Cmpnts***)l_arr)[k_mid][j_mid][im_phys].z);
1612 }
1613
1614 // --- J-Direction Boundaries ---
1615 if (info.ys == 0) { // Rank on -Eta boundary
1616 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][0][i]) = ", rank, 0);
1617 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][0][i_mid]);
1618 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][0][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][0][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][0][i_mid].z);
1619
1620 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][0][i]) = ", rank, 1);
1621 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][1][i_mid]);
1622 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][1][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][1][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][1][i_mid].z);
1623 }
1624
1625 if (info.ys + info.ym == info.my) { // Rank on +Eta boundary
1626 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][%d][i]) = ", rank, jm_phys - 1, jm_phys - 2);
1627 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][jm_phys - 1][i_mid]);
1628 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][jm_phys - 1][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][jm_phys - 1][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][jm_phys - 1][i_mid].z);
1629
1630 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][%d][i]) = ", rank, jm_phys, jm_phys - 2);
1631 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[k_mid][jm_phys][i_mid]);
1632 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[k_mid][jm_phys][i_mid].x, ((const Cmpnts***)l_arr)[k_mid][jm_phys][i_mid].y, ((const Cmpnts***)l_arr)[k_mid][jm_phys][i_mid].z);
1633 }
1634
1635 // --- K-Direction Boundaries ---
1636 if (info.zs == 0) { // Rank on -Zeta boundary
1637 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Ghost for Cell[0][j][i]) = ", rank, 0);
1638 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[0][j_mid][i_mid]);
1639 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[0][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[0][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[0][j_mid][i_mid].z);
1640 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Value for Cell[0][j][i]) = ", rank, 1);
1641 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[1][j_mid][i_mid]);
1642 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[1][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[1][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[1][j_mid][i_mid].z);
1643 }
1644 if (info.zs + info.zm == info.mz) { // Rank on +Zeta boundary
1645 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Value for Cell[%d][j][i]) = ", rank, km_phys - 1, km_phys - 2);
1646 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[km_phys - 1][j_mid][i_mid]);
1647 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[km_phys - 1][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[km_phys - 1][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[km_phys - 1][j_mid][i_mid].z);
1648 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Ghost for Cell[%d][j][i]) = ", rank, km_phys, km_phys - 2);
1649 if(dof==1) PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f)\n", ((const PetscReal***)l_arr)[km_phys][j_mid][i_mid]);
1650 else PetscSynchronizedPrintf(PETSC_COMM_WORLD, "(%.5f, %.5f, %.5f)\n", ((const Cmpnts***)l_arr)[km_phys][j_mid][i_mid].x, ((const Cmpnts***)l_arr)[km_phys][j_mid][i_mid].y, ((const Cmpnts***)l_arr)[km_phys][j_mid][i_mid].z);
1651 }
1652 ierr = DMDAVecRestoreArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
1653 }
1654 // ======================================================================
1655 // === CASE 2: Face-Centered Fields - NUANCED DIRECTIONAL LOGIC ===
1656 // ======================================================================
1657 else if (strcmp(data_layout, "Face-Centered") == 0) {
1658 const Cmpnts ***l_arr;
1659 ierr = DMDAVecGetArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
1660
1661 // --- I-Direction Boundaries ---
1662 if (info.xs == 0) { // Rank on -Xi boundary
1663 if (dominant_dir == 'x') { // Node-like in I-dir
1664 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (First Phys. X-Face) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][j_mid][0].x, l_arr[k_mid][j_mid][0].y, l_arr[k_mid][j_mid][0].z);
1665 } else if (dominant_dir == 'y' || dominant_dir == 'z') { // Cell-like in I-dir
1666 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][0]) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][j_mid][0].x, l_arr[k_mid][j_mid][0].y, l_arr[k_mid][j_mid][0].z);
1667 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][0]) = (%.5f, %.5f, %.5f)\n", rank, 1, l_arr[k_mid][j_mid][1].x, l_arr[k_mid][j_mid][1].y, l_arr[k_mid][j_mid][1].z);
1668 } else if (dominant_dir == 'm') { // Ucont: Mixed
1669 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: u-comp @ Idx %2d (1st X-Face) = %.5f\n", rank, 0, l_arr[k_mid][j_mid][0].x);
1670 }
1671 }
1672 if (info.xs + info.xm == info.mx) { // Rank on +Xi boundary
1673 if (dominant_dir == 'x') { // Node-like in I-dir
1674 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Last Phys. X-Face) = (%.5f, %.5f, %.5f)\n", rank, im_phys - 1, l_arr[k_mid][j_mid][im_phys - 1].x, l_arr[k_mid][j_mid][im_phys-1].y, l_arr[k_mid][j_mid][im_phys - 1].z);
1675 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost Location) = (%.5f, %.5f, %.5f)\n", rank, im_phys, l_arr[k_mid][j_mid][im_phys].x, l_arr[k_mid][j_mid][im_phys].y, l_arr[k_mid][j_mid][im_phys].z);
1676 } else if (dominant_dir == 'y' || dominant_dir == 'z') { // Cell-like in I-dir
1677 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Value for Cell[k][j][%d]) = (%.5f, %.5f, %.5f)\n", rank, im_phys - 1, im_phys - 2, l_arr[k_mid][j_mid][im_phys - 1].x, l_arr[k_mid][j_mid][im_phys - 1].y, l_arr[k_mid][j_mid][im_phys-1].z);
1678 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Ghost for Cell[k][j][%d]) = (%.5f, %.5f, %.5f)\n", rank, im_phys, im_phys - 2, l_arr[k_mid][j_mid][im_phys].x, l_arr[k_mid][j_mid][im_phys].y, l_arr[k_mid][j_mid][im_phys].z);
1679 } else if (dominant_dir == 'm') { // Ucont: Mixed
1680 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: u-comp @ Idx %2d (Last X-Face) = %.5f\n", rank, im_phys - 1, l_arr[k_mid][j_mid][im_phys - 1].x);
1681 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: u-comp @ Idx %2d (Ghost Location) = %.5f\n", rank, im_phys, l_arr[k_mid][j_mid][im_phys].x);
1682 }
1683 }
1684
1685 // --- J-Direction Boundaries ---
1686 if (info.ys == 0) { // Rank on -Eta boundary
1687 if (dominant_dir == 'y') { // Node-like in J-dir
1688 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (First Phys. Y-Face) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][0][i_mid].x, l_arr[k_mid][0][i_mid].y, l_arr[k_mid][0][i_mid].z);
1689 } else if (dominant_dir == 'x' || dominant_dir == 'z') { // Cell-like in J-dir
1690 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][0][i]) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][0][i_mid].x, l_arr[k_mid][0][i_mid].y, l_arr[k_mid][0][i_mid].z);
1691 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][0][i]) = (%.5f, %.5f, %.5f)\n", rank, 1, l_arr[k_mid][1][i_mid].x, l_arr[k_mid][1][i_mid].y, l_arr[k_mid][1][i_mid].z);
1692 } else if (dominant_dir == 'm') { // Ucont: Mixed
1693 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: v-comp @ Jdx %2d (1st Y-Face) = %.5f\n", rank, 0, l_arr[k_mid][0][i_mid].y);
1694 }
1695 }
1696 if (info.ys + info.ym == info.my) { // Rank on +Eta boundary
1697 if (dominant_dir == 'y') { // Node-like in J-dir
1698 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Last Phys. Y-Face) = (%.5f, %.5f, %.5f)\n", rank, jm_phys - 1, l_arr[k_mid][jm_phys - 1][i_mid].x, l_arr[k_mid][jm_phys - 1][i_mid].y, l_arr[k_mid][jm_phys - 1][i_mid].z);
1699 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost Location) = (%.5f, %.5f, %.5f)\n", rank, jm_phys, l_arr[k_mid][jm_phys][i_mid].x, l_arr[k_mid][jm_phys][i_mid].y, l_arr[k_mid][jm_phys][i_mid].z);
1700 } else if (dominant_dir == 'x' || dominant_dir == 'z') { // Cell-like in J-dir
1701 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Value for Cell[k][%d][i]) = (%.5f, %.5f, %.5f)\n", rank, jm_phys-1, jm_phys-2, l_arr[k_mid][jm_phys - 1][i_mid].x, l_arr[k_mid][jm_phys - 1][i_mid].y, l_arr[k_mid][jm_phys - 1][i_mid].z);
1702 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Ghost for Cell[k][%d][i]) = (%.5f, %.5f, %.5f)\n", rank, jm_phys, jm_phys-2, l_arr[k_mid][jm_phys][i_mid].x, l_arr[k_mid][jm_phys][i_mid].y, l_arr[k_mid][jm_phys][i_mid].z);
1703 } else if (dominant_dir == 'm') { // Ucont: Mixed
1704 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: v-comp @ Jdx %2d (Last Y-Face) = %.5f\n", rank, jm_phys - 1, l_arr[k_mid][jm_phys - 1][i_mid].y);
1705 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: v-comp @ Jdx %2d (Ghost Location) = %.5f\n", rank, jm_phys, l_arr[k_mid][jm_phys][i_mid].y);
1706 }
1707 }
1708
1709 // --- K-Direction Boundaries ---
1710 if (info.zs == 0) { // Rank on -Zeta boundary
1711 if (dominant_dir == 'z') { // Node-like in K-dir
1712 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (First Phys. Z-Face) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[0][j_mid][i_mid].x, l_arr[0][j_mid][i_mid].y, l_arr[0][j_mid][i_mid].z);
1713 } else if (dominant_dir == 'x' || dominant_dir == 'y') { // Cell-like in K-dir
1714 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Ghost for Cell[0][j][i]) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[0][j_mid][i_mid].x, l_arr[0][j_mid][i_mid].y, l_arr[0][j_mid][i_mid].z);
1715 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Value for Cell[0][j][i]) = (%.5f, %.5f, %.5f)\n", rank, 1, l_arr[1][j_mid][i_mid].x, l_arr[1][j_mid][i_mid].y, l_arr[1][j_mid][i_mid].z);
1716 } else if (dominant_dir == 'm') { // Ucont: Mixed
1717 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: w-comp @ Idx %2d (1st Z-Face) = %.5f\n", rank, 0, l_arr[0][j_mid][i_mid].z);
1718 }
1719 }
1720 if (info.zs + info.zm == info.mz) { // Rank on +Zeta boundary
1721 if (dominant_dir == 'z') { // Node-like in K-dir
1722 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Last Phys. Z-Face) = (%.5f, %.5f, %.5f)\n", rank, km_phys - 1, l_arr[km_phys - 1][j_mid][i_mid].x, l_arr[km_phys - 1][j_mid][i_mid].y, l_arr[km_phys - 1][j_mid][i_mid].z);
1723 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Ghost Location) = (%.5f, %.5f, %.5f)\n", rank, km_phys, l_arr[km_phys][j_mid][i_mid].x, l_arr[km_phys][j_mid][i_mid].y, l_arr[km_phys][j_mid][i_mid].z);
1724 } else if (dominant_dir == 'x' || dominant_dir == 'y') { // Cell-like in K-dir
1725 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Value for Cell[%d][j][i]) = (%.5f, %.5f, %.5f)\n", rank, km_phys-1, km_phys-2, l_arr[km_phys-1][j_mid][i_mid].x, l_arr[km_phys-1][j_mid][i_mid].y, l_arr[km_phys - 1][j_mid][i_mid].z);
1726 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Idx %2d (Ghost for Cell[%d][j][i]) = (%.5f, %.5f, %.5f)\n", rank, km_phys, km_phys-2, l_arr[km_phys][j_mid][i_mid].x, l_arr[km_phys][j_mid][i_mid].y, l_arr[km_phys][j_mid][i_mid].z);
1727 } else if (dominant_dir == 'm') { // Ucont: Mixed
1728 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: w-comp @ Idx %2d (Last Z-Face) = %.5f\n", rank, km_phys - 1, l_arr[km_phys - 1][j_mid][i_mid].z);
1729 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: w-comp @ Idx %2d (Ghost Loc.) = %.5f\n", rank, km_phys, l_arr[km_phys][j_mid][i_mid].z);
1730
1731 }
1732 }
1733 ierr = DMDAVecRestoreArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
1734 }
1735 // ======================================================================
1736 // === CASE 3: Node-Centered Fields - USES DIRECT INDEX ===
1737 // ======================================================================
1738 else if (strcmp(data_layout, "Node-Centered") == 0) {
1739 const Cmpnts ***l_arr;
1740 ierr = DMDAVecGetArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
1741
1742 // --- I-Direction Boundaries ---
1743 if (info.xs == 0) {
1744 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (First Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][j_mid][0].x, l_arr[k_mid][j_mid][0].y, l_arr[k_mid][j_mid][0].z);
1745 }
1746 if (info.xs + info.xm == info.mx) {
1747 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Last Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, im_phys - 1, l_arr[k_mid][j_mid][im_phys - 1].x, l_arr[k_mid][j_mid][im_phys - 1].y, l_arr[k_mid][j_mid][im_phys - 1].z);
1748 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, I-DIR]: Idx %2d (Unused/Ghost Loc) = (%.5f, %.5f, %.5f)\n", rank, im_phys, l_arr[k_mid][j_mid][im_phys].x, l_arr[k_mid][j_mid][im_phys].y, l_arr[k_mid][j_mid][im_phys].z);
1749 }
1750 // --- J-Direction Boundaries ---
1751 if (info.ys == 0) {
1752 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (First Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[k_mid][0][i_mid].x, l_arr[k_mid][0][i_mid].y, l_arr[k_mid][0][i_mid].z);
1753 }
1754 if (info.ys + info.ym == info.my) {
1755 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Last Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, jm_phys - 1, l_arr[k_mid][jm_phys - 1][i_mid].x, l_arr[k_mid][jm_phys - 1][i_mid].y, l_arr[k_mid][jm_phys - 1][i_mid].z);
1756 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, J-DIR]: Jdx %2d (Unused/Ghost Loc) = (%.5f, %.5f, %.5f)\n", rank, jm_phys, l_arr[k_mid][jm_phys][i_mid].x, l_arr[k_mid][jm_phys][i_mid].y, l_arr[k_mid][jm_phys][i_mid].z);
1757 }
1758 // --- K-Direction Boundaries ---
1759 if (info.zs == 0) {
1760 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (First Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, 0, l_arr[0][j_mid][i_mid].x, l_arr[0][j_mid][i_mid].y, l_arr[0][j_mid][i_mid].z);
1761 }
1762 if(info.zs + info.zm == info.mz) {
1763 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Last Phys. Node) = (%.5f, %.5f, %.5f)\n", rank, km_phys - 1, l_arr[km_phys - 1][j_mid][i_mid].x, l_arr[km_phys - 1][j_mid][i_mid].y, l_arr[km_phys - 1][j_mid][i_mid].z);
1764 PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[Rank %d, K-DIR]: Kdx %2d (Unused/Ghost Loc) = (%.5f, %.5f, %.5f)\n", rank, km_phys, l_arr[km_phys][j_mid][i_mid].x, l_arr[km_phys][j_mid][i_mid].y, l_arr[km_phys][j_mid][i_mid].z);
1765 }
1766 ierr = DMDAVecRestoreArrayRead(dm, vec_local, (void*)&l_arr); CHKERRQ(ierr);
1767 }
1768 else {
1769 SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "LOG_FIELD_ANATOMY encountered an unknown data layout: %s", data_layout);
1770 }
1771
1772 ierr = PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT); CHKERRQ(ierr);
1773 ierr = PetscBarrier(NULL);
1774 PetscFunctionReturn(0);
1775}
Vec lDiffusivityGradient
Definition variables.h:841
Vec lCent
Definition variables.h:858
Vec lZet
Definition variables.h:858
Vec lCellFieldAtCorner
Definition variables.h:846
Vec lPsi
Definition variables.h:883
Vec lCsi
Definition variables.h:858
Vec CellFieldAtCorner
Definition variables.h:846
Vec lUcat
Definition variables.h:837
Vec lEta
Definition variables.h:858
Vec lDiffusivity
Definition variables.h:840
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 1785 of file logging.c.

1786{
1787 SimCtx *simCtx = user->simCtx;
1788 PetscErrorCode ierr;
1789 DM swarm = user->swarm;
1790 Vec positionVec, analyticalvelocityVec, velocityVec, errorVec;
1791 PetscReal Interpolation_error = 0.0;
1792 PetscReal Maximum_Interpolation_error = 0.0;
1793 PetscReal AnalyticalSolution_magnitude = 0.0;
1794 PetscReal ErrorPercentage = 0.0;
1795
1796 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Creating global vectors.\n");
1797 ierr = DMSwarmCreateGlobalVectorFromField(swarm, "position", &positionVec); CHKERRQ(ierr);
1798 ierr = DMSwarmCreateGlobalVectorFromField(swarm, "velocity", &velocityVec); CHKERRQ(ierr);
1799
1800 ierr = VecDuplicate(positionVec, &analyticalvelocityVec); CHKERRQ(ierr);
1801 ierr = VecCopy(positionVec, analyticalvelocityVec); CHKERRQ(ierr);
1802
1803 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Computing analytical solution.\n");
1804 ierr = SetAnalyticalSolutionForParticles(analyticalvelocityVec, simCtx); CHKERRQ(ierr);
1805
1806 ierr = VecDuplicate(analyticalvelocityVec, &errorVec); CHKERRQ(ierr);
1807 ierr = VecCopy(analyticalvelocityVec, errorVec); CHKERRQ(ierr);
1808
1809 ierr = VecNorm(analyticalvelocityVec, NORM_2, &AnalyticalSolution_magnitude); CHKERRQ(ierr);
1810
1811 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Computing error.\n");
1812 ierr = VecAXPY(errorVec, -1.0, velocityVec); CHKERRQ(ierr);
1813 ierr = VecNorm(errorVec, NORM_2, &Interpolation_error); CHKERRQ(ierr);
1814 ierr = VecNorm(errorVec,NORM_INFINITY,&Maximum_Interpolation_error); CHKERRQ(ierr);
1815
1816 ErrorPercentage = (AnalyticalSolution_magnitude > 0) ?
1817 (Interpolation_error / AnalyticalSolution_magnitude * 100.0) : 0.0;
1818
1819 /* --- CSV output (always, rank 0 only) --- */
1820 if (simCtx->rank == 0) {
1821 char csv_path[PETSC_MAX_PATH_LEN + 32];
1822 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/interpolation_error.csv", simCtx->log_dir); CHKERRQ(ierr);
1823 FILE *f = fopen(csv_path, "a");
1824 if (f) {
1825 if (ftell(f) == 0) {
1826 fprintf(f, "step,time,L2_error,Linf_error,L2_analytical,error_pct\n");
1827 }
1828 PetscReal t = (PetscReal)simCtx->ti * simCtx->dt;
1829 fprintf(f, "%d,%.6e,%.6e,%.6e,%.6e,%.4f\n",
1830 (int)simCtx->step, t,
1831 Interpolation_error, Maximum_Interpolation_error,
1832 AnalyticalSolution_magnitude, ErrorPercentage);
1833 fclose(f);
1834 }
1835 }
1836
1837 /* --- Console output (only at INFO level or above) --- */
1838 if (get_log_level() >= LOG_INFO) {
1839 LOG_ALLOW(GLOBAL, LOG_INFO, "Interpolation error (%%): %g\n", ErrorPercentage);
1840 PetscPrintf(PETSC_COMM_WORLD, "Interpolation error (%%): %g\n", ErrorPercentage);
1841 LOG_ALLOW(GLOBAL, LOG_INFO, "Maximum Interpolation error: %g\n", Maximum_Interpolation_error);
1842 PetscPrintf(PETSC_COMM_WORLD, "Maximum Interpolation error: %g\n", Maximum_Interpolation_error);
1843 }
1844
1845 ierr = VecDestroy(&analyticalvelocityVec); CHKERRQ(ierr);
1846 ierr = VecDestroy(&errorVec); CHKERRQ(ierr);
1847 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, "position", &positionVec); CHKERRQ(ierr);
1848 ierr = DMSwarmDestroyGlobalVectorFromField(swarm, "velocity", &velocityVec); CHKERRQ(ierr);
1849
1850 return 0;
1851}
PetscErrorCode SetAnalyticalSolutionForParticles(Vec tempVec, SimCtx *simCtx)
Applies the analytical solution to particle velocity vector.
PetscReal dt
Definition variables.h:658
PetscReal ti
Definition variables.h:652
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 1861 of file logging.c.

1862{
1863 PetscErrorCode ierr;
1864 SimCtx *simCtx = NULL;
1865 DMDALocalInfo info;
1866 PetscInt xs, xe, ys, ye, zs, ze, mx, my, mz;
1867 PetscInt lxs, lxe, lys, lye, lzs, lze;
1868 Vec reference_vec = NULL;
1869 PetscReal ***psi = NULL;
1870 PetscReal ***psi_ref = NULL;
1871 PetscReal ***aj = NULL;
1872 PetscReal ***count = NULL;
1873 PetscReal *particle_psi = NULL;
1874 PetscInt nlocal = 0;
1875 PetscReal local_l1 = 0.0, global_l1 = 0.0;
1876 PetscReal local_l2_sq = 0.0, global_l2_sq = 0.0;
1877 PetscReal local_linf = 0.0, global_linf = 0.0;
1878 PetscReal local_ref_l2_sq = 0.0, global_ref_l2_sq = 0.0;
1879 PetscReal local_grid_integral = 0.0, global_grid_integral = 0.0;
1880 PetscReal local_domain_volume = 0.0, global_domain_volume = 0.0;
1881 PetscReal local_particle_sum = 0.0, global_particle_sum = 0.0;
1882 PetscInt64 local_particle_count = 0, global_particle_count = 0;
1883 PetscInt64 local_cell_count = 0, global_cell_count = 0;
1884 PetscInt64 local_occupied_count = 0, global_occupied_count = 0;
1885 PetscReal particle_integral = 0.0;
1886 PetscReal occupancy_fraction = 0.0;
1887 PetscReal mean_particles_per_occupied_cell = 0.0;
1888 PetscReal l2_error = 0.0;
1889 PetscReal relative_l2_error = 0.0;
1890
1891 PetscFunctionBeginUser;
1892 if (!user) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx cannot be NULL.");
1893 simCtx = user->simCtx;
1894 if (!VerificationScalarOverrideActive(simCtx) || !user->swarm || !user->Psi || !user->ParticleCount) {
1895 PetscFunctionReturn(0);
1896 }
1897
1898 info = user->info;
1899 xs = info.xs; xe = info.xs + info.xm;
1900 ys = info.ys; ye = info.ys + info.ym;
1901 zs = info.zs; ze = info.zs + info.zm;
1902 mx = info.mx; my = info.my; mz = info.mz;
1903 lxs = (xs == 0) ? xs + 1 : xs; lxe = (xe == mx) ? xe - 1 : xe;
1904 lys = (ys == 0) ? ys + 1 : ys; lye = (ye == my) ? ye - 1 : ye;
1905 lzs = (zs == 0) ? zs + 1 : zs; lze = (ze == mz) ? ze - 1 : ze;
1906
1907 ierr = VecDuplicate(user->Psi, &reference_vec); CHKERRQ(ierr);
1908 ierr = SetAnalyticalScalarFieldAtCellCenters(user, reference_vec); CHKERRQ(ierr);
1909
1910 ierr = DMDAVecGetArrayRead(user->da, user->Psi, &psi); CHKERRQ(ierr);
1911 ierr = DMDAVecGetArrayRead(user->da, reference_vec, &psi_ref); CHKERRQ(ierr);
1912 ierr = DMDAVecGetArrayRead(user->da, user->Aj, &aj); CHKERRQ(ierr);
1913 ierr = DMDAVecGetArrayRead(user->da, user->ParticleCount, &count); CHKERRQ(ierr);
1914
1915 for (PetscInt k = lzs; k < lze; ++k) {
1916 for (PetscInt j = lys; j < lye; ++j) {
1917 for (PetscInt i = lxs; i < lxe; ++i) {
1918 const PetscReal cell_volume = (PetscAbsReal(aj[k][j][i]) > 1.0e-14) ? (1.0 / aj[k][j][i]) : 0.0;
1919 const PetscReal err = psi[k][j][i] - psi_ref[k][j][i];
1920 local_cell_count += 1;
1921 local_domain_volume += cell_volume;
1922 local_grid_integral += psi[k][j][i] * cell_volume;
1923 local_l1 += PetscAbsReal(err) * cell_volume;
1924 local_l2_sq += err * err * cell_volume;
1925 local_ref_l2_sq += psi_ref[k][j][i] * psi_ref[k][j][i] * cell_volume;
1926 local_linf = PetscMax(local_linf, PetscAbsReal(err));
1927 if (count[k][j][i] > 0.0) local_occupied_count += 1;
1928 }
1929 }
1930 }
1931
1932 ierr = DMDAVecRestoreArrayRead(user->da, user->ParticleCount, &count); CHKERRQ(ierr);
1933 ierr = DMDAVecRestoreArrayRead(user->da, user->Aj, &aj); CHKERRQ(ierr);
1934 ierr = DMDAVecRestoreArrayRead(user->da, reference_vec, &psi_ref); CHKERRQ(ierr);
1935 ierr = DMDAVecRestoreArrayRead(user->da, user->Psi, &psi); CHKERRQ(ierr);
1936 ierr = VecDestroy(&reference_vec); CHKERRQ(ierr);
1937
1938 ierr = DMSwarmGetLocalSize(user->swarm, &nlocal); CHKERRQ(ierr);
1939 local_particle_count = (PetscInt64)nlocal;
1940 if (nlocal > 0) {
1941 ierr = DMSwarmGetField(user->swarm, "Psi", NULL, NULL, (void **)&particle_psi); CHKERRQ(ierr);
1942 for (PetscInt p = 0; p < nlocal; ++p) local_particle_sum += particle_psi[p];
1943 ierr = DMSwarmRestoreField(user->swarm, "Psi", NULL, NULL, (void **)&particle_psi); CHKERRQ(ierr);
1944 }
1945
1946 ierr = MPI_Allreduce(&local_l1, &global_l1, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1947 ierr = MPI_Allreduce(&local_l2_sq, &global_l2_sq, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1948 ierr = MPI_Allreduce(&local_linf, &global_linf, 1, MPIU_REAL, MPI_MAX, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1949 ierr = MPI_Allreduce(&local_ref_l2_sq, &global_ref_l2_sq, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1950 ierr = MPI_Allreduce(&local_grid_integral, &global_grid_integral, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1951 ierr = MPI_Allreduce(&local_domain_volume, &global_domain_volume, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1952 ierr = MPI_Allreduce(&local_particle_sum, &global_particle_sum, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1953 ierr = MPI_Allreduce(&local_particle_count, &global_particle_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1954 ierr = MPI_Allreduce(&local_cell_count, &global_cell_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1955 ierr = MPI_Allreduce(&local_occupied_count, &global_occupied_count, 1, MPIU_INT64, MPI_SUM, PETSC_COMM_WORLD); CHKERRMPI(ierr);
1956
1957 l2_error = PetscSqrtReal(global_l2_sq);
1958 relative_l2_error = (global_ref_l2_sq > 0.0) ? (l2_error / PetscSqrtReal(global_ref_l2_sq)) : 0.0;
1959 occupancy_fraction = (global_cell_count > 0) ? ((PetscReal)global_occupied_count / (PetscReal)global_cell_count) : 0.0;
1960 mean_particles_per_occupied_cell =
1961 (global_occupied_count > 0) ? ((PetscReal)global_particle_count / (PetscReal)global_occupied_count) : 0.0;
1962 particle_integral =
1963 (global_particle_count > 0) ? (global_domain_volume * global_particle_sum / (PetscReal)global_particle_count) : 0.0;
1964
1965 if (simCtx->rank == 0) {
1966 char csv_path[PETSC_MAX_PATH_LEN + 32];
1967 FILE *f = NULL;
1968 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/scatter_metrics.csv", simCtx->log_dir); CHKERRQ(ierr);
1969 f = fopen(csv_path, "a");
1970 if (f) {
1971 if (ftell(f) == 0) {
1972 fprintf(f,
1973 "step,time,total_particles,total_cells,occupied_cells,occupancy_fraction,"
1974 "mean_particles_per_occupied_cell,particle_integral,grid_integral,"
1975 "conservation_error_abs,L1_error,L2_error,Linf_error,relative_L2_error\n");
1976 }
1977 fprintf(f, "%d,%.6e,%lld,%lld,%lld,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e,%.6e\n",
1978 (int)simCtx->step,
1979 (double)simCtx->ti,
1980 (long long)global_particle_count,
1981 (long long)global_cell_count,
1982 (long long)global_occupied_count,
1983 (double)occupancy_fraction,
1984 (double)mean_particles_per_occupied_cell,
1985 (double)particle_integral,
1986 (double)global_grid_integral,
1987 (double)PetscAbsReal(global_grid_integral - particle_integral),
1988 (double)global_l1,
1989 (double)l2_error,
1990 (double)global_linf,
1991 (double)relative_l2_error);
1992 fclose(f);
1993 }
1994 }
1995
1996 if (get_log_level() >= LOG_INFO) {
1997 LOG_ALLOW(GLOBAL, LOG_INFO, "Scatter relative L2 error: %.6e\n", (double)relative_l2_error);
1998 LOG_ALLOW(GLOBAL, LOG_INFO, "Scatter occupancy fraction: %.6e\n", (double)occupancy_fraction);
1999 }
2000
2001 PetscFunctionReturn(0);
2002}
PetscErrorCode SetAnalyticalScalarFieldAtCellCenters(UserCtx *user, Vec targetVec)
Writes the configured verification scalar profile at physical cell centers into a scalar Vec.
Vec ParticleCount
Definition variables.h:882
DMDALocalInfo info
Definition variables.h:818
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 2012 of file logging.c.

2013{
2014 PetscFunctionBeginUser;
2015 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be NULL for ResetSearchMetrics.");
2016
2017 simCtx->searchMetrics.searchAttempts = 0;
2018 simCtx->searchMetrics.searchPopulation = 0;
2020 simCtx->searchMetrics.searchLostCount = 0;
2021 simCtx->searchMetrics.traversalStepsSum = 0;
2022 simCtx->searchMetrics.reSearchCount = 0;
2023 simCtx->searchMetrics.maxTraversalSteps = 0;
2025 simCtx->searchMetrics.tieBreakCount = 0;
2031
2032 PetscFunctionReturn(0);
2033}
PetscInt64 searchLocatedCount
Definition variables.h:224
PetscInt64 searchLostCount
Definition variables.h:225
PetscInt64 boundaryClampCount
Definition variables.h:231
PetscInt64 traversalStepsSum
Definition variables.h:226
PetscInt64 searchPopulation
Definition variables.h:223
PetscInt currentSettlementPass
Definition variables.h:235
PetscInt64 reSearchCount
Definition variables.h:227
PetscInt64 bboxGuessFallbackCount
Definition variables.h:233
PetscInt64 bboxGuessSuccessCount
Definition variables.h:232
PetscInt64 maxParticlePassDepth
Definition variables.h:234
PetscInt64 maxTraversalSteps
Definition variables.h:228
SearchMetricsState searchMetrics
Definition variables.h:752
PetscInt64 searchAttempts
Definition variables.h:222
PetscInt64 tieBreakCount
Definition variables.h:230
PetscInt64 maxTraversalFailCount
Definition variables.h:229
Here is the caller graph for this function:

◆ CalculateAdvancedParticleMetrics()

PetscErrorCode CalculateAdvancedParticleMetrics ( UserCtx user)

Computes advanced particle statistics and stores them in SimCtx.

This function calculates:

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

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

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

Computes advanced particle statistics and stores them in SimCtx.

Local to this translation unit.

Definition at line 2194 of file logging.c.

2195{
2196 PetscErrorCode ierr;
2197 SimCtx *simCtx = user->simCtx;
2198 PetscMPIInt size, rank;
2199
2200 PetscFunctionBeginUser;
2201 ierr = MPI_Comm_size(PETSC_COMM_WORLD, &size); CHKERRQ(ierr);
2202 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2203
2204 // --- 1. Particle Load Imbalance ---
2205 PetscInt nLocal, nGlobal, nLocalMax;
2206 ierr = DMSwarmGetLocalSize(user->swarm, &nLocal); CHKERRQ(ierr);
2207 ierr = DMSwarmGetSize(user->swarm, &nGlobal); CHKERRQ(ierr);
2208 ierr = MPI_Allreduce(&nLocal, &nLocalMax, 1, MPIU_INT, MPI_MAX, PETSC_COMM_WORLD); CHKERRQ(ierr);
2209
2210 PetscReal avg_per_rank = (size > 0) ? ((PetscReal)nGlobal / size) : 0.0;
2211 // Handle division by zero if there are no particles
2212 simCtx->particleLoadImbalance = (avg_per_rank > 1e-9) ? (nLocalMax / avg_per_rank) : 1.0;
2213
2214
2215 // --- 2. Number of Occupied Cells ---
2216 // This part requires access to the user->ParticleCount vector.
2217 PetscInt local_occupied_cells = 0;
2218 PetscInt global_occupied_cells;
2219 const PetscScalar *count_array;
2220 PetscInt vec_local_size;
2221
2222 ierr = VecGetLocalSize(user->ParticleCount, &vec_local_size); CHKERRQ(ierr);
2223 ierr = VecGetArrayRead(user->ParticleCount, &count_array); CHKERRQ(ierr);
2224
2225 for (PetscInt i = 0; i < vec_local_size; ++i) {
2226 if (count_array[i] > 0.5) { // Use 0.5 to be safe with floating point
2227 local_occupied_cells++;
2228 }
2229 }
2230 ierr = VecRestoreArrayRead(user->ParticleCount, &count_array); CHKERRQ(ierr);
2231
2232 ierr = MPI_Allreduce(&local_occupied_cells, &global_occupied_cells, 1, MPIU_INT, MPI_SUM, PETSC_COMM_WORLD); CHKERRQ(ierr);
2233 simCtx->occupiedCellCount = global_occupied_cells;
2234
2235 LOG_ALLOW_SYNC(GLOBAL, LOG_INFO, "[Rank %d] Advanced Metrics: Imbalance=%.2f, OccupiedCells=%d\n", rank, simCtx->particleLoadImbalance, simCtx->occupiedCellCount);
2236
2237 PetscFunctionReturn(0);
2238}
PetscInt occupiedCellCount
Definition variables.h:750
PetscReal particleLoadImbalance
Definition variables.h:751
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 2043 of file logging.c.

2044{
2045 PetscErrorCode ierr;
2046 SimCtx *simCtx = NULL;
2047 PetscInt totalParticles = 0;
2048 PetscReal local_metrics[SEARCH_METRIC_REDUCTION_LEN] = {0.0};
2049 PetscReal global_metrics[SEARCH_METRIC_REDUCTION_LEN] = {0.0};
2050 PetscReal meanTraversalSteps = 0.0;
2051 PetscReal searchFailureFraction = 0.0;
2052 PetscReal searchWorkIndex = 0.0;
2053 PetscReal reSearchFraction = 0.0;
2054 long long searchAttempts = 0;
2055 long long searchPopulation = 0;
2056 long long searchLocatedCount = 0;
2057 long long searchLostCount = 0;
2058 long long traversalStepsSum = 0;
2059 long long reSearchCount = 0;
2060 long long tieBreakCount = 0;
2061 long long boundaryClampCount = 0;
2062 long long bboxGuessSuccessCount = 0;
2063 long long bboxGuessFallbackCount = 0;
2064 long long maxTraversalFailCount = 0;
2065 long long maxTraversalSteps = 0;
2066 long long maxPassDepth = 0;
2067 MPI_Op reduction_op = MPI_OP_NULL;
2068
2069 PetscFunctionBeginUser;
2070 if (!user || !user->simCtx) {
2071 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "UserCtx and SimCtx are required for LOG_SEARCH_METRICS.");
2072 }
2073 simCtx = user->simCtx;
2074
2075 if (simCtx->np <= 0) {
2076 PetscFunctionReturn(0);
2077 }
2078
2079 ierr = DMSwarmGetSize(user->swarm, &totalParticles); CHKERRQ(ierr);
2080
2081 local_metrics[SEARCH_METRIC_SUM_SEARCH_ATTEMPTS] = (PetscReal)simCtx->searchMetrics.searchAttempts;
2082 local_metrics[SEARCH_METRIC_SUM_SEARCH_POPULATION] = (PetscReal)simCtx->searchMetrics.searchPopulation;
2083 local_metrics[SEARCH_METRIC_SUM_SEARCH_LOCATED] = (PetscReal)simCtx->searchMetrics.searchLocatedCount;
2084 local_metrics[SEARCH_METRIC_SUM_SEARCH_LOST] = (PetscReal)simCtx->searchMetrics.searchLostCount;
2085 local_metrics[SEARCH_METRIC_SUM_TRAVERSAL_STEPS] = (PetscReal)simCtx->searchMetrics.traversalStepsSum;
2086 local_metrics[SEARCH_METRIC_SUM_RESEARCH] = (PetscReal)simCtx->searchMetrics.reSearchCount;
2087 local_metrics[SEARCH_METRIC_SUM_TIE_BREAKS] = (PetscReal)simCtx->searchMetrics.tieBreakCount;
2088 local_metrics[SEARCH_METRIC_SUM_BOUNDARY_CLAMPS] = (PetscReal)simCtx->searchMetrics.boundaryClampCount;
2089 local_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS] = (PetscReal)simCtx->searchMetrics.bboxGuessSuccessCount;
2090 local_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK] = (PetscReal)simCtx->searchMetrics.bboxGuessFallbackCount;
2091 local_metrics[SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS] = (PetscReal)simCtx->searchMetrics.maxTraversalFailCount;
2092 local_metrics[SEARCH_METRIC_MAX_TRAVERSAL_STEPS] = (PetscReal)simCtx->searchMetrics.maxTraversalSteps;
2093 local_metrics[SEARCH_METRIC_MAX_PASS_DEPTH] = (PetscReal)simCtx->searchMetrics.maxParticlePassDepth;
2094
2095 ierr = MPI_Op_create(SearchMetricsReduceOp, PETSC_TRUE, &reduction_op); CHKERRMPI(ierr);
2096 ierr = MPI_Allreduce(local_metrics, global_metrics, SEARCH_METRIC_REDUCTION_LEN, MPIU_REAL, reduction_op, PETSC_COMM_WORLD); CHKERRMPI(ierr);
2097 ierr = MPI_Op_free(&reduction_op); CHKERRMPI(ierr);
2098 reduction_op = MPI_OP_NULL;
2099
2100 searchAttempts = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_ATTEMPTS] + 0.5);
2101 searchPopulation = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_POPULATION] + 0.5);
2102 searchLocatedCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_LOCATED] + 0.5);
2103 searchLostCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_SEARCH_LOST] + 0.5);
2104 traversalStepsSum = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_TRAVERSAL_STEPS] + 0.5);
2105 reSearchCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_RESEARCH] + 0.5);
2106 tieBreakCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_TIE_BREAKS] + 0.5);
2107 boundaryClampCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BOUNDARY_CLAMPS] + 0.5);
2108 bboxGuessSuccessCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS] + 0.5);
2109 bboxGuessFallbackCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK] + 0.5);
2110 maxTraversalFailCount = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS] + 0.5);
2111 maxTraversalSteps = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_MAX_TRAVERSAL_STEPS] + 0.5);
2112 maxPassDepth = (long long)PetscFloorReal(global_metrics[SEARCH_METRIC_MAX_PASS_DEPTH] + 0.5);
2113
2114 if (searchAttempts > 0) {
2115 meanTraversalSteps = (PetscReal)traversalStepsSum / (PetscReal)searchAttempts;
2116 }
2117 if (searchPopulation > 0) {
2118 searchFailureFraction = (PetscReal)searchLostCount / (PetscReal)searchPopulation;
2119 searchWorkIndex = (PetscReal)traversalStepsSum / (PetscReal)searchPopulation;
2120 reSearchFraction = (PetscReal)reSearchCount / (PetscReal)searchPopulation;
2121 }
2122
2123 if (simCtx->rank == 0) {
2124 char csv_path[PETSC_MAX_PATH_LEN + 32];
2125 FILE *f = NULL;
2126
2127 ierr = PetscSNPrintf(csv_path, sizeof(csv_path), "%s/search_metrics.csv", simCtx->log_dir); CHKERRQ(ierr);
2128 f = fopen(csv_path, "a");
2129 if (!f) {
2130 LOG_ALLOW(GLOBAL, LOG_WARNING, "LOG_SEARCH_METRICS: could not open '%s' for writing.\n", csv_path);
2131 } else {
2132 if (ftell(f) == 0) {
2133 fprintf(f,
2134 "step,time,total_particles,lost,lost_cumulative,migrated,migration_passes,search_attempts,"
2135 "mean_traversal_steps,max_traversal_steps,tie_break_count,boundary_clamp_count,"
2136 "bbox_guess_success_count,bbox_guess_fallback_count,max_particle_pass_depth,load_imbalance,"
2137 "search_population,search_located_count,search_lost_count,traversal_steps_sum,re_search_count,"
2138 "max_traversal_fail_count,search_failure_fraction,search_work_index,re_search_fraction\n");
2139 }
2140 fprintf(f,
2141 "%d,%.6e,%d,%d,%d,%d,%d,%lld,%.6e,%lld,%lld,%lld,%lld,%lld,%lld,%.6e,%lld,%lld,%lld,%lld,%lld,%lld,%.6e,%.6e,%.6e\n",
2142 (int)simCtx->step,
2143 (double)simCtx->ti,
2144 (int)totalParticles,
2145 (int)simCtx->particlesLostLastStep,
2146 (int)simCtx->particlesLostCumulative,
2147 (int)simCtx->particlesMigratedLastStep,
2148 (int)simCtx->migrationPassesLastStep,
2149 searchAttempts,
2150 (double)meanTraversalSteps,
2151 maxTraversalSteps,
2152 tieBreakCount,
2153 boundaryClampCount,
2154 bboxGuessSuccessCount,
2155 bboxGuessFallbackCount,
2156 maxPassDepth,
2157 (double)simCtx->particleLoadImbalance,
2158 searchPopulation,
2159 searchLocatedCount,
2160 searchLostCount,
2161 traversalStepsSum,
2162 reSearchCount,
2163 maxTraversalFailCount,
2164 (double)searchFailureFraction,
2165 (double)searchWorkIndex,
2166 (double)reSearchFraction);
2167 fclose(f);
2168 }
2169 }
2170
2172 "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",
2173 (double)searchFailureFraction,
2174 (double)searchWorkIndex,
2175 (double)reSearchFraction,
2176 (int)simCtx->particlesLostLastStep,
2177 (int)simCtx->particlesLostCumulative,
2178 (int)simCtx->particlesMigratedLastStep,
2179 (int)simCtx->migrationPassesLastStep,
2180 (double)meanTraversalSteps,
2181 maxTraversalSteps,
2182 tieBreakCount,
2183 maxPassDepth);
2184
2185 PetscFunctionReturn(0);
2186}
@ SEARCH_METRIC_SUM_SEARCH_LOCATED
Definition logging.c:33
@ SEARCH_METRIC_SUM_MAX_TRAVERSAL_FAILS
Definition logging.c:41
@ SEARCH_METRIC_REDUCTION_LEN
Definition logging.c:44
@ SEARCH_METRIC_SUM_BBOX_GUESS_FALLBACK
Definition logging.c:40
@ SEARCH_METRIC_SUM_RESEARCH
Definition logging.c:36
@ SEARCH_METRIC_SUM_TRAVERSAL_STEPS
Definition logging.c:35
@ SEARCH_METRIC_MAX_TRAVERSAL_STEPS
Definition logging.c:42
@ SEARCH_METRIC_SUM_BOUNDARY_CLAMPS
Definition logging.c:38
@ SEARCH_METRIC_SUM_SEARCH_POPULATION
Definition logging.c:32
@ SEARCH_METRIC_MAX_PASS_DEPTH
Definition logging.c:43
@ SEARCH_METRIC_SUM_TIE_BREAKS
Definition logging.c:37
@ SEARCH_METRIC_SUM_SEARCH_LOST
Definition logging.c:34
@ SEARCH_METRIC_SUM_BBOX_GUESS_SUCCESS
Definition logging.c:39
@ SEARCH_METRIC_SUM_SEARCH_ATTEMPTS
Definition logging.c:31
static void SearchMetricsReduceOp(void *invec, void *inoutvec, int *len, MPI_Datatype *datatype)
Internal reduction callback for packed search metrics.
Definition logging.c:51
Here is the call graph for this function:
Here is the caller graph for this function:

◆ LOG_PARTICLE_METRICS()

PetscErrorCode LOG_PARTICLE_METRICS ( UserCtx user,
const char *  stageName 
)

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

This function serves a dual purpose:

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

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

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

See also
LOG_PARTICLE_METRICS()

Definition at line 2248 of file logging.c.

2249{
2250 PetscErrorCode ierr;
2251 PetscMPIInt rank;
2252 SimCtx *simCtx = user->simCtx;
2253 const char *stage_label = (stageName && stageName[0] != '\0') ? stageName : "N/A";
2254
2255 PetscFunctionBeginUser;
2256 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
2257
2258 PetscInt totalParticles;
2259 ierr = DMSwarmGetSize(user->swarm, &totalParticles); CHKERRQ(ierr);
2260
2261 if (!rank) {
2262 FILE *f;
2263 char filen[PETSC_MAX_PATH_LEN + 64];
2264 ierr = PetscSNPrintf(filen, sizeof(filen), "%s/Particle_Metrics.log", simCtx->log_dir); CHKERRQ(ierr);
2265 f = fopen(filen, "a");
2266 if (!f) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open particle log file: %s", filen);
2267
2268 if (ftell(f) == 0) {
2269 PetscFPrintf(PETSC_COMM_SELF, f, "%-18s | %-10s | %-12s | %-10s | %-10s | %-10s | %-15s | %-10s | %-10s\n",
2270 "Stage", "Timestep", "Total Ptls", "Lost", "Lost Total", "Migrated", "Occupied Cells", "Imbalance", "Mig Passes");
2271 PetscFPrintf(PETSC_COMM_SELF, f, "-------------------------------------------------------------------------------------------------------------------------------------------\n");
2272 }
2273
2274 PetscFPrintf(PETSC_COMM_SELF, f, "%-18s | %-10d | %-12d | %-10d | %-10d | %-10d | %-15d | %-10.2f | %-10d\n",
2275 stage_label, (int)simCtx->step, (int)totalParticles, (int)simCtx->particlesLostLastStep,
2276 (int)simCtx->particlesLostCumulative, (int)simCtx->particlesMigratedLastStep, (int)simCtx->occupiedCellCount,
2277 (double)simCtx->particleLoadImbalance, (int)simCtx->migrationPassesLastStep);
2278 fclose(f);
2279 }
2280 PetscFunctionReturn(0);
2281}
PetscInt particlesLostLastStep
Definition variables.h:746
PetscInt particlesLostCumulative
Definition variables.h:747
PetscInt particlesMigratedLastStep
Definition variables.h:749
PetscInt migrationPassesLastStep
Definition variables.h:748
Here is the caller graph for this function: