xref: /honee/src/honee-file.c (revision 93ca29b6e094721a136ad10375037d18cdc7fb9d)
1*93ca29b6SJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
2*93ca29b6SJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
3*93ca29b6SJames Wright 
4*93ca29b6SJames Wright /// @file
5*93ca29b6SJames Wright /// Custom file I/O functions for HONEE
6*93ca29b6SJames Wright 
7*93ca29b6SJames Wright #include <honee-file.h>
8*93ca29b6SJames Wright 
9*93ca29b6SJames Wright const PetscInt32 FLUIDS_FILE_TOKEN    = 0xceedf00;  // for backwards compatibility
10*93ca29b6SJames Wright const PetscInt32 FLUIDS_FILE_TOKEN_32 = 0xceedf32;
11*93ca29b6SJames Wright const PetscInt32 FLUIDS_FILE_TOKEN_64 = 0xceedf64;
12*93ca29b6SJames Wright 
13*93ca29b6SJames Wright static PetscErrorCode BinaryReadIntoInt(PetscViewer viewer, PetscInt *out, PetscDataType file_type) {
14*93ca29b6SJames Wright   PetscFunctionBeginUser;
15*93ca29b6SJames Wright   *out = -13;  // appease the overzealous GCC compiler warning Gods
16*93ca29b6SJames Wright   if (file_type == PETSC_INT32) {
17*93ca29b6SJames Wright     PetscInt32 val;
18*93ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &val, 1, NULL, PETSC_INT32));
19*93ca29b6SJames Wright     *out = val;
20*93ca29b6SJames Wright   } else if (file_type == PETSC_INT64) {
21*93ca29b6SJames Wright     PetscInt64 val;
22*93ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &val, 1, NULL, PETSC_INT64));
23*93ca29b6SJames Wright     *out = val;
24*93ca29b6SJames Wright   } else {
25*93ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, out, 1, NULL, PETSC_INT));
26*93ca29b6SJames Wright   }
27*93ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
28*93ca29b6SJames Wright }
29*93ca29b6SJames Wright 
30*93ca29b6SJames Wright // @brief Load vector from binary file, possibly with embedded solution time and step number
31*93ca29b6SJames Wright PetscErrorCode LoadFluidsBinaryVec(MPI_Comm comm, PetscViewer viewer, Vec Q, PetscReal *time, PetscInt *step_number) {
32*93ca29b6SJames Wright   PetscInt      file_step_number;
33*93ca29b6SJames Wright   PetscInt32    token;
34*93ca29b6SJames Wright   PetscReal     file_time;
35*93ca29b6SJames Wright   PetscDataType file_type = PETSC_INT32;
36*93ca29b6SJames Wright 
37*93ca29b6SJames Wright   PetscFunctionBeginUser;
38*93ca29b6SJames Wright   PetscCall(PetscViewerBinaryRead(viewer, &token, 1, NULL, PETSC_INT32));
39*93ca29b6SJames Wright   if (token == FLUIDS_FILE_TOKEN_32 || token == FLUIDS_FILE_TOKEN_64 ||
40*93ca29b6SJames Wright       token == FLUIDS_FILE_TOKEN) {  // New style format; we're reading a file with step number and time in the header
41*93ca29b6SJames Wright     if (token == FLUIDS_FILE_TOKEN_32) file_type = PETSC_INT32;
42*93ca29b6SJames Wright     else if (token == FLUIDS_FILE_TOKEN_64) file_type = PETSC_INT64;
43*93ca29b6SJames Wright     PetscCall(BinaryReadIntoInt(viewer, &file_step_number, file_type));
44*93ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &file_time, 1, NULL, PETSC_REAL));
45*93ca29b6SJames Wright     if (time) *time = file_time;
46*93ca29b6SJames Wright     if (step_number) *step_number = file_step_number;
47*93ca29b6SJames Wright   } else if (token == VEC_FILE_CLASSID) {  // Legacy format of just the vector, encoded as [VEC_FILE_CLASSID, length, ]
48*93ca29b6SJames Wright     PetscInt length, N;
49*93ca29b6SJames Wright     PetscCall(BinaryReadIntoInt(viewer, &length, file_type));
50*93ca29b6SJames Wright     PetscCall(VecGetSize(Q, &N));
51*93ca29b6SJames Wright     PetscCheck(length == N, comm, PETSC_ERR_ARG_INCOMP, "File Vec has length %" PetscInt_FMT " but DM has global Vec size %" PetscInt_FMT, length, N);
52*93ca29b6SJames Wright     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_TRUE));
53*93ca29b6SJames Wright   } else SETERRQ(comm, PETSC_ERR_FILE_UNEXPECTED, "Not a fluids header token or a PETSc Vec in file");
54*93ca29b6SJames Wright 
55*93ca29b6SJames Wright   PetscCall(VecLoad(Q, viewer));
56*93ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
57*93ca29b6SJames Wright }
58*93ca29b6SJames Wright 
59*93ca29b6SJames Wright /*
60*93ca29b6SJames Wright  * @brief Open a PHASTA *.dat file, grabbing dimensions and file pointer
61*93ca29b6SJames Wright  *
62*93ca29b6SJames Wright  * This function opens the file specified by `path` using `PetscFOpen` and passes the file pointer in `fp`.
63*93ca29b6SJames Wright  * It is not closed in this function, thus `fp` must be closed sometime after this function has been called (using `PetscFClose` for example).
64*93ca29b6SJames Wright  *
65*93ca29b6SJames Wright  * Assumes that the first line of the file has the number of rows and columns as the only two entries, separated by a single space.
66*93ca29b6SJames Wright  *
67*93ca29b6SJames Wright  * @param[in]  comm           MPI_Comm for the program
68*93ca29b6SJames Wright  * @param[in]  path           Path to the file
69*93ca29b6SJames Wright  * @param[in]  char_array_len Length of the character array that should contain each line
70*93ca29b6SJames Wright  * @param[out] dims           Dimensions of the file, taken from the first line of the file
71*93ca29b6SJames Wright  * @param[out] fp File        pointer to the opened file
72*93ca29b6SJames Wright  */
73*93ca29b6SJames Wright PetscErrorCode PhastaDatFileOpen(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], const PetscInt char_array_len, PetscInt dims[2],
74*93ca29b6SJames Wright                                  FILE **fp) {
75*93ca29b6SJames Wright   int    ndims;
76*93ca29b6SJames Wright   char   line[char_array_len];
77*93ca29b6SJames Wright   char **array;
78*93ca29b6SJames Wright 
79*93ca29b6SJames Wright   PetscFunctionBeginUser;
80*93ca29b6SJames Wright   PetscCall(PetscFOpen(comm, path, "r", fp));
81*93ca29b6SJames Wright   PetscCall(PetscSynchronizedFGets(comm, *fp, char_array_len, line));
82*93ca29b6SJames Wright   PetscCall(PetscStrToArray(line, ' ', &ndims, &array));
83*93ca29b6SJames Wright   PetscCheck(ndims == 2, comm, PETSC_ERR_FILE_UNEXPECTED, "Found %d dimensions instead of 2 on the first line of %s", ndims, path);
84*93ca29b6SJames Wright 
85*93ca29b6SJames Wright   for (PetscInt i = 0; i < ndims; i++) dims[i] = atoi(array[i]);
86*93ca29b6SJames Wright   PetscCall(PetscStrToArrayDestroy(ndims, array));
87*93ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
88*93ca29b6SJames Wright }
89*93ca29b6SJames Wright 
90*93ca29b6SJames Wright /*
91*93ca29b6SJames Wright  * @brief Get the number of rows for the PHASTA file at path.
92*93ca29b6SJames Wright  *
93*93ca29b6SJames Wright  * Assumes that the first line of the file has the number of rows and columns as the only two entries, separated by a single space.
94*93ca29b6SJames Wright  *
95*93ca29b6SJames Wright  * @param[in]  comm  MPI_Comm for the program
96*93ca29b6SJames Wright  * @param[in]  path  Path to the file
97*93ca29b6SJames Wright  * @param[out] nrows Number of rows
98*93ca29b6SJames Wright  */
99*93ca29b6SJames Wright PetscErrorCode PhastaDatFileGetNRows(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], PetscInt *nrows) {
100*93ca29b6SJames Wright   const PetscInt char_array_len = 512;
101*93ca29b6SJames Wright   PetscInt       dims[2];
102*93ca29b6SJames Wright   FILE          *fp;
103*93ca29b6SJames Wright 
104*93ca29b6SJames Wright   PetscFunctionBeginUser;
105*93ca29b6SJames Wright   PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp));
106*93ca29b6SJames Wright   *nrows = dims[0];
107*93ca29b6SJames Wright   PetscCall(PetscFClose(comm, fp));
108*93ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
109*93ca29b6SJames Wright }
110*93ca29b6SJames Wright 
111*93ca29b6SJames Wright PetscErrorCode PhastaDatFileReadToArrayReal(MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], PetscReal array[]) {
112*93ca29b6SJames Wright   PetscInt       dims[2];
113*93ca29b6SJames Wright   FILE          *fp;
114*93ca29b6SJames Wright   const PetscInt char_array_len = 512;
115*93ca29b6SJames Wright   char           line[char_array_len];
116*93ca29b6SJames Wright 
117*93ca29b6SJames Wright   PetscFunctionBeginUser;
118*93ca29b6SJames Wright   PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp));
119*93ca29b6SJames Wright 
120*93ca29b6SJames Wright   for (PetscInt i = 0; i < dims[0]; i++) {
121*93ca29b6SJames Wright     int    ndims;
122*93ca29b6SJames Wright     char **row_array;
123*93ca29b6SJames Wright 
124*93ca29b6SJames Wright     PetscCall(PetscSynchronizedFGets(comm, fp, char_array_len, line));
125*93ca29b6SJames Wright     PetscCall(PetscStrToArray(line, ' ', &ndims, &row_array));
126*93ca29b6SJames Wright     PetscCheck(ndims == dims[1], comm, PETSC_ERR_FILE_UNEXPECTED,
127*93ca29b6SJames Wright                "Line %" PetscInt_FMT " of %s does not contain enough columns (%d instead of %" PetscInt_FMT ")", i, path, ndims, dims[1]);
128*93ca29b6SJames Wright 
129*93ca29b6SJames Wright     for (PetscInt j = 0; j < dims[1]; j++) array[i * dims[1] + j] = (PetscReal)atof(row_array[j]);
130*93ca29b6SJames Wright     PetscCall(PetscStrToArrayDestroy(ndims, row_array));
131*93ca29b6SJames Wright   }
132*93ca29b6SJames Wright 
133*93ca29b6SJames Wright   PetscCall(PetscFClose(comm, fp));
134*93ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
135*93ca29b6SJames Wright }
136