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