LCOV - code coverage report
Current view: top level - include/mfem/equation_systems - EquationSystem.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 329044 Lines: 40 42 95.2 %
Date: 2026-08-03 21:12:22 Functions: 15 16 93.8 %
Legend: Lines: hit not hit

          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 "libmesh/ignore_warnings.h"
      15             : #include "mfem/miniapps/common/pfem_extras.hpp"
      16             : #include "libmesh/restore_warnings.h"
      17             : #include "MFEMIntegratedBC.h"
      18             : #include "MFEMEssentialBC.h"
      19             : #include "MFEMContainers.h"
      20             : #include "MFEMKernel.h"
      21             : #include "MFEMMixedBilinearFormKernel.h"
      22             : #include "ScaleIntegrator.h"
      23             : #include "NLScaleIntegrator.h"
      24             : 
      25             : namespace Moose::MFEM
      26             : {
      27             : class CoefficientManager;
      28             : 
      29             : /**
      30             :  * Owns the weak-form mathematics of a MOOSE MFEM problem.
      31             :  *
      32             :  * An EquationSystem stores weak-form components (bilinear, linear, mixed-bilinear,
      33             :  * and nonlinear forms) contributed by kernels and boundary conditions.  It forms the
      34             :  * constrained linear part, keeps nonlinear action forms for residual/Jacobian
      35             :  * evaluation, and exposes the solve interface as an mfem::Operator.  It is responsible
      36             :  * for applying essential-DoF constraints and propagating either itself or the assembled
      37             :  * linear operator (and bilinear form, for LOR) to the configured solver tree.
      38             :  *
      39             :  * EquationSystem is *not* responsible for grid-function bookkeeping, time stepping, or
      40             :  * solver selection - those belong to the ProblemOperator layer.
      41             :  *
      42             :  * @see ProblemOperatorBase for the conceptual split between the two layers.
      43             :  */
      44             : class EquationSystem : public mfem::Operator
      45             : {
      46             : 
      47             : public:
      48        1705 :   EquationSystem() = default;
      49             :   ~EquationSystem() override;
      50             : 
      51             :   /// Add kernels.
      52             :   virtual void AddKernel(std::shared_ptr<MFEMKernel> kernel);
      53             :   virtual void AddIntegratedBC(std::shared_ptr<MFEMIntegratedBC> kernel);
      54             :   /// Add BC associated with essentially constrained DoFs on boundaries.
      55             :   virtual void AddEssentialBC(std::shared_ptr<MFEMEssentialBC> bc);
      56             : 
      57             :   /// Initialise
      58             :   virtual void Init(GridFunctions & gridfunctions,
      59             :                     ComplexGridFunctions & cmplx_gridfunctions,
      60             :                     mfem::AssemblyLevel assembly_level);
      61             :   /**
      62             :    * Build all weak-form components via BuildEquationSystem(), form the constrained linear part of
      63             :    * the system, and populate the true-DoF vectors used by the solve.
      64             :    *
      65             :    * For nonlinear problems, nonlinear forms are registered here but are not folded into the
      66             :    * assembled linear operator. Their residual action is evaluated by Mult(), and any Jacobian
      67             :    * contribution is formed at the current nonlinear iterate by GetGradient().
      68             :    *
      69             :    * This is the single public entry point for callers that want the equation system prepared for a
      70             :    * solve. Subclasses customize the form-building step by overriding BuildEquationSystem().
      71             :    */
      72             :   void FormSystem(mfem::BlockVector & trueX, mfem::BlockVector & trueRHS);
      73             :   /// Compute residual y = Mu
      74             :   void Mult(const mfem::Vector & u, mfem::Vector & residual) const override;
      75             :   /// Compute the contribution to the residual from nonlinear forms only.
      76             :   virtual void ComputeNonlinearResidual(const mfem::Vector & u, mfem::Vector & residual) const;
      77             :   /// Get Jacobian at the provided vector of true DoFs of trial variables
      78             :   mfem::Operator & GetGradient(const mfem::Vector & u) const override;
      79             :   /// Get operator handle for linear component of system operator
      80          26 :   mfem::OperatorHandle & GetLinearOperator() const { return _linear_operator; };
      81             : 
      82             :   /// Update variable from solution vector after solve
      83             :   virtual void SetTrialVariablesFromTrueVectors(const mfem::BlockVector & trueX) const;
      84             : 
      85             :   /// Set whether an external object (such as a nonlinear solver) requires Jacobian information for this EquationSystem.
      86          62 :   void SetGradientRequired(bool requires_gradient) { _gradient_required = requires_gradient; }
      87             : 
      88             :   /// Set the coefficient manager to notify when trial variables are updated, so that stored
      89             :   /// projections of solution-dependent coefficients are invalidated.
      90        1635 :   void SetCoefficientManager(CoefficientManager & coefficients)
      91             :   {
      92        1635 :     _coefficient_manager = &coefficients;
      93        1635 :   }
      94             : 
      95             :   // Test variables are associated with linear forms,
      96             :   // whereas trial variables are associated with gridfunctions.
      97        1661 :   const std::vector<std::string> & GetTrialVarNames() const { return _trial_var_names; }
      98        1751 :   const std::vector<std::string> & GetTestVarNames() const { return _test_var_names; }
      99             : 
     100             :   /// Getter for block true offsets associated with the EquationSystem operator
     101             :   const mfem::Array<int> & GetBlockOffsets() const { return _block_true_offsets; }
     102             : 
     103             :   /**
     104             :    * @returns a reference to the MFEM ParBilinearForm corresponding to test_var_name
     105             :    */
     106          64 :   mfem::ParBilinearForm & GetBilinearForm(const std::string & test_var_name)
     107             :   {
     108          64 :     return _blfs.GetRef(test_var_name);
     109             :   }
     110             : 
     111             :   /**
     112             :    * @returns a reference to the MFEM ParGridFunction corresponding to trial_var_name
     113             :    */
     114             :   mfem::ParGridFunction & GetGridFunction(const std::string & trial_var_name)
     115             :   {
     116             :     return _gfuncs->GetRef(trial_var_name);
     117             :   }
     118             : 
     119             :   /**
     120             :    * @returns Whether nonlinear integrators are present
     121             :    */
     122             :   bool Nonlinear() const { return _non_linear; }
     123             : 
     124             :   /// The true-DoF vector used for the most recent Jacobian linearization.
     125             :   const mfem::Vector & GetLinearizationPoint() const;
     126             : 
     127             :   /**
     128             :    * Build a fresh ParBilinearForm on the given FESpace using the same kernels as the main
     129             :    * system's bilinear form for var_name. Caller owns the returned form.
     130             :    */
     131             :   std::shared_ptr<mfem::ParBilinearForm>
     132             :   BuildBilinearFormForFESpace(const std::string & var_name,
     133             :                               mfem::ParFiniteElementSpace & fespace,
     134             :                               mfem::AssemblyLevel assembly_level);
     135             : 
     136             :   /**
     137             :    * Build a fresh ParNonlinearForm on the given FESpace using the same kernels as the main
     138             :    * system's nonlinear form for var_name. Caller owns the returned form.
     139             :    */
     140             :   std::shared_ptr<mfem::ParNonlinearForm>
     141             :   BuildNonlinearFormForFESpace(const std::string & var_name,
     142             :                                mfem::ParFiniteElementSpace & fespace,
     143             :                                mfem::AssemblyLevel assembly_level);
     144             : 
     145             :   /**
     146             :    * Return the essential boundary attribute marker array for a given trial variable.
     147             :    * The returned array has size == pmesh.bdr_attributes.Max() with 1 at essential boundaries.
     148             :    */
     149             :   mfem::Array<int> & GetEssentialBoundaryMarkers(const std::string & var_name);
     150             : 
     151             :   /// @returns Whether this EquationSystem includes complex components
     152          73 :   virtual bool IsComplex() const { return false; }
     153             :   /// @returns Whether this EquationSystem represents an eigenproblem
     154          11 :   virtual bool IsEigen() const { return false; }
     155             :   /// @returns Whether this EquationSystem has time-dependent components
     156           0 :   virtual bool IsTimeDependent() const { return false; }
     157             :   /// @returns Whether this is a multivariate (maybe mixed) equation system
     158          71 :   bool IsMultivariate() const { return _test_var_names.size() > 1; }
     159             :   /// @returns Whether nonlinear integrators are present in the equation system
     160           9 :   bool IsNonlinear() const { return _non_linear; }
     161             : 
     162             :   /// Build all forms comprising this EquationSystem
     163             :   virtual void BuildEquationSystem();
     164             : 
     165             : protected:
     166             :   /// Add coupled variable to EquationSystem.
     167             :   virtual void AddCoupledVariableNameIfMissing(const std::string & coupled_var_name);
     168             :   /// Add eliminated variable to EquationSystem.
     169             :   virtual void AddEliminatedVariableNameIfMissing(const std::string & eliminated_var_name);
     170             :   /// Add test variable to EquationSystem.
     171             :   virtual void AddTestVariableNameIfMissing(const std::string & test_var_name);
     172             :   /// Set trial variable names from subset of coupled variables that have an associated test variable.
     173             :   virtual void SetTrialVariableNames();
     174             : 
     175             :   /// Deletes the HypreParMatrix associated with any pointer stored in _h_blocks,
     176             :   /// and then proceeds to delete all dynamically allocated memory for _h_blocks
     177             :   /// itself, resetting all dimensions to zero.
     178             :   void DeleteHBlocks();
     179             : 
     180             :   /// Deletes the HypreParMatrix associated with any pointer stored in _jacobian_blocks,
     181             :   /// and then proceeds to delete all dynamically allocated memory for _jacobian_blocks
     182             :   /// itself, resetting all dimensions to zero.
     183             :   void DeleteJacobianBlocks();
     184             : 
     185             :   bool VectorContainsName(const std::vector<std::string> & the_vector,
     186             :                           const std::string & name) const;
     187             : 
     188             :   /// Apply essential BC(s) associated with var_name to set true DoFs of trial_gf and update
     189             :   /// markers of all essential boundaries
     190             :   virtual void ApplyEssentialBC(const std::string & var_name,
     191             :                                 mfem::ParGridFunction & trial_gf,
     192             :                                 mfem::Array<int> & global_ess_markers);
     193             :   /// Update all essentially constrained true DoF markers and values on boundaries
     194             :   virtual void ApplyEssentialBCs();
     195             :   /// Perform trivial eliminations of coupled variables lacking corresponding test variables
     196             :   virtual void EliminateCoupledVariables();
     197             :   /// Build linear forms and eliminate constrained DoFs
     198             :   virtual void BuildLinearForms();
     199             :   /// Build non-linear action forms
     200             :   virtual void BuildNonlinearForms();
     201             :   /// Build bilinear forms (diagonal Jacobian contributions)
     202             :   virtual void BuildBilinearForms();
     203             :   /// Build mixed bilinear forms (off-diagonal Jacobian contributions)
     204             :   virtual void BuildMixedBilinearForms();
     205             : 
     206             :   /// Form linear components of system based on on- and off-diagonal bilinear form
     207             :   /// contributions, populate solution and RHS vectors of true DoFs, and apply constraints.
     208             :   virtual void FormLinearSystem(mfem::OperatorHandle & op,
     209             :                                 mfem::BlockVector & trueX,
     210             :                                 mfem::BlockVector & trueRHS);
     211             :   using mfem::Operator::FormSystemOperator;
     212             :   /// Form matrix-free representation of linear components of system operator.
     213             :   /// Used when EquationSystem assembly level is set to 'FULL', 'ELEMENT', 'PARTIAL', or 'NONE'.
     214             :   virtual void FormSystemOperator(mfem::OperatorHandle & op,
     215             :                                   mfem::BlockVector & trueX,
     216             :                                   mfem::BlockVector & trueRHS);
     217             :   /// Form matrix representation of linear components of system operator as a HypreParMatrix.
     218             :   /// Used when EquationSystem assembly level is set to 'LEGACY'.
     219             :   virtual void FormSystemMatrix(mfem::OperatorHandle & op,
     220             :                                 mfem::BlockVector & trueX,
     221             :                                 mfem::BlockVector & trueRHS);
     222             :   /// Compute Jacobian matrix at the provided vector of true DoFs of trial variables
     223             :   void FormJacobianMatrix(const mfem::Vector & u);
     224             : 
     225             :   /**
     226             :    * Template method for applying BilinearFormIntegrators on domains from kernels to a BilinearForm,
     227             :    * or MixedBilinearForm
     228             :    */
     229             :   template <class FormType>
     230             :   void ApplyDomainBLFIntegrators(
     231             :       const std::string & trial_var_name,
     232             :       const std::string & test_var_name,
     233             :       std::shared_ptr<FormType> form,
     234             :       NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>> & kernels_map,
     235             :       std::optional<mfem::real_t> scale_factor = std::nullopt);
     236             : 
     237             :   /**
     238             :    * Apply domain LinearFormIntegrators from kernels to the linear form associated with the
     239             :    * supplied test variable.
     240             :    */
     241             :   void ApplyDomainLFIntegrators(
     242             :       const std::string & test_var_name,
     243             :       std::shared_ptr<mfem::ParLinearForm> form,
     244             :       NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>> & kernels_map);
     245             : 
     246             :   /**
     247             :    * Apply domain NonlinearFormIntegrators from kernels to the nonlinear form associated with the
     248             :    * supplied test variable.
     249             :    */
     250             :   void ApplyDomainNLFIntegrators(
     251             :       const std::string & test_var_name,
     252             :       std::shared_ptr<mfem::ParNonlinearForm> form,
     253             :       NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>> & kernels_map,
     254             :       std::optional<mfem::real_t> scale_factor = std::nullopt);
     255             : 
     256             :   /**
     257             :    * Template method for applying BilinearFormIntegrators on boundaries from integrated boundary
     258             :    * conditions to a BilinearForm, or MixedBilinearForm.
     259             :    */
     260             :   template <class FormType>
     261             :   void ApplyBoundaryBLFIntegrators(
     262             :       const std::string & trial_var_name,
     263             :       const std::string & test_var_name,
     264             :       std::shared_ptr<FormType> form,
     265             :       NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMIntegratedBC>>>> &
     266             :           integrated_bc_map,
     267             :       std::optional<mfem::real_t> scale_factor = std::nullopt);
     268             : 
     269             :   /**
     270             :    * Apply boundary LinearFormIntegrators from integrated boundary conditions to the linear form
     271             :    * associated with the supplied test variable.
     272             :    */
     273             :   void ApplyBoundaryLFIntegrators(
     274             :       const std::string & test_var_name,
     275             :       std::shared_ptr<mfem::ParLinearForm> form,
     276             :       NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMIntegratedBC>>>> &
     277             :           integrated_bc_map);
     278             : 
     279             :   /**
     280             :    * Apply boundary NonlinearFormIntegrators from integrated boundary conditions to the nonlinear
     281             :    * form associated with the supplied test variable.
     282             :    */
     283             :   void ApplyBoundaryNLFIntegrators(
     284             :       const std::string & test_var_name,
     285             :       std::shared_ptr<mfem::ParNonlinearForm> form,
     286             :       NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMIntegratedBC>>>> &
     287             :           integrated_bc_map,
     288             :       std::optional<mfem::real_t> scale_factor = std::nullopt);
     289             : 
     290             :   /// Names of all trial variables of kernels and boundary conditions
     291             :   /// added to this EquationSystem.
     292             :   std::vector<std::string> _coupled_var_names;
     293             :   /// Subset of _coupled_var_names of all variables corresponding to gridfunctions with degrees of
     294             :   /// freedom that comprise the state vector of this EquationSystem. This will differ from
     295             :   /// _coupled_var_names when time derivatives or other eliminated variables are present.
     296             :   std::vector<std::string> _trial_var_names;
     297             :   /// Names of all coupled variables without a corresponding test variable.
     298             :   std::vector<std::string> _eliminated_var_names;
     299             :   /// Pointers to coupled variables not part of the reduced EquationSystem.
     300             :   Moose::MFEM::GridFunctions _eliminated_variables;
     301             :   /// Names of all test variables corresponding to linear forms in this equation system
     302             :   std::vector<std::string> _test_var_names;
     303             :   /// Pointers to finite element spaces associated with test variables.
     304             :   std::vector<mfem::ParFiniteElementSpace *> _test_pfespaces;
     305             :   /// Pointers to finite element spaces associated with coupled variables.
     306             :   std::vector<mfem::ParFiniteElementSpace *> _coupled_pfespaces;
     307             : 
     308             :   // Components of weak form, named according to test variable
     309             :   NamedFieldsMap<mfem::ParBilinearForm> _blfs;
     310             :   NamedFieldsMap<mfem::ParLinearForm> _lfs;
     311             :   NamedFieldsMap<mfem::ParNonlinearForm> _nlfs;
     312             :   NamedFieldsMap<NamedFieldsMap<mfem::ParMixedBilinearForm>> _mblfs; // named according to trial var
     313             : 
     314             :   /// Gridfunctions holding essential constraints from Dirichlet BCs
     315             :   std::vector<std::unique_ptr<mfem::ParGridFunction>> _var_ess_constraints;
     316             :   std::vector<mfem::Array<int>> _ess_tdof_lists;
     317             :   std::vector<mfem::Array<int>> _ess_markers;
     318             : 
     319             :   mfem::Array2D<const mfem::HypreParMatrix *> _h_blocks, _jacobian_blocks;
     320             :   /// Arrays to store kernels to act on each component of weak form.
     321             :   /// Named according to test and trial variables.
     322             :   NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>> _kernels_map;
     323             :   /// Arrays to store integrated BCs to act on each component of weak form.
     324             :   /// Named according to test and trial variables.
     325             :   NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMIntegratedBC>>>> _integrated_bc_map;
     326             :   /// Arrays to store essential BCs to act on each component of weak form.
     327             :   /// Named according to test variable.
     328             :   NamedFieldsMap<std::vector<std::shared_ptr<MFEMEssentialBC>>> _essential_bc_map;
     329             : 
     330             :   // Operator handle for the jacobian
     331             :   mutable mfem::OperatorHandle _jacobian;
     332             :   // Operator handle for the linear components of the system operator
     333             :   mutable mfem::OperatorHandle _linear_operator;
     334             :   mfem::AssemblyLevel _assembly_level;
     335             : 
     336             :   // Pointer to GridFunctions to enable updates during nonlinear iterations
     337             :   Moose::MFEM::GridFunctions * _gfuncs;
     338             :   // Array storing block offsets of solution and residual vector
     339             :   mfem::Array<int> _block_true_offsets;
     340             :   // Non-owning pointer to the vector passed into the most recent GetGradient() call.
     341             :   mutable const mfem::Vector * _linearization_point = nullptr;
     342             :   // Boolean indicating if EquationSystem contains nonlinear integrators
     343             :   bool _non_linear = false;
     344             :   // Whether an external object (e.g. solver) requires Jacobian/gradient information.
     345             :   bool _gradient_required = false;
     346             :   // Coefficient manager notified when trial variables are updated, so that stored projections
     347             :   // of solution-dependent coefficients are invalidated.
     348             :   CoefficientManager * _coefficient_manager = nullptr;
     349             : 
     350             : private:
     351             :   /// Disallowed inherited method
     352             :   using mfem::Operator::RecoverFEMSolution;
     353             : };
     354             : 
     355             : template <class FormType>
     356             : void
     357        6412 : EquationSystem::ApplyDomainBLFIntegrators(
     358             :     const std::string & trial_var_name,
     359             :     const std::string & test_var_name,
     360             :     std::shared_ptr<FormType> form,
     361             :     NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>> & kernels_map,
     362             :     std::optional<mfem::real_t> scale_factor)
     363             : {
     364        6412 :   if (kernels_map.Has(test_var_name) && kernels_map.Get(test_var_name)->Has(trial_var_name))
     365             :   {
     366        6261 :     auto kernels = kernels_map.GetRef(test_var_name).GetRef(trial_var_name);
     367       13772 :     for (auto & kernel : kernels)
     368             :     {
     369        7511 :       mfem::BilinearFormIntegrator * integ = kernel->createBFIntegrator();
     370             : 
     371        7511 :       if (integ)
     372             :       {
     373        6308 :         if (scale_factor.has_value())
     374        1704 :           integ = new ScaleIntegrator(integ, scale_factor.value(), true);
     375        6308 :         kernel->isSubdomainRestricted()
     376        6308 :             ? form->AddDomainIntegrator(std::move(integ), kernel->getSubdomainMarkers())
     377        6216 :             : form->AddDomainIntegrator(std::move(integ));
     378             :       }
     379             :     }
     380        6261 :   }
     381        6412 : }
     382             : 
     383             : template <class FormType>
     384             : void
     385        2726 : EquationSystem::ApplyBoundaryBLFIntegrators(
     386             :     const std::string & trial_var_name,
     387             :     const std::string & test_var_name,
     388             :     std::shared_ptr<FormType> form,
     389             :     NamedFieldsMap<NamedFieldsMap<std::vector<std::shared_ptr<MFEMIntegratedBC>>>> &
     390             :         integrated_bc_map,
     391             :     std::optional<mfem::real_t> scale_factor)
     392             : {
     393        2864 :   if (integrated_bc_map.Has(test_var_name) &&
     394         138 :       integrated_bc_map.Get(test_var_name)->Has(trial_var_name))
     395             :   {
     396         116 :     auto bcs = integrated_bc_map.GetRef(test_var_name).GetRef(trial_var_name);
     397         250 :     for (auto & bc : bcs)
     398             :     {
     399         134 :       mfem::BilinearFormIntegrator * integ = bc->createBFIntegrator();
     400             : 
     401         134 :       if (integ)
     402             :       {
     403          36 :         if (scale_factor.has_value())
     404          36 :           integ = new ScaleIntegrator(integ, scale_factor.value(), true);
     405          36 :         bc->isBoundaryRestricted()
     406          36 :             ? form->AddBoundaryIntegrator(std::move(integ), bc->getBoundaryMarkers())
     407           0 :             : form->AddBoundaryIntegrator(std::move(integ));
     408             :       }
     409             :     }
     410         116 :   }
     411        2726 : }
     412             : 
     413             : } // namespace Moose::MFEM
     414             : 
     415             : #endif

Generated by: LCOV version 1.14