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

Go to the source code of this file.

Functions

static PetscErrorCode WriteVTKAppendedBlock (FILE *fp, const void *data, PetscInt num_elements, size_t element_size)
 Write one binary data block in VTK appended-data format.
 
static PetscErrorCode WriteVTSXMLHeader (FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
 Write the XML header for a VTK structured-grid (.vts) file.
 
static PetscErrorCode WriteVTPXMLHeader (FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
 Write the XML header for a VTK polydata (.vtp) file.
 
static PetscErrorCode WriteVTKFileHeader (FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
 Open a VTK XML document and write its file-level header.
 
static PetscErrorCode WriteVTKFileFooter (FILE *fp, const VTKMetaData *meta)
 Close a VTK XML document after all appended data have been written.
 
PetscErrorCode CreateVTKFileFromMetadata (const char *filename, const VTKMetaData *meta, MPI_Comm comm)
 Implementation of CreateVTKFileFromMetadata().
 
PetscErrorCode PrepareOutputCoordinates (UserCtx *user, PetscScalar **out_coords, PetscInt *out_nx, PetscInt *out_ny, PetscInt *out_nz, PetscInt *out_npoints)
 Internal helper implementation: PrepareOutputCoordinates().
 
PetscErrorCode BeginStructuredVTKOutput (UserCtx *user, VTKMetaData *meta)
 Implementation of BeginStructuredVTKOutput().
 
PetscErrorCode AppendStructuredVTKField (UserCtx *user, VTKMetaData *meta, const char *name, Vec field_vec, PetscInt components)
 Implementation of AppendStructuredVTKField().
 
PetscErrorCode FinishStructuredVTKOutput (VTKMetaData *meta, const char *filename)
 Implementation of FinishStructuredVTKOutput().
 
PetscErrorCode PrepareOutputEulerianFieldData (UserCtx *user, Vec field_vec, PetscInt num_components, PetscScalar **out_data)
 Implementation of PrepareOutputEulerianFieldData().
 
PetscErrorCode PrepareOutputParticleData (UserCtx *user, PostProcessParams *pps, VTKMetaData *meta, PetscInt *p_n_total)
 Internal helper implementation: PrepareOutputParticleData().
 

Function Documentation

◆ WriteVTKAppendedBlock()

static PetscErrorCode WriteVTKAppendedBlock ( FILE *  fp,
const void *  data,
PetscInt  num_elements,
size_t  element_size 
)
static

Write one binary data block in VTK appended-data format.

Definition at line 21 of file vtk_io.c.

21 {
22 uint32_t block_size = num_elements * (uint32_t)element_size;
23 if (fwrite(&block_size, sizeof(uint32_t), 1, fp) != 1) return PETSC_ERR_FILE_WRITE;
24 if (fwrite(data, element_size, num_elements, fp) != (size_t)num_elements) return PETSC_ERR_FILE_WRITE;
25 return 0;
26}
Here is the caller graph for this function:

◆ WriteVTSXMLHeader()

static PetscErrorCode WriteVTSXMLHeader ( FILE *  fp,
const VTKMetaData meta,
PetscInt *  boffset 
)
static

Write the XML header for a VTK structured-grid (.vts) file.

Definition at line 31 of file vtk_io.c.

32{
33 const char *byte_order = "LittleEndian";
34 const char *precision = "Float64";
35
36 const PetscInt header = (PetscInt)sizeof(uint32_t);
37
38 fprintf(fp, "<?xml version=\"1.0\"?>\n");
39 fprintf(fp, "<VTKFile type=\"StructuredGrid\" version=\"1.0\" byte_order=\"%s\">\n", byte_order);
40 fprintf(fp, " <StructuredGrid WholeExtent=\"0 %" PetscInt_FMT " 0 %" PetscInt_FMT " 0 %" PetscInt_FMT "\">\n", meta->mx - 1, meta->my - 1, meta->mz - 1);
41 fprintf(fp, " <Piece Extent=\"0 %" PetscInt_FMT " 0 %" PetscInt_FMT " 0 %" PetscInt_FMT "\">\n", meta->mx - 1, meta->my - 1, meta->mz - 1);
42
43 fprintf(fp, " <Points>\n");
44 fprintf(fp, " <DataArray type=\"%s\" Name=\"Position\" NumberOfComponents=\"3\" format=\"appended\" offset=\"%" PetscInt_FMT "\" />\n",
45 precision, *boffset);
46 *boffset += header + 3 * meta->npoints * (PetscInt)sizeof(PetscScalar);
47 fprintf(fp, " </Points>\n");
48
49 if (meta->num_point_data_fields > 0) {
50 fprintf(fp, " <PointData>\n");
51 for (PetscInt i = 0; i < meta->num_point_data_fields; i++) {
52 const VTKFieldInfo* field = &meta->point_data_fields[i];
53 fprintf(fp, " <DataArray type=\"%s\" Name=\"%s\" NumberOfComponents=\"%" PetscInt_FMT "\" format=\"appended\" offset=\"%" PetscInt_FMT "\" />\n",
54 precision, field->name, field->num_components, *boffset);
55 *boffset += header + field->num_components * meta->npoints * (PetscInt)sizeof(PetscScalar);
56 }
57 fprintf(fp, " </PointData>\n");
58 }
59
60 fprintf(fp, " </Piece>\n");
61 fprintf(fp, " </StructuredGrid>\n");
62 fprintf(fp, " <AppendedData encoding=\"raw\">\n_");
63
64 return 0;
65}
PetscInt npoints
Definition variables.h:656
PetscInt num_components
Definition variables.h:643
PetscInt num_point_data_fields
Definition variables.h:659
char name[64]
Definition variables.h:642
VTKFieldInfo point_data_fields[20]
Definition variables.h:658
PetscInt mz
Definition variables.h:655
PetscInt my
Definition variables.h:655
PetscInt mx
Definition variables.h:655
Stores all necessary information for a single data array in a VTK file.
Definition variables.h:641
Here is the caller graph for this function:

◆ WriteVTPXMLHeader()

static PetscErrorCode WriteVTPXMLHeader ( FILE *  fp,
const VTKMetaData meta,
PetscInt *  boffset 
)
static

Write the XML header for a VTK polydata (.vtp) file.

Definition at line 70 of file vtk_io.c.

71{
72 const char *byte_order = "LittleEndian";
73 const char *precision = "Float64";
74 const char *int_type_str = (sizeof(PetscInt) == 8) ? "Int64" : "Int32";
75 const PetscInt header = (PetscInt)sizeof(uint32_t);
76
77 fprintf(fp, "<?xml version=\"1.0\"?>\n");
78 fprintf(fp, "<VTKFile type=\"PolyData\" version=\"1.0\" byte_order=\"%s\">\n", byte_order);
79 fprintf(fp, " <PolyData>\n");
80 fprintf(fp, " <Piece NumberOfPoints=\"%" PetscInt_FMT "\" NumberOfVerts=\"%" PetscInt_FMT "\" NumberOfLines=\"0\" NumberOfStrips=\"0\" NumberOfPolys=\"0\">\n",
81 meta->npoints, meta->npoints);
82
83 fprintf(fp, " <Points>\n");
84 fprintf(fp, " <DataArray type=\"%s\" Name=\"Position\" NumberOfComponents=\"3\" format=\"appended\" offset=\"%" PetscInt_FMT "\" />\n",
85 precision, *boffset);
86 *boffset += header + 3 * meta->npoints * (PetscInt)sizeof(PetscScalar);
87 fprintf(fp, " </Points>\n");
88
89 if (meta->num_point_data_fields > 0) {
90 fprintf(fp, " <PointData>\n");
91 for (PetscInt i = 0; i < meta->num_point_data_fields; i++) {
92 const VTKFieldInfo* field = &meta->point_data_fields[i];
93 fprintf(fp, " <DataArray type=\"%s\" Name=\"%s\" NumberOfComponents=\"%" PetscInt_FMT "\" format=\"appended\" offset=\"%" PetscInt_FMT "\" />\n",
94 precision, field->name, field->num_components, *boffset);
95 *boffset += header + field->num_components * meta->npoints * (PetscInt)sizeof(PetscScalar);
96 }
97 fprintf(fp, " </PointData>\n");
98 }
99
100 fprintf(fp, " <Verts>\n");
101 fprintf(fp, " <DataArray type=\"%s\" Name=\"connectivity\" format=\"appended\" offset=\"%" PetscInt_FMT "\" />\n",
102 int_type_str, *boffset);
103 *boffset += (uint32_t)sizeof(uint32_t) + meta->npoints * (PetscInt)sizeof(PetscInt);
104 fprintf(fp, " <DataArray type=\"%s\" Name=\"offsets\" format=\"appended\" offset=\"%" PetscInt_FMT "\" />\n",
105 int_type_str, *boffset);
106 *boffset += (uint32_t)sizeof(uint32_t) + meta->npoints * (PetscInt)sizeof(PetscInt);
107 fprintf(fp, " </Verts>\n");
108
109 fprintf(fp, " </Piece>\n");
110 fprintf(fp, " </PolyData>\n");
111 fprintf(fp, " <AppendedData encoding=\"raw\">\n_");
112
113 return 0;
114}
Here is the caller graph for this function:

◆ WriteVTKFileHeader()

static PetscErrorCode WriteVTKFileHeader ( FILE *  fp,
const VTKMetaData meta,
PetscInt *  boffset 
)
static

Open a VTK XML document and write its file-level header.

Definition at line 119 of file vtk_io.c.

120{
121 if (meta->fileType == VTK_STRUCTURED) {
122 return WriteVTSXMLHeader(fp, meta, boffset);
123 } else if (meta->fileType == VTK_POLYDATA) {
124 return WriteVTPXMLHeader(fp, meta, boffset);
125 }
126 return PETSC_ERR_ARG_WRONG;
127}
VTKFileType fileType
Definition variables.h:654
@ VTK_POLYDATA
Definition variables.h:650
@ VTK_STRUCTURED
Definition variables.h:649
static PetscErrorCode WriteVTSXMLHeader(FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
Write the XML header for a VTK structured-grid (.vts) file.
Definition vtk_io.c:31
static PetscErrorCode WriteVTPXMLHeader(FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
Write the XML header for a VTK polydata (.vtp) file.
Definition vtk_io.c:70
Here is the call graph for this function:
Here is the caller graph for this function:

◆ WriteVTKFileFooter()

static PetscErrorCode WriteVTKFileFooter ( FILE *  fp,
const VTKMetaData meta 
)
static

Close a VTK XML document after all appended data have been written.

Definition at line 132 of file vtk_io.c.

133{
134 (void)meta;
135 fprintf(fp, "\n </AppendedData>\n");
136 fprintf(fp, "</VTKFile>\n");
137 return 0;
138}
Here is the caller graph for this function:

◆ CreateVTKFileFromMetadata()

PetscErrorCode CreateVTKFileFromMetadata ( const char *  filename,
const VTKMetaData meta,
MPI_Comm  comm 
)

Implementation of CreateVTKFileFromMetadata().

Creates and writes a VTK file (either .vts or .vtp) from a populated metadata struct.

Creates a VTK file from prepared metadata and field payloads.

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

See also
CreateVTKFileFromMetadata()

Definition at line 149 of file vtk_io.c.

150{
151 PetscMPIInt rank;
152 MPI_Comm_rank(comm, &rank);
153 PetscErrorCode ierr = 0;
154
155 if (!rank) {
156 char tmp_filename[PETSC_MAX_PATH_LEN];
157 FILE *fp = NULL;
158
159 ierr = PetscSNPrintf(tmp_filename, sizeof(tmp_filename), "%s.tmp", filename);CHKERRQ(ierr);
160 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank 0 writing combined VTK file '%s'.\n", filename);
161 fp = fopen(tmp_filename, "wb");
162 if (!fp) {
163 LOG_ALLOW(GLOBAL, LOG_ERROR, "fopen failed for %s.\n", tmp_filename);
164 return PETSC_ERR_FILE_OPEN;
165 }
166
167 PetscInt boffset = 0;
168
169 ierr = WriteVTKFileHeader(fp, meta, &boffset);
170 if (ierr) {
171 fclose(fp);
172 remove(tmp_filename);
173 return ierr;
174 }
175
176 if (meta->coords) {
177 ierr = WriteVTKAppendedBlock(fp, meta->coords, 3 * meta->npoints, sizeof(PetscScalar));
178 if (ierr) {
179 fclose(fp);
180 remove(tmp_filename);
181 return ierr;
182 }
183 }
184
185 for (PetscInt i = 0; i < meta->num_point_data_fields; i++) {
186 const VTKFieldInfo *field = &meta->point_data_fields[i];
187 if (field->data) {
188 ierr = WriteVTKAppendedBlock(fp, field->data, field->num_components * meta->npoints, sizeof(PetscScalar));
189 if (ierr) {
190 fclose(fp);
191 remove(tmp_filename);
192 return ierr;
193 }
194 }
195 }
196 if (meta->fileType == VTK_POLYDATA) {
197 if (meta->connectivity) {
198 ierr = WriteVTKAppendedBlock(fp, meta->connectivity, meta->npoints, sizeof(PetscInt));
199 if (ierr) {
200 fclose(fp);
201 remove(tmp_filename);
202 return ierr;
203 }
204 }
205 if (meta->offsets) {
206 ierr = WriteVTKAppendedBlock(fp, meta->offsets, meta->npoints, sizeof(PetscInt));
207 if (ierr) {
208 fclose(fp);
209 remove(tmp_filename);
210 return ierr;
211 }
212 }
213 }
214 ierr = WriteVTKFileFooter(fp, meta);
215 if (ierr) {
216 fclose(fp);
217 remove(tmp_filename);
218 return ierr;
219 }
220 if (fclose(fp) != 0) {
221 remove(tmp_filename);
222 return PETSC_ERR_FILE_WRITE;
223 }
224 if (rename(tmp_filename, filename) != 0) {
225 remove(tmp_filename);
226 return PETSC_ERR_FILE_WRITE;
227 }
228 LOG_ALLOW(GLOBAL, LOG_INFO, "Rank 0 finished writing VTK file '%s'.\n", filename);
229 }
230 return 0;
231}
#define GLOBAL
Scope for global logging across all processes.
Definition logging.h:46
#define LOG_ALLOW(scope, level, fmt,...)
Logging macro that checks both the log level and whether the calling function is in the allowed-funct...
Definition logging.h:200
@ LOG_ERROR
Critical errors that may halt the program.
Definition logging.h:29
@ LOG_INFO
Informational messages about program execution.
Definition logging.h:31
PetscInt * connectivity
Definition variables.h:660
PetscInt * offsets
Definition variables.h:661
PetscScalar * data
Definition variables.h:644
PetscScalar * coords
Definition variables.h:657
static PetscErrorCode WriteVTKFileFooter(FILE *fp, const VTKMetaData *meta)
Close a VTK XML document after all appended data have been written.
Definition vtk_io.c:132
static PetscErrorCode WriteVTKAppendedBlock(FILE *fp, const void *data, PetscInt num_elements, size_t element_size)
Write one binary data block in VTK appended-data format.
Definition vtk_io.c:21
static PetscErrorCode WriteVTKFileHeader(FILE *fp, const VTKMetaData *meta, PetscInt *boffset)
Open a VTK XML document and write its file-level header.
Definition vtk_io.c:119
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PrepareOutputCoordinates()

PetscErrorCode PrepareOutputCoordinates ( UserCtx user,
PetscScalar **  out_coords,
PetscInt *  out_nx,
PetscInt *  out_ny,
PetscInt *  out_nz,
PetscInt *  out_npoints 
)

Internal helper implementation: PrepareOutputCoordinates().

Creates a C array of coordinates corresponding to a subsampled (legacy-style) grid.

Local to this translation unit.

Definition at line 241 of file vtk_io.c.

242{
243 PetscErrorCode ierr;
244 Vec coords_global;
245 PetscInt IM, JM, KM;
246 PetscInt N_full_coords;
247 PetscScalar *full_coords_arr = NULL;
248
249 PetscFunctionBeginUser;
250 ierr = DMDAGetInfo(user->da, NULL, &IM, &JM, &KM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); CHKERRQ(ierr);
251
252 // Set the dimensions of the output grid
253 *out_nx = IM - 1;
254 *out_ny = JM - 1;
255 *out_nz = KM - 1;
256 *out_npoints = (*out_nx) * (*out_ny) * (*out_nz);
257
258 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Preparing subsampled coordinates for a %" PetscInt_FMT "x%" PetscInt_FMT "x%" PetscInt_FMT " grid.\n", *out_nx, *out_ny, *out_nz);
259
260 // --- Step 1: Gather the full coordinate vector to rank 0 ---
261 ierr = DMGetCoordinates(user->da, &coords_global); CHKERRQ(ierr);
262 // Reuse of your existing, proven utility function's logic
263 ierr = VecToArrayOnRank0(coords_global, &N_full_coords, &full_coords_arr); CHKERRQ(ierr);
264
265 // --- Step 2: On rank 0, subsample the gathered array ---
266 if (user->simCtx->rank == 0) {
267 // We expect N_full_coords to be IM * JM * KM * 3
268 if (N_full_coords != IM * JM * KM * 3) {
269 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Gathered coordinate array has wrong size. Expected %" PetscInt_FMT ", got %" PetscInt_FMT, IM * JM * KM * 3, N_full_coords);
270 }
271
272 // Allocate the smaller output C array
273 ierr = PetscMalloc1(3 * (*out_npoints), out_coords); CHKERRQ(ierr);
274
275 // Loop over the smaller grid dimensions and copy data
276 PetscInt p_out = 0; // Index for the small output array
277 for (PetscInt k = 0; k < *out_nz; k++) {
278 for (PetscInt j = 0; j < *out_ny; j++) {
279 for (PetscInt i = 0; i < *out_nx; i++) {
280 // Calculate the index in the full, 1D source array
281 PetscInt p_in = 3 * (k * (JM * IM) + j * IM + i);
282
283 (*out_coords)[p_out++] = full_coords_arr[p_in + 0]; // x
284 (*out_coords)[p_out++] = full_coords_arr[p_in + 1]; // y
285 (*out_coords)[p_out++] = full_coords_arr[p_in + 2]; // z
286 }
287 }
288 }
289 // Free the temporary full array that was allocated by VecToArrayOnRank0
290 ierr = PetscFree(full_coords_arr); CHKERRQ(ierr);
291 } else {
292 // On other ranks, the output pointer is NULL
293 *out_coords = NULL;
294 }
295
296 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Subsampled coordinates prepared on rank 0 with total %" PetscInt_FMT " points.\n", *out_npoints);
297
298 PetscFunctionReturn(0);
299}
PetscErrorCode VecToArrayOnRank0(Vec inVec, PetscInt *N, double **arrayOut)
Gathers the contents of a distributed PETSc Vec into a single array on rank 0.
Definition io.c:2650
@ LOG_DEBUG
Detailed debugging information.
Definition logging.h:32
PetscMPIInt rank
Definition variables.h:698
SimCtx * simCtx
Back-pointer to the master simulation context.
Definition variables.h:909
Here is the call graph for this function:
Here is the caller graph for this function:

◆ BeginStructuredVTKOutput()

PetscErrorCode BeginStructuredVTKOutput ( UserCtx user,
VTKMetaData meta 
)

Implementation of BeginStructuredVTKOutput().

Begins one structured VTK file: clears the metadata and builds its coordinates.

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

See also
BeginStructuredVTKOutput()

Definition at line 308 of file vtk_io.c.

309{
310 PetscFunctionBeginUser;
311 PetscCheck(user != NULL && meta != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
312 "Context and metadata are required.");
313 PetscCall(PetscMemzero(meta, sizeof(*meta)));
314 meta->fileType = VTK_STRUCTURED;
315 PetscCall(PrepareOutputCoordinates(user, &meta->coords, &meta->mx, &meta->my, &meta->mz,
316 &meta->npoints));
317 PetscFunctionReturn(0);
318}
PetscErrorCode PrepareOutputCoordinates(UserCtx *user, PetscScalar **out_coords, PetscInt *out_nx, PetscInt *out_ny, PetscInt *out_nz, PetscInt *out_npoints)
Internal helper implementation: PrepareOutputCoordinates().
Definition vtk_io.c:241
Here is the call graph for this function:
Here is the caller graph for this function:

◆ AppendStructuredVTKField()

PetscErrorCode AppendStructuredVTKField ( UserCtx user,
VTKMetaData meta,
const char *  name,
Vec  field_vec,
PetscInt  components 
)

Implementation of AppendStructuredVTKField().

Adds one point-data field to a structured VTK file being assembled.

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

See also
AppendStructuredVTKField()

Definition at line 326 of file vtk_io.c.

328{
329 VTKFieldInfo *entry = NULL;
330
331 PetscFunctionBeginUser;
332 PetscCheck(user != NULL && meta != NULL && name != NULL && field_vec != NULL,
333 PETSC_COMM_SELF, PETSC_ERR_ARG_NULL, "Context, metadata, name, and vector are required.");
336 "Reached the %d point-data field limit; '%s' is not written.\n",
338 PetscFunctionReturn(0);
339 }
340 entry = &meta->point_data_fields[meta->num_point_data_fields];
341 PetscCall(PetscStrncpy(entry->name, name, MAX_VTK_FIELD_NAME_LENGTH));
342 entry->num_components = components;
343 PetscCall(PrepareOutputEulerianFieldData(user, field_vec, components, &entry->data));
344 meta->num_point_data_fields++;
345 PetscFunctionReturn(0);
346}
@ LOG_WARNING
Non-critical issues that warrant attention.
Definition logging.h:30
#define MAX_POINT_DATA_FIELDS
Defines the maximum number of data fields for VTK point data.
Definition variables.h:590
#define MAX_VTK_FIELD_NAME_LENGTH
Maximum length for VTK field names.
Definition variables.h:591
PetscErrorCode PrepareOutputEulerianFieldData(UserCtx *user, Vec field_vec, PetscInt num_components, PetscScalar **out_data)
Implementation of PrepareOutputEulerianFieldData().
Definition vtk_io.c:377
Here is the call graph for this function:
Here is the caller graph for this function:

◆ FinishStructuredVTKOutput()

PetscErrorCode FinishStructuredVTKOutput ( VTKMetaData meta,
const char *  filename 
)

Implementation of FinishStructuredVTKOutput().

Writes an assembled structured VTK file and releases its buffers.

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

See also
FinishStructuredVTKOutput()

Definition at line 354 of file vtk_io.c.

355{
356 PetscFunctionBeginUser;
357 PetscCheck(meta != NULL && filename != NULL, PETSC_COMM_SELF, PETSC_ERR_ARG_NULL,
358 "Metadata and filename are required.");
359 PetscCall(CreateVTKFileFromMetadata(filename, meta, PETSC_COMM_WORLD));
360 for (PetscInt index = 0; index < meta->num_point_data_fields; ++index) {
361 if (meta->point_data_fields[index].data) {
362 PetscCall(PetscFree(meta->point_data_fields[index].data));
363 }
364 }
365 if (meta->coords) PetscCall(PetscFree(meta->coords));
366 meta->num_point_data_fields = 0;
367 PetscFunctionReturn(0);
368}
PetscErrorCode CreateVTKFileFromMetadata(const char *filename, const VTKMetaData *meta, MPI_Comm comm)
Implementation of CreateVTKFileFromMetadata().
Definition vtk_io.c:149
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PrepareOutputEulerianFieldData()

PetscErrorCode PrepareOutputEulerianFieldData ( UserCtx user,
Vec  field_vec,
PetscInt  num_components,
PetscScalar **  out_data 
)

Implementation of PrepareOutputEulerianFieldData().

Creates a C array of field data corresponding to a subsampled (legacy-style) grid.

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

See also
PrepareOutputEulerianFieldData()

Definition at line 377 of file vtk_io.c.

378{
379 PetscErrorCode ierr;
380 PetscInt IM, JM, KM, nx, ny, nz, npoints;
381 PetscInt N_full_field = 0;
382 PetscScalar *full_field_arr = NULL;
383
384 PetscFunctionBeginUser;
385 ierr = DMDAGetInfo(user->da, NULL, &IM, &JM, &KM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); CHKERRQ(ierr);
386 nx = IM - 1; ny = JM - 1; nz = KM - 1;
387 npoints = nx * ny * nz;
388
390 "Preparing subsampled field data (dof=%" PetscInt_FMT ") for a %" PetscInt_FMT "x%" PetscInt_FMT "x%" PetscInt_FMT " grid.\n",
391 num_components, nx, ny, nz);
392
393 // --- Step 1: Gather the full field vector to rank 0 ---
394 ierr = VecToArrayOnRank0(field_vec, &N_full_field, &full_field_arr); CHKERRQ(ierr);
395
396 // --- Step 2: On rank 0, subsample the gathered array ---
397 if (user->simCtx->rank == 0) {
398 // Sanity check the size of the gathered array
399 if (N_full_field != IM * JM * KM * num_components) {
400 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED,
401 "Gathered field array has wrong size. Expected %" PetscInt_FMT ", got %" PetscInt_FMT,
402 IM * JM * KM * num_components, N_full_field);
403 }
404
405 // Allocate the smaller output C array (AoS layout expected by your writer)
406 ierr = PetscMalloc1(num_components * npoints, out_data); CHKERRQ(ierr);
407
408 /*
409 // ======== Layout diagnostics (rank 0 only, read-only) ========
410 if (num_components > 1 && full_field_arr) {
411 const PetscInt n_full = IM * JM * KM;
412
413 // Choose a safe interior probe point and its +i neighbor
414 const PetscInt ic = (IM > 4) ? IM/2 : 1;
415 const PetscInt jc = (JM > 4) ? JM/2 : 1;
416 const PetscInt kc = (KM > 4) ? KM/2 : 1;
417 const PetscInt ic1 = (ic + 1 < IM-1) ? (ic + 1) : ic; // stay interior
418
419 const PetscInt t_full_c = (kc * JM + jc) * IM + ic;
420 const PetscInt t_full_c1 = (kc * JM + jc) * IM + ic1;
421
422 // If source were AoS: full[num_components * t + comp]
423 PetscScalar aos_c0 = full_field_arr[num_components * t_full_c + 0];
424 PetscScalar aos_c1 = full_field_arr[num_components * t_full_c1 + 0];
425 PetscScalar aos_c0_y = (num_components > 1) ? full_field_arr[num_components * t_full_c + 1] : 0.0;
426 PetscScalar aos_c0_z = (num_components > 2) ? full_field_arr[num_components * t_full_c + 2] : 0.0;
427
428 // If source were SoA: full[comp * n_full + t]
429 PetscScalar soa_c0 = full_field_arr[0 * n_full + t_full_c];
430 PetscScalar soa_c1 = full_field_arr[0 * n_full + t_full_c1];
431 PetscScalar soa_c0_y = (num_components > 1) ? full_field_arr[1 * n_full + t_full_c] : 0.0;
432 PetscScalar soa_c0_z = (num_components > 2) ? full_field_arr[2 * n_full + t_full_c] : 0.0;
433
434 double dAOS = fabs((double)(aos_c1 - aos_c0)); // spatial delta along +i
435 double dSOA = fabs((double)(soa_c1 - soa_c0));
436
437 const char *verdict = (dSOA < dAOS) ? "LIKELY SoA (component-major)" : "LIKELY AoS (interleaved)";
438
439 LOG_ALLOW(GLOBAL, LOG_INFO,
440 "Layout probe @ (i=%" PetscInt_FMT ", j=%" PetscInt_FMT ", k=%" PetscInt_FMT ") vs +i neighbor:\n"
441 " AoS-candidate: Ux(center)=%.6e Ux(+i)=%.6e |Δ|=%.6e ; Uy(center)=%.6e Uz(center)=%.6e\n"
442 " SoA-candidate: Ux(center)=%.6e Ux(+i)=%.6e |Δ|=%.6e ; Uy(center)=%.6e Uz(center)=%.6e\n"
443 " Verdict: %s\n",
444 ic, jc, kc,
445 (double)aos_c0, (double)aos_c1, dAOS, (double)aos_c0_y, (double)aos_c0_z,
446 (double)soa_c0, (double)soa_c1, dSOA, (double)soa_c0_y, (double)soa_c0_z,
447 verdict
448 );
449 } else if (num_components == 1) {
450 LOG_ALLOW(GLOBAL, LOG_INFO, "Layout probe: scalar field (dof=1) — no component interleave to detect.\n");
451 }
452 // ======== END diagnostics ========
453 */
454
455 // --- PACK: assumes source is already AoS ---
456 {
457 PetscInt p_out = 0;
458 for (PetscInt k = 0; k < nz; k++) {
459 for (PetscInt j = 0; j < ny; j++) {
460 for (PetscInt i = 0; i < nx; i++) {
461 const PetscInt p_in_start = num_components * (k * (JM * IM) + j * IM + i);
462 for (PetscInt c = 0; c < num_components; c++) {
463 (*out_data)[p_out++] = full_field_arr[p_in_start + c];
464 }
465 }
466 }
467 }
468 }
469
470 // Free temporary gathered array
471 ierr = PetscFree(full_field_arr); CHKERRQ(ierr);
472 } else {
473 // Other ranks: no allocation
474 *out_data = NULL;
475 }
476
477 LOG_ALLOW(GLOBAL, LOG_DEBUG, "Subsampled field data prepared on rank 0 with total %" PetscInt_FMT " points.\n", npoints);
478
479 PetscFunctionReturn(0);
480}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PrepareOutputParticleData()

PetscErrorCode PrepareOutputParticleData ( UserCtx user,
PostProcessParams pps,
VTKMetaData meta,
PetscInt *  p_n_total 
)

Internal helper implementation: PrepareOutputParticleData().

Gathers, subsamples, and prepares all particle data for VTK output.

Local to this translation unit.

Definition at line 486 of file vtk_io.c.

487{
488 PetscErrorCode ierr;
489 PetscInt n_total_particles, n_components;
490 PetscInt stride = pps->particle_output_freq > 0 ? pps->particle_output_freq : 1;
491
492 PetscFunctionBeginUser;
493
494 // Initialize output parameters on all ranks
495 *p_n_total = 0;
496
497 // --- The entire preparation process is a series of collective gathers followed by rank-0 processing ---
498
499 // --- Step 1: Gather Full Coordinates from SOURCE Swarm (Collective) ---
500 // This establishes the ground truth for particle positions and total count.
501 PetscReal *full_coords_arr = NULL;
502 PetscDataType coordinate_type;
503 // NOTE: This assumes SwarmFieldToArrayOnRank0 exists and works for PetscScalar fields.
504 // If not, it may need to be generalized like the logic below.
506 &n_total_particles, &n_components, &coordinate_type,
507 (void**)&full_coords_arr); CHKERRQ(ierr);
508 PetscCheck(coordinate_type == PETSC_REAL,
509 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
510 "Particle position field must use PETSC_REAL storage, not %s.",
511 PetscDataTypes[coordinate_type]);
512
513 *p_n_total = n_total_particles;
514 if (n_total_particles == 0) {
515 ierr = PetscFree(full_coords_arr); CHKERRQ(ierr);
516 PetscFunctionReturn(0);
517 }
518 PetscCheck(n_components == 3,
519 PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG,
520 "Coordinate field position must have 3 components, but has %" PetscInt_FMT,
521 n_components);
522
523 // --- Step 2: Prepare and Subsample Coordinates (Rank 0 Only) ---
524 if (user->simCtx->rank == 0) {
525 // --- Subsampling Calculation ---
526 meta->npoints = (n_total_particles > 0) ? (n_total_particles - 1) / stride + 1 : 0;
527
528 LOG_ALLOW(LOCAL, LOG_DEBUG, "Subsampling %" PetscInt_FMT " total particles with stride %" PetscInt_FMT " -> %" PetscInt_FMT " output particles.\n",
529 n_total_particles, stride, meta->npoints);
530
531 // --- Prepare Final Coordinates Array ---
532 ierr = PetscMalloc1(3 * meta->npoints, &meta->coords); CHKERRQ(ierr);
533 for (PetscInt i = 0; i < meta->npoints; i++) {
534 PetscInt source_idx = i * stride;
535 for (int d = 0; d < 3; d++) meta->coords[3 * i + d] = full_coords_arr[3 * source_idx + d];
536 }
537 }
538 ierr = PetscFree(full_coords_arr); CHKERRQ(ierr);
539
540 // --- Step 3: Gather Fields (Collective), then Subsample and Store (Rank 0 Only) ---
541 char *fields_copy, *field_name;
542 PetscInt num_fields = 0;
543 ierr = PetscStrallocpy(pps->particle_fields, &fields_copy); CHKERRQ(ierr);
544 field_name = strtok(fields_copy, ",");
545 while (field_name && num_fields < MAX_POINT_DATA_FIELDS) {
546 TrimWhitespace(field_name);
547 if (!*field_name || strcasecmp(field_name, "position") == 0) {
548 field_name = strtok(NULL, ","); continue;
549 }
550
551 // A. Determine which swarm is the source for this field on every rank.
552 DM swarm_to_use = user->swarm; // Default to the main solver swarm.
553 const char* internal_name = field_name; // Default internal name to user-facing name.
554
555 PetscErrorCode check_ierr;
556 ierr = PetscPushErrorHandler(PetscIgnoreErrorHandler, NULL); CHKERRQ(ierr);
557 check_ierr = DMSwarmGetField(user->post_swarm, field_name, NULL, NULL, NULL);
558 ierr = PetscPopErrorHandler(); CHKERRQ(ierr);
559 if (!check_ierr) {
560 swarm_to_use = user->post_swarm;
561 ierr = DMSwarmRestoreField(user->post_swarm, field_name, NULL, NULL, NULL); CHKERRQ(ierr);
562 if (user->simCtx->rank == 0) {
563 LOG_ALLOW(LOCAL, LOG_DEBUG, "Field '%s' will be sourced from the post-processing swarm.\n", field_name);
564 }
565 } else {
566 if (user->simCtx->rank == 0) {
567 LOG_ALLOW(LOCAL, LOG_DEBUG, "Field '%s' will be sourced from the main solver swarm.\n", field_name);
568 }
569 if (strcasecmp(field_name, "pid") == 0) internal_name = "DMSwarm_pid";
570 else if (strcasecmp(field_name, "CellID") == 0) internal_name = "DMSwarm_CellID";
571 else if (strcasecmp(field_name, "Migration Status") == 0) internal_name = "DMSwarm_location_status";
572 }
573
574 // B. Gather the complete field on rank 0 before applying the output stride.
575 // SwarmFieldToArrayOnRank0 handles both scalar and vector field layouts.
576 void* full_field_arr_void = NULL;
577 PetscInt field_total_particles, field_num_components;
578 PetscDataType field_data_type;
579
580 ierr = SwarmFieldToArrayOnRank0(swarm_to_use, internal_name,
581 &field_total_particles, &field_num_components,
582 &field_data_type, &full_field_arr_void); CHKERRQ(ierr);
583
584 if (field_total_particles != n_total_particles) {
585 if (user->simCtx->rank == 0) {
586 LOG_ALLOW(LOCAL, LOG_WARNING, "Field '%s' has %" PetscInt_FMT " particles, but expected %" PetscInt_FMT ". Skipping.\n", field_name, field_total_particles, n_total_particles);
587 }
588 ierr = PetscFree(full_field_arr_void); CHKERRQ(ierr);
589 field_name = strtok(NULL, ","); continue;
590 }
591
592 if (user->simCtx->rank == 0) {
593 // C. Allocate final array (ALWAYS as PetscScalar) and copy/cast subsampled data.
594 VTKFieldInfo* current_field = &meta->point_data_fields[meta->num_point_data_fields];
595 strncpy(current_field->name, field_name, MAX_VTK_FIELD_NAME_LENGTH - 1);
596 current_field->name[MAX_VTK_FIELD_NAME_LENGTH - 1] = '\0';
597 current_field->num_components = field_num_components;
598 ierr = PetscMalloc1(current_field->num_components * meta->npoints, (PetscScalar**)&current_field->data); CHKERRQ(ierr);
599
600 PetscScalar* final_data_arr = (PetscScalar*)current_field->data;
601
602 // D. Perform the subsampling and potential casting
603 if (field_data_type == PETSC_INT64) {
604 PetscInt64* source_arr = (PetscInt64*)full_field_arr_void;
605 for (PetscInt i = 0; i < meta->npoints; i++) {
606 final_data_arr[i] = (PetscScalar)source_arr[i * stride];
607 }
608 } else if (field_data_type == PETSC_INT) {
609 PetscInt* source_arr = (PetscInt*)full_field_arr_void;
610 for (PetscInt i = 0; i < meta->npoints; i++) {
611 PetscInt source_idx = i * stride;
612 for (PetscInt c = 0; c < current_field->num_components; c++) {
613 final_data_arr[current_field->num_components * i + c] = (PetscScalar)source_arr[current_field->num_components * source_idx + c];
614 }
615 }
616 } else if (field_data_type == PETSC_REAL) {
617 PetscReal* source_arr = (PetscReal*)full_field_arr_void;
618 for (PetscInt i = 0; i < meta->npoints; i++) {
619 PetscInt source_idx = i * stride;
620 for (PetscInt c = 0; c < current_field->num_components; c++) {
621 final_data_arr[current_field->num_components * i + c] = source_arr[current_field->num_components * source_idx + c];
622 }
623 }
624#if defined(PETSC_USE_COMPLEX)
625 } else if (field_data_type == PETSC_SCALAR) {
626 PetscScalar* source_arr = (PetscScalar*)full_field_arr_void;
627 for (PetscInt i = 0; i < meta->npoints; i++) {
628 PetscInt source_idx = i * stride;
629 for (PetscInt c = 0; c < current_field->num_components; c++) {
630 final_data_arr[current_field->num_components * i + c] = source_arr[current_field->num_components * source_idx + c];
631 }
632 }
633#endif
634 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP,
635 "VTK particle output does not support field '%s' with PETSc type %s.",
636 field_name, PetscDataTypes[field_data_type]);
637
638 meta->num_point_data_fields++;
639 }
640 ierr = PetscFree(full_field_arr_void); CHKERRQ(ierr);
641 num_fields++;
642 field_name = strtok(NULL, ",");
643 }
644 ierr = PetscFree(fields_copy); CHKERRQ(ierr);
645
646 // --- Step 4: Finalize VTK MetaData for PolyData (Rank 0 Only) ---
647 if (user->simCtx->rank == 0) {
648 if (meta->npoints > 0) {
649 meta->fileType = VTK_POLYDATA;
650 ierr = PetscMalloc1(meta->npoints, &meta->connectivity); CHKERRQ(ierr);
651 ierr = PetscMalloc1(meta->npoints, &meta->offsets); CHKERRQ(ierr);
652 for (PetscInt i = 0; i < meta->npoints; i++) {
653 meta->connectivity[i] = i;
654 meta->offsets[i] = i + 1;
655 }
656 }
657 }
658
659 ierr = MPI_Barrier(PETSC_COMM_WORLD); CHKERRQ(ierr);
660
661 PetscFunctionReturn(0);
662}
PetscErrorCode SwarmFieldToArrayOnRank0(DM swarm, const char *field_name, PetscInt *n_total_particles, PetscInt *n_components, PetscDataType *field_type_out, void **gathered_array)
Gathers any DMSwarm field from all ranks to a single, contiguous array on rank 0.
Definition io.c:2686
void TrimWhitespace(char *str)
Removes leading and trailing ASCII whitespace from a mutable string.
Definition io.c:399
#define LOCAL
Logging scope definitions for controlling message output.
Definition logging.h:45
const char * ParticleFieldName(ParticleFieldId field_id)
Return the canonical PETSc DMSwarm name for an ID.
@ PARTICLE_FIELD_ID_POSITION
DM post_swarm
Definition variables.h:1000
PetscInt particle_output_freq
Definition variables.h:613
char particle_fields[1024]
Definition variables.h:611
Here is the call graph for this function:
Here is the caller graph for this function: