xref: /honee/src/honee-file.c (revision d85b32c91a70d8de3dc122ff47ecac274d4c5311)
193ca29b6SJames Wright // SPDX-FileCopyrightText: Copyright (c) 2017-2024, HONEE contributors.
293ca29b6SJames Wright // SPDX-License-Identifier: Apache-2.0 OR BSD-2-Clause
393ca29b6SJames Wright 
493ca29b6SJames Wright /// @file
593ca29b6SJames Wright /// Custom file I/O functions for HONEE
693ca29b6SJames Wright 
793ca29b6SJames Wright #include <honee-file.h>
893ca29b6SJames Wright 
9*d85b32c9SJames Wright /**
10*d85b32c9SJames Wright   @brief Check if a filename has a file extension
11*d85b32c9SJames Wright 
12*d85b32c9SJames Wright   @param[in]  comm         `MPI_Comm` used for error handling
13*d85b32c9SJames Wright   @param[in]  filename     Filename to check
14*d85b32c9SJames Wright   @param[in]  extension    Extension to check for
15*d85b32c9SJames Wright   @param[out] is_extension Whether the filename has the extension
16*d85b32c9SJames Wright **/
17*d85b32c9SJames Wright PetscErrorCode HoneeCheckFilenameExtension(MPI_Comm comm, const char filename[], const char extension[], PetscBool *is_extension) {
18*d85b32c9SJames Wright   size_t len, ext_len;
19*d85b32c9SJames Wright 
20*d85b32c9SJames Wright   PetscFunctionBeginUser;
21*d85b32c9SJames Wright   PetscCall(PetscStrlen(filename, &len));
22*d85b32c9SJames Wright   PetscCall(PetscStrlen(extension, &ext_len));
23*d85b32c9SJames Wright   PetscCheck(ext_len, comm, PETSC_ERR_ARG_WRONG, "Zero-size extension: %s", extension);
24*d85b32c9SJames Wright   if (len < ext_len) *is_extension = PETSC_FALSE;
25*d85b32c9SJames Wright   else PetscCall(PetscStrncmp(filename + len - ext_len, extension, ext_len, is_extension));
26*d85b32c9SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
27*d85b32c9SJames Wright }
28*d85b32c9SJames Wright 
29c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN    = 0xceedf00;  // for backwards compatibility
30c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN_32 = 0xceedf32;
31c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN_64 = 0xceedf64;
3293ca29b6SJames Wright 
33c9ff4f08SJames Wright // @brief Read in binary int based on it's data type
3493ca29b6SJames Wright static PetscErrorCode BinaryReadIntoInt(PetscViewer viewer, PetscInt *out, PetscDataType file_type) {
3593ca29b6SJames Wright   PetscFunctionBeginUser;
3693ca29b6SJames Wright   *out = -13;  // appease the overzealous GCC compiler warning Gods
3793ca29b6SJames Wright   if (file_type == PETSC_INT32) {
3893ca29b6SJames Wright     PetscInt32 val;
3993ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &val, 1, NULL, PETSC_INT32));
4093ca29b6SJames Wright     *out = val;
4193ca29b6SJames Wright   } else if (file_type == PETSC_INT64) {
4293ca29b6SJames Wright     PetscInt64 val;
4393ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &val, 1, NULL, PETSC_INT64));
4493ca29b6SJames Wright     *out = val;
4593ca29b6SJames Wright   } else {
4693ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, out, 1, NULL, PETSC_INT));
4793ca29b6SJames Wright   }
4893ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
4993ca29b6SJames Wright }
5093ca29b6SJames Wright 
51c9ff4f08SJames Wright /**
52c9ff4f08SJames Wright   @brief Load vector from binary file, possibly with embedded solution time and step number
53c9ff4f08SJames Wright 
54c9ff4f08SJames Wright   Reads in Vec from binary file, possibly written by HONEE.
55c9ff4f08SJames Wright   If written by HONEE, will also load the solution time and timestep, otherwise not.
56c9ff4f08SJames Wright   Also handles case where file was written with different PetscInt size than is read with.
57c9ff4f08SJames Wright 
58360b37c9SJames Wright   @param[in]  viewer      `PetscViewer` to read the vec from. Must be a binary viewer
59c9ff4f08SJames Wright   @param[out] Q           `Vec` to read the data into
60c9ff4f08SJames Wright   @param[out] time        Solution time the Vec was written at, or `NULL`. Set to 0 if legacy file format.
61c9ff4f08SJames Wright   @param[out] step_number Timestep number the Vec was written at, or `NULL`. Set to 0 if legacy file format.
62c9ff4f08SJames Wright **/
63360b37c9SJames Wright PetscErrorCode HoneeLoadBinaryVec(PetscViewer viewer, Vec Q, PetscReal *time, PetscInt *step_number) {
6493ca29b6SJames Wright   PetscInt      file_step_number;
6593ca29b6SJames Wright   PetscInt32    token;
6693ca29b6SJames Wright   PetscReal     file_time;
6793ca29b6SJames Wright   PetscDataType file_type = PETSC_INT32;
68360b37c9SJames Wright   MPI_Comm      comm      = PetscObjectComm((PetscObject)viewer);
6993ca29b6SJames Wright 
7093ca29b6SJames Wright   PetscFunctionBeginUser;
7193ca29b6SJames Wright   PetscCall(PetscViewerBinaryRead(viewer, &token, 1, NULL, PETSC_INT32));
72c9ff4f08SJames Wright   if (token == HONEE_FILE_TOKEN_32 || token == HONEE_FILE_TOKEN_64 ||
73c9ff4f08SJames Wright       token == HONEE_FILE_TOKEN) {  // New style format; we're reading a file with step number and time in the header
74c9ff4f08SJames Wright     if (token == HONEE_FILE_TOKEN_32) file_type = PETSC_INT32;
75c9ff4f08SJames Wright     else if (token == HONEE_FILE_TOKEN_64) file_type = PETSC_INT64;
7693ca29b6SJames Wright     PetscCall(BinaryReadIntoInt(viewer, &file_step_number, file_type));
7793ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &file_time, 1, NULL, PETSC_REAL));
7893ca29b6SJames Wright   } else if (token == VEC_FILE_CLASSID) {  // Legacy format of just the vector, encoded as [VEC_FILE_CLASSID, length, ]
7993ca29b6SJames Wright     PetscInt length, N;
8093ca29b6SJames Wright     PetscCall(BinaryReadIntoInt(viewer, &length, file_type));
8193ca29b6SJames Wright     PetscCall(VecGetSize(Q, &N));
8293ca29b6SJames 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);
8393ca29b6SJames Wright     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_TRUE));
84c9ff4f08SJames Wright     file_time        = 0;
85c9ff4f08SJames Wright     file_step_number = 0;
8693ca29b6SJames Wright   } else SETERRQ(comm, PETSC_ERR_FILE_UNEXPECTED, "Not a fluids header token or a PETSc Vec in file");
8793ca29b6SJames Wright 
88c9ff4f08SJames Wright   if (time) *time = file_time;
89c9ff4f08SJames Wright   if (step_number) *step_number = file_step_number;
9093ca29b6SJames Wright   PetscCall(VecLoad(Q, viewer));
9193ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
9293ca29b6SJames Wright }
9393ca29b6SJames Wright 
94c9ff4f08SJames Wright /**
95b237916aSJames Wright   @brief Write vector to binary file with solution time and step number
96b237916aSJames Wright 
97b237916aSJames Wright   @param[in] viewer      `PetscViewer` for binary file. Must be binary viewer and in write mode
98b237916aSJames Wright   @param[in] Q           `Vec` of the solution
99b237916aSJames Wright   @param[in] time        Solution time of the `Vec`
100b237916aSJames Wright   @param[in] step_number Timestep number of the Vec
101b237916aSJames Wright **/
102b237916aSJames Wright PetscErrorCode HoneeWriteBinaryVec(PetscViewer viewer, Vec Q, PetscReal time, PetscInt step_number) {
103b237916aSJames Wright   PetscInt32 token = PetscDefined(USE_64BIT_INDICES) ? HONEE_FILE_TOKEN_64 : HONEE_FILE_TOKEN_32;
104b237916aSJames Wright 
105b237916aSJames Wright   PetscFunctionBeginUser;
106b237916aSJames Wright   {  // Verify viewer is in correct state
107b237916aSJames Wright     PetscViewerType viewer_type;
108b237916aSJames Wright     PetscFileMode   file_mode;
109b237916aSJames Wright     PetscBool       is_binary_viewer;
110b237916aSJames Wright     MPI_Comm        comm = PetscObjectComm((PetscObject)viewer);
111b237916aSJames Wright 
112b237916aSJames Wright     PetscCall(PetscViewerGetType(viewer, &viewer_type));
113b237916aSJames Wright     PetscCall(PetscStrcmp(viewer_type, PETSCVIEWERBINARY, &is_binary_viewer));
114b237916aSJames Wright     PetscCheck(is_binary_viewer, comm, PETSC_ERR_ARG_WRONGSTATE, "Viewer must be binary type; instead got %s", viewer_type);
115b237916aSJames Wright     PetscCall(PetscViewerFileGetMode(viewer, &file_mode));
116b237916aSJames Wright     PetscCheck(file_mode == FILE_MODE_WRITE, comm, PETSC_ERR_ARG_WRONGSTATE, "Viewer must be binary type; instead got %s",
117b237916aSJames Wright                file_mode == -1 ? "UNDEFINED" : PetscFileModes[file_mode]);
118b237916aSJames Wright   }
119b237916aSJames Wright 
120b237916aSJames Wright   PetscCall(PetscViewerBinaryWrite(viewer, &token, 1, PETSC_INT32));
121b237916aSJames Wright   PetscCall(PetscViewerBinaryWrite(viewer, &step_number, 1, PETSC_INT));
122b237916aSJames Wright   PetscCall(PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL));
123b237916aSJames Wright   PetscCall(VecView(Q, viewer));
124b237916aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
125b237916aSJames Wright }
126b237916aSJames Wright 
127b237916aSJames Wright /**
128c9ff4f08SJames Wright   @brief Open a PHASTA *.dat file, grabbing dimensions and file pointer
129c9ff4f08SJames Wright 
130c9ff4f08SJames Wright   This function opens the file specified by `path` using `PetscFOpen` and passes the file pointer in `fp`.
131c9ff4f08SJames Wright   It is not closed in this function, thus `fp` must be closed sometime after this function has been called (using `PetscFClose` for example).
132c9ff4f08SJames Wright 
133c9ff4f08SJames 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.
134c9ff4f08SJames Wright 
135c9ff4f08SJames Wright   @param[in]  comm           MPI_Comm for the program
136c9ff4f08SJames Wright   @param[in]  path           Path to the file
137c9ff4f08SJames Wright   @param[in]  char_array_len Length of the character array that should contain each line
138c9ff4f08SJames Wright   @param[out] dims           Dimensions of the file, taken from the first line of the file
139c9ff4f08SJames Wright   @param[out] fp File        pointer to the opened file
140c9ff4f08SJames Wright **/
1417ce151adSJames Wright PetscErrorCode PhastaDatFileOpen(const MPI_Comm comm, const char path[], const PetscInt char_array_len, PetscInt dims[2], FILE **fp) {
14293ca29b6SJames Wright   int    ndims;
14393ca29b6SJames Wright   char   line[char_array_len];
14493ca29b6SJames Wright   char **array;
14593ca29b6SJames Wright 
14693ca29b6SJames Wright   PetscFunctionBeginUser;
14793ca29b6SJames Wright   PetscCall(PetscFOpen(comm, path, "r", fp));
14893ca29b6SJames Wright   PetscCall(PetscSynchronizedFGets(comm, *fp, char_array_len, line));
14993ca29b6SJames Wright   PetscCall(PetscStrToArray(line, ' ', &ndims, &array));
15093ca29b6SJames Wright   PetscCheck(ndims == 2, comm, PETSC_ERR_FILE_UNEXPECTED, "Found %d dimensions instead of 2 on the first line of %s", ndims, path);
15193ca29b6SJames Wright 
15293ca29b6SJames Wright   for (PetscInt i = 0; i < ndims; i++) dims[i] = atoi(array[i]);
15393ca29b6SJames Wright   PetscCall(PetscStrToArrayDestroy(ndims, array));
15493ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
15593ca29b6SJames Wright }
15693ca29b6SJames Wright 
157c9ff4f08SJames Wright /**
158c9ff4f08SJames Wright   @brief Get the number of rows for the PHASTA file at path.
159c9ff4f08SJames Wright 
160c9ff4f08SJames 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.
161c9ff4f08SJames Wright 
162c9ff4f08SJames Wright   @param[in]  comm  `MPI_Comm` for the program
163c9ff4f08SJames Wright   @param[in]  path  Path to the file
164c9ff4f08SJames Wright   @param[out] nrows Number of rows
165c9ff4f08SJames Wright **/
1667ce151adSJames Wright PetscErrorCode PhastaDatFileGetNRows(const MPI_Comm comm, const char path[], PetscInt *nrows) {
16793ca29b6SJames Wright   const PetscInt char_array_len = 512;
16893ca29b6SJames Wright   PetscInt       dims[2];
16993ca29b6SJames Wright   FILE          *fp;
17093ca29b6SJames Wright 
17193ca29b6SJames Wright   PetscFunctionBeginUser;
17293ca29b6SJames Wright   PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp));
17393ca29b6SJames Wright   *nrows = dims[0];
17493ca29b6SJames Wright   PetscCall(PetscFClose(comm, fp));
17593ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
17693ca29b6SJames Wright }
17793ca29b6SJames Wright 
178c9ff4f08SJames Wright /**
179c9ff4f08SJames Wright   @brief Read PetscReal values from PHASTA file
180c9ff4f08SJames Wright 
181c9ff4f08SJames Wright   @param[in]  comm  `MPI_Comm` for the program
182c9ff4f08SJames Wright   @param[in]  path  Path to the file
183c9ff4f08SJames Wright   @param[out] array Pointer to allocated array of correct size
184c9ff4f08SJames Wright **/
1857ce151adSJames Wright PetscErrorCode PhastaDatFileReadToArrayReal(MPI_Comm comm, const char path[], PetscReal array[]) {
18693ca29b6SJames Wright   PetscInt       dims[2];
18793ca29b6SJames Wright   FILE          *fp;
18893ca29b6SJames Wright   const PetscInt char_array_len = 512;
18993ca29b6SJames Wright   char           line[char_array_len];
19093ca29b6SJames Wright 
19193ca29b6SJames Wright   PetscFunctionBeginUser;
19293ca29b6SJames Wright   PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp));
19393ca29b6SJames Wright 
19493ca29b6SJames Wright   for (PetscInt i = 0; i < dims[0]; i++) {
19593ca29b6SJames Wright     int    ndims;
19693ca29b6SJames Wright     char **row_array;
19793ca29b6SJames Wright 
19893ca29b6SJames Wright     PetscCall(PetscSynchronizedFGets(comm, fp, char_array_len, line));
19993ca29b6SJames Wright     PetscCall(PetscStrToArray(line, ' ', &ndims, &row_array));
20093ca29b6SJames Wright     PetscCheck(ndims == dims[1], comm, PETSC_ERR_FILE_UNEXPECTED,
20193ca29b6SJames Wright                "Line %" PetscInt_FMT " of %s does not contain enough columns (%d instead of %" PetscInt_FMT ")", i, path, ndims, dims[1]);
20293ca29b6SJames Wright 
20393ca29b6SJames Wright     for (PetscInt j = 0; j < dims[1]; j++) array[i * dims[1] + j] = (PetscReal)atof(row_array[j]);
20493ca29b6SJames Wright     PetscCall(PetscStrToArrayDestroy(ndims, row_array));
20593ca29b6SJames Wright   }
20693ca29b6SJames Wright 
20793ca29b6SJames Wright   PetscCall(PetscFClose(comm, fp));
20893ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
20993ca29b6SJames Wright }
210