xref: /honee/src/honee-file.c (revision b237916a9590bf625a0bae8c535d86eaebf4f448)
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 
9c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN    = 0xceedf00;  // for backwards compatibility
10c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN_32 = 0xceedf32;
11c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN_64 = 0xceedf64;
1293ca29b6SJames Wright 
13c9ff4f08SJames Wright // @brief Read in binary int based on it's data type
1493ca29b6SJames Wright static PetscErrorCode BinaryReadIntoInt(PetscViewer viewer, PetscInt *out, PetscDataType file_type) {
1593ca29b6SJames Wright   PetscFunctionBeginUser;
1693ca29b6SJames Wright   *out = -13;  // appease the overzealous GCC compiler warning Gods
1793ca29b6SJames Wright   if (file_type == PETSC_INT32) {
1893ca29b6SJames Wright     PetscInt32 val;
1993ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &val, 1, NULL, PETSC_INT32));
2093ca29b6SJames Wright     *out = val;
2193ca29b6SJames Wright   } else if (file_type == PETSC_INT64) {
2293ca29b6SJames Wright     PetscInt64 val;
2393ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &val, 1, NULL, PETSC_INT64));
2493ca29b6SJames Wright     *out = val;
2593ca29b6SJames Wright   } else {
2693ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, out, 1, NULL, PETSC_INT));
2793ca29b6SJames Wright   }
2893ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
2993ca29b6SJames Wright }
3093ca29b6SJames Wright 
31c9ff4f08SJames Wright /**
32c9ff4f08SJames Wright   @brief Load vector from binary file, possibly with embedded solution time and step number
33c9ff4f08SJames Wright 
34c9ff4f08SJames Wright   Reads in Vec from binary file, possibly written by HONEE.
35c9ff4f08SJames Wright   If written by HONEE, will also load the solution time and timestep, otherwise not.
36c9ff4f08SJames Wright   Also handles case where file was written with different PetscInt size than is read with.
37c9ff4f08SJames Wright 
38360b37c9SJames Wright   @param[in]  viewer      `PetscViewer` to read the vec from. Must be a binary viewer
39c9ff4f08SJames Wright   @param[out] Q           `Vec` to read the data into
40c9ff4f08SJames Wright   @param[out] time        Solution time the Vec was written at, or `NULL`. Set to 0 if legacy file format.
41c9ff4f08SJames Wright   @param[out] step_number Timestep number the Vec was written at, or `NULL`. Set to 0 if legacy file format.
42c9ff4f08SJames Wright **/
43360b37c9SJames Wright PetscErrorCode HoneeLoadBinaryVec(PetscViewer viewer, Vec Q, PetscReal *time, PetscInt *step_number) {
4493ca29b6SJames Wright   PetscInt      file_step_number;
4593ca29b6SJames Wright   PetscInt32    token;
4693ca29b6SJames Wright   PetscReal     file_time;
4793ca29b6SJames Wright   PetscDataType file_type = PETSC_INT32;
48360b37c9SJames Wright   MPI_Comm      comm      = PetscObjectComm((PetscObject)viewer);
4993ca29b6SJames Wright 
5093ca29b6SJames Wright   PetscFunctionBeginUser;
5193ca29b6SJames Wright   PetscCall(PetscViewerBinaryRead(viewer, &token, 1, NULL, PETSC_INT32));
52c9ff4f08SJames Wright   if (token == HONEE_FILE_TOKEN_32 || token == HONEE_FILE_TOKEN_64 ||
53c9ff4f08SJames Wright       token == HONEE_FILE_TOKEN) {  // New style format; we're reading a file with step number and time in the header
54c9ff4f08SJames Wright     if (token == HONEE_FILE_TOKEN_32) file_type = PETSC_INT32;
55c9ff4f08SJames Wright     else if (token == HONEE_FILE_TOKEN_64) file_type = PETSC_INT64;
5693ca29b6SJames Wright     PetscCall(BinaryReadIntoInt(viewer, &file_step_number, file_type));
5793ca29b6SJames Wright     PetscCall(PetscViewerBinaryRead(viewer, &file_time, 1, NULL, PETSC_REAL));
5893ca29b6SJames Wright   } else if (token == VEC_FILE_CLASSID) {  // Legacy format of just the vector, encoded as [VEC_FILE_CLASSID, length, ]
5993ca29b6SJames Wright     PetscInt length, N;
6093ca29b6SJames Wright     PetscCall(BinaryReadIntoInt(viewer, &length, file_type));
6193ca29b6SJames Wright     PetscCall(VecGetSize(Q, &N));
6293ca29b6SJames 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);
6393ca29b6SJames Wright     PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_TRUE));
64c9ff4f08SJames Wright     file_time        = 0;
65c9ff4f08SJames Wright     file_step_number = 0;
6693ca29b6SJames Wright   } else SETERRQ(comm, PETSC_ERR_FILE_UNEXPECTED, "Not a fluids header token or a PETSc Vec in file");
6793ca29b6SJames Wright 
68c9ff4f08SJames Wright   if (time) *time = file_time;
69c9ff4f08SJames Wright   if (step_number) *step_number = file_step_number;
7093ca29b6SJames Wright   PetscCall(VecLoad(Q, viewer));
7193ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
7293ca29b6SJames Wright }
7393ca29b6SJames Wright 
74c9ff4f08SJames Wright /**
75*b237916aSJames Wright   @brief Write vector to binary file with solution time and step number
76*b237916aSJames Wright 
77*b237916aSJames Wright   @param[in] viewer      `PetscViewer` for binary file. Must be binary viewer and in write mode
78*b237916aSJames Wright   @param[in] Q           `Vec` of the solution
79*b237916aSJames Wright   @param[in] time        Solution time of the `Vec`
80*b237916aSJames Wright   @param[in] step_number Timestep number of the Vec
81*b237916aSJames Wright **/
82*b237916aSJames Wright PetscErrorCode HoneeWriteBinaryVec(PetscViewer viewer, Vec Q, PetscReal time, PetscInt step_number) {
83*b237916aSJames Wright   PetscInt32 token = PetscDefined(USE_64BIT_INDICES) ? HONEE_FILE_TOKEN_64 : HONEE_FILE_TOKEN_32;
84*b237916aSJames Wright 
85*b237916aSJames Wright   PetscFunctionBeginUser;
86*b237916aSJames Wright   {  // Verify viewer is in correct state
87*b237916aSJames Wright     PetscViewerType viewer_type;
88*b237916aSJames Wright     PetscFileMode   file_mode;
89*b237916aSJames Wright     PetscBool       is_binary_viewer;
90*b237916aSJames Wright     MPI_Comm        comm = PetscObjectComm((PetscObject)viewer);
91*b237916aSJames Wright 
92*b237916aSJames Wright     PetscCall(PetscViewerGetType(viewer, &viewer_type));
93*b237916aSJames Wright     PetscCall(PetscStrcmp(viewer_type, PETSCVIEWERBINARY, &is_binary_viewer));
94*b237916aSJames Wright     PetscCheck(is_binary_viewer, comm, PETSC_ERR_ARG_WRONGSTATE, "Viewer must be binary type; instead got %s", viewer_type);
95*b237916aSJames Wright     PetscCall(PetscViewerFileGetMode(viewer, &file_mode));
96*b237916aSJames Wright     PetscCheck(file_mode == FILE_MODE_WRITE, comm, PETSC_ERR_ARG_WRONGSTATE, "Viewer must be binary type; instead got %s",
97*b237916aSJames Wright                file_mode == -1 ? "UNDEFINED" : PetscFileModes[file_mode]);
98*b237916aSJames Wright   }
99*b237916aSJames Wright 
100*b237916aSJames Wright   PetscCall(PetscViewerBinaryWrite(viewer, &token, 1, PETSC_INT32));
101*b237916aSJames Wright   PetscCall(PetscViewerBinaryWrite(viewer, &step_number, 1, PETSC_INT));
102*b237916aSJames Wright   PetscCall(PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL));
103*b237916aSJames Wright   PetscCall(VecView(Q, viewer));
104*b237916aSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
105*b237916aSJames Wright }
106*b237916aSJames Wright 
107*b237916aSJames Wright /**
108c9ff4f08SJames Wright   @brief Open a PHASTA *.dat file, grabbing dimensions and file pointer
109c9ff4f08SJames Wright 
110c9ff4f08SJames Wright   This function opens the file specified by `path` using `PetscFOpen` and passes the file pointer in `fp`.
111c9ff4f08SJames Wright   It is not closed in this function, thus `fp` must be closed sometime after this function has been called (using `PetscFClose` for example).
112c9ff4f08SJames Wright 
113c9ff4f08SJames 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.
114c9ff4f08SJames Wright 
115c9ff4f08SJames Wright   @param[in]  comm           MPI_Comm for the program
116c9ff4f08SJames Wright   @param[in]  path           Path to the file
117c9ff4f08SJames Wright   @param[in]  char_array_len Length of the character array that should contain each line
118c9ff4f08SJames Wright   @param[out] dims           Dimensions of the file, taken from the first line of the file
119c9ff4f08SJames Wright   @param[out] fp File        pointer to the opened file
120c9ff4f08SJames Wright **/
12193ca29b6SJames Wright PetscErrorCode PhastaDatFileOpen(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], const PetscInt char_array_len, PetscInt dims[2],
12293ca29b6SJames Wright                                  FILE **fp) {
12393ca29b6SJames Wright   int    ndims;
12493ca29b6SJames Wright   char   line[char_array_len];
12593ca29b6SJames Wright   char **array;
12693ca29b6SJames Wright 
12793ca29b6SJames Wright   PetscFunctionBeginUser;
12893ca29b6SJames Wright   PetscCall(PetscFOpen(comm, path, "r", fp));
12993ca29b6SJames Wright   PetscCall(PetscSynchronizedFGets(comm, *fp, char_array_len, line));
13093ca29b6SJames Wright   PetscCall(PetscStrToArray(line, ' ', &ndims, &array));
13193ca29b6SJames Wright   PetscCheck(ndims == 2, comm, PETSC_ERR_FILE_UNEXPECTED, "Found %d dimensions instead of 2 on the first line of %s", ndims, path);
13293ca29b6SJames Wright 
13393ca29b6SJames Wright   for (PetscInt i = 0; i < ndims; i++) dims[i] = atoi(array[i]);
13493ca29b6SJames Wright   PetscCall(PetscStrToArrayDestroy(ndims, array));
13593ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
13693ca29b6SJames Wright }
13793ca29b6SJames Wright 
138c9ff4f08SJames Wright /**
139c9ff4f08SJames Wright   @brief Get the number of rows for the PHASTA file at path.
140c9ff4f08SJames Wright 
141c9ff4f08SJames 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.
142c9ff4f08SJames Wright 
143c9ff4f08SJames Wright   @param[in]  comm  `MPI_Comm` for the program
144c9ff4f08SJames Wright   @param[in]  path  Path to the file
145c9ff4f08SJames Wright   @param[out] nrows Number of rows
146c9ff4f08SJames Wright **/
14793ca29b6SJames Wright PetscErrorCode PhastaDatFileGetNRows(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], PetscInt *nrows) {
14893ca29b6SJames Wright   const PetscInt char_array_len = 512;
14993ca29b6SJames Wright   PetscInt       dims[2];
15093ca29b6SJames Wright   FILE          *fp;
15193ca29b6SJames Wright 
15293ca29b6SJames Wright   PetscFunctionBeginUser;
15393ca29b6SJames Wright   PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp));
15493ca29b6SJames Wright   *nrows = dims[0];
15593ca29b6SJames Wright   PetscCall(PetscFClose(comm, fp));
15693ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
15793ca29b6SJames Wright }
15893ca29b6SJames Wright 
159c9ff4f08SJames Wright /**
160c9ff4f08SJames Wright   @brief Read PetscReal values from PHASTA file
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] array Pointer to allocated array of correct size
165c9ff4f08SJames Wright **/
16693ca29b6SJames Wright PetscErrorCode PhastaDatFileReadToArrayReal(MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], PetscReal array[]) {
16793ca29b6SJames Wright   PetscInt       dims[2];
16893ca29b6SJames Wright   FILE          *fp;
16993ca29b6SJames Wright   const PetscInt char_array_len = 512;
17093ca29b6SJames Wright   char           line[char_array_len];
17193ca29b6SJames Wright 
17293ca29b6SJames Wright   PetscFunctionBeginUser;
17393ca29b6SJames Wright   PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp));
17493ca29b6SJames Wright 
17593ca29b6SJames Wright   for (PetscInt i = 0; i < dims[0]; i++) {
17693ca29b6SJames Wright     int    ndims;
17793ca29b6SJames Wright     char **row_array;
17893ca29b6SJames Wright 
17993ca29b6SJames Wright     PetscCall(PetscSynchronizedFGets(comm, fp, char_array_len, line));
18093ca29b6SJames Wright     PetscCall(PetscStrToArray(line, ' ', &ndims, &row_array));
18193ca29b6SJames Wright     PetscCheck(ndims == dims[1], comm, PETSC_ERR_FILE_UNEXPECTED,
18293ca29b6SJames Wright                "Line %" PetscInt_FMT " of %s does not contain enough columns (%d instead of %" PetscInt_FMT ")", i, path, ndims, dims[1]);
18393ca29b6SJames Wright 
18493ca29b6SJames Wright     for (PetscInt j = 0; j < dims[1]; j++) array[i * dims[1] + j] = (PetscReal)atof(row_array[j]);
18593ca29b6SJames Wright     PetscCall(PetscStrToArrayDestroy(ndims, row_array));
18693ca29b6SJames Wright   }
18793ca29b6SJames Wright 
18893ca29b6SJames Wright   PetscCall(PetscFClose(comm, fp));
18993ca29b6SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
19093ca29b6SJames Wright }
191