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 /** 75b237916aSJames Wright @brief Write vector to binary file with solution time and step number 76b237916aSJames Wright 77b237916aSJames Wright @param[in] viewer `PetscViewer` for binary file. Must be binary viewer and in write mode 78b237916aSJames Wright @param[in] Q `Vec` of the solution 79b237916aSJames Wright @param[in] time Solution time of the `Vec` 80b237916aSJames Wright @param[in] step_number Timestep number of the Vec 81b237916aSJames Wright **/ 82b237916aSJames Wright PetscErrorCode HoneeWriteBinaryVec(PetscViewer viewer, Vec Q, PetscReal time, PetscInt step_number) { 83b237916aSJames Wright PetscInt32 token = PetscDefined(USE_64BIT_INDICES) ? HONEE_FILE_TOKEN_64 : HONEE_FILE_TOKEN_32; 84b237916aSJames Wright 85b237916aSJames Wright PetscFunctionBeginUser; 86b237916aSJames Wright { // Verify viewer is in correct state 87b237916aSJames Wright PetscViewerType viewer_type; 88b237916aSJames Wright PetscFileMode file_mode; 89b237916aSJames Wright PetscBool is_binary_viewer; 90b237916aSJames Wright MPI_Comm comm = PetscObjectComm((PetscObject)viewer); 91b237916aSJames Wright 92b237916aSJames Wright PetscCall(PetscViewerGetType(viewer, &viewer_type)); 93b237916aSJames Wright PetscCall(PetscStrcmp(viewer_type, PETSCVIEWERBINARY, &is_binary_viewer)); 94b237916aSJames Wright PetscCheck(is_binary_viewer, comm, PETSC_ERR_ARG_WRONGSTATE, "Viewer must be binary type; instead got %s", viewer_type); 95b237916aSJames Wright PetscCall(PetscViewerFileGetMode(viewer, &file_mode)); 96b237916aSJames Wright PetscCheck(file_mode == FILE_MODE_WRITE, comm, PETSC_ERR_ARG_WRONGSTATE, "Viewer must be binary type; instead got %s", 97b237916aSJames Wright file_mode == -1 ? "UNDEFINED" : PetscFileModes[file_mode]); 98b237916aSJames Wright } 99b237916aSJames Wright 100b237916aSJames Wright PetscCall(PetscViewerBinaryWrite(viewer, &token, 1, PETSC_INT32)); 101b237916aSJames Wright PetscCall(PetscViewerBinaryWrite(viewer, &step_number, 1, PETSC_INT)); 102b237916aSJames Wright PetscCall(PetscViewerBinaryWrite(viewer, &time, 1, PETSC_REAL)); 103b237916aSJames Wright PetscCall(VecView(Q, viewer)); 104b237916aSJames Wright PetscFunctionReturn(PETSC_SUCCESS); 105b237916aSJames Wright } 106b237916aSJames Wright 107b237916aSJames 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 **/ 121*7ce151adSJames Wright PetscErrorCode PhastaDatFileOpen(const MPI_Comm comm, const char path[], const PetscInt char_array_len, PetscInt dims[2], FILE **fp) { 12293ca29b6SJames Wright int ndims; 12393ca29b6SJames Wright char line[char_array_len]; 12493ca29b6SJames Wright char **array; 12593ca29b6SJames Wright 12693ca29b6SJames Wright PetscFunctionBeginUser; 12793ca29b6SJames Wright PetscCall(PetscFOpen(comm, path, "r", fp)); 12893ca29b6SJames Wright PetscCall(PetscSynchronizedFGets(comm, *fp, char_array_len, line)); 12993ca29b6SJames Wright PetscCall(PetscStrToArray(line, ' ', &ndims, &array)); 13093ca29b6SJames Wright PetscCheck(ndims == 2, comm, PETSC_ERR_FILE_UNEXPECTED, "Found %d dimensions instead of 2 on the first line of %s", ndims, path); 13193ca29b6SJames Wright 13293ca29b6SJames Wright for (PetscInt i = 0; i < ndims; i++) dims[i] = atoi(array[i]); 13393ca29b6SJames Wright PetscCall(PetscStrToArrayDestroy(ndims, array)); 13493ca29b6SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 13593ca29b6SJames Wright } 13693ca29b6SJames Wright 137c9ff4f08SJames Wright /** 138c9ff4f08SJames Wright @brief Get the number of rows for the PHASTA file at path. 139c9ff4f08SJames Wright 140c9ff4f08SJames 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. 141c9ff4f08SJames Wright 142c9ff4f08SJames Wright @param[in] comm `MPI_Comm` for the program 143c9ff4f08SJames Wright @param[in] path Path to the file 144c9ff4f08SJames Wright @param[out] nrows Number of rows 145c9ff4f08SJames Wright **/ 146*7ce151adSJames Wright PetscErrorCode PhastaDatFileGetNRows(const MPI_Comm comm, const char path[], PetscInt *nrows) { 14793ca29b6SJames Wright const PetscInt char_array_len = 512; 14893ca29b6SJames Wright PetscInt dims[2]; 14993ca29b6SJames Wright FILE *fp; 15093ca29b6SJames Wright 15193ca29b6SJames Wright PetscFunctionBeginUser; 15293ca29b6SJames Wright PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp)); 15393ca29b6SJames Wright *nrows = dims[0]; 15493ca29b6SJames Wright PetscCall(PetscFClose(comm, fp)); 15593ca29b6SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 15693ca29b6SJames Wright } 15793ca29b6SJames Wright 158c9ff4f08SJames Wright /** 159c9ff4f08SJames Wright @brief Read PetscReal values from PHASTA file 160c9ff4f08SJames Wright 161c9ff4f08SJames Wright @param[in] comm `MPI_Comm` for the program 162c9ff4f08SJames Wright @param[in] path Path to the file 163c9ff4f08SJames Wright @param[out] array Pointer to allocated array of correct size 164c9ff4f08SJames Wright **/ 165*7ce151adSJames Wright PetscErrorCode PhastaDatFileReadToArrayReal(MPI_Comm comm, const char path[], PetscReal array[]) { 16693ca29b6SJames Wright PetscInt dims[2]; 16793ca29b6SJames Wright FILE *fp; 16893ca29b6SJames Wright const PetscInt char_array_len = 512; 16993ca29b6SJames Wright char line[char_array_len]; 17093ca29b6SJames Wright 17193ca29b6SJames Wright PetscFunctionBeginUser; 17293ca29b6SJames Wright PetscCall(PhastaDatFileOpen(comm, path, char_array_len, dims, &fp)); 17393ca29b6SJames Wright 17493ca29b6SJames Wright for (PetscInt i = 0; i < dims[0]; i++) { 17593ca29b6SJames Wright int ndims; 17693ca29b6SJames Wright char **row_array; 17793ca29b6SJames Wright 17893ca29b6SJames Wright PetscCall(PetscSynchronizedFGets(comm, fp, char_array_len, line)); 17993ca29b6SJames Wright PetscCall(PetscStrToArray(line, ' ', &ndims, &row_array)); 18093ca29b6SJames Wright PetscCheck(ndims == dims[1], comm, PETSC_ERR_FILE_UNEXPECTED, 18193ca29b6SJames Wright "Line %" PetscInt_FMT " of %s does not contain enough columns (%d instead of %" PetscInt_FMT ")", i, path, ndims, dims[1]); 18293ca29b6SJames Wright 18393ca29b6SJames Wright for (PetscInt j = 0; j < dims[1]; j++) array[i * dims[1] + j] = (PetscReal)atof(row_array[j]); 18493ca29b6SJames Wright PetscCall(PetscStrToArrayDestroy(ndims, row_array)); 18593ca29b6SJames Wright } 18693ca29b6SJames Wright 18793ca29b6SJames Wright PetscCall(PetscFClose(comm, fp)); 18893ca29b6SJames Wright PetscFunctionReturn(PETSC_SUCCESS); 18993ca29b6SJames Wright } 190