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 1177841947SLeila Ghaffari #include "../navierstokes.h" 1277841947SLeila Ghaffari 132b730f8bSJeremy L Thompson PetscErrorCode ICs_FixMultiplicity(DM dm, CeedData ceed_data, User user, Vec Q_loc, Vec Q, CeedScalar time) { 1477841947SLeila Ghaffari PetscFunctionBeginUser; 1577841947SLeila Ghaffari 1677841947SLeila Ghaffari // --------------------------------------------------------------------------- 17a0add3c9SJed Brown // Update time for evaluation 1877841947SLeila Ghaffari // --------------------------------------------------------------------------- 192b730f8bSJeremy L Thompson if (user->phys->ics_time_label) CeedOperatorContextSetDouble(ceed_data->op_ics, user->phys->ics_time_label, &time); 2077841947SLeila Ghaffari 2177841947SLeila Ghaffari // --------------------------------------------------------------------------- 2277841947SLeila Ghaffari // ICs 2377841947SLeila Ghaffari // --------------------------------------------------------------------------- 2477841947SLeila Ghaffari // -- CEED Restriction 2577841947SLeila Ghaffari CeedVector q0_ceed; 2677841947SLeila Ghaffari CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &q0_ceed, NULL); 2777841947SLeila Ghaffari 2877841947SLeila Ghaffari // -- Place PETSc vector in CEED vector 2977841947SLeila Ghaffari CeedScalar *q0; 3077841947SLeila Ghaffari PetscMemType q0_mem_type; 312b730f8bSJeremy L Thompson PetscCall(VecGetArrayAndMemType(Q_loc, (PetscScalar **)&q0, &q0_mem_type)); 3277841947SLeila Ghaffari CeedVectorSetArray(q0_ceed, MemTypeP2C(q0_mem_type), CEED_USE_POINTER, q0); 3377841947SLeila Ghaffari 3477841947SLeila Ghaffari // -- Apply CEED Operator 352b730f8bSJeremy L Thompson CeedOperatorApply(ceed_data->op_ics, ceed_data->x_coord, q0_ceed, CEED_REQUEST_IMMEDIATE); 3677841947SLeila Ghaffari 3777841947SLeila Ghaffari // -- Restore vectors 3877841947SLeila Ghaffari CeedVectorTakeArray(q0_ceed, MemTypeP2C(q0_mem_type), NULL); 392b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayReadAndMemType(Q_loc, (const PetscScalar **)&q0)); 4077841947SLeila Ghaffari 4177841947SLeila Ghaffari // -- Local-to-Global 422b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Q)); 432b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(dm, Q_loc, ADD_VALUES, Q)); 4477841947SLeila Ghaffari 4577841947SLeila Ghaffari // --------------------------------------------------------------------------- 4677841947SLeila Ghaffari // Fix multiplicity for output of ICs 4777841947SLeila Ghaffari // --------------------------------------------------------------------------- 4877841947SLeila Ghaffari // -- CEED Restriction 4977841947SLeila Ghaffari CeedVector mult_vec; 5077841947SLeila Ghaffari CeedElemRestrictionCreateVector(ceed_data->elem_restr_q, &mult_vec, NULL); 5177841947SLeila Ghaffari 5277841947SLeila Ghaffari // -- Place PETSc vector in CEED vector 5377841947SLeila Ghaffari CeedScalar *mult; 5477841947SLeila Ghaffari PetscMemType m_mem_type; 5577841947SLeila Ghaffari Vec multiplicity_loc; 562b730f8bSJeremy L Thompson PetscCall(DMGetLocalVector(dm, &multiplicity_loc)); 572b730f8bSJeremy L Thompson PetscCall(VecGetArrayAndMemType(multiplicity_loc, (PetscScalar **)&mult, &m_mem_type)); 5877841947SLeila Ghaffari CeedVectorSetArray(mult_vec, MemTypeP2C(m_mem_type), CEED_USE_POINTER, mult); 5977841947SLeila Ghaffari 6077841947SLeila Ghaffari // -- Get multiplicity 6177841947SLeila Ghaffari CeedElemRestrictionGetMultiplicity(ceed_data->elem_restr_q, mult_vec); 6277841947SLeila Ghaffari 6377841947SLeila Ghaffari // -- Restore vectors 6477841947SLeila Ghaffari CeedVectorTakeArray(mult_vec, MemTypeP2C(m_mem_type), NULL); 652b730f8bSJeremy L Thompson PetscCall(VecRestoreArrayReadAndMemType(multiplicity_loc, (const PetscScalar **)&mult)); 6677841947SLeila Ghaffari 6777841947SLeila Ghaffari // -- Local-to-Global 6877841947SLeila Ghaffari Vec multiplicity; 692b730f8bSJeremy L Thompson PetscCall(DMGetGlobalVector(dm, &multiplicity)); 702b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(multiplicity)); 712b730f8bSJeremy L Thompson PetscCall(DMLocalToGlobal(dm, multiplicity_loc, ADD_VALUES, multiplicity)); 7277841947SLeila Ghaffari 7377841947SLeila Ghaffari // -- Fix multiplicity 742b730f8bSJeremy L Thompson PetscCall(VecPointwiseDivide(Q, Q, multiplicity)); 752b730f8bSJeremy L Thompson PetscCall(VecPointwiseDivide(Q_loc, Q_loc, multiplicity_loc)); 7677841947SLeila Ghaffari 7777841947SLeila Ghaffari // -- Restore vectors 782b730f8bSJeremy L Thompson PetscCall(DMRestoreLocalVector(dm, &multiplicity_loc)); 792b730f8bSJeremy L Thompson PetscCall(DMRestoreGlobalVector(dm, &multiplicity)); 8077841947SLeila Ghaffari 8177841947SLeila Ghaffari // Cleanup 8277841947SLeila Ghaffari CeedVectorDestroy(&mult_vec); 8377841947SLeila Ghaffari CeedVectorDestroy(&q0_ceed); 8477841947SLeila Ghaffari 8577841947SLeila Ghaffari PetscFunctionReturn(0); 8677841947SLeila Ghaffari } 8777841947SLeila Ghaffari 882b730f8bSJeremy L Thompson PetscErrorCode DMPlexInsertBoundaryValues_NS(DM dm, PetscBool insert_essential, Vec Q_loc, PetscReal time, Vec face_geom_FVM, Vec cell_geom_FVM, 892b730f8bSJeremy L Thompson Vec grad_FVM) { 905571c6fdSJames Wright Vec Qbc, boundary_mask; 9177841947SLeila Ghaffari PetscFunctionBegin; 9277841947SLeila Ghaffari 935571c6fdSJames Wright // Mask (zero) Dirichlet entries 945571c6fdSJames Wright PetscCall(DMGetNamedLocalVector(dm, "boundary mask", &boundary_mask)); 955571c6fdSJames Wright PetscCall(VecPointwiseMult(Q_loc, Q_loc, boundary_mask)); 965571c6fdSJames Wright PetscCall(DMRestoreNamedLocalVector(dm, "boundary mask", &boundary_mask)); 975571c6fdSJames Wright 982b730f8bSJeremy L Thompson PetscCall(DMGetNamedLocalVector(dm, "Qbc", &Qbc)); 992b730f8bSJeremy L Thompson PetscCall(VecAXPY(Q_loc, 1., Qbc)); 1002b730f8bSJeremy L Thompson PetscCall(DMRestoreNamedLocalVector(dm, "Qbc", &Qbc)); 10177841947SLeila Ghaffari 10277841947SLeila Ghaffari PetscFunctionReturn(0); 10377841947SLeila Ghaffari } 10477841947SLeila Ghaffari 10577841947SLeila Ghaffari // Compare reference solution values with current test run for CI 10677841947SLeila Ghaffari PetscErrorCode RegressionTests_NS(AppCtx app_ctx, Vec Q) { 10777841947SLeila Ghaffari Vec Qref; 10877841947SLeila Ghaffari PetscViewer viewer; 10977841947SLeila Ghaffari PetscReal error, Qrefnorm; 11077841947SLeila Ghaffari PetscFunctionBegin; 11177841947SLeila Ghaffari 11277841947SLeila Ghaffari // Read reference file 1132b730f8bSJeremy L Thompson PetscCall(VecDuplicate(Q, &Qref)); 1142b730f8bSJeremy L Thompson PetscCall(PetscViewerBinaryOpen(PetscObjectComm((PetscObject)Q), app_ctx->file_path, FILE_MODE_READ, &viewer)); 1152b730f8bSJeremy L Thompson PetscCall(VecLoad(Qref, viewer)); 11677841947SLeila Ghaffari 11777841947SLeila Ghaffari // Compute error with respect to reference solution 1182b730f8bSJeremy L Thompson PetscCall(VecAXPY(Q, -1.0, Qref)); 1192b730f8bSJeremy L Thompson PetscCall(VecNorm(Qref, NORM_MAX, &Qrefnorm)); 1202b730f8bSJeremy L Thompson PetscCall(VecScale(Q, 1. / Qrefnorm)); 1212b730f8bSJeremy L Thompson PetscCall(VecNorm(Q, NORM_MAX, &error)); 12277841947SLeila Ghaffari 12377841947SLeila Ghaffari // Check error 12477841947SLeila Ghaffari if (error > app_ctx->test_tol) { 1252b730f8bSJeremy L Thompson PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Test failed with error norm %g\n", (double)error)); 12677841947SLeila Ghaffari } 12777841947SLeila Ghaffari 12877841947SLeila Ghaffari // Cleanup 1292b730f8bSJeremy L Thompson PetscCall(PetscViewerDestroy(&viewer)); 1302b730f8bSJeremy L Thompson PetscCall(VecDestroy(&Qref)); 13177841947SLeila Ghaffari 13277841947SLeila Ghaffari PetscFunctionReturn(0); 13377841947SLeila Ghaffari } 13477841947SLeila Ghaffari 13577841947SLeila Ghaffari // Get error for problems with exact solutions 1362b730f8bSJeremy L Thompson PetscErrorCode GetError_NS(CeedData ceed_data, DM dm, User user, Vec Q, PetscScalar final_time) { 13777841947SLeila Ghaffari PetscInt loc_nodes; 13877841947SLeila Ghaffari Vec Q_exact, Q_exact_loc; 13977841947SLeila Ghaffari PetscReal rel_error, norm_error, norm_exact; 14077841947SLeila Ghaffari PetscFunctionBegin; 14177841947SLeila Ghaffari 14277841947SLeila Ghaffari // Get exact solution at final time 1432b730f8bSJeremy L Thompson PetscCall(DMCreateGlobalVector(dm, &Q_exact)); 1442b730f8bSJeremy L Thompson PetscCall(DMGetLocalVector(dm, &Q_exact_loc)); 1452b730f8bSJeremy L Thompson PetscCall(VecGetSize(Q_exact_loc, &loc_nodes)); 1462b730f8bSJeremy L Thompson PetscCall(ICs_FixMultiplicity(dm, ceed_data, user, Q_exact_loc, Q_exact, final_time)); 14777841947SLeila Ghaffari 14877841947SLeila Ghaffari // Get |exact solution - obtained solution| 1492b730f8bSJeremy L Thompson PetscCall(VecNorm(Q_exact, NORM_1, &norm_exact)); 1502b730f8bSJeremy L Thompson PetscCall(VecAXPY(Q, -1.0, Q_exact)); 1512b730f8bSJeremy L Thompson PetscCall(VecNorm(Q, NORM_1, &norm_error)); 15277841947SLeila Ghaffari 15377841947SLeila Ghaffari // Compute relative error 15477841947SLeila Ghaffari rel_error = norm_error / norm_exact; 15577841947SLeila Ghaffari 15677841947SLeila Ghaffari // Output relative error 1572b730f8bSJeremy L Thompson PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Relative Error: %g\n", (double)rel_error)); 15877841947SLeila Ghaffari // Cleanup 1592b730f8bSJeremy L Thompson PetscCall(DMRestoreLocalVector(dm, &Q_exact_loc)); 1602b730f8bSJeremy L Thompson PetscCall(VecDestroy(&Q_exact)); 16177841947SLeila Ghaffari 16277841947SLeila Ghaffari PetscFunctionReturn(0); 16377841947SLeila Ghaffari } 16477841947SLeila Ghaffari 16577841947SLeila Ghaffari // Post-processing 1662b730f8bSJeremy L Thompson PetscErrorCode PostProcess_NS(TS ts, CeedData ceed_data, DM dm, ProblemData *problem, User user, Vec Q, PetscScalar final_time) { 16777841947SLeila Ghaffari PetscInt steps; 168*cf7a0454SJed Brown TSConvergedReason reason; 16977841947SLeila Ghaffari PetscFunctionBegin; 17077841947SLeila Ghaffari 17177841947SLeila Ghaffari // Print relative error 172841e4c73SJed Brown if (problem->non_zero_time && !user->app_ctx->test_mode) { 1732b730f8bSJeremy L Thompson PetscCall(GetError_NS(ceed_data, dm, user, Q, final_time)); 17477841947SLeila Ghaffari } 17577841947SLeila Ghaffari 17677841947SLeila Ghaffari // Print final time and number of steps 1772b730f8bSJeremy L Thompson PetscCall(TSGetStepNumber(ts, &steps)); 178*cf7a0454SJed Brown PetscCall(TSGetConvergedReason(ts, &reason)); 179841e4c73SJed Brown if (!user->app_ctx->test_mode) { 180*cf7a0454SJed Brown PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Time integrator %s on time step %" PetscInt_FMT " with final time %g\n", TSConvergedReasons[reason], 181*cf7a0454SJed Brown steps, (double)final_time)); 18277841947SLeila Ghaffari } 18377841947SLeila Ghaffari 18477841947SLeila Ghaffari // Output numerical values from command line 1852b730f8bSJeremy L Thompson PetscCall(VecViewFromOptions(Q, NULL, "-vec_view")); 18677841947SLeila Ghaffari 18777841947SLeila Ghaffari // Compare reference solution values with current test run for CI 188841e4c73SJed Brown if (user->app_ctx->test_mode) { 1892b730f8bSJeremy L Thompson PetscCall(RegressionTests_NS(user->app_ctx, Q)); 19077841947SLeila Ghaffari } 19177841947SLeila Ghaffari 19277841947SLeila Ghaffari PetscFunctionReturn(0); 19377841947SLeila Ghaffari } 19477841947SLeila Ghaffari 1954de8550aSJed Brown const PetscInt FLUIDS_FILE_TOKEN = 0xceedf00; 1964de8550aSJed Brown 19777841947SLeila Ghaffari // Gather initial Q values in case of continuation of simulation 19877841947SLeila Ghaffari PetscErrorCode SetupICsFromBinary(MPI_Comm comm, AppCtx app_ctx, Vec Q) { 19977841947SLeila Ghaffari PetscViewer viewer; 2004de8550aSJed Brown PetscInt token, step_number; 2014de8550aSJed Brown PetscReal time; 2022b730f8bSJeremy L Thompson 20377841947SLeila Ghaffari PetscFunctionBegin; 20477841947SLeila Ghaffari 20577841947SLeila Ghaffari // Read input 2062b730f8bSJeremy L Thompson PetscCall(PetscViewerBinaryOpen(comm, app_ctx->cont_file, FILE_MODE_READ, &viewer)); 20777841947SLeila Ghaffari 2084de8550aSJed Brown // Attempt 2094de8550aSJed Brown PetscCall(PetscViewerBinaryRead(viewer, &token, 1, NULL, PETSC_INT)); 2104de8550aSJed Brown if (token == FLUIDS_FILE_TOKEN) { // New style format; we're reading a file with step number and time in the header 2114de8550aSJed Brown PetscCall(PetscViewerBinaryRead(viewer, &step_number, 1, NULL, PETSC_INT)); 2124de8550aSJed Brown PetscCall(PetscViewerBinaryRead(viewer, &time, 1, NULL, PETSC_REAL)); 2134de8550aSJed Brown app_ctx->cont_steps = step_number; 2144de8550aSJed Brown app_ctx->cont_time = time; 2154de8550aSJed Brown } else if (token == VEC_FILE_CLASSID) { // Legacy format of just the vector, encoded as [VEC_FILE_CLASSID, length, ] 2164de8550aSJed Brown PetscInt length, N; 2174de8550aSJed Brown PetscCall(PetscViewerBinaryRead(viewer, &length, 1, NULL, PETSC_INT)); 2184de8550aSJed Brown PetscCall(VecGetSize(Q, &N)); 2194de8550aSJed Brown PetscCheck(length == N, comm, PETSC_ERR_ARG_INCOMP, "File Vec has length %" PetscInt_FMT " but DM has global Vec size %" PetscInt_FMT, length, N); 2204de8550aSJed Brown PetscCall(PetscViewerBinarySetSkipHeader(viewer, PETSC_TRUE)); 2214de8550aSJed Brown } else SETERRQ(comm, PETSC_ERR_FILE_UNEXPECTED, "Not a fluids header token or a PETSc Vec in file"); 2224de8550aSJed Brown 22377841947SLeila Ghaffari // Load Q from existent solution 2242b730f8bSJeremy L Thompson PetscCall(VecLoad(Q, viewer)); 22577841947SLeila Ghaffari 22677841947SLeila Ghaffari // Cleanup 2272b730f8bSJeremy L Thompson PetscCall(PetscViewerDestroy(&viewer)); 22877841947SLeila Ghaffari 22977841947SLeila Ghaffari PetscFunctionReturn(0); 23077841947SLeila Ghaffari } 23177841947SLeila Ghaffari 23277841947SLeila Ghaffari // Record boundary values from initial condition 23377841947SLeila Ghaffari PetscErrorCode SetBCsFromICs_NS(DM dm, Vec Q, Vec Q_loc) { 2345571c6fdSJames Wright Vec Qbc, boundary_mask; 23577841947SLeila Ghaffari PetscFunctionBegin; 23677841947SLeila Ghaffari 2372b730f8bSJeremy L Thompson PetscCall(DMGetNamedLocalVector(dm, "Qbc", &Qbc)); 2382b730f8bSJeremy L Thompson PetscCall(VecCopy(Q_loc, Qbc)); 2392b730f8bSJeremy L Thompson PetscCall(VecZeroEntries(Q_loc)); 2402b730f8bSJeremy L Thompson PetscCall(DMGlobalToLocal(dm, Q, INSERT_VALUES, Q_loc)); 2412b730f8bSJeremy L Thompson PetscCall(VecAXPY(Qbc, -1., Q_loc)); 2422b730f8bSJeremy L Thompson PetscCall(DMRestoreNamedLocalVector(dm, "Qbc", &Qbc)); 2432b730f8bSJeremy L Thompson PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexInsertBoundaryValues_C", DMPlexInsertBoundaryValues_NS)); 24477841947SLeila Ghaffari 2455571c6fdSJames Wright PetscCall(DMGetNamedLocalVector(dm, "boundary mask", &boundary_mask)); 2465571c6fdSJames Wright PetscCall(DMGetGlobalVector(dm, &Q)); 2475571c6fdSJames Wright PetscCall(VecZeroEntries(boundary_mask)); 2485571c6fdSJames Wright PetscCall(VecSet(Q, 1.0)); 2495571c6fdSJames Wright PetscCall(DMGlobalToLocal(dm, Q, INSERT_VALUES, boundary_mask)); 2505571c6fdSJames Wright PetscCall(DMRestoreNamedLocalVector(dm, "boundary mask", &boundary_mask)); 2515571c6fdSJames Wright 25277841947SLeila Ghaffari PetscFunctionReturn(0); 25377841947SLeila Ghaffari } 254841e4c73SJed Brown 255841e4c73SJed Brown // Free a plain data context that was allocated using PETSc; returning libCEED error codes 256841e4c73SJed Brown int FreeContextPetsc(void *data) { 2572b730f8bSJeremy L Thompson if (PetscFree(data)) return CeedError(NULL, CEED_ERROR_ACCESS, "PetscFree failed"); 258841e4c73SJed Brown return CEED_ERROR_SUCCESS; 259841e4c73SJed Brown } 260