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] comm `MPI_Comm` 39 @param[in] viewer Viewer to read the vec from 40 @param[out] Q `Vec` to read the data into 41 @param[out] time Solution time the Vec was written at, or `NULL`. Set to 0 if legacy file format. 42 @param[out] step_number Timestep number the Vec was written at, or `NULL`. Set to 0 if legacy file format. 43 **/ 44 PetscErrorCode HoneeLoadBinaryVec(MPI_Comm comm, PetscViewer viewer, Vec Q, PetscReal *time, PetscInt *step_number) { 45 PetscInt file_step_number; 46 PetscInt32 token; 47 PetscReal file_time; 48 PetscDataType file_type = PETSC_INT32; 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