20 PetscScalar *coords = NULL;
21 PetscInt nx = 0, ny = 0, nz = 0, npoints = 0;
22 PetscReal expected_last_coord = 0.0;
24 PetscFunctionBeginUser;
26 expected_last_coord = (PetscReal)(user->
IM - 1) / (PetscReal)user->
IM;
29 PetscCall(
PicurvAssertIntEqual(4, nx,
"PrepareOutputCoordinates should output nx based on the production IM+1 DA"));
30 PetscCall(
PicurvAssertIntEqual(4, ny,
"PrepareOutputCoordinates should output ny based on the production JM+1 DA"));
31 PetscCall(
PicurvAssertIntEqual(4, nz,
"PrepareOutputCoordinates should output nz based on the production KM+1 DA"));
32 PetscCall(
PicurvAssertIntEqual(64, npoints,
"PrepareOutputCoordinates should output the full physical-node lattice"));
34 if (simCtx->
rank == 0) {
35 PetscCall(
PicurvAssertBool((PetscBool)(coords != NULL),
"PrepareOutputCoordinates should allocate coordinates on rank 0"));
36 PetscCall(
PicurvAssertRealNear(0.0, PetscRealPart(coords[0]), 1.0e-12,
"First coordinate x should be 0"));
37 PetscCall(
PicurvAssertRealNear(0.0, PetscRealPart(coords[1]), 1.0e-12,
"First coordinate y should be 0"));
38 PetscCall(
PicurvAssertRealNear(0.0, PetscRealPart(coords[2]), 1.0e-12,
"First coordinate z should be 0"));
40 PetscCall(
PicurvAssertRealNear(expected_last_coord, PetscRealPart(coords[3 * (npoints - 1) + 0]), 1.0e-12,
"Last output coordinate x should be the normalized physical-node domain end"));
41 PetscCall(
PicurvAssertRealNear(expected_last_coord, PetscRealPart(coords[3 * (npoints - 1) + 1]), 1.0e-12,
"Last output coordinate y should be the normalized physical-node domain end"));
42 PetscCall(
PicurvAssertRealNear(expected_last_coord, PetscRealPart(coords[3 * (npoints - 1) + 2]), 1.0e-12,
"Last output coordinate z should be the normalized physical-node domain end"));
44 PetscCall(PetscFree(coords));
48 PetscFunctionReturn(0);
58 PetscScalar *field_out = NULL;
59 PetscInt start = 0, end = 0;
61 PetscFunctionBeginUser;
64 PetscCall(VecGetOwnershipRange(user->
P_nodal, &start, &end));
65 for (PetscInt idx = start; idx < end; ++idx) {
66 PetscCall(VecSetValue(user->
P_nodal, idx, (PetscScalar)idx, INSERT_VALUES));
68 PetscCall(VecAssemblyBegin(user->
P_nodal));
69 PetscCall(VecAssemblyEnd(user->
P_nodal));
72 if (simCtx->
rank == 0) {
74 "PrepareOutputEulerianFieldData should allocate subsampled data on rank 0"));
75 PetscCall(
PicurvAssertRealNear(0.0, PetscRealPart(field_out[0]), 1.0e-12,
"Subsampled first value should map to source index 0"));
77 "Subsampled last value should map to source index (3,3,3)=93 in the production-sized DA"));
78 PetscCall(PetscFree(field_out));
82 PetscFunctionReturn(0);
95 PetscReal (*position)[3] = NULL;
96 PetscReal (*velocity)[3] = NULL;
98 PetscFunctionBeginUser;
99 PetscCall(PetscMemzero(&pps,
sizeof(pps)));
100 PetscCall(PetscMemzero(&meta,
sizeof(meta)));
107 PetscCall(DMSwarmGetField(user->
swarm,
"position", NULL, NULL, (
void *)&position));
108 PetscCall(DMSwarmGetField(user->
swarm,
"velocity", NULL, NULL, (
void *)&velocity));
109 for (PetscInt p = 0; p < 5; ++p) {
110 position[p][0] = (PetscReal)p;
111 position[p][1] = 0.0;
112 position[p][2] = 0.0;
113 velocity[p][0] = 10.0 + (PetscReal)p;
114 velocity[p][1] = 20.0 + (PetscReal)p;
115 velocity[p][2] = 30.0 + (PetscReal)p;
117 PetscCall(DMSwarmRestoreField(user->
swarm,
"position", NULL, NULL, (
void *)&position));
118 PetscCall(DMSwarmRestoreField(user->
swarm,
"velocity", NULL, NULL, (
void *)&velocity));
121 if (simCtx->
rank == 0) {
122 PetscCall(
PicurvAssertIntEqual(5, n_total,
"PrepareOutputParticleData should report total particles before subsampling"));
127 "Particle field name should propagate to VTK metadata"));
133 PetscCall(PetscFree(meta.
coords));
138 PetscCall(PetscFree(meta.
offsets));
142 PetscFunctionReturn(0);
150 char tmpdir[PETSC_MAX_PATH_LEN];
151 char vtk_path[PETSC_MAX_PATH_LEN];
157 PetscFunctionBeginUser;
158 PetscCall(PetscMemzero(&meta,
sizeof(meta)));
160 PetscCall(PetscSNPrintf(vtk_path,
sizeof(vtk_path),
"%s/field_00001.vts", tmpdir));
174 for (PetscInt p = 0; p < meta.
npoints; ++p) {
175 meta.
coords[3 * p + 0] = (PetscScalar)(p % 2);
176 meta.
coords[3 * p + 1] = (PetscScalar)((p / 2) % 2);
177 meta.
coords[3 * p + 2] = (PetscScalar)(p / 4);
184 file = fopen(vtk_path,
"rb");
185 PetscCheck(file != NULL, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN,
"Failed to open generated VTK file '%s'.", vtk_path);
186 nread = fread(probe, 1,
sizeof(probe) - 1, file);
189 PetscCall(
PicurvAssertBool((PetscBool)(strstr(probe,
"StructuredGrid") != NULL),
190 "Generated VTK header should declare StructuredGrid type"));
192 PetscCall(PetscFree(meta.
coords));
195 PetscFunctionReturn(0);
211 ierr = PetscInitialize(&argc, &argv, NULL,
"PICurv VTK I/O tests");
216 ierr =
PicurvRunTests(
"unit-post-vtk", cases,
sizeof(cases) /
sizeof(cases[0]));
222 ierr = PetscFinalize();
PetscInt CreateVTKFileFromMetadata(const char *filename, const VTKMetaData *meta, MPI_Comm comm)
Creates a VTK file from prepared metadata and field payloads.
PetscErrorCode PicurvMakeTempDir(char *path, size_t path_len)
Creates a unique temporary directory for one test case.
PetscErrorCode PicurvCreateMinimalContexts(SimCtx **simCtx_out, UserCtx **user_out, PetscInt mx, PetscInt my, PetscInt mz)
Builds minimal SimCtx and UserCtx fixtures for C unit tests.
PetscErrorCode PicurvAssertRealNear(PetscReal expected, PetscReal actual, PetscReal tol, const char *context)
Asserts that two real values agree within tolerance.
PetscErrorCode PicurvDestroyMinimalContexts(SimCtx **simCtx_ptr, UserCtx **user_ptr)
Destroys minimal SimCtx/UserCtx fixtures and all owned PETSc objects.
PetscErrorCode PicurvCreateSwarmPair(UserCtx *user, PetscInt nlocal, const char *post_field_name)
Creates matched solver and post-processing swarms for tests.
PetscErrorCode PicurvRunTests(const char *suite_name, const PicurvTestCase *cases, size_t case_count)
Runs a named C test suite and prints pass/fail progress markers.
PetscErrorCode PicurvAssertFileExists(const char *path, const char *context)
Asserts that a filesystem path exists as a readable file.
PetscErrorCode PicurvAssertIntEqual(PetscInt expected, PetscInt actual, const char *context)
Asserts that two integer values are equal.
PetscErrorCode PicurvAssertBool(PetscBool value, const char *context)
Asserts that one boolean condition is true.
PetscErrorCode PicurvRemoveTempDir(const char *path)
Recursively removes a temporary directory created by PicurvMakeTempDir.
Shared declarations for the PICurv C test fixture and assertion layer.
Named test case descriptor consumed by PicurvRunTests.
static PetscErrorCode TestPrepareOutputEulerianFieldDataSubsamplesScalar(void)
Tests Eulerian scalar field extraction with subsampling.
static PetscErrorCode TestPrepareOutputParticleDataSubsampling(void)
Tests particle-data extraction with output subsampling.
int main(int argc, char **argv)
Runs the unit-post-vtk PETSc test binary.
static PetscErrorCode TestCreateVTKFileFromMetadataWritesStructuredGrid(void)
Tests structured-grid VTK file creation from assembled metadata.
static PetscErrorCode TestPrepareOutputCoordinatesSubsamplesInteriorGrid(void)
Tests coordinate extraction with interior-grid subsampling.
PetscInt num_point_data_fields
PetscInt particle_output_freq
char particle_fields[1024]
VTKFieldInfo point_data_fields[20]
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.
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.