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*c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN = 0xceedf00; // for backwards compatibility 10*c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN_32 = 0xceedf32; 11*c9ff4f08SJames Wright const PetscInt32 HONEE_FILE_TOKEN_64 = 0xceedf64; 1293ca29b6SJames Wright 13*c9ff4f08SJames 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 31*c9ff4f08SJames Wright /** 32*c9ff4f08SJames Wright @brief Load vector from binary file, possibly with embedded solution time and step number 33*c9ff4f08SJames Wright 34*c9ff4f08SJames Wright Reads in Vec from binary file, possibly written by HONEE. 35*c9ff4f08SJames Wright If written by HONEE, will also load the solution time and timestep, otherwise not. 36*c9ff4f08SJames Wright Also handles case where file was written with different PetscInt size than is read with. 37*c9ff4f08SJames Wright 38*c9ff4f08SJames Wright @param[in] comm `MPI_Comm` 39*c9ff4f08SJames Wright @param[in] viewer Viewer to read the vec from 40*c9ff4f08SJames Wright @param[out] Q `Vec` to read the data into 41*c9ff4f08SJames Wright @param[out] time Solution time the Vec was written at, or `NULL`. Set to 0 if legacy file format. 42*c9ff4f08SJames Wright @param[out] step_number Timestep number the Vec was written at, or `NULL`. Set to 0 if legacy file format. 43*c9ff4f08SJames Wright **/ 44*c9ff4f08SJames Wright PetscErrorCode HoneeLoadBinaryVec(MPI_Comm comm, PetscViewer viewer, Vec Q, PetscReal *time, PetscInt *step_number) { 4593ca29b6SJames Wright PetscInt file_step_number; 4693ca29b6SJames Wright PetscInt32 token; 4793ca29b6SJames Wright PetscReal file_time; 4893ca29b6SJames Wright PetscDataType file_type = PETSC_INT32; 4993ca29b6SJames Wright 5093ca29b6SJames Wright PetscFunctionBeginUser; 5193ca29b6SJames Wright PetscCall(PetscViewerBinaryRead(viewer, &token, 1, NULL, PETSC_INT32)); 52*c9ff4f08SJames Wright if (token == HONEE_FILE_TOKEN_32 || token == HONEE_FILE_TOKEN_64 || 53*c9ff4f08SJames Wright token == HONEE_FILE_TOKEN) { // New style format; we're reading a file with step number and time in the header 54*c9ff4f08SJames Wright if (token == HONEE_FILE_TOKEN_32) file_type = PETSC_INT32; 55*c9ff4f08SJames 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)); 64*c9ff4f08SJames Wright file_time = 0; 65*c9ff4f08SJames 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 68*c9ff4f08SJames Wright if (time) *time = file_time; 69*c9ff4f08SJames Wright if (step_number) *step_number = file_step_number; 7093ca29b6SJames Wright PetscCall(VecLoad(Q, viewer)); 7193ca29b6SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 7293ca29b6SJames Wright } 7393ca29b6SJames Wright 74*c9ff4f08SJames Wright /** 75*c9ff4f08SJames Wright @brief Open a PHASTA *.dat file, grabbing dimensions and file pointer 76*c9ff4f08SJames Wright 77*c9ff4f08SJames Wright This function opens the file specified by `path` using `PetscFOpen` and passes the file pointer in `fp`. 78*c9ff4f08SJames Wright It is not closed in this function, thus `fp` must be closed sometime after this function has been called (using `PetscFClose` for example). 79*c9ff4f08SJames Wright 80*c9ff4f08SJames 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. 81*c9ff4f08SJames Wright 82*c9ff4f08SJames Wright @param[in] comm MPI_Comm for the program 83*c9ff4f08SJames Wright @param[in] path Path to the file 84*c9ff4f08SJames Wright @param[in] char_array_len Length of the character array that should contain each line 85*c9ff4f08SJames Wright @param[out] dims Dimensions of the file, taken from the first line of the file 86*c9ff4f08SJames Wright @param[out] fp File pointer to the opened file 87*c9ff4f08SJames Wright **/ 8893ca29b6SJames Wright PetscErrorCode PhastaDatFileOpen(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], const PetscInt char_array_len, PetscInt dims[2], 8993ca29b6SJames Wright FILE **fp) { 9093ca29b6SJames Wright int ndims; 9193ca29b6SJames Wright char line[char_array_len]; 9293ca29b6SJames Wright char **array; 9393ca29b6SJames Wright 9493ca29b6SJames Wright PetscFunctionBeginUser; 9593ca29b6SJames Wright PetscCall(PetscFOpen(comm, path, "r", fp)); 9693ca29b6SJames Wright PetscCall(PetscSynchronizedFGets(comm, *fp, char_array_len, line)); 9793ca29b6SJames Wright PetscCall(PetscStrToArray(line, ' ', &ndims, &array)); 9893ca29b6SJames Wright PetscCheck(ndims == 2, comm, PETSC_ERR_FILE_UNEXPECTED, "Found %d dimensions instead of 2 on the first line of %s", ndims, path); 9993ca29b6SJames Wright 10093ca29b6SJames Wright for (PetscInt i = 0; i < ndims; i++) dims[i] = atoi(array[i]); 10193ca29b6SJames Wright PetscCall(PetscStrToArrayDestroy(ndims, array)); 10293ca29b6SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 10393ca29b6SJames Wright } 10493ca29b6SJames Wright 105*c9ff4f08SJames Wright /** 106*c9ff4f08SJames Wright @brief Get the number of rows for the PHASTA file at path. 107*c9ff4f08SJames Wright 108*c9ff4f08SJames 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. 109*c9ff4f08SJames Wright 110*c9ff4f08SJames Wright @param[in] comm `MPI_Comm` for the program 111*c9ff4f08SJames Wright @param[in] path Path to the file 112*c9ff4f08SJames Wright @param[out] nrows Number of rows 113*c9ff4f08SJames Wright **/ 11493ca29b6SJames Wright PetscErrorCode PhastaDatFileGetNRows(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], PetscInt *nrows) { 11593ca29b6SJames Wright const PetscInt char_array_len = 512; 11693ca29b6SJames Wright PetscInt dims[2]; 11793ca29b6SJames Wright FILE *fp; 11893ca29b6SJames Wright 11993ca29b6SJames Wright PetscFunctionBeginUser; 12093ca29b6SJames Wright PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp)); 12193ca29b6SJames Wright *nrows = dims[0]; 12293ca29b6SJames Wright PetscCall(PetscFClose(comm, fp)); 12393ca29b6SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 12493ca29b6SJames Wright } 12593ca29b6SJames Wright 126*c9ff4f08SJames Wright /** 127*c9ff4f08SJames Wright @brief Read PetscReal values from PHASTA file 128*c9ff4f08SJames Wright 129*c9ff4f08SJames Wright @param[in] comm `MPI_Comm` for the program 130*c9ff4f08SJames Wright @param[in] path Path to the file 131*c9ff4f08SJames Wright @param[out] array Pointer to allocated array of correct size 132*c9ff4f08SJames Wright **/ 13393ca29b6SJames Wright PetscErrorCode PhastaDatFileReadToArrayReal(MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], PetscReal array[]) { 13493ca29b6SJames Wright PetscInt dims[2]; 13593ca29b6SJames Wright FILE *fp; 13693ca29b6SJames Wright const PetscInt char_array_len = 512; 13793ca29b6SJames Wright char line[char_array_len]; 13893ca29b6SJames Wright 13993ca29b6SJames Wright PetscFunctionBeginUser; 14093ca29b6SJames Wright PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp)); 14193ca29b6SJames Wright 14293ca29b6SJames Wright for (PetscInt i = 0; i < dims[0]; i++) { 14393ca29b6SJames Wright int ndims; 14493ca29b6SJames Wright char **row_array; 14593ca29b6SJames Wright 14693ca29b6SJames Wright PetscCall(PetscSynchronizedFGets(comm, fp, char_array_len, line)); 14793ca29b6SJames Wright PetscCall(PetscStrToArray(line, ' ', &ndims, &row_array)); 14893ca29b6SJames Wright PetscCheck(ndims == dims[1], comm, PETSC_ERR_FILE_UNEXPECTED, 14993ca29b6SJames Wright "Line %" PetscInt_FMT " of %s does not contain enough columns (%d instead of %" PetscInt_FMT ")", i, path, ndims, dims[1]); 15093ca29b6SJames Wright 15193ca29b6SJames Wright for (PetscInt j = 0; j < dims[1]; j++) array[i * dims[1] + j] = (PetscReal)atof(row_array[j]); 15293ca29b6SJames Wright PetscCall(PetscStrToArrayDestroy(ndims, row_array)); 15393ca29b6SJames Wright } 15493ca29b6SJames Wright 15593ca29b6SJames Wright PetscCall(PetscFClose(comm, fp)); 15693ca29b6SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 15793ca29b6SJames Wright } 158