PICurv 0.1.0
A Parallel Particle-In-Cell Solver for Curvilinear LES
Loading...
Searching...
No Matches
logging.c File Reference
#include "logging.h"
Include dependency graph for logging.c:

Go to the source code of this file.

Data Structures

struct  ProfiledFunction
 

Macros

#define TMP_BUF_SIZE   128
 
#define __FUNCT__   "DualKSPMonitor"
 A custom KSP monitor that logs the true residual to a file and optionally to the console.
 
#define __FUNCT__   "LOG_CONTINUITY_METRICS"
 A custom KSP monitor that logs the true residual to a file and optionally to the console.
 

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 the given function name 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.
 
static void IntToStr (int value, char *buf, size_t bufsize)
 
static void Int64ToStr (PetscInt64 value, char *buf, size_t bufsize)
 
static void CellToStr (const PetscInt *cell, char *buf, size_t bufsize)
 
static void TripleRealToStr (const PetscReal *arr, char *buf, size_t bufsize)
 
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)
 
static void BuildRowFormatString (PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt, char *fmtStr, size_t bufSize)
 
static void BuildHeaderString (char *headerStr, size_t bufSize, PetscMPIInt wRank, PetscInt wPID, PetscInt wCell, PetscInt wPos, PetscInt wVel, PetscInt wWt)
 
PetscErrorCode LOG_PARTICLE_FIELDS (UserCtx *user, PetscInt printInterval)
 Prints particle fields in a table that automatically adjusts its column widths.
 
static void trim (char *s)
 
PetscErrorCode LoadAllowedFunctionsFromFile (const char filename[], char ***funcsOut, PetscInt *nOut)
 Load function names from a text file.
 
PetscErrorCode FreeAllowedFunctions (char **funcs, PetscInt n)
 Free an array previously returned by LoadAllowedFunctionsFromFile().
 
const char * BCFaceToString (BCFace face)
 Helper function to convert BCFace enum 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 DualMonitorDestroy (void **ctx)
 Destroys the DualMonitorCtx.
 
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 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.
 
static PetscErrorCode _FindOrCreateEntry (const char *func_name, PetscInt *idx)
 
PetscErrorCode ProfilingInitialize (SimCtx *simCtx)
 Initializes the custom profiling system using configuration from SimCtx.
 
void _ProfilingStart (const char *func_name)
 
void _ProfilingEnd (const char *func_name)
 
PetscErrorCode ProfilingLogTimestepSummary (PetscInt step)
 Logs the performance summary for the current timestep and resets timers.
 
static int _CompareProfiledFunctions (const void *a, const void *b)
 
PetscErrorCode ProfilingFinalize (void)
 Prints the final, cumulative performance summary and cleans up resources.
 

Variables

static LogLevel current_log_level = -1
 Static variable to cache the current logging level.
 
static char ** gAllowedFunctions = NULL
 Global/static array of function names allowed to log.
 
static int gNumAllowed = 0
 Number of entries in the gAllowedFunctions array.
 
PetscLogEvent EVENT_Individualwalkingsearch = 0
 
PetscLogEvent EVENT_walkingsearch = 0
 
PetscLogEvent EVENT_GlobalParticleLocation = 0
 
PetscLogEvent EVENT_IndividualLocation = 0
 
static ProfiledFunctiong_profiler_registry = NULL
 
static PetscInt g_profiler_count = 0
 
static PetscInt g_profiler_capacity = 0
 

Data Structure Documentation

◆ ProfiledFunction

struct ProfiledFunction

Definition at line 893 of file logging.c.

Data Fields
const char * name
double total_time
double current_step_time
long long total_call_count
long long current_step_call_count
double start_time
PetscBool always_log

Macro Definition Documentation

◆ TMP_BUF_SIZE

#define TMP_BUF_SIZE   128

Definition at line 5 of file logging.c.

◆ __FUNCT__ [1/2]

#define __FUNCT__   "DualKSPMonitor"

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

Logs continuity metrics for a single block to a file.

This function replicates the behavior of KSPMonitorTrueResidualNorm by calculating the true residual norm ||b - Ax|| itself. It unconditionally logs to a file viewer and conditionally logs to the console based on a flag in the context.

Parameters
kspThe Krylov subspace context.
itThe current iteration number.
rnormThe preconditioned residual norm (ignored, we compute our own).
ctxA pointer to the DualMonitorCtx structure.
Returns
PetscErrorCode 0 on success.

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.

Definition at line 758 of file logging.c.

◆ __FUNCT__ [2/2]

#define __FUNCT__   "LOG_CONTINUITY_METRICS"

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

Logs continuity metrics for a single block to a file.

This function replicates the behavior of KSPMonitorTrueResidualNorm by calculating the true residual norm ||b - Ax|| itself. It unconditionally logs to a file viewer and conditionally logs to the console based on a flag in the context.

Parameters
kspThe Krylov subspace context.
itThe current iteration number.
rnormThe preconditioned residual norm (ignored, we compute our own).
ctxA pointer to the DualMonitorCtx structure.
Returns
PetscErrorCode 0 on success.

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.

Definition at line 758 of file logging.c.

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 "DEBUG", "INFO", "WARNING", and defaults to "ERROR" if not set or unrecognized. The log level is cached after the first call to avoid repeated environment variable checks.

Returns
LogLevel The current logging level.

Definition at line 49 of file logging.c.

49 {
50 if (current_log_level == -1) { // Log level not set yet
51 const char *env = getenv("LOG_LEVEL");
52 if (!env) {
53 current_log_level = LOG_ERROR; // Default level
54 }
55 else if (strcmp(env, "DEBUG") == 0) {
57 }
58 else if (strcmp(env, "INFO") == 0) {
60 }
61 else if (strcmp(env, "WARNING") == 0) {
63 }
64 else if (strcmp(env, "PROFILE") == 0) { // <-- New profile level
66 }
67 else {
68 current_log_level = LOG_ERROR; // Default if unrecognized
69 }
70 }
71 return current_log_level;
72}
static LogLevel current_log_level
Static variable to cache the current logging level.
Definition logging.c:14
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
@ LOG_PROFILE
Exclusive log level for performance timing and profiling.
Definition logging.h:31
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:32
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:33
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.

Note
The log level is determined from the LOG_LEVEL environment variable. If LOG_LEVEL is not set, it defaults to LOG_INFO.
See also
get_log_level()

Definition at line 86 of file logging.c.

87{
88 PetscMPIInt rank;
89 PetscErrorCode ierr;
90 int level;
91 const char *level_name;
92
93 PetscFunctionBeginUser;
94 /* get MPI rank */
95 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRMPI(ierr);
96
97 /* decide level name */
98 level = get_log_level();
99 level_name = (level == LOG_ERROR) ? "ERROR" :
100 (level == LOG_WARNING) ? "WARNING" :
101 (level == LOG_INFO) ? "INFO" :
102 (level == LOG_DEBUG) ? "DEBUG" :
103 (level == LOG_PROFILE) ? "PROFILE" : "UNKNOWN";
104
105 /* print it out */
106 ierr = PetscPrintf(PETSC_COMM_SELF,
107 "Current log level: %s (%d) | rank: %d\n",
108 level_name, level, (int)rank);
109 CHKERRMPI(ierr);
110
111 PetscFunctionReturn(PETSC_SUCCESS);
112}
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
Definition logging.c:49
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.

Parameters
functionListAn array of function name strings (e.g., {"foo", "bar"}).
countThe number of entries in the array.

The existing allow-list is cleared and replaced by the new one. If you pass an empty list (count = 0), then no function will be allowed unless you change it later.

Definition at line 124 of file logging.c.

125{
126 // 1. Free any existing entries
127 if (gAllowedFunctions) {
128 for (int i = 0; i < gNumAllowed; ++i) {
129 free(gAllowedFunctions[i]); // each was strdup'ed
130 }
131 free(gAllowedFunctions);
132 gAllowedFunctions = NULL;
133 gNumAllowed = 0;
134 }
135
136 // 2. Allocate new array
137 if (count > 0) {
138 gAllowedFunctions = (char**)malloc(sizeof(char*) * count);
139 }
140
141 // 3. Copy the new entries
142 for (int i = 0; i < count; ++i) {
143 // strdup is a POSIX function. If not available, implement your own string copy.
144 gAllowedFunctions[i] = strdup(functionList[i]);
145 }
146 gNumAllowed = count;
147}
static char ** gAllowedFunctions
Global/static array of function names allowed to log.
Definition logging.c:21
static int gNumAllowed
Number of entries in the gAllowedFunctions array.
Definition logging.c:26
Here is the caller graph for this function:

◆ is_function_allowed()

PetscBool is_function_allowed ( const char *  functionName)

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

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

Parameters
functionNameThe name of the function to check.
Returns
PETSC_TRUE if functionName is allowed, otherwise PETSC_FALSE.

If no functions are in the list, nothing is allowed by default. You can reverse this logic if you prefer to allow everything unless specified otherwise.

Definition at line 159 of file logging.c.

160{
161 /* no list ⇒ allow all */
162 if (gNumAllowed == 0) {
163 return PETSC_TRUE;
164 }
165
166 /* otherwise only the listed functions are allowed */
167 for (int i = 0; i < gNumAllowed; ++i) {
168 if (strcmp(gAllowedFunctions[i], functionName) == 0) {
169 return PETSC_TRUE;
170 }
171 }
172 return PETSC_FALSE;
173}
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..

Definition at line 189 of file logging.c.

190{
191
192 // Validate input pointers
193 if (cell == NULL) {
194 LOG_ALLOW(LOCAL,LOG_ERROR, "LOG_CELL_VERTICES - 'cell' is NULL.\n");
195 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "LOG_CELL_VERTICES - Input parameter 'cell' is NULL.");
196 }
197
198 LOG_ALLOW(LOCAL,LOG_DEBUG, "LOG_CELL_VERTICES - Rank %d, Cell Vertices:\n", rank);
199 for(int i = 0; i < 8; i++){
200 LOG_ALLOW(LOCAL,LOG_DEBUG, " Vertex[%d]: (%.2f, %.2f, %.2f)\n",
201 i, cell->vertices[i].x, cell->vertices[i].y, cell->vertices[i].z);
202 }
203
204 return 0; // Indicate successful execution
205}
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:44
#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:207
PetscScalar x
Definition variables.h:100
PetscScalar z
Definition variables.h:100
PetscScalar y
Definition variables.h:100
Cmpnts vertices[8]
Coordinates of the eight vertices of the cell.
Definition variables.h:160
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.

Definition at line 229 of file logging.c.

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

◆ IntToStr()

static void IntToStr ( int  value,
char *  buf,
size_t  bufsize 
)
static

Definition at line 252 of file logging.c.

253{
254 snprintf(buf, bufsize, "%d", value);
255}
Here is the caller graph for this function:

◆ Int64ToStr()

static void Int64ToStr ( PetscInt64  value,
char *  buf,
size_t  bufsize 
)
static

Definition at line 260 of file logging.c.

261{
262 snprintf(buf, bufsize, "%ld", value);
263}
Here is the caller graph for this function:

◆ CellToStr()

static void CellToStr ( const PetscInt *  cell,
char *  buf,
size_t  bufsize 
)
static

Definition at line 268 of file logging.c.

269{
270 snprintf(buf, bufsize, "(%d, %d, %d)", cell[0], cell[1], cell[2]);
271}
Here is the caller graph for this function:

◆ TripleRealToStr()

static void TripleRealToStr ( const PetscReal *  arr,
char *  buf,
size_t  bufsize 
)
static

Definition at line 276 of file logging.c.

277{
278 snprintf(buf, bufsize, "(%.4f, %.4f, %.4f)", arr[0], arr[1], arr[2]);
279}
Here is the caller graph for this function:

◆ ComputeMaxColumnWidths()

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 
)
static

Definition at line 301 of file logging.c.

310{
311 char tmp[TMP_BUF_SIZE];
312
313 *wRank = strlen("Rank"); /* Start with the header label lengths */
314 *wPID = strlen("PID");
315 *wCell = strlen("Cell (i,j,k)");
316 *wPos = strlen("Position (x,y,z)");
317 *wVel = strlen("Velocity (x,y,z)");
318 *wWt = strlen("Weights (a1,a2,a3)");
319
320 for (PetscInt i = 0; i < nParticles; i++) {
321 /* Rank */
322 IntToStr(ranks[i], tmp, TMP_BUF_SIZE);
323 if ((int)strlen(tmp) > *wRank) *wRank = (int)strlen(tmp);
324
325 /* PID */
326 Int64ToStr(pids[i], tmp, TMP_BUF_SIZE);
327 if ((int)strlen(tmp) > *wPID) *wPID = (int)strlen(tmp);
328
329 /* Cell: use the three consecutive values */
330 CellToStr(&cellIDs[3 * i], tmp, TMP_BUF_SIZE);
331 if ((int)strlen(tmp) > *wCell) *wCell = (int)strlen(tmp);
332
333 /* Position */
334 TripleRealToStr(&positions[3 * i], tmp, TMP_BUF_SIZE);
335 if ((int)strlen(tmp) > *wPos) *wPos = (int)strlen(tmp);
336
337 /* Velocity */
338 TripleRealToStr(&velocities[3 * i], tmp, TMP_BUF_SIZE);
339 if ((int)strlen(tmp) > *wVel) *wVel = (int)strlen(tmp);
340
341 /* Weights */
342 TripleRealToStr(&weights[3 * i], tmp, TMP_BUF_SIZE);
343 if ((int)strlen(tmp) > *wWt) *wWt = (int)strlen(tmp);
344 }
345 return 0;
346}
#define TMP_BUF_SIZE
Definition logging.c:5
static void CellToStr(const PetscInt *cell, char *buf, size_t bufsize)
Definition logging.c:268
static void TripleRealToStr(const PetscReal *arr, char *buf, size_t bufsize)
Definition logging.c:276
static void Int64ToStr(PetscInt64 value, char *buf, size_t bufsize)
Definition logging.c:260
static void IntToStr(int value, char *buf, size_t bufsize)
Definition logging.c:252
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BuildRowFormatString()

static void BuildRowFormatString ( PetscMPIInt  wRank,
PetscInt  wPID,
PetscInt  wCell,
PetscInt  wPos,
PetscInt  wVel,
PetscInt  wWt,
char *  fmtStr,
size_t  bufSize 
)
static

Definition at line 365 of file logging.c.

366{
367 // Build a format string using snprintf.
368 // We assume that the Rank is an int (%d), PID is a 64-bit int (%ld)
369 // and the remaining columns are strings (which have been formatted already).
370 snprintf(fmtStr, bufSize,
371 "| %%-%dd | %%-%dd | %%-%ds | %%-%ds | %%-%ds | %%-%ds |\n",
372 wRank, wPID, wCell, wPos, wVel, wWt);
373}
Here is the caller graph for this function:

◆ BuildHeaderString()

static void BuildHeaderString ( char *  headerStr,
size_t  bufSize,
PetscMPIInt  wRank,
PetscInt  wPID,
PetscInt  wCell,
PetscInt  wPos,
PetscInt  wVel,
PetscInt  wWt 
)
static

Definition at line 378 of file logging.c.

379{
380 snprintf(headerStr, bufSize,
381 "| %-*s | %-*s | %-*s | %-*s | %-*s | %-*s |\n",
382 (int)wRank, "Rank",
383 (int)wPID, "PID",
384 (int)wCell, "Cell (i,j,k)",
385 (int)wPos, "Position (x,y,z)",
386 (int)wVel, "Velocity (x,y,z)",
387 (int)wWt, "Weights (a1,a2,a3)");
388}
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.

Definition at line 402 of file logging.c.

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

◆ trim()

static void trim ( char *  s)
static

Definition at line 524 of file logging.c.

525{
526 if (!s) return;
527
528 /* ---- 1. strip leading blanks ----------------------------------- */
529 char *p = s;
530 while (*p && isspace((unsigned char)*p))
531 ++p;
532
533 if (p != s) /* move the trimmed text forward */
534 memmove(s, p, strlen(p) + 1); /* +1 to copy the final NUL */
535
536 /* ---- 2. strip trailing blanks ---------------------------------- */
537 size_t len = strlen(s);
538 while (len > 0 && isspace((unsigned char)s[len - 1]))
539 s[--len] = '\0';
540}
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)
Definition picsolver.c:24

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).

Definition at line 568 of file logging.c.

571{
572 FILE *fp = NULL;
573 char **funcs = NULL;
574 size_t cap = 16; /* initial capacity */
575 size_t n = 0; /* number of names */
576 char line[PETSC_MAX_PATH_LEN];
577 PetscErrorCode ierr;
578
579 PetscFunctionBegin;
580
581 /* ---------------------------------------------------------------------- */
582 /* 1. Open file */
583 fp = fopen(filename, "r");
584 if (!fp) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
585 "Cannot open %s", filename);
586
587 /* 2. Allocate initial pointer array */
588 ierr = PetscMalloc1(cap, &funcs); CHKERRQ(ierr);
589
590 /* 3. Read file line by line */
591 while (fgets(line, sizeof line, fp)) {
592 /* Strip everything after a comment character '#'. */
593 char *hash = strchr(line, '#');
594 if (hash) *hash = '\0';
595
596 trim(line); /* remove leading/trailing blanks */
597 if (!*line) continue; /* skip if empty */
598
599 /* Grow the array if necessary */
600 if (n == cap) {
601 cap *= 2;
602 ierr = PetscRealloc(cap * sizeof(*funcs), (void **)&funcs); CHKERRQ(ierr);
603 }
604
605 /* Deep‑copy the cleaned identifier */
606 ierr = PetscStrallocpy(line, &funcs[n++]); CHKERRQ(ierr);
607 }
608 fclose(fp);
609
610 /* 4. Return results to caller */
611 *funcsOut = funcs;
612 *nOut = (PetscInt)n;
613
614 PetscFunctionReturn(0);
615}
static void trim(char *s)
Definition logging.c:524
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.

Definition at line 627 of file logging.c.

628{
629 PetscErrorCode ierr;
630 PetscFunctionBegin;
631 if (funcs) {
632 for (PetscInt i = 0; i < n; ++i) {
633 ierr = PetscFree(funcs[i]); CHKERRQ(ierr);
634 }
635 ierr = PetscFree(funcs); CHKERRQ(ierr);
636 }
637 PetscFunctionReturn(0);
638}

◆ 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.

Definition at line 645 of file logging.c.

645 {
646 switch (face) {
647 case BC_FACE_NEG_X: return "-Xi (I-Min)";
648 case BC_FACE_POS_X: return "+Xi (I-Max)";
649 case BC_FACE_NEG_Y: return "-Eta (J-Min)";
650 case BC_FACE_POS_Y: return "+Eta (J-Max)";
651 case BC_FACE_NEG_Z: return "-Zeta (K-Min)";
652 case BC_FACE_POS_Z: return "+Zeta (K-Max)";
653 default: return "Unknown Face";
654 }
655}
@ BC_FACE_NEG_X
Definition variables.h:200
@ BC_FACE_POS_Z
Definition variables.h:202
@ BC_FACE_POS_Y
Definition variables.h:201
@ BC_FACE_NEG_Z
Definition variables.h:202
@ BC_FACE_POS_X
Definition variables.h:200
@ BC_FACE_NEG_Y
Definition variables.h:201
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.

Definition at line 662 of file logging.c.

662 {
663 switch (type) {
664 // case DIRICHLET: return "DIRICHLET";
665 // case NEUMANN: return "NEUMANN";
666 case WALL: return "WALL";
667 case INLET: return "INLET";
668 case OUTLET: return "OUTLET";
669 case FARFIELD: return "FARFIELD";
670 case PERIODIC: return "PERIODIC";
671 case INTERFACE: return "INTERFACE";
672 case NOGRAD: return "NOGRAD";
673
674 // case CUSTOM: return "CUSTOM";
675 default: return "Unknown BC Type";
676 }
677}
@ INLET
Definition variables.h:210
@ NOGRAD
Definition variables.h:216
@ INTERFACE
Definition variables.h:208
@ FARFIELD
Definition variables.h:211
@ OUTLET
Definition variables.h:211
@ PERIODIC
Definition variables.h:211
@ WALL
Definition variables.h:209
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.

Definition at line 689 of file logging.c.

689 {
690 switch (handler_type) {
691 // Wall & Symmetry Handlers
692 case BC_HANDLER_WALL_NOSLIP: return "noslip";
693 case BC_HANDLER_WALL_MOVING: return "moving";
694 case BC_HANDLER_SYMMETRY_PLANE: return "symmetry_plane";
695
696 // Inlet Handlers
697 case BC_HANDLER_INLET_CONSTANT_VELOCITY: return "constant_velocity";
698 case BC_HANDLER_INLET_PULSANTILE_FLUX: return "pulsatile_flux";
699 case BC_HANDLER_INLET_PARABOLIC: return "parabolic";
700
701 // Outlet Handlers
702 case BC_HANDLER_OUTLET_CONSERVATION: return "conservation";
703 case BC_HANDLER_OUTLET_PRESSURE: return "pressure";
704
705 // Other Physical Handlers
706 case BC_HANDLER_FARFIELD_NONREFLECTING: return "nonreflecting";
707 case BC_HANDLER_NOGRAD_COPY_GHOST: return "no_gradient";
708
709 // Multi-Block / Interface Handlers
710 case BC_HANDLER_PERIODIC: return "periodic";
711 case BC_HANDLER_INTERFACE_OVERSET: return "overset";
712
713 // Default case
715 default: return "UNKNOWN_HANDLER";
716 }
717}
@ BC_HANDLER_INLET_PULSANTILE_FLUX
Definition variables.h:224
@ BC_HANDLER_INLET_PARABOLIC
Definition variables.h:223
@ BC_HANDLER_INLET_CONSTANT_VELOCITY
Definition variables.h:224
@ BC_HANDLER_INTERFACE_OVERSET
Definition variables.h:227
@ BC_HANDLER_WALL_MOVING
Definition variables.h:222
@ BC_HANDLER_NOGRAD_COPY_GHOST
Definition variables.h:221
@ BC_HANDLER_WALL_NOSLIP
Definition variables.h:222
@ BC_HANDLER_OUTLET_CONSERVATION
Definition variables.h:225
@ BC_HANDLER_PERIODIC
Definition variables.h:227
@ BC_HANDLER_FARFIELD_NONREFLECTING
Definition variables.h:226
@ BC_HANDLER_OUTLET_PRESSURE
Definition variables.h:225
@ BC_HANDLER_SYMMETRY_PLANE
Definition variables.h:223
@ BC_HANDLER_UNDEFINED
Definition variables.h:221
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

Definition at line 727 of file logging.c.

728{
729 DualMonitorCtx *monctx = (DualMonitorCtx*)*ctx;
730 PetscErrorCode ierr;
731 PetscMPIInt rank;
732
733 PetscFunctionBeginUser;
734 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
735 if(!rank && monctx->file_handle){
736 fclose(monctx->file_handle);
737 }
738
739 ierr = PetscFree(monctx); CHKERRQ(ierr);
740 *ctx = NULL;
741 PetscFunctionReturn(0);
742}
FILE * file_handle
Definition logging.h:64
Context for a dual-purpose KSP monitor.
Definition logging.h:63
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.

Definition at line 759 of file logging.c.

760{
761 DualMonitorCtx *monctx = (DualMonitorCtx*)ctx;
762 PetscErrorCode ierr;
763 PetscReal trnorm, relnorm;
764 Vec r;
765 char norm_buf[256];
766 PetscMPIInt rank;
767
768 PetscFunctionBeginUser;
769 ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank); CHKERRQ(ierr);
770
771 // 1. Calculate the true residual norm.
772 ierr = KSPBuildResidual(ksp, NULL, NULL, &r); CHKERRQ(ierr);
773 ierr = VecNorm(r, NORM_2, &trnorm); CHKERRQ(ierr);
774
775 // 2. On the first iteration, compute and store the norm of the RHS vector `b`.
776 if (it == 0) {
777 Vec b;
778 ierr = KSPGetRhs(ksp, &b); CHKERRQ(ierr);
779 ierr = VecNorm(b, NORM_2, &monctx->bnorm); CHKERRQ(ierr);
780 }
781
782 if(!rank){
783 // 3. Compute the relative norm and format the output string.
784 if (monctx->bnorm > 1.e-15) {
785 relnorm = trnorm / monctx->bnorm;
786 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);
787 } else {
788 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);
789 }
790
791 // 4. Log to the file viewer (unconditionally).
792 if(monctx->file_handle){
793 ierr = PetscFPrintf(PETSC_COMM_SELF,monctx->file_handle,"%s\n", norm_buf); CHKERRQ(ierr);
794 }
795 // 5. Log to the console (conditionally).
796 if (monctx->log_to_console) {
797 PetscFPrintf(PETSC_COMM_SELF,stdout, "%s\n", norm_buf); CHKERRQ(ierr);
798 }
799
800 } //rank
801
802 PetscFunctionReturn(0);
803}
PetscBool log_to_console
Definition logging.h:65
PetscReal bnorm
Definition logging.h:66
PetscInt step
Definition logging.h:67
PetscInt block_id
Definition logging.h:68
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.

Definition at line 819 of file logging.c.

820{
821 PetscErrorCode ierr;
822 PetscMPIInt rank;
823 SimCtx *simCtx = user->simCtx; // Get the shared SimCtx
824 const PetscInt bi = user->_this; // Get this block's specific ID
825 const PetscInt ti = simCtx->step; // Get the current timestep
826
827 PetscFunctionBeginUser;
828 ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
829
830 // Only rank 0 performs file I/O.
831 if (!rank) {
832 FILE *f;
833 char filen[128];
834 sprintf(filen, "logs/Continuity_Metrics.log");
835
836 // Open the log file in append mode.
837 f = fopen(filen, "a");
838 if (!f) {
839 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Cannot open log file: %s", filen);
840 }
841
842 // Write a header only for the very first block (bi=0) on the very
843 // first timestep (ti=StartStep). This ensures it's written only once.
844 if (ti == simCtx->StartStep && bi == 0) {
845 PetscFPrintf(PETSC_COMM_SELF, f, "%-10s | %-6s | %-18s | %-30s | %-18s | %-18s | %-18s | %-18s\n",
846 "Timestep", "Block", "Max Divergence", "Max Divergence Location ([k][j][i]=idx)", "Sum(RHS)","Total Flux In", "Total Flux Out", "Net Flux");
847 PetscFPrintf(PETSC_COMM_SELF, f, "------------------------------------------------------------------------------------------------------------------------------------------\n");
848 }
849
850 // Prepare the data strings and values for the current block.
851 PetscReal net_flux = simCtx->FluxInSum - simCtx->FluxOutSum;
852 char location_str[64];
853 sprintf(location_str, "([%d][%d][%d] = %d)", (int)simCtx->MaxDivz, (int)simCtx->MaxDivy, (int)simCtx->MaxDivx, (int)simCtx->MaxDivFlatArg);
854
855 // Write the formatted line for the current block.
856 PetscFPrintf(PETSC_COMM_SELF, f, "%-10d | %-6d | %-18.10e | %-39s | %-18.10e | %-18.10e | %-18.10e | %-18.10e\n",
857 (int)ti,
858 (int)bi,
859 (double)simCtx->MaxDiv,
860 location_str,
861 (double)simCtx->summationRHS,
862 (double)simCtx->FluxInSum,
863 (double)simCtx->FluxOutSum,
864 (double)net_flux);
865
866 fclose(f);
867 }
868
869 PetscFunctionReturn(0);
870}
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:633
PetscReal FluxOutSum
Definition variables.h:571
PetscInt _this
Definition variables.h:643
PetscInt StartStep
Definition variables.h:523
PetscReal MaxDiv
Definition variables.h:606
PetscInt MaxDivx
Definition variables.h:607
PetscInt MaxDivy
Definition variables.h:607
PetscInt MaxDivz
Definition variables.h:607
PetscInt MaxDivFlatArg
Definition variables.h:607
PetscReal FluxInSum
Definition variables.h:571
PetscInt step
Definition variables.h:521
PetscReal summationRHS
Definition variables.h:605
The master context for the entire simulation.
Definition variables.h:513
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.

Definition at line 878 of file logging.c.

879{
880 switch (level) {
881 case NEEDS_LOCATION: return "NEEDS_LOCATION";
882 case ACTIVE_AND_LOCATED: return "ACTIVE_AND_LOCATED";
883 case MIGRATING_OUT: return "MIGRATING_OUT";
884 case LOST: return "LOST";
885 case UNINITIALIZED: return "UNINITIALIZED";
886 default: return "UNKNOWN_LEVEL";
887 }
888}
@ LOST
Definition variables.h:138
@ NEEDS_LOCATION
Definition variables.h:135
@ ACTIVE_AND_LOCATED
Definition variables.h:136
@ UNINITIALIZED
Definition variables.h:139
@ MIGRATING_OUT
Definition variables.h:137

◆ _FindOrCreateEntry()

static PetscErrorCode _FindOrCreateEntry ( const char *  func_name,
PetscInt *  idx 
)
static

Definition at line 909 of file logging.c.

910{
911 PetscFunctionBeginUser;
912 // Search for existing entry
913 for (PetscInt i = 0; i < g_profiler_count; ++i) {
914 if (strcmp(g_profiler_registry[i].name, func_name) == 0) {
915 *idx = i;
916 PetscFunctionReturn(0);
917 }
918 }
919
920 // Not found, create a new entry
922 PetscInt new_capacity = g_profiler_capacity == 0 ? 16 : g_profiler_capacity * 2;
923 PetscErrorCode ierr = PetscRealloc(sizeof(ProfiledFunction) * new_capacity, &g_profiler_registry); CHKERRQ(ierr);
924 g_profiler_capacity = new_capacity;
925 }
926
927 *idx = g_profiler_count;
928 g_profiler_registry[*idx].name = func_name;
934 g_profiler_registry[*idx].always_log = PETSC_FALSE;
936
937 PetscFunctionReturn(0);
938}
PetscBool always_log
Definition logging.c:900
static PetscInt g_profiler_count
Definition logging.c:905
long long total_call_count
Definition logging.c:897
static PetscInt g_profiler_capacity
Definition logging.c:906
double total_time
Definition logging.c:895
double current_step_time
Definition logging.c:896
long long current_step_call_count
Definition logging.c:898
static ProfiledFunction * g_profiler_registry
Definition logging.c:904
double start_time
Definition logging.c:899
const char * name
Definition logging.c:894
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

Definition at line 955 of file logging.c.

956{
957 PetscFunctionBeginUser;
958 if (!simCtx) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "SimCtx cannot be null for ProfilingInitialize");
959
960 // Iterate through the list of critical functions provided in SimCtx
961 for (PetscInt i = 0; i < simCtx->nCriticalFuncs; ++i) {
962 PetscInt idx;
963 const char *func_name = simCtx->criticalFuncs[i];
964 PetscErrorCode ierr = _FindOrCreateEntry(func_name, &idx); CHKERRQ(ierr);
965 g_profiler_registry[idx].always_log = PETSC_TRUE;
966
967 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Marked '%s' as a critical function for profiling.\n", func_name);
968 }
969 PetscFunctionReturn(0);
970}
static PetscErrorCode _FindOrCreateEntry(const char *func_name, PetscInt *idx)
Definition logging.c:909
char ** criticalFuncs
Definition variables.h:611
PetscInt nCriticalFuncs
Definition variables.h:612
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _ProfilingStart()

void _ProfilingStart ( const char *  func_name)

Definition at line 972 of file logging.c.

973{
974 PetscInt idx;
975 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
976 PetscTime(&g_profiler_registry[idx].start_time);
977}
Here is the call graph for this function:

◆ _ProfilingEnd()

void _ProfilingEnd ( const char *  func_name)

Definition at line 979 of file logging.c.

980{
981 double end_time;
982 PetscTime(&end_time);
983
984 PetscInt idx;
985 if (_FindOrCreateEntry(func_name, &idx) != 0) return; // Fail silently
986
987 double elapsed = end_time - g_profiler_registry[idx].start_time;
988 g_profiler_registry[idx].total_time += elapsed;
992}
Here is the call graph for this function:

◆ ProfilingLogTimestepSummary()

PetscErrorCode ProfilingLogTimestepSummary ( PetscInt  step)

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

Depending on the current log level, this function will print:

  • LOG_PROFILE: Timings for ALL functions called during the step.
  • LOG_INFO/LOG_DEBUG: Timings for only the "always log" functions.

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
stepThe current simulation step number, for logging context.
Returns
PetscErrorCode

Definition at line 994 of file logging.c.

995{
996 LogLevel log_level = get_log_level();
997 PetscBool should_print = PETSC_FALSE;
998
999 PetscFunctionBeginUser;
1000
1001 // Decide if we should print anything at all
1002 if (log_level >= LOG_INFO) {
1003 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1004 if (g_profiler_registry[i].current_step_call_count > 0) {
1005 if (log_level == LOG_PROFILE || g_profiler_registry[i].always_log) {
1006 should_print = PETSC_TRUE;
1007 break;
1008 }
1009 }
1010 }
1011 }
1012
1013 if (should_print) {
1014 PetscPrintf(MPI_COMM_WORLD, "[PROFILE] ----- Timestep %d Summary -----\n", step);
1015 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1016 if (g_profiler_registry[i].current_step_call_count > 0) {
1017 if (log_level == LOG_PROFILE || g_profiler_registry[i].always_log) {
1018 PetscPrintf(MPI_COMM_WORLD, "[PROFILE] %-25s: %.6f s (%lld calls)\n",
1019 g_profiler_registry[i].name,
1020 g_profiler_registry[i].current_step_time,
1021 g_profiler_registry[i].current_step_call_count);
1022 }
1023 }
1024 }
1025 }
1026
1027 // Reset per-step counters for the next iteration
1028 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1031 }
1032 PetscFunctionReturn(0);
1033}
LogLevel
Enumeration of logging levels.
Definition logging.h:28
Here is the call graph for this function:

◆ _CompareProfiledFunctions()

static int _CompareProfiledFunctions ( const void *  a,
const void *  b 
)
static

Definition at line 1036 of file logging.c.

1037{
1038 const ProfiledFunction *func_a = (const ProfiledFunction *)a;
1039 const ProfiledFunction *func_b = (const ProfiledFunction *)b;
1040
1041 if (func_a->total_time < func_b->total_time) return 1;
1042 if (func_a->total_time > func_b->total_time) return -1;
1043 return 0;
1044}
Here is the caller graph for this function:

◆ ProfilingFinalize()

PetscErrorCode ProfilingFinalize ( void  )

Prints the final, cumulative performance summary and cleans up resources.

This should be called once at the end of the simulation, before PetscFinalize(). It prints a table with total time, call count, and average time per call for every function that was profiled. This summary is only printed if the log level is LOG_PROFILE.

Returns
PetscErrorCode

Definition at line 1046 of file logging.c.

1047{
1048 PetscFunctionBeginUser;
1049 if (get_log_level() >= LOG_PROFILE) {
1050
1051 // --- Step 1: Sort the data for readability ---
1053
1054 // --- Step 2: Dynamically determine the width for the function name column ---
1055 PetscInt max_name_len = strlen("Function"); // Start with the header's length
1056 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1057 if (g_profiler_registry[i].total_call_count > 0) {
1058 PetscInt len = strlen(g_profiler_registry[i].name);
1059 if (len > max_name_len) {
1060 max_name_len = len;
1061 }
1062 }
1063 }
1064 // Add a little padding
1065 max_name_len += 2;
1066
1067 // --- Step 3: Define fixed widths for numeric columns for consistent alignment ---
1068 const int time_width = 18;
1069 const int count_width = 15;
1070 const int avg_width = 22;
1071
1072 // --- Step 4: Print the formatted table ---
1073 PetscPrintf(MPI_COMM_WORLD, "\n=======================================================================================\n");
1074 PetscPrintf(MPI_COMM_WORLD, " FINAL PROFILING SUMMARY (Sorted by Total Time)\n");
1075 PetscPrintf(MPI_COMM_WORLD, "=======================================================================================\n");
1076
1077 // Header Row
1078 PetscPrintf(MPI_COMM_WORLD, "%-*s | %-*s | %-*s | %-*s\n",
1079 max_name_len, "Function",
1080 time_width, "Total Time (s)",
1081 count_width, "Call Count",
1082 avg_width, "Avg. Time/Call (ms)");
1083
1084 // Separator Line (dynamically sized)
1085 for (int i = 0; i < max_name_len; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1086 PetscPrintf(MPI_COMM_WORLD, "-|-");
1087 for (int i = 0; i < time_width; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1088 PetscPrintf(MPI_COMM_WORLD, "-|-");
1089 for (int i = 0; i < count_width; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1090 PetscPrintf(MPI_COMM_WORLD, "-|-");
1091 for (int i = 0; i < avg_width; i++) PetscPrintf(MPI_COMM_WORLD, "-");
1092 PetscPrintf(MPI_COMM_WORLD, "\n");
1093
1094 // Data Rows
1095 for (PetscInt i = 0; i < g_profiler_count; ++i) {
1096 if (g_profiler_registry[i].total_call_count > 0) {
1097 double avg_time_ms = (g_profiler_registry[i].total_time / g_profiler_registry[i].total_call_count) * 1000.0;
1098 PetscPrintf(MPI_COMM_WORLD, "%-*s | %*.*f | %*lld | %*.*f\n",
1099 max_name_len, g_profiler_registry[i].name,
1100 time_width, 6, g_profiler_registry[i].total_time,
1101 count_width, g_profiler_registry[i].total_call_count,
1102 avg_width, 6, avg_time_ms);
1103 }
1104 }
1105 PetscPrintf(MPI_COMM_WORLD, "=======================================================================================\n");
1106 }
1107
1108 // --- Final Cleanup ---
1109 PetscFree(g_profiler_registry);
1110 g_profiler_registry = NULL;
1111 g_profiler_count = 0;
1113 PetscFunctionReturn(0);
1114}
static int _CompareProfiledFunctions(const void *a, const void *b)
Definition logging.c:1036
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ current_log_level

LogLevel current_log_level = -1
static

Static variable to cache the current logging level.

Initialized to -1 to indicate that the log level has not been set yet.

Definition at line 14 of file logging.c.

◆ gAllowedFunctions

char** gAllowedFunctions = NULL
static

Global/static array of function names allowed to log.

Definition at line 21 of file logging.c.

◆ gNumAllowed

int gNumAllowed = 0
static

Number of entries in the gAllowedFunctions array.

Definition at line 26 of file logging.c.

◆ EVENT_Individualwalkingsearch

PetscLogEvent EVENT_Individualwalkingsearch = 0

Definition at line 33 of file logging.c.

◆ EVENT_walkingsearch

PetscLogEvent EVENT_walkingsearch = 0

Definition at line 34 of file logging.c.

◆ EVENT_GlobalParticleLocation

PetscLogEvent EVENT_GlobalParticleLocation = 0

Definition at line 35 of file logging.c.

◆ EVENT_IndividualLocation

PetscLogEvent EVENT_IndividualLocation = 0

Definition at line 36 of file logging.c.

◆ g_profiler_registry

ProfiledFunction* g_profiler_registry = NULL
static

Definition at line 904 of file logging.c.

◆ g_profiler_count

PetscInt g_profiler_count = 0
static

Definition at line 905 of file logging.c.

◆ g_profiler_capacity

PetscInt g_profiler_capacity = 0
static

Definition at line 906 of file logging.c.