13d8e8822SJeremy L Thompson // Copyright (c) 2017-2022, Lawrence Livermore National Security, LLC and other CEED contributors. 23d8e8822SJeremy L Thompson // All Rights Reserved. See the top-level LICENSE and NOTICE files for details. 377841947SLeila Ghaffari // 43d8e8822SJeremy L Thompson // SPDX-License-Identifier: BSD-2-Clause 577841947SLeila Ghaffari // 63d8e8822SJeremy L Thompson // This file is part of CEED: http://github.com/ceed 777841947SLeila Ghaffari 877841947SLeila Ghaffari /// @file 977841947SLeila Ghaffari /// Miscellaneous utility functions 1077841947SLeila Ghaffari 1149aac155SJeremy L Thompson #include <ceed.h> 1249aac155SJeremy L Thompson #include <petscdm.h> 1349aac155SJeremy L Thompson #include <petscts.h> 1449aac155SJeremy L Thompson 1577841947SLeila Ghaffari #include "../navierstokes.h" 16ef080ff9SJames Wright #include "../qfunctions/mass.h" 1777841947SLeila Ghaffari 182b730f8bSJeremy L Thompson PetscErrorCode ICs_FixMultiplicity(DM dm, CeedData ceed_data, User user, Vec Q_loc, Vec Q, CeedScalar time) { 1977841947SLeila Ghaffari PetscFunctionBeginUser; 2077841947SLeila Ghaffari 2177841947SLeila Ghaffari // --------------------------------------------------------------------------- 22a0add3c9SJed Brown // Update time for evaluation 2377841947SLeila Ghaffari // --------------------------------------------------------------------------- 2417b0d5c6SJeremy L Thompson if (user->phys->ics_time_label) CeedOperatorSetContextDouble(ceed_data->op_ics, user->phys->ics_time_label, &time); 2577841947SLeila Ghaffari 2677841947SLeila Ghaffari // --------------------------------------------------------------------------- 2777841947SLeila Ghaffari // ICs 2877841947SLeila Ghaffari // --------------------------------------------------------------------------- 2977841947SLeila Ghaffari // -- CEED Restriction 3077841947SLeila Ghaffari CeedVector q0_ceed; 3177841947SLeila Ghaffari CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &q0_ceed, NULL); 3277841947SLeila Ghaffari 3377841947SLeila Ghaffari // -- Place PETSc vector in CEED vector 3477841947SLeila Ghaffari PetscMemType q0_mem_type; 35c798d55aSJames Wright PetscCall(VecP2C(Q_loc, &q0_mem_type, q0_ceed)); 3677841947SLeila Ghaffari 3777841947SLeila Ghaffari // -- Apply CEED Operator 382b730f8bSJeremy L Thompson CeedOperatorApply(ceed_data->op_ics, ceed_data->x_coord, q0_ceed, CEED_REQUEST_IMMEDIATE); 3977841947SLeila Ghaffari 4077841947SLeila Ghaffari // -- Restore vectors 41c798d55aSJames Wright PetscCall(VecC2P(q0_ceed, q0_mem_type, Q_loc)); 4277841947SLeila Ghaffari 4377841947SLeila Ghaffari // -- Local-to-Global 442b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Q)); 452b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(dm, Q_loc, ADD_VALUES, Q)); 4677841947SLeila Ghaffari 4777841947SLeila Ghaffari // --------------------------------------------------------------------------- 4877841947SLeila Ghaffari // Fix multiplicity for output of ICs 4977841947SLeila Ghaffari // --------------------------------------------------------------------------- 5077841947SLeila Ghaffari // -- CEED Restriction 5177841947SLeila Ghaffari CeedVector mult_vec; 5277841947SLeila Ghaffari CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &mult_vec, NULL); 5377841947SLeila Ghaffari 5477841947SLeila Ghaffari // -- Place PETSc vector in CEED vector 5577841947SLeila Ghaffari PetscMemType m_mem_type; 5677841947SLeila Ghaffari Vec multiplicity_loc; 572b730f8bSJeremy L Thompson PetscCall(DMGetLocalVector(dm, &multiplicity_loc)); 58c798d55aSJames Wright PetscCall(VecP2C(multiplicity_loc, &m_mem_type, mult_vec)); 5977841947SLeila Ghaffari 6077841947SLeila Ghaffari // -- Get multiplicity 6177841947SLeila Ghaffari CeedElemRestrictionGetMultiplicity(ceed_data->elem_restr_q, mult_vec); 6277841947SLeila Ghaffari 6377841947SLeila Ghaffari // -- Restore vectors 64c798d55aSJames Wright PetscCall(VecC2P(mult_vec, m_mem_type, multiplicity_loc)); 6577841947SLeila Ghaffari 6677841947SLeila Ghaffari // -- Local-to-Global 6777841947SLeila Ghaffari Vec multiplicity; 682b730f8bSJeremy L Thompson PetscCall(DMGetGlobalVector(dm, &multiplicity)); 692b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(multiplicity)); 702b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(dm, multiplicity_loc, ADD_VALUES, multiplicity)); 7177841947SLeila Ghaffari 7277841947SLeila Ghaffari // -- Fix multiplicity 732b730f8bSJeremy L Thompson PetscCall(VecPointwiseDivide(Q, Q, multiplicity)); 742b730f8bSJeremy L Thompson PetscCall(VecPointwiseDivide(Q_loc, Q_loc, multiplicity_loc)); 7577841947SLeila Ghaffari 7677841947SLeila Ghaffari // -- Restore vectors 772b730f8bSJeremy L Thompson PetscCall(DMRestoreLocalVector(dm, &multiplicity_loc)); 782b730f8bSJeremy L Thompson PetscCall(DMRestoreGlobalVector(dm, &multiplicity)); 7977841947SLeila Ghaffari 8077841947SLeila Ghaffari // Cleanup 8177841947SLeila Ghaffari CeedVectorDestroy(&mult_vec); 8277841947SLeila Ghaffari CeedVectorDestroy(&q0_ceed); 8377841947SLeila Ghaffari 8477841947SLeila Ghaffari PetscFunctionReturn(0); 8577841947SLeila Ghaffari } 8677841947SLeila Ghaffari 872b730f8bSJeremy L Thompson PetscErrorCode DMPlexInsertBoundaryValues_NS(DM dm, PetscBool insert_essential, Vec Q_loc, PetscReal time, Vec face_geom_FVM, Vec cell_geom_FVM, 882b730f8bSJeremy L Thompson Vec grad_FVM) { 895571c6fdSJames Wright Vec Qbc, boundary_mask; 9077841947SLeila Ghaffari PetscFunctionBegin; 9177841947SLeila Ghaffari 925571c6fdSJames Wright // Mask (zero) Dirichlet entries 935571c6fdSJames Wright PetscCall(DMGetNamedLocalVector(dm, "boundary mask", &boundary_mask)); 945571c6fdSJames Wright PetscCall(VecPointwiseMult(Q_loc, Q_loc, boundary_mask)); 955571c6fdSJames Wright PetscCall(DMRestoreNamedLocalVector(dm, "boundary mask", &boundary_mask)); 965571c6fdSJames Wright 972b730f8bSJeremy L Thompson PetscCall(DMGetNamedLocalVector(dm, "Qbc", &Qbc)); 982b730f8bSJeremy L Thompson PetscCall(VecAXPY(Q_loc, 1., Qbc)); 992b730f8bSJeremy L Thompson PetscCall(DMRestoreNamedLocalVector(dm, "Qbc", &Qbc)); 10077841947SLeila Ghaffari 10177841947SLeila Ghaffari PetscFunctionReturn(0); 10277841947SLeila Ghaffari } 10377841947SLeila Ghaffari 104530ad8c4SKenneth E. Jansen // @brief Load vector from binary file, possibly with embedded solution time and step number 105530ad8c4SKenneth E. Jansen PetscErrorCode LoadFluidsBinaryVec(MPI_Comm comm, PetscViewer viewer, Vec Q, PetscReal *time, PetscInt *step_number) { 106530ad8c4SKenneth E. Jansen PetscInt token, file_step_number; 107530ad8c4SKenneth E. Jansen PetscReal file_time; 108530ad8c4SKenneth E. Jansen PetscFunctionBeginUser; 109530ad8c4SKenneth E. Jansen 110530ad8c4SKenneth E. Jansen // Attempt 111530ad8c4SKenneth E. Jansen PetscCall(PetscViewerBinaryRead(viewer, &token, 1, NULL, PETSC_INT)); 112530ad8c4SKenneth E. Jansen if (token == FLUIDS_FILE_TOKEN) { // New style format; we're reading a file with step number and time in the header 113530ad8c4SKenneth E. Jansen PetscCall(PetscViewerBinaryRead(viewer, &file_step_number, 1, NULL, PETSC_INT)); 114530ad8c4SKenneth E. Jansen PetscCall(PetscViewerBinaryRead(viewer, &file_time, 1, NULL, PETSC_REAL)); 115530ad8c4SKenneth E. Jansen if (time) *time = file_time; 116530ad8c4SKenneth E. Jansen if (step_number) *step_number = file_step_number; 117530ad8c4SKenneth E. Jansen } else if (token == VEC_FILE_CLASSID) { // Legacy format of just the vector, encoded as [VEC_FILE_CLASSID, length, ] 118530ad8c4SKenneth E. Jansen PetscInt length, N; 119530ad8c4SKenneth E. Jansen PetscCall(PetscViewerBinaryRead(viewer, &length, 1, NULL, PETSC_INT)); 120530ad8c4SKenneth E. Jansen PetscCall(VecGetSize(Q, &N)); 121530ad8c4SKenneth E. Jansen PetscCheck(length == N, comm, PETSC_ERR_ARG_INCOMP, "File Vec has length %" PetscInt_FMT " but DM has global Vec size %" PetscInt_FMT, length, N); 122530ad8c4SKenneth E. Jansen PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_TRUE)); 123530ad8c4SKenneth E. Jansen } else SETERRQ(comm, PETSC_ERR_FILE_UNEXPECTED, "Not a fluids header token or a PETSc Vec in file"); 124530ad8c4SKenneth E. Jansen 125530ad8c4SKenneth E. Jansen // Load Q from existent solution 126530ad8c4SKenneth E. Jansen PetscCall(VecLoad(Q, viewer)); 127530ad8c4SKenneth E. Jansen 128530ad8c4SKenneth E. Jansen PetscFunctionReturn(0); 129530ad8c4SKenneth E. Jansen } 130530ad8c4SKenneth E. Jansen 13177841947SLeila Ghaffari // Compare reference solution values with current test run for CI 13277841947SLeila Ghaffari PetscErrorCode RegressionTests_NS(AppCtx app_ctx, Vec Q) { 13377841947SLeila Ghaffari Vec Qref; 13477841947SLeila Ghaffari PetscViewer viewer; 13577841947SLeila Ghaffari PetscReal error, Qrefnorm; 136530ad8c4SKenneth E. Jansen MPI_Comm comm = PetscObjectComm((PetscObject)Q); 13777841947SLeila Ghaffari PetscFunctionBegin; 13877841947SLeila Ghaffari 13977841947SLeila Ghaffari // Read reference file 1402b730f8bSJeremy L Thompson PetscCall(VecDuplicate(Q, &Qref)); 141530ad8c4SKenneth E. Jansen PetscCall(PetscViewerBinaryOpen(comm, app_ctx->test_file_path, FILE_MODE_READ, &viewer)); 142530ad8c4SKenneth E. Jansen PetscCall(LoadFluidsBinaryVec(comm, viewer, Qref, NULL, NULL)); 14377841947SLeila Ghaffari 14477841947SLeila Ghaffari // Compute error with respect to reference solution 1452b730f8bSJeremy L Thompson PetscCall(VecAXPY(Q, -1.0, Qref)); 1462b730f8bSJeremy L Thompson PetscCall(VecNorm(Qref, NORM_MAX, &Qrefnorm)); 1472b730f8bSJeremy L Thompson PetscCall(VecScale(Q, 1. / Qrefnorm)); 1482b730f8bSJeremy L Thompson PetscCall(VecNorm(Q, NORM_MAX, &error)); 14977841947SLeila Ghaffari 15077841947SLeila Ghaffari // Check error 15177841947SLeila Ghaffari if (error > app_ctx->test_tol) { 1522b730f8bSJeremy L Thompson PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test failed with error norm %g\n", (double)error)); 15377841947SLeila Ghaffari } 15477841947SLeila Ghaffari 15577841947SLeila Ghaffari // Cleanup 1562b730f8bSJeremy L Thompson PetscCall(PetscViewerDestroy(&viewer)); 1572b730f8bSJeremy L Thompson PetscCall(VecDestroy(&Qref)); 15877841947SLeila Ghaffari 15977841947SLeila Ghaffari PetscFunctionReturn(0); 16077841947SLeila Ghaffari } 16177841947SLeila Ghaffari 16277841947SLeila Ghaffari // Get error for problems with exact solutions 1632b730f8bSJeremy L Thompson PetscErrorCode GetError_NS(CeedData ceed_data, DM dm, User user, Vec Q, PetscScalar final_time) { 16477841947SLeila Ghaffari PetscInt loc_nodes; 16577841947SLeila Ghaffari Vec Q_exact, Q_exact_loc; 16677841947SLeila Ghaffari PetscReal rel_error, norm_error, norm_exact; 16777841947SLeila Ghaffari PetscFunctionBegin; 16877841947SLeila Ghaffari 16977841947SLeila Ghaffari // Get exact solution at final time 1702b730f8bSJeremy L Thompson PetscCall(DMCreateGlobalVector(dm, &Q_exact)); 1712b730f8bSJeremy L Thompson PetscCall(DMGetLocalVector(dm, &Q_exact_loc)); 1722b730f8bSJeremy L Thompson PetscCall(VecGetSize(Q_exact_loc, &loc_nodes)); 1732b730f8bSJeremy L Thompson PetscCall(ICs_FixMultiplicity(dm, ceed_data, user, Q_exact_loc, Q_exact, final_time)); 17477841947SLeila Ghaffari 17577841947SLeila Ghaffari // Get |exact solution - obtained solution| 1762b730f8bSJeremy L Thompson PetscCall(VecNorm(Q_exact, NORM_1, &norm_exact)); 1772b730f8bSJeremy L Thompson PetscCall(VecAXPY(Q, -1.0, Q_exact)); 1782b730f8bSJeremy L Thompson PetscCall(VecNorm(Q, NORM_1, &norm_error)); 17977841947SLeila Ghaffari 18077841947SLeila Ghaffari // Compute relative error 18177841947SLeila Ghaffari rel_error = norm_error / norm_exact; 18277841947SLeila Ghaffari 18377841947SLeila Ghaffari // Output relative error 1842b730f8bSJeremy L Thompson PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Relative Error: %g\n", (double)rel_error)); 18577841947SLeila Ghaffari // Cleanup 1862b730f8bSJeremy L Thompson PetscCall(DMRestoreLocalVector(dm, &Q_exact_loc)); 1872b730f8bSJeremy L Thompson PetscCall(VecDestroy(&Q_exact)); 18877841947SLeila Ghaffari 18977841947SLeila Ghaffari PetscFunctionReturn(0); 19077841947SLeila Ghaffari } 19177841947SLeila Ghaffari 19277841947SLeila Ghaffari // Post-processing 1932b730f8bSJeremy L Thompson PetscErrorCode PostProcess_NS(TS ts, CeedData ceed_data, DM dm, ProblemData *problem, User user, Vec Q, PetscScalar final_time) { 19477841947SLeila Ghaffari PetscInt steps; 195cf7a0454SJed Brown TSConvergedReason reason; 19677841947SLeila Ghaffari PetscFunctionBegin; 19777841947SLeila Ghaffari 19877841947SLeila Ghaffari // Print relative error 1998fb33541SJames Wright if (problem->non_zero_time && user->app_ctx->test_type == TESTTYPE_NONE) { 2002b730f8bSJeremy L Thompson PetscCall(GetError_NS(ceed_data, dm, user, Q, final_time)); 20177841947SLeila Ghaffari } 20277841947SLeila Ghaffari 20377841947SLeila Ghaffari // Print final time and number of steps 2042b730f8bSJeremy L Thompson PetscCall(TSGetStepNumber(ts, &steps)); 205cf7a0454SJed Brown PetscCall(TSGetConvergedReason(ts, &reason)); 2068fb33541SJames Wright if (user->app_ctx->test_type == TESTTYPE_NONE) { 207cf7a0454SJed Brown PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Time integrator %s on time step %" PetscInt_FMT " with final time %g\n", TSConvergedReasons[reason], 208cf7a0454SJed Brown steps, (double)final_time)); 20977841947SLeila Ghaffari } 21077841947SLeila Ghaffari 21177841947SLeila Ghaffari // Output numerical values from command line 2122b730f8bSJeremy L Thompson PetscCall(VecViewFromOptions(Q, NULL, "-vec_view")); 21377841947SLeila Ghaffari 21477841947SLeila Ghaffari // Compare reference solution values with current test run for CI 2158fb33541SJames Wright if (user->app_ctx->test_type == TESTTYPE_SOLVER) { 2162b730f8bSJeremy L Thompson PetscCall(RegressionTests_NS(user->app_ctx, Q)); 21777841947SLeila Ghaffari } 21877841947SLeila Ghaffari 21977841947SLeila Ghaffari PetscFunctionReturn(0); 22077841947SLeila Ghaffari } 22177841947SLeila Ghaffari 2224de8550aSJed Brown const PetscInt FLUIDS_FILE_TOKEN = 0xceedf00; 2234de8550aSJed Brown 22477841947SLeila Ghaffari // Gather initial Q values in case of continuation of simulation 22577841947SLeila Ghaffari PetscErrorCode SetupICsFromBinary(MPI_Comm comm, AppCtx app_ctx, Vec Q) { 22677841947SLeila Ghaffari PetscViewer viewer; 2272b730f8bSJeremy L Thompson 22877841947SLeila Ghaffari PetscFunctionBegin; 22977841947SLeila Ghaffari 2302b730f8bSJeremy L Thompson PetscCall(PetscViewerBinaryOpen(comm, app_ctx->cont_file, FILE_MODE_READ, &viewer)); 231530ad8c4SKenneth E. Jansen PetscCall(LoadFluidsBinaryVec(comm, viewer, Q, &app_ctx->cont_time, &app_ctx->cont_steps)); 2322b730f8bSJeremy L Thompson PetscCall(PetscViewerDestroy(&viewer)); 23377841947SLeila Ghaffari 23477841947SLeila Ghaffari PetscFunctionReturn(0); 23577841947SLeila Ghaffari } 23677841947SLeila Ghaffari 23777841947SLeila Ghaffari // Record boundary values from initial condition 23877841947SLeila Ghaffari PetscErrorCode SetBCsFromICs_NS(DM dm, Vec Q, Vec Q_loc) { 2395571c6fdSJames Wright Vec Qbc, boundary_mask; 24077841947SLeila Ghaffari PetscFunctionBegin; 24177841947SLeila Ghaffari 2422b730f8bSJeremy L Thompson PetscCall(DMGetNamedLocalVector(dm, "Qbc", &Qbc)); 2432b730f8bSJeremy L Thompson PetscCall(VecCopy(Q_loc, Qbc)); 2442b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Q_loc)); 2452b730f8bSJeremy L Thompson PetscCall(DMGlobalToLocal(dm, Q, INSERT_VALUES, Q_loc)); 2462b730f8bSJeremy L Thompson PetscCall(VecAXPY(Qbc, -1., Q_loc)); 2472b730f8bSJeremy L Thompson PetscCall(DMRestoreNamedLocalVector(dm, "Qbc", &Qbc)); 2482b730f8bSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_NS)); 24977841947SLeila Ghaffari 2505571c6fdSJames Wright PetscCall(DMGetNamedLocalVector(dm, "boundary mask", &boundary_mask)); 2515571c6fdSJames Wright PetscCall(DMGetGlobalVector(dm, &Q)); 2525571c6fdSJames Wright PetscCall(VecZeroEntries(boundary_mask)); 2535571c6fdSJames Wright PetscCall(VecSet(Q, 1.0)); 2545571c6fdSJames Wright PetscCall(DMGlobalToLocal(dm, Q, INSERT_VALUES, boundary_mask)); 2555571c6fdSJames Wright PetscCall(DMRestoreNamedLocalVector(dm, "boundary mask", &boundary_mask)); 2565571c6fdSJames Wright 25777841947SLeila Ghaffari PetscFunctionReturn(0); 25877841947SLeila Ghaffari } 259841e4c73SJed Brown 260841e4c73SJed Brown // Free a plain data context that was allocated using PETSc; returning libCEED error codes 261841e4c73SJed Brown int FreeContextPetsc(void *data) { 2622b730f8bSJeremy L Thompson if (PetscFree(data)) return CeedError(NULL, CEED_ERROR_ACCESS, "PetscFree failed"); 263841e4c73SJed Brown return CEED_ERROR_SUCCESS; 264841e4c73SJed Brown } 265ef080ff9SJames Wright 266ef080ff9SJames Wright // Return mass qfunction specification for number of components N 267ef080ff9SJames Wright PetscErrorCode CreateMassQFunction(Ceed ceed, CeedInt N, CeedInt q_data_size, CeedQFunction *qf) { 268ef080ff9SJames Wright CeedQFunctionUser qfunction_ptr; 269ef080ff9SJames Wright const char *qfunction_loc; 270ef080ff9SJames Wright PetscFunctionBeginUser; 271ef080ff9SJames Wright 272ef080ff9SJames Wright switch (N) { 273ef080ff9SJames Wright case 1: 274ef080ff9SJames Wright qfunction_ptr = Mass_1; 275ef080ff9SJames Wright qfunction_loc = Mass_1_loc; 276ef080ff9SJames Wright break; 277ef080ff9SJames Wright case 5: 278ef080ff9SJames Wright qfunction_ptr = Mass_5; 279ef080ff9SJames Wright qfunction_loc = Mass_5_loc; 280ef080ff9SJames Wright break; 281ef080ff9SJames Wright case 9: 282ef080ff9SJames Wright qfunction_ptr = Mass_9; 283ef080ff9SJames Wright qfunction_loc = Mass_9_loc; 284ef080ff9SJames Wright break; 285ef080ff9SJames Wright case 22: 286ef080ff9SJames Wright qfunction_ptr = Mass_22; 287ef080ff9SJames Wright qfunction_loc = Mass_22_loc; 288ef080ff9SJames Wright break; 289ef080ff9SJames Wright default: 290ef080ff9SJames Wright SETERRQ(PETSC_COMM_WORLD, -1, "Could not find mass qfunction of size %d", N); 291ef080ff9SJames Wright } 292ef080ff9SJames Wright CeedQFunctionCreateInterior(ceed, 1, qfunction_ptr, qfunction_loc, qf); 293ef080ff9SJames Wright 294ef080ff9SJames Wright CeedQFunctionAddInput(*qf, "u", N, CEED_EVAL_INTERP); 295ef080ff9SJames Wright CeedQFunctionAddInput(*qf, "qdata", q_data_size, CEED_EVAL_NONE); 296ef080ff9SJames Wright CeedQFunctionAddOutput(*qf, "v", N, CEED_EVAL_INTERP); 297ef080ff9SJames Wright PetscFunctionReturn(0); 298ef080ff9SJames Wright } 2990df12fefSJames Wright 3000df12fefSJames Wright /* @brief L^2 Projection of a source FEM function to a target FEM space 3010df12fefSJames Wright * 3020df12fefSJames Wright * To solve system using a lumped mass matrix, pass a KSP object with ksp_type=preonly, pc_type=jacobi, pc_jacobi_type=rowsum. 3030df12fefSJames Wright * 3040df12fefSJames Wright * @param[in] source_vec Global Vec of the source FEM function. NULL indicates using rhs_matop_ctx->X_loc 3050df12fefSJames Wright * @param[out] target_vec Global Vec of the target (result) FEM function. NULL indicates using rhs_matop_ctx->Y_loc 3060df12fefSJames Wright * @param[in] rhs_matop_ctx MatopApplyContext for performing the RHS evaluation 3070df12fefSJames Wright * @param[in] ksp KSP for solving the consistent projection problem 3080df12fefSJames Wright */ 3094021610dSJames Wright PetscErrorCode ComputeL2Projection(Vec source_vec, Vec target_vec, OperatorApplyContext rhs_matop_ctx, KSP ksp) { 3100df12fefSJames Wright PetscFunctionBeginUser; 3110df12fefSJames Wright 3124021610dSJames Wright PetscCall(ApplyCeedOperatorGlobalToGlobal(source_vec, target_vec, rhs_matop_ctx)); 3130df12fefSJames Wright PetscCall(KSPSolve(ksp, target_vec, target_vec)); 3140df12fefSJames Wright 3150df12fefSJames Wright PetscFunctionReturn(0); 3160df12fefSJames Wright } 317*8b892a05SJames Wright 318*8b892a05SJames Wright /* 319*8b892a05SJames Wright * @brief Open a PHASTA *.dat file, grabbing dimensions and file pointer 320*8b892a05SJames Wright * 321*8b892a05SJames Wright * This function opens the file specified by `path` using `PetscFOpen` and passes the file pointer in `fp`. 322*8b892a05SJames Wright * It is not closed in this function, thus `fp` must be closed sometime after this function has been called (using `PetscFClose` for example). 323*8b892a05SJames Wright * 324*8b892a05SJames 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. 325*8b892a05SJames Wright * 326*8b892a05SJames Wright * @param[in] comm MPI_Comm for the program 327*8b892a05SJames Wright * @param[in] path Path to the file 328*8b892a05SJames Wright * @param[in] char_array_len Length of the character array that should contain each line 329*8b892a05SJames Wright * @param[out] dims Dimensions of the file, taken from the first line of the file 330*8b892a05SJames Wright * @param[out] fp File pointer to the opened file 331*8b892a05SJames Wright */ 332*8b892a05SJames Wright PetscErrorCode PHASTADatFileOpen(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], const PetscInt char_array_len, PetscInt dims[2], 333*8b892a05SJames Wright FILE **fp) { 334*8b892a05SJames Wright PetscInt ndims; 335*8b892a05SJames Wright char line[char_array_len]; 336*8b892a05SJames Wright char **array; 337*8b892a05SJames Wright 338*8b892a05SJames Wright PetscFunctionBeginUser; 339*8b892a05SJames Wright PetscCall(PetscFOpen(comm, path, "r", fp)); 340*8b892a05SJames Wright PetscCall(PetscSynchronizedFGets(comm, *fp, char_array_len, line)); 341*8b892a05SJames Wright PetscCall(PetscStrToArray(line, ' ', &ndims, &array)); 342*8b892a05SJames Wright if (ndims != 2) { 343*8b892a05SJames Wright SETERRQ(comm, -1, "Found %" PetscInt_FMT " dimensions instead of 2 on the first line of %s", ndims, path); 344*8b892a05SJames Wright } 345*8b892a05SJames Wright 346*8b892a05SJames Wright for (PetscInt i = 0; i < ndims; i++) dims[i] = atoi(array[i]); 347*8b892a05SJames Wright PetscCall(PetscStrToArrayDestroy(ndims, array)); 348*8b892a05SJames Wright 349*8b892a05SJames Wright PetscFunctionReturn(0); 350*8b892a05SJames Wright } 351*8b892a05SJames Wright 352*8b892a05SJames Wright /* 353*8b892a05SJames Wright * @brief Get the number of rows for the PHASTA file at path. 354*8b892a05SJames Wright * 355*8b892a05SJames 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. 356*8b892a05SJames Wright * 357*8b892a05SJames Wright * @param[in] comm MPI_Comm for the program 358*8b892a05SJames Wright * @param[in] path Path to the file 359*8b892a05SJames Wright * @param[out] nrows Number of rows 360*8b892a05SJames Wright */ 361*8b892a05SJames Wright PetscErrorCode PHASTADatFileGetNRows(const MPI_Comm comm, const char path[PETSC_MAX_PATH_LEN], PetscInt *nrows) { 362*8b892a05SJames Wright const PetscInt char_array_len = 512; 363*8b892a05SJames Wright PetscInt dims[2]; 364*8b892a05SJames Wright FILE *fp; 365*8b892a05SJames Wright 366*8b892a05SJames Wright PetscFunctionBeginUser; 367*8b892a05SJames Wright PetscCall(PHASTADatFileOpen(comm, path, char_array_len, dims, &fp)); 368*8b892a05SJames Wright *nrows = dims[0]; 369*8b892a05SJames Wright PetscCall(PetscFClose(comm, fp)); 370*8b892a05SJames Wright 371*8b892a05SJames Wright PetscFunctionReturn(0); 372*8b892a05SJames Wright } 373