Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #ifdef MOOSE_MFEM_ENABLED 11 : 12 : #pragma once 13 : 14 : #include "MFEMLinearSolverBase.h" 15 : 16 : namespace Moose::MFEM 17 : { 18 : /** 19 : * Base class for LOR compatible linear MFEM solvers and preconditioners. 20 : * Any LOR-capable MFEM solver T must inherit from LORLinearSolverBase<T>. 21 : * The user is free to specialize LORLinearSolverBase<T>::UpdateEquationSystemContext() 22 : * if the provided template definition is not appropriate, for instance if additional 23 : * setup is required or if building an mfem::LORSolver<T> object is unnecessary. 24 : */ 25 : template <class MFEMSolverType> 26 : class LORLinearSolverBase : public LinearSolverBase 27 : { 28 : public: 29 : static InputParameters validParams(); 30 : 31 : LORLinearSolverBase(const InputParameters & parameters); 32 : 33 : protected: 34 : /// Update the wrapped MFEM solver parameters 35 : virtual void SetSolverParameters(MFEMSolverType & solver) = 0; 36 : 37 : virtual void UpdateEquationSystemContext() override; 38 : 39 : /// Variable defining whether to use LOR solver 40 : bool _lor; 41 : mfem::ParBilinearForm * _a; 42 : mfem::Array<int> _ess_bdr_markers; 43 : mfem::Array<int> _ess_tdofs; 44 : 45 : private: 46 : void SetLORSolver(); 47 : 48 : /// Checks for the correct configuration of quadrature bases for LOR spectral equivalence 49 : virtual void CheckSpectralEquivalence(mfem::ParBilinearForm & blf) const; 50 : 51 : /// Rebuild any Low-Order-Refined components from the unreduced bilinear form. Called only when 52 : /// _lor is true, before the assembled linear operator has been set via SetOperator. Default 53 : /// no-op; override in solvers or preconditioners that construct LOR-related data from the 54 : /// bilinear form. 55 : virtual void SetupLOR(std::shared_ptr<Moose::MFEM::EquationSystem> equation_system); 56 : }; 57 : 58 : template <class MFEMSolverType> 59 : InputParameters 60 25244 : LORLinearSolverBase<MFEMSolverType>::validParams() 61 : { 62 25244 : InputParameters params = LinearSolverBase::validParams(); 63 75732 : params.addParam<bool>("low_order_refined", false, "Set usage of Low-Order Refined solver."); 64 25244 : return params; 65 0 : } 66 : 67 : template <class MFEMSolverType> 68 1969 : LORLinearSolverBase<MFEMSolverType>::LORLinearSolverBase(const InputParameters & parameters) 69 1969 : : LinearSolverBase(parameters), _lor(parameters.get<bool>("low_order_refined")) 70 : { 71 1969 : } 72 : 73 : template <typename T, typename... Ts> 74 : constexpr bool is_any_of_v = (std::is_same_v<T, Ts> || ...); 75 : 76 : template <class MFEMSolverType> 77 : void 78 64 : LORLinearSolverBase<MFEMSolverType>::CheckSpectralEquivalence(mfem::ParBilinearForm & blf) const 79 : { 80 64 : if (auto fec = dynamic_cast<const mfem::H1_FECollection *>(blf.FESpace()->FEColl())) 81 : { 82 43 : if (fec->GetBasisType() != mfem::BasisType::GaussLobatto) 83 0 : mooseError("Low-Order-Refined solver requires the FESpace basis to be GaussLobatto " 84 : "for H1 elements."); 85 : } 86 21 : else if (auto fec = dynamic_cast<const mfem::ND_FECollection *>(blf.FESpace()->FEColl())) 87 : { 88 28 : if (fec->GetClosedBasisType() != mfem::BasisType::GaussLobatto || 89 14 : fec->GetOpenBasisType() != mfem::BasisType::IntegratedGLL) 90 0 : mooseError("Low-Order-Refined solver requires the FESpace closed-basis to be GaussLobatto " 91 : "and the open-basis to be IntegratedGLL for ND elements."); 92 : } 93 7 : else if (auto fec = dynamic_cast<const mfem::RT_FECollection *>(blf.FESpace()->FEColl())) 94 : { 95 14 : if (fec->GetClosedBasisType() != mfem::BasisType::GaussLobatto || 96 7 : fec->GetOpenBasisType() != mfem::BasisType::IntegratedGLL) 97 0 : mooseError("Low-Order-Refined solver requires the FESpace closed-basis to be GaussLobatto " 98 : "and the open-basis to be IntegratedGLL for RT elements."); 99 : } 100 64 : } 101 : 102 : template <class MFEMSolverType> 103 : void 104 3726 : LORLinearSolverBase<MFEMSolverType>::UpdateEquationSystemContext() 105 : { 106 3726 : Moose::MFEM::LinearSolverBase::UpdateEquationSystemContext(); 107 3726 : if (_lor && GetPreconditioner()) 108 0 : mooseError("LOR solver cannot take a preconditioner"); 109 3726 : if (_lor) 110 : { 111 57 : SetupLOR(_equation_system); 112 : if constexpr (is_any_of_v<MFEMSolverType, mfem::HypreAMS, mfem::HypreADS>) 113 14 : if (_a->ParFESpace()->GetMesh()->GetTypicalElementGeometry() != mfem::Geometry::Type::CUBE) 114 0 : mooseError("LOR HypreAMS/ADS Solver only supports hex meshes."); 115 57 : SetLORSolver(); 116 : } 117 : else if constexpr (!is_any_of_v<MFEMSolverType, 118 : mfem::OperatorJacobiSmoother, 119 : mfem::HypreBoomerAMG, 120 : mfem::HypreAMS, 121 : mfem::HypreADS>) 122 1843 : SetPreconditioner(static_cast<MFEMSolverType &>(GetSolver())); 123 3726 : } 124 : 125 : template <class MFEMSolverType> 126 : void 127 64 : LORLinearSolverBase<MFEMSolverType>::SetupLOR( 128 : std::shared_ptr<Moose::MFEM::EquationSystem> equation_system) 129 : { 130 64 : if (!equation_system) 131 0 : mooseError("LOR solver setup requires an EquationSystem to be defined."); 132 64 : if (equation_system->IsComplex()) 133 0 : mooseError("LOR solve is not supported for complex equation systems."); 134 64 : if (equation_system->IsMultivariate()) 135 0 : mooseError("LOR solve is only supported for single-variable systems"); 136 : 137 64 : const auto & test_var_name = equation_system->GetTestVarNames().at(0); 138 64 : _a = &equation_system->GetBilinearForm(test_var_name); 139 64 : CheckSpectralEquivalence(*_a); 140 64 : _ess_bdr_markers = equation_system->GetEssentialBoundaryMarkers(test_var_name); 141 64 : _a->ParFESpace()->GetEssentialTrueDofs(_ess_bdr_markers, _ess_tdofs); 142 64 : } 143 : 144 : template <class MFEMSolverType> 145 : void 146 57 : LORLinearSolverBase<MFEMSolverType>::SetLORSolver() 147 : { 148 : mfem::LORSolver<MFEMSolverType> * lor_solver; 149 : if constexpr (is_any_of_v<MFEMSolverType, mfem::HypreGMRES, mfem::HypreFGMRES, mfem::HyprePCG>) 150 : { 151 6 : mfem::ParLORDiscretization lor_disc(*_a, _ess_tdofs); 152 6 : lor_solver = new mfem::LORSolver<MFEMSolverType>(lor_disc, _a->ParFESpace()->GetComm()); 153 6 : } 154 : else 155 51 : lor_solver = new mfem::LORSolver<MFEMSolverType>(*_a, _ess_tdofs); 156 57 : SetSolverParameters(lor_solver->GetSolver()); 157 57 : SetSolver(lor_solver); 158 57 : } 159 : 160 : } // namespace Moose::MFEM 161 : 162 : #endif