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