13#define __FUNCT__ "SetupPostProcessSwarm"
21 PetscFunctionBeginUser;
23 char *pipeline_copy, *step_token, *step_saveptr;
24 PetscBool finalize_needed = PETSC_FALSE;
26 ierr = DMCreate(PETSC_COMM_WORLD, &user->
post_swarm); CHKERRQ(ierr);
27 ierr = DMSetType(user->
post_swarm, DMSWARM); CHKERRQ(ierr);
28 ierr = DMSetDimension(user->
post_swarm, 3); CHKERRQ(ierr);
29 ierr = DMSwarmSetType(user->
post_swarm, DMSWARM_BASIC); CHKERRQ(ierr);
32 ierr = DMSwarmSetCellDM(user->
post_swarm, user->
da); CHKERRQ(ierr);
45 step_token = strtok_r(pipeline_copy,
";", &step_saveptr);
48 if (strlen(step_token) == 0) { step_token = strtok_r(NULL,
";", &step_saveptr);
continue; }
50 char *keyword = strtok(step_token,
":");
51 char *args_str = strtok(NULL,
"");
53 PetscInt output_field_dimensions = 1;
55 if (strcasecmp(keyword,
"ComputeSpecificKE") == 0) {
56 if (!args_str) SETERRQ(PETSC_COMM_SELF, 1,
"Error (ComputeSpecificKE): Missing arguments.");
57 char *input_field = strtok(args_str,
">");
58 char *output_field = strtok(NULL,
">");
59 output_field_dimensions = 1;
60 if (!input_field) SETERRQ(PETSC_COMM_SELF, 1,
"Error (ComputeSpecificKE): Missing input field in 'in>out' syntax.");
61 if (!output_field) SETERRQ(PETSC_COMM_SELF, 1,
"Error (ComputeSpecificKE): Missing output field in 'in>out' syntax.");
64 if (strlen(input_field) == 0) SETERRQ(PETSC_COMM_SELF, 1,
"Error (ComputeSpecificKE): Empty input field name.");
65 if (strlen(output_field) == 0) SETERRQ(PETSC_COMM_SELF, 1,
"Error (ComputeSpecificKE): Empty output field name.");
68 LOG_ALLOW(
GLOBAL,
LOG_INFO,
"Registered particle field '%s' (ComputeSpecificKE input='%s').\n", output_field, input_field);
69 finalize_needed = PETSC_TRUE;
76 step_token = strtok_r(NULL,
";", &step_saveptr);
79 ierr = PetscFree(pipeline_copy); CHKERRQ(ierr);
82 if (finalize_needed) {
85 LOG_ALLOW(
GLOBAL,
LOG_INFO,
"No custom particle fields requested; finalizing an empty post-processing swarm for safe use.\n");
87 ierr = DMSwarmFinalizeFieldRegister(user->
post_swarm); CHKERRQ(ierr);
92 PetscFunctionReturn(0);
97#define __FUNCT__ "EulerianDataProcessingPipeline"
107 char *pipeline_copy, *step_token, *step_saveptr;
109 PetscFunctionBeginUser;
116 PetscFunctionReturn(0);
122 ierr = PetscStrallocpy(pps->
process_pipeline, &pipeline_copy); CHKERRQ(ierr);
125 step_token = strtok_r(pipeline_copy,
";", &step_saveptr);
128 if (strlen(step_token) == 0) {
129 step_token = strtok_r(NULL,
";", &step_saveptr);
133 char *keyword = strtok(step_token,
":");
134 char *args_str = strtok(NULL,
"");
137 step_token = strtok_r(NULL,
";", &step_saveptr);
144 LOG_ALLOW(
GLOBAL,
LOG_INFO,
"Executing Transformation: '%s' on args: '%s'\n", keyword, args_str ? args_str :
"None");
147 if (strcasecmp(keyword,
"CellToNodeAverage") == 0) {
148 if (!args_str) SETERRQ(PETSC_COMM_SELF, 1,
"CellToNodeAverage requires arguments in 'in_field>out_field' format.");
149 char *in_field = strtok(args_str,
">");
150 char *out_field = strtok(NULL,
">");
151 if (!in_field || !out_field) SETERRQ(PETSC_COMM_SELF, 1,
"CellToNodeAverage requires 'in>out' syntax (e.g., P>P_nodal).");
152 if(strcmp(in_field,out_field)==0) SETERRQ(PETSC_COMM_SELF, 1,
"CellToNodeAverage input and output fields must be different.");
153 if(user->
simCtx->
np == 0 && (strcmp(out_field,
"Psi_nodal")==0 || strcmp(in_field,
"Psi_nodal")==0)){
154 LOG(
GLOBAL,
LOG_WARNING,
"CellToNodeAverage cannot process 'Psi_nodal' when no particles are present in the simulation.\n");
155 step_token = strtok_r(NULL,
";", &step_saveptr);
161 else if (strcasecmp(keyword,
"ComputeQCriterion") == 0) {
164 else if (strcasecmp(keyword,
"NormalizeRelativeField") == 0) {
165 if (!args_str) SETERRQ(PETSC_COMM_SELF, 1,
"NormalizePressure requires the pressure field name (e.g., 'P') as an argument.");
174 step_token = strtok_r(NULL,
";", &step_saveptr);
177 ierr = PetscFree(pipeline_copy); CHKERRQ(ierr);
180 PetscFunctionReturn(0);
185#define __FUNCT__ "WriteEulerianFile"
198 PetscFunctionBeginUser;
202 LOG_ALLOW(
GLOBAL,
LOG_DEBUG,
"No instantaneous fields requested for output at ti=%" PetscInt_FMT
". Skipping.\n", ti);
203 PetscFunctionReturn(0);
209 ierr = PetscMemzero(&meta,
sizeof(
VTKMetaData)); CHKERRQ(ierr);
214 LOG_ALLOW(
GLOBAL,
LOG_DEBUG,
"Using coords linearization order: fast=i mid=j slow=k (sizes: %" PetscInt_FMT
" x %" PetscInt_FMT
" x %" PetscInt_FMT
")\n",
215 meta.
mx, meta.
my, meta.
mz);
219 char *fields_copy, *field_name;
222 field_name = strtok(fields_copy,
",");
225 if (!*field_name) { field_name = strtok(NULL,
",");
continue; }
229 Vec field_vec = NULL;
230 PetscInt num_components = 0;
232 if (!strcasecmp(field_name,
"P_nodal")) {
233 field_vec = user->
P_nodal; num_components = 1;
234 }
else if (!strcasecmp(field_name,
"Ucat_nodal")) {
235 field_vec = user->
Ucat_nodal; num_components = 3;
236 }
else if (!strcasecmp(field_name,
"Qcrit")) {
237 field_vec = user->
Qcrit; num_components = 1;
238 }
else if (!strcasecmp(field_name,
"Psi_nodal")){
241 field_name = strtok(NULL,
",");
244 field_vec = user->
Psi_nodal; num_components = 1;
247 field_name = strtok(NULL,
",");
253 field_name = strtok(NULL,
",");
400 field_name = strtok(NULL,
",");
403 ierr = PetscFree(fields_copy); CHKERRQ(ierr);
469 ierr = PetscSNPrintf(filename,
sizeof(filename),
"%s_%05" PetscInt_FMT
".vts", pps->
output_prefix, ti); CHKERRQ(ierr);
474 PetscFunctionReturn(0);
479#define __FUNCT__ "ParticleDataProcessingPipeline"
489 char *pipeline_copy, *step_token, *step_saveptr;
491 PetscFunctionBeginUser;
496 PetscFunctionReturn(0);
500 PetscInt n_global_source;
501 ierr = DMSwarmGetSize(user->
swarm, &n_global_source); CHKERRQ(ierr);
511 step_token = strtok_r(pipeline_copy,
";", &step_saveptr);
514 if (strlen(step_token) == 0) { step_token = strtok_r(NULL,
";", &step_saveptr);
continue; }
516 char *keyword = strtok(step_token,
":");
517 char *args_str = strtok(NULL,
"");
521 LOG_ALLOW(
GLOBAL,
LOG_INFO,
"Executing Particle Transformation: '%s' on args: '%s'\n", keyword, args_str ? args_str :
"None");
523 if (strcasecmp(keyword,
"ComputeSpecificKE") == 0) {
524 if (!args_str) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
"ComputeSpecificKE requires 'input_field>output_field' arguments.");
525 char *velocity_field = strtok(args_str,
">");
526 char *ske_field = strtok(NULL,
">");
527 if (!velocity_field || !ske_field) {
528 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"ComputeSpecificKE requires 'input_field>output_field' arguments.");
531 if (strlen(velocity_field) == 0 || strlen(ske_field) == 0) {
532 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
"ComputeSpecificKE does not allow empty input/output field names.");
541 step_token = strtok_r(NULL,
";", &step_saveptr);
543 ierr = PetscFree(pipeline_copy); CHKERRQ(ierr);
548 PetscFunctionReturn(0);
552#define __FUNCT__ "GlobalStatisticsPipeline"
560 char *pipeline_copy, *step_token, *step_saveptr;
562 PetscFunctionBeginUser;
567 ierr = DMSwarmGetSize(user->
swarm, &n_global); CHKERRQ(ierr);
568 if (n_global == 0) PetscFunctionReturn(0);
573 step_token = strtok_r(pipeline_copy,
";", &step_saveptr);
576 if (strlen(step_token) == 0) {
577 step_token = strtok_r(NULL,
";", &step_saveptr);
continue;
579 char *keyword = strtok(step_token,
":");
582 if (strcasecmp(keyword,
"ComputeMSD") == 0) {
586 "Unknown statistics keyword '%s'. Skipping.\n", keyword);
590 step_token = strtok_r(NULL,
";", &step_saveptr);
592 ierr = PetscFree(pipeline_copy); CHKERRQ(ierr);
595 PetscFunctionReturn(0);
599#define __FUNCT__ "WriteParticleFile"
611 PetscInt n_total_particles_before_subsample;
613 PetscFunctionBeginUser;
618 PetscFunctionReturn(0);
621 ierr = DMSwarmGetSize(user->
swarm, &n_global); CHKERRQ(ierr);
624 PetscFunctionReturn(0);
627 ierr = PetscMemzero(&part_meta,
sizeof(
VTKMetaData)); CHKERRQ(ierr);
635 LOG_ALLOW(
GLOBAL,
LOG_INFO,
"--- Starting VTP Particle File Writing for ti = %" PetscInt_FMT
" (writing %" PetscInt_FMT
" of %" PetscInt_FMT
" particles) ---\n",
636 ti, part_meta.
npoints, n_total_particles_before_subsample);
645 ierr = PetscSNPrintf(filename,
sizeof(filename),
"%s_%05" PetscInt_FMT
".vtp", pps->
particle_output_prefix, ti); CHKERRQ(ierr);
656 PetscFunctionReturn(0);
660#define __FUNCT__ "main"
661#ifndef PICURV_POSTPROCESSOR_NO_MAIN
673 ierr = PetscInitialize(&argc, &argv, (
char *)0,
"Unified Post-Processing Tool"); CHKERRQ(ierr);
694 if(needs_particle_stage) {
700 SETERRQ(PETSC_COMM_SELF,1,
701 "Particle post-processing requested (particle output or statistics pipeline) but np=0. "
702 "Please set np>0 during solver run to enable particle post-processing.");
722 if(needs_particle_stage) {
741 if(simCtx->
rank == 0){
743 PetscReal currentTime = (PetscReal)ti*simCtx->
dt;
751 if (simCtx->
rank == 0) {
752 PetscInt endTime = pps->
endTime-1;
754 PetscReal endTimeValue = (PetscReal)pps->
endTime*simCtx->
dt;
756 PetscPrintf(PETSC_COMM_SELF,
"\n");
767 ierr = PetscFinalize();
PetscErrorCode ResizeSwarmGlobally(DM swarm, PetscInt N_target)
Resizes a swarm collectively to a target global particle count.
PetscErrorCode PreCheckAndResizeSwarm(UserCtx *user, PetscInt ti, const char *ext)
Checks particle count in the reference file and resizes the swarm if needed.
PetscErrorCode InitializeParticleSwarm(SimCtx *simCtx)
High-level particle initialization orchestrator for a simulation run.
PetscErrorCode RegisterSwarmField(DM swarm, const char *fieldName, PetscInt fieldDim, PetscDataType dtype)
Registers a swarm field without finalizing registration.
PetscErrorCode ReadSimulationFields(UserCtx *user, PetscInt ti)
Reads binary field data for velocity, pressure, and other required vectors.
void TrimWhitespace(char *str)
Helper function to trim leading/trailing whitespace from a string.
PetscErrorCode ReadAllSwarmFields(UserCtx *user, PetscInt ti)
Reads multiple fields (positions, velocity, CellID, and weight) into a DMSwarm.
PetscInt CreateVTKFileFromMetadata(const char *filename, const VTKMetaData *meta, MPI_Comm comm)
Creates a VTK file from prepared metadata and field payloads.
#define LOCAL
Logging scope definitions for controlling message output.
#define GLOBAL
Scope for global logging across all processes.
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
#define PROFILE_FUNCTION_END
Marks the end of a profiled code block.
PetscErrorCode ProfilingFinalize(SimCtx *simCtx)
the profiling excercise and build a profiling summary which is then printed to a log file.
#define LOG(scope, level, fmt,...)
Logging macro for PETSc-based applications with scope control.
void PrintProgressBar(PetscInt step, PetscInt startStep, PetscInt totalSteps, PetscReal currentTime)
Prints a progress bar to the console.
LogLevel get_log_level()
Retrieves the current logging level from the environment variable LOG_LEVEL.
@ LOG_ERROR
Critical errors that may halt the program.
@ LOG_INFO
Informational messages about program execution.
@ LOG_WARNING
Non-critical issues that warrant attention.
@ LOG_DEBUG
Detailed debugging information.
#define PROFILE_FUNCTION_BEGIN
Marks the beginning of a profiled code block (typically a function).
PetscErrorCode ComputeParticleMSD(UserCtx *user, const char *stats_prefix, PetscInt ti)
Computes the mean-squared displacement (MSD) of a particle cloud.
PetscErrorCode ComputeQCriterion(UserCtx *user)
Computes the Q-criterion diagnostic from the local velocity-gradient tensor.
PetscErrorCode ComputeSpecificKE(UserCtx *user, const char *velocity_field, const char *ske_field)
Computes the specific kinetic energy (KE per unit mass) for each particle.
PetscErrorCode NormalizeRelativeField(UserCtx *user, const char *relative_field_name)
Normalizes a relative scalar field using the configured reference pressure scale.
PetscErrorCode ComputeNodalAverage(UserCtx *user, const char *in_field_name, const char *out_field_name)
Interpolates a cell-centered field to nodal locations using local stencil averaging.
PetscErrorCode EulerianDataProcessingPipeline(UserCtx *user, PostProcessParams *pps)
Implementation of EulerianDataProcessingPipeline().
PetscErrorCode WriteEulerianFile(UserCtx *user, PostProcessParams *pps, PetscInt ti)
Implementation of WriteEulerianFile().
PetscErrorCode GlobalStatisticsPipeline(UserCtx *user, PostProcessParams *pps, PetscInt ti)
Internal helper implementation: GlobalStatisticsPipeline().
int main(int argc, char **argv)
Entry point for the postprocessor executable.
PetscErrorCode ParticleDataProcessingPipeline(UserCtx *user, PostProcessParams *pps)
Implementation of ParticleDataProcessingPipeline().
PetscErrorCode WriteParticleFile(UserCtx *user, PostProcessParams *pps, PetscInt ti)
Implementation of WriteParticleFile().
PetscErrorCode SetupPostProcessSwarm(UserCtx *user, PostProcessParams *pps)
Internal helper implementation: SetupPostProcessSwarm().
PetscErrorCode SetupDomainRankInfo(SimCtx *simCtx)
Sets up the full rank communication infrastructure, including neighbor ranks and bounding box exchang...
PetscErrorCode SetupGridAndSolvers(SimCtx *simCtx)
The main orchestrator for setting up all grid-related components.
PetscErrorCode SetupSimulationEnvironment(SimCtx *simCtx)
Verifies and prepares the complete I/O environment for a simulation run.
PetscErrorCode CreateSimulationContext(int argc, char **argv, SimCtx **p_simCtx)
Allocates and populates the master SimulationContext object.
PetscErrorCode SetupBoundaryConditions(SimCtx *simCtx)
(Orchestrator) Sets up all boundary conditions for the simulation.
PetscErrorCode FinalizeSimulation(SimCtx *simCtx)
Main cleanup function for the entire simulation context.
char statistics_output_prefix[256]
basename for CSV output, e.g.
#define MAX_POINT_DATA_FIELDS
Defines the maximum number of data fields for VTK point data.
char particle_output_prefix[256]
PetscInt num_point_data_fields
SimCtx * simCtx
Back-pointer to the master simulation context.
#define MAX_FILENAME_LENGTH
char statistics_pipeline[1024]
e.g.
char output_fields_instantaneous[1024]
char particle_pipeline[1024]
char process_pipeline[1024]
char particle_fields[1024]
PetscBool outputParticles
VTKFieldInfo point_data_fields[20]
@ EXEC_MODE_POSTPROCESSOR
#define MAX_VTK_FIELD_NAME_LENGTH
Maximum length for VTK field names.
Holds all configuration parameters for a post-processing run.
The master context for the entire simulation.
User-defined context containing data specific to a single computational grid level.
Stores all necessary information for a single data array in a VTK file.
PetscErrorCode PrepareOutputEulerianFieldData(UserCtx *user, Vec field_vec, PetscInt num_components, PetscScalar **out_data)
Creates a C array of field data corresponding to a subsampled (legacy-style) grid.
PetscErrorCode PrepareOutputCoordinates(UserCtx *user, PetscScalar **out_coords, PetscInt *out_nx, PetscInt *out_ny, PetscInt *out_nz, PetscInt *out_npoints)
Creates a C array of coordinates corresponding to a subsampled (legacy-style) grid.
PetscErrorCode PrepareOutputParticleData(UserCtx *user, PostProcessParams *pps, VTKMetaData *meta, PetscInt *p_n_total)
Gathers, subsamples, and prepares all particle data for VTK output.