27 char expected_extent[128];
28 PetscBool saw_pressure = PETSC_FALSE;
29 PetscBool saw_velocity = PETSC_FALSE;
30 PetscBool saw_qcrit = PETSC_FALSE;
31 PetscBool saw_extent = PETSC_FALSE;
32 uint32_t block_size = 0;
33 PetscInt npoints = mx * my * mz;
34 PetscScalar *coords = NULL;
35 PetscScalar *pressure = NULL;
36 PetscScalar *velocity = NULL;
37 PetscScalar *qcrit = NULL;
38 size_t footer_size = 0;
39 PetscBool valid = PETSC_FALSE;
41 file = fopen(path,
"rb");
42 if (!file)
return PETSC_FALSE;
43 snprintf(expected_extent,
sizeof(expected_extent),
44 "WholeExtent=\"0 %d 0 %d 0 %d\"", (
int)(mx - 1), (
int)(my - 1), (
int)(mz - 1));
46 while (fgets(line,
sizeof(line), file)) {
47 if (strstr(line,
"Name=\"P_nodal\"")) saw_pressure = PETSC_TRUE;
48 if (strstr(line,
"Name=\"Ucat_nodal\"")) saw_velocity = PETSC_TRUE;
49 if (strstr(line,
"Name=\"Qcrit\"")) saw_qcrit = PETSC_TRUE;
50 if (strstr(line, expected_extent)) saw_extent = PETSC_TRUE;
51 if (strstr(line,
"<AppendedData encoding=\"raw\">"))
break;
53 if (!saw_pressure || !saw_velocity || !saw_qcrit || !saw_extent || fgetc(file) !=
'_')
goto cleanup;
56 if (fread(&block_size,
sizeof(block_size), 1, file) != 1 ||
57 block_size != (uint32_t)(3 * npoints * (PetscInt)
sizeof(PetscScalar)))
goto cleanup;
58 coords = malloc((
size_t)(3 * npoints) *
sizeof(*coords));
60 fread(coords,
sizeof(PetscScalar), (
size_t)(3 * npoints), file) != (
size_t)(3 * npoints))
goto cleanup;
63 if (fread(&block_size,
sizeof(block_size), 1, file) != 1 ||
64 block_size != (uint32_t)(npoints * (PetscInt)
sizeof(PetscScalar)))
goto cleanup;
65 pressure = malloc((
size_t)npoints *
sizeof(*pressure));
67 fread(pressure,
sizeof(PetscScalar), (
size_t)npoints, file) != (
size_t)npoints)
goto cleanup;
70 if (fread(&block_size,
sizeof(block_size), 1, file) != 1 ||
71 block_size != (uint32_t)(3 * npoints * (PetscInt)
sizeof(PetscScalar)))
goto cleanup;
72 velocity = malloc((
size_t)(3 * npoints) *
sizeof(*velocity));
74 fread(velocity,
sizeof(PetscScalar), (
size_t)(3 * npoints), file) != (
size_t)(3 * npoints))
goto cleanup;
77 if (fread(&block_size,
sizeof(block_size), 1, file) != 1 ||
78 block_size != (uint32_t)(npoints * (PetscInt)
sizeof(PetscScalar)))
goto cleanup;
79 qcrit = malloc((
size_t)npoints *
sizeof(*qcrit));
81 fread(qcrit,
sizeof(PetscScalar), (
size_t)npoints, file) != (
size_t)npoints)
goto cleanup;
83 for (PetscInt k = 0; k < mz; ++k) {
84 for (PetscInt j = 0; j < my; ++j) {
85 for (PetscInt i = 0; i < mx; ++i) {
86 const PetscInt point = (k * my + j) * mx + i;
87 const PetscReal base = (PetscReal)(10000 * k + 100 * j + i);
89 if (!
ScalarMatches(coords[3 * point + 0], (PetscReal)i / (PetscReal)mx) ||
90 !
ScalarMatches(coords[3 * point + 1], (PetscReal)j / (PetscReal)my) ||
91 !
ScalarMatches(coords[3 * point + 2], (PetscReal)k / (PetscReal)mz) ||
101 footer_size = fread(footer, 1,
sizeof(footer) - 1, file);
102 footer[footer_size] =
'\0';
103 if (!strstr(footer,
"</AppendedData>") || !strstr(footer,
"</VTKFile>"))
goto cleanup;
124 char vtk_path[PETSC_MAX_PATH_LEN];
125 char vtk_tmp_path[PETSC_MAX_PATH_LEN];
126 PetscReal ***pressure = NULL;
127 PetscReal ***qcrit = NULL;
128 Cmpnts ***velocity = NULL;
129 PetscMPIInt rank = 0, size = 1;
130 PetscMPIInt local_owner = -1, probe_owner = -1;
131 PetscBool parsed = PETSC_FALSE;
132 PetscBool tmp_exists = PETSC_FALSE;
133 PetscBool prefix_set = PETSC_FALSE;
135 PetscFunctionBeginUser;
136 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
137 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
139 PetscCall(PetscMemzero(&pps,
sizeof(pps)));
141 PetscCall(PetscOptionsGetString(NULL, NULL,
"-vtk_test_output_prefix",
144 "the focused Eulerian VTK test requires -vtk_test_output_prefix"));
145 PetscCall(PetscSNPrintf(vtk_path,
sizeof(vtk_path),
"%s_00003.vts", pps.
output_prefix));
146 PetscCall(PetscSNPrintf(vtk_tmp_path,
sizeof(vtk_tmp_path),
"%s.tmp", vtk_path));
148 PetscCall(DMDAVecGetArray(user->
da, user->
P_nodal, &pressure));
149 PetscCall(DMDAVecGetArray(user->
fda, user->
Ucat_nodal, &velocity));
150 PetscCall(DMDAVecGetArray(user->
da, user->
Qcrit, &qcrit));
151 for (PetscInt k = user->
info.zs; k < user->
info.zs + user->
info.zm; ++k) {
152 for (PetscInt j = user->
info.ys; j < user->
info.ys + user->
info.ym; ++j) {
153 for (PetscInt i = user->
info.xs; i < user->
info.xs + user->
info.xm; ++i) {
154 const PetscReal base = (PetscReal)(10000 * k + 100 * j + i);
156 pressure[k][j][i] = base + 0.25;
157 velocity[k][j][i] = (
Cmpnts){base + 1.0, base + 2.0, base + 3.0};
158 qcrit[k][j][i] = -base - 0.5;
162 PetscCall(DMDAVecRestoreArray(user->
da, user->
P_nodal, &pressure));
163 PetscCall(DMDAVecRestoreArray(user->
fda, user->
Ucat_nodal, &velocity));
164 PetscCall(DMDAVecRestoreArray(user->
da, user->
Qcrit, &qcrit));
166 if (user->
IM - 1 >= user->
info.xs && user->
IM - 1 < user->
info.xs + user->
info.xm &&
167 user->
JM - 1 >= user->
info.ys && user->
JM - 1 < user->
info.ys + user->
info.ym &&
168 user->
KM - 1 >= user->
info.zs && user->
KM - 1 < user->
info.zs + user->
info.zm) {
171 PetscCallMPI(MPI_Allreduce(&local_owner, &probe_owner, 1, MPI_INT, MPI_MAX, PETSC_COMM_WORLD));
172 PetscCall(
PicurvAssertBool((PetscBool)(probe_owner == ((size > 1) ? size - 1 : 0)),
173 "the final physical VTK point should have the expected owner"));
176 "P_nodal,Ucat_nodal,Qcrit",
180 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
182 "multirank WriteEulerianFile should emit one combined .vts file"));
183 PetscCall(PetscTestFile(vtk_tmp_path,
'r', &tmp_exists));
185 "successful multirank Eulerian VTK output should not leave a temporary file"));
190 PetscCallMPI(MPI_Bcast(&parsed, 1, MPIU_BOOL, 0, PETSC_COMM_WORLD));
192 "every coordinate and Eulerian field value in the generated VTK should match"));
195 PetscFunctionReturn(0);
PetscErrorCode WriteEulerianFile(UserCtx *user, PostProcessParams *pps, PetscInt ti)
Orchestrates the writing of a combined, multi-field VTK file for a single time step.
static PetscBool ScalarMatches(PetscScalar actual, PetscReal expected)
Compare one scalar from the raw VTK payload with its deterministic truth.
int main(int argc, char **argv)
Runs the focused serial/MPI Eulerian VTK regression.
static PetscErrorCode TestWriteEulerianFileCollectiveMultiRank(void)
Ensures every Eulerian field and coordinate is correct after collective output.
static PetscBool ValidateEulerianVTKFile(const char *path, PetscInt mx, PetscInt my, PetscInt mz)
Read and exhaustively validate every appended value in a generated VTS file.
Holds all configuration parameters for a post-processing run.