LCOV - code coverage report
Current view: top level - src/mfem/equation_systems - EquationSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32463 (9b8a52) with base a052fd Lines: 301 307 98.0 %
Date: 2026-05-26 14:49:46 Functions: 28 29 96.6 %
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             : #include "EquationSystem.h"
      13             : #include "libmesh/int_range.h"
      14             : 
      15             : namespace Moose::MFEM
      16             : {
      17             : 
      18        1372 : EquationSystem::~EquationSystem()
      19             : {
      20        1372 :   DeleteHBlocks();
      21        1372 :   DeleteJacobianBlocks();
      22        1372 : }
      23             : 
      24             : void
      25        3174 : EquationSystem::DeleteHBlocks()
      26             : {
      27        5018 :   for (const auto i : make_range(_h_blocks.NumRows()))
      28        3772 :     for (const auto j : make_range(_h_blocks.NumCols()))
      29             :     {
      30        1928 :       if (_jacobian_blocks.NumRows() && _jacobian_blocks(i, j) == _h_blocks(i, j))
      31           0 :         _jacobian_blocks(i, j) = nullptr;
      32        1928 :       delete _h_blocks(i, j);
      33             :     }
      34        3174 :   _h_blocks.DeleteAll();
      35        3174 : }
      36             : 
      37             : void
      38        3552 : EquationSystem::DeleteJacobianBlocks()
      39             : {
      40        5732 :   for (const auto i : make_range(_jacobian_blocks.NumRows()))
      41        4360 :     for (const auto j : make_range(_jacobian_blocks.NumCols()))
      42        2180 :       if (!_h_blocks.NumRows() || _jacobian_blocks(i, j) != _h_blocks(i, j))
      43        2180 :         delete _jacobian_blocks(i, j);
      44        3552 :   _jacobian_blocks.DeleteAll();
      45        3552 : }
      46             : 
      47             : bool
      48        6895 : EquationSystem::VectorContainsName(const std::vector<std::string> & the_vector,
      49             :                                    const std::string & name) const
      50             : {
      51        6895 :   return std::find(the_vector.begin(), the_vector.end(), name) != the_vector.end();
      52             : }
      53             : 
      54             : void
      55        1653 : EquationSystem::AddCoupledVariableNameIfMissing(const std::string & coupled_var_name)
      56             : {
      57        1653 :   if (!VectorContainsName(_coupled_var_names, coupled_var_name))
      58        1041 :     _coupled_var_names.push_back(coupled_var_name);
      59        1653 : }
      60             : 
      61             : void
      62         145 : EquationSystem::AddEliminatedVariableNameIfMissing(const std::string & eliminated_var_name)
      63             : {
      64         145 :   if (!VectorContainsName(_eliminated_var_names, eliminated_var_name))
      65         139 :     _eliminated_var_names.push_back(eliminated_var_name);
      66         145 : }
      67             : 
      68             : void
      69        2979 : EquationSystem::AddTestVariableNameIfMissing(const std::string & test_var_name)
      70             : {
      71        2979 :   if (!VectorContainsName(_test_var_names, test_var_name))
      72         959 :     _test_var_names.push_back(test_var_name);
      73        2979 : }
      74             : 
      75             : void
      76        1372 : EquationSystem::SetTrialVariableNames()
      77             : {
      78             :   // If a coupled variable has an equation associated with it,
      79             :   // add it to the set of trial variables.
      80        2331 :   for (const auto & test_var_name : _test_var_names)
      81         959 :     if (VectorContainsName(_coupled_var_names, test_var_name))
      82         959 :       _trial_var_names.push_back(test_var_name);
      83             : 
      84             :   // Otherwise, add it to the set of eliminated variables.
      85        2413 :   for (const auto & coupled_var_name : _coupled_var_names)
      86        1041 :     if (!VectorContainsName(_test_var_names, coupled_var_name))
      87          82 :       _eliminated_var_names.push_back(coupled_var_name);
      88        1372 : }
      89             : 
      90             : void
      91        1524 : EquationSystem::AddKernel(std::shared_ptr<MFEMKernel> kernel)
      92             : {
      93        1524 :   const auto & trial_var_name = kernel->getTrialVariableName();
      94        1524 :   const auto & test_var_name = kernel->getTestVariableName();
      95        1524 :   AddCoupledVariableNameIfMissing(trial_var_name);
      96        1524 :   AddTestVariableNameIfMissing(test_var_name);
      97             :   // Register new kernels map if not present for the test variable
      98        1524 :   if (!_kernels_map.Has(test_var_name))
      99             :   {
     100             :     auto kernel_field_map =
     101         912 :         std::make_shared<Moose::MFEM::NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>>();
     102         912 :     _kernels_map.Register(test_var_name, std::move(kernel_field_map));
     103         912 :   }
     104             :   // Register new kernels map if not present for the test/trial variable pair
     105        1524 :   if (!_kernels_map.Get(test_var_name)->Has(trial_var_name))
     106             :   {
     107        1018 :     auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMKernel>>>();
     108        1018 :     _kernels_map.Get(test_var_name)->Register(trial_var_name, std::move(kernels));
     109        1018 :   }
     110        1524 :   _kernels_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(kernel));
     111        1524 : }
     112             : 
     113             : void
     114          56 : EquationSystem::AddIntegratedBC(std::shared_ptr<MFEMIntegratedBC> bc)
     115             : {
     116          56 :   const auto & trial_var_name = bc->getTrialVariableName();
     117          56 :   const auto & test_var_name = bc->getTestVariableName();
     118          56 :   AddCoupledVariableNameIfMissing(trial_var_name);
     119          56 :   AddTestVariableNameIfMissing(test_var_name);
     120             :   // Register new integrated bc map if not present for the test variable
     121          56 :   if (!_integrated_bc_map.Has(test_var_name))
     122             :   {
     123             :     auto integrated_bc_field_map = std::make_shared<
     124          50 :         Moose::MFEM::NamedFieldsMap<std::vector<std::shared_ptr<MFEMIntegratedBC>>>>();
     125          50 :     _integrated_bc_map.Register(test_var_name, std::move(integrated_bc_field_map));
     126          50 :   }
     127             :   // Register new integrated bc map if not present for the test/trial variable pair
     128          56 :   if (!_integrated_bc_map.Get(test_var_name)->Has(trial_var_name))
     129             :   {
     130          50 :     auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMIntegratedBC>>>();
     131          50 :     _integrated_bc_map.Get(test_var_name)->Register(trial_var_name, std::move(bcs));
     132          50 :   }
     133          56 :   _integrated_bc_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(bc));
     134          56 : }
     135             : 
     136             : void
     137        1119 : EquationSystem::AddEssentialBC(std::shared_ptr<MFEMEssentialBC> bc)
     138             : {
     139        1119 :   const auto & test_var_name = bc->getTestVariableName();
     140        1119 :   AddTestVariableNameIfMissing(test_var_name);
     141             :   // Register new essential bc map if not present for the test variable
     142        1119 :   if (!_essential_bc_map.Has(test_var_name))
     143             :   {
     144         836 :     auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMEssentialBC>>>();
     145         836 :     _essential_bc_map.Register(test_var_name, std::move(bcs));
     146         836 :   }
     147        1119 :   _essential_bc_map.GetRef(test_var_name).push_back(std::move(bc));
     148        1119 : }
     149             : 
     150             : void
     151        1310 : EquationSystem::Init(Moose::MFEM::GridFunctions & gridfunctions,
     152             :                      Moose::MFEM::ComplexGridFunctions & cmplx_gridfunctions,
     153             :                      mfem::AssemblyLevel assembly_level)
     154             : {
     155        1310 :   _assembly_level = assembly_level;
     156             : 
     157        1310 :   if (cmplx_gridfunctions.size())
     158           0 :     mooseError("Complex variables have been created but the executioner numeric type has not been "
     159             :                "set to complex. Please set Executioner/numeric_type = complex.");
     160             : 
     161             :   // Extract which coupled variables are to be trivially eliminated and which are trial variables
     162        1310 :   SetTrialVariableNames();
     163             : 
     164        2228 :   for (auto & test_var_name : _test_var_names)
     165             :   {
     166         918 :     if (!gridfunctions.Has(test_var_name))
     167             :     {
     168           0 :       mooseError("MFEM variable ",
     169             :                  test_var_name,
     170             :                  " requested by equation system during initialization was "
     171             :                  "not found in gridfunctions");
     172             :     }
     173             :     // Store pointers to test FESpaces
     174         918 :     _test_pfespaces.push_back(gridfunctions.Get(test_var_name)->ParFESpace());
     175             :   }
     176             : 
     177        2228 :   for (auto & trial_var_name : _trial_var_names)
     178             :   {
     179         918 :     if (!gridfunctions.Has(trial_var_name))
     180             :     {
     181           0 :       mooseError("MFEM variable ",
     182             :                  trial_var_name,
     183             :                  " requested by equation system during initialization was "
     184             :                  "not found in gridfunctions");
     185             :     }
     186             :     // Create auxiliary gridfunctions for storing essential constraints from Dirichlet conditions
     187         918 :     _var_ess_constraints.emplace_back(
     188        1836 :         std::make_unique<mfem::ParGridFunction>(gridfunctions.Get(trial_var_name)->ParFESpace()));
     189             :   }
     190             : 
     191             :   // Store pointers to FESpaces of all coupled variables
     192        2310 :   for (auto & coupled_var_name : _coupled_var_names)
     193        1000 :     _coupled_pfespaces.push_back(gridfunctions.Get(coupled_var_name)->ParFESpace());
     194             : 
     195             :   // Store pointers to coupled variable GridFunctions that are to be eliminated prior to forming the
     196             :   // jacobian
     197        1531 :   for (auto & eliminated_var_name : _eliminated_var_names)
     198         221 :     _eliminated_variables.Register(eliminated_var_name,
     199         442 :                                    gridfunctions.GetShared(eliminated_var_name));
     200             : 
     201             :   // Get a reference to the GridFunctions
     202        1310 :   _gfuncs = &gridfunctions;
     203        1310 : }
     204             : 
     205             : void
     206        1839 : EquationSystem::ApplyEssentialBC(const std::string & var_name,
     207             :                                  mfem::ParGridFunction & trial_gf,
     208             :                                  mfem::Array<int> & global_ess_markers)
     209             : {
     210        1839 :   if (_essential_bc_map.Has(var_name))
     211             :   {
     212        1427 :     auto & bcs = _essential_bc_map.GetRef(var_name);
     213        3682 :     for (auto & bc : bcs)
     214             :     {
     215             :       // Set constrained DoFs values on essential boundaries
     216        2255 :       bc->ApplyBC(trial_gf);
     217             :       // Fetch marker array labelling essential boundaries of current BC
     218        2255 :       mfem::Array<int> ess_bdrs(bc->getBoundaryMarkers());
     219             :       // Add these boundary markers to the set of markers labelling all essential boundaries
     220       11214 :       for (const auto i : make_range(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max()))
     221        8959 :         global_ess_markers[i] = std::max(global_ess_markers[i], ess_bdrs[i]);
     222        2255 :     }
     223             :   }
     224        1839 : }
     225             : 
     226             : void
     227        1797 : EquationSystem::ApplyEssentialBCs()
     228             : {
     229        1797 :   _ess_tdof_lists.resize(_trial_var_names.size());
     230        3636 :   for (const auto i : index_range(_trial_var_names))
     231             :   {
     232        1839 :     const auto & trial_var_name = _trial_var_names.at(i);
     233        1839 :     mfem::ParGridFunction & trial_gf = *_var_ess_constraints.at(i);
     234             : 
     235             :     // Make sure we update the size, if this mesh has changed recently for instance
     236        1839 :     trial_gf.Update();
     237             : 
     238             :     // Initial guess for non-linear problems (initial condition or the previous time step solution)
     239        1839 :     trial_gf = _gfuncs->GetRef(trial_var_name);
     240             : 
     241        1839 :     mfem::Array<int> global_ess_markers(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max());
     242        1839 :     global_ess_markers = 0;
     243             :     // Set strongly constrained DoFs of trial_gf on essential boundaries and add markers for all
     244             :     // essential boundaries to the global_ess_markers array
     245        1839 :     ApplyEssentialBC(trial_var_name, trial_gf, global_ess_markers);
     246        1839 :     trial_gf.ParFESpace()->GetEssentialTrueDofs(global_ess_markers, _ess_tdof_lists.at(i));
     247        1839 :   }
     248        1797 : }
     249             : 
     250             : void
     251        1823 : EquationSystem::EliminateCoupledVariables()
     252             : {
     253        3688 :   for (const auto & test_var_name : _test_var_names)
     254        3043 :     for (const auto & eliminated_var_name : _eliminated_var_names)
     255        1296 :       if (_mblfs.Has(test_var_name) && _mblfs.Get(test_var_name)->Has(eliminated_var_name) &&
     256         118 :           !VectorContainsName(_test_var_names, eliminated_var_name))
     257             :       {
     258          82 :         auto & mblf = *_mblfs.Get(test_var_name)->Get(eliminated_var_name);
     259          82 :         mblf.AddMult(*_eliminated_variables.Get(eliminated_var_name), *_lfs.Get(test_var_name), -1);
     260             :       }
     261        1823 : }
     262             : 
     263             : void
     264        1838 : EquationSystem::FormLinearSystem(mfem::OperatorHandle & op,
     265             :                                  mfem::BlockVector & trueX,
     266             :                                  mfem::BlockVector & trueRHS)
     267             : {
     268             :   mooseAssert(_test_var_names.size() == _trial_var_names.size(),
     269             :               "Number of test and trial variables must be the same for block matrix assembly.");
     270             : 
     271        1838 :   if (_assembly_level == mfem::AssemblyLevel::LEGACY)
     272        1802 :     FormSystemMatrix(op, trueX, trueRHS);
     273             :   else
     274             :   {
     275             :     mooseAssert(_test_var_names.size() == 1 && _test_var_names.size() == _trial_var_names.size(),
     276             :                 "Non-legacy assembly is only supported for single test and trial variable systems");
     277          36 :     FormSystemOperator(op, trueX, trueRHS);
     278             :   }
     279        1838 : }
     280             : 
     281             : void
     282          36 : EquationSystem::FormSystemOperator(mfem::OperatorHandle & op,
     283             :                                    mfem::BlockVector & trueX,
     284             :                                    mfem::BlockVector & trueRHS)
     285             : {
     286          36 :   auto & test_var_name = _test_var_names.at(0);
     287          36 :   mfem::Vector aux_x, aux_rhs;
     288          36 :   mfem::OperatorPtr aux_a;
     289             : 
     290          36 :   auto blf = _blfs.Get(test_var_name);
     291          36 :   blf->FormLinearSystem(_ess_tdof_lists.at(0),
     292          36 :                         *_var_ess_constraints.at(0),
     293          36 :                         *_lfs.Get(test_var_name),
     294             :                         aux_a,
     295             :                         aux_x,
     296             :                         aux_rhs,
     297             :                         /*copy_interior=*/true);
     298             : 
     299          36 :   trueX.GetBlock(0) = aux_x;
     300          36 :   trueRHS.GetBlock(0) = aux_rhs;
     301          36 :   trueX.SyncFromBlocks();
     302          36 :   trueRHS.SyncFromBlocks();
     303             : 
     304          36 :   op.Reset(aux_a.Ptr());
     305          36 :   aux_a.SetOperatorOwner(false);
     306          36 : }
     307             : 
     308             : void
     309        1761 : EquationSystem::FormSystemMatrix(mfem::OperatorHandle & op,
     310             :                                  mfem::BlockVector & trueX,
     311             :                                  mfem::BlockVector & trueRHS)
     312             : {
     313             :   // Allocate block operator
     314        1761 :   DeleteHBlocks();
     315        1761 :   _h_blocks.SetSize(_test_var_names.size(), _trial_var_names.size());
     316        1761 :   _h_blocks = nullptr;
     317             :   // Zero out RHS and sync memory
     318        1761 :   trueRHS = 0.0;
     319        1761 :   trueRHS.SyncToBlocks();
     320             : 
     321        3564 :   for (const auto i : index_range(_test_var_names))
     322             :   {
     323        1803 :     auto test_var_name = _test_var_names.at(i);
     324             : 
     325        3690 :     for (const auto j : index_range(_trial_var_names))
     326             :     {
     327        1887 :       auto trial_var_name = _trial_var_names.at(j);
     328             : 
     329        1887 :       mfem::Vector aux_x, aux_rhs;
     330        1887 :       mfem::ParLinearForm aux_lf(_test_pfespaces.at(i));
     331        1887 :       mfem::HypreParMatrix * aux_a = new mfem::HypreParMatrix;
     332             : 
     333        1887 :       if (test_var_name == trial_var_name)
     334             :       {
     335             :         mooseAssert(i == j, "Trial and test variables must have the same ordering.");
     336        1803 :         auto blf = _blfs.Get(test_var_name);
     337        1803 :         blf->FormLinearSystem(_ess_tdof_lists.at(j),
     338        1803 :                               *_var_ess_constraints.at(j),
     339        1803 :                               *_lfs.Get(test_var_name),
     340             :                               *aux_a,
     341             :                               aux_x,
     342             :                               aux_rhs,
     343             :                               /*copy_interior=*/true);
     344        1803 :         trueX.GetBlock(j) = aux_x;
     345             :       }
     346          84 :       else if (_mblfs.Has(test_var_name) && _mblfs.Get(test_var_name)->Has(trial_var_name))
     347             :       {
     348          73 :         auto mblf = _mblfs.Get(test_var_name)->Get(trial_var_name);
     349          73 :         mblf->FormRectangularLinearSystem(_ess_tdof_lists.at(j),
     350          73 :                                           _ess_tdof_lists.at(i),
     351          73 :                                           *_var_ess_constraints.at(j),
     352          73 :                                           aux_lf = 0,
     353             :                                           *aux_a,
     354             :                                           aux_x,
     355             :                                           aux_rhs);
     356             :       }
     357             :       else
     358          11 :         continue;
     359             : 
     360        1876 :       trueRHS.GetBlock(i) += aux_rhs;
     361        1876 :       _h_blocks(i, j) = aux_a;
     362        1920 :     }
     363        1803 :   }
     364             :   // Sync memory
     365        1761 :   trueX.SyncFromBlocks();
     366        1761 :   trueRHS.SyncFromBlocks();
     367             : 
     368             :   // Create monolithic matrix
     369        1761 :   op.Reset(mfem::HypreParMatrixFromBlocks(_h_blocks));
     370        1761 : }
     371             : 
     372             : void
     373        1838 : EquationSystem::FormSystem(mfem::BlockVector & trueX, mfem::BlockVector & trueRHS)
     374             : {
     375        1838 :   height = trueX.Size();
     376        1838 :   width = trueRHS.Size();
     377             :   // Store block offsets
     378        1838 :   _block_true_offsets.SetSize(trueX.NumBlocks() + 1);
     379        1838 :   _block_true_offsets[0] = 0;
     380        3718 :   for (unsigned i = 0; i < _trial_var_names.size(); i++)
     381        1880 :     _block_true_offsets[i + 1] = trueX.BlockSize(i);
     382        1838 :   _block_true_offsets.PartialSum();
     383        1838 :   FormLinearSystem(_linear_operator, trueX, trueRHS);
     384        1838 : }
     385             : 
     386             : void
     387        5430 : EquationSystem::Mult(const mfem::Vector & sol, mfem::Vector & residual) const
     388             : {
     389             :   // Update gridfunctions that may be referenced by coefficients within nonlinear integrators
     390        5430 :   const mfem::BlockVector blockSolution(const_cast<mfem::Vector &>(sol), _block_true_offsets);
     391        5430 :   SetTrialVariablesFromTrueVectors(blockSolution);
     392             : 
     393        5430 :   if (_non_linear)
     394             :   {
     395        2524 :     mfem::BlockVector blockResidual(residual, _block_true_offsets);
     396        5048 :     for (unsigned int i = 0; i < _test_var_names.size(); i++)
     397             :     {
     398        2524 :       auto & test_var_name = _test_var_names.at(i);
     399        2524 :       auto nlf = _nlfs.GetShared(test_var_name);
     400        2524 :       nlf->Mult(blockSolution.GetBlock(i), blockResidual.GetBlock(i));
     401        2524 :       blockResidual.GetBlock(i).SyncAliasMemory(blockResidual);
     402        2524 :     }
     403        2524 :     _linear_operator->AddMult(sol, residual);
     404        2524 :   }
     405             :   else
     406             :   {
     407        2906 :     residual = 0.0;
     408        2906 :     _linear_operator->Mult(sol, residual);
     409             :   }
     410             : 
     411        5430 :   sol.HostRead();
     412        5430 :   residual.HostRead();
     413        5430 : }
     414             : 
     415             : void
     416        2180 : EquationSystem::FormJacobianMatrix(const mfem::Vector & u)
     417             : {
     418        2180 :   DeleteJacobianBlocks();
     419        2180 :   _jacobian_blocks.SetSize(_test_var_names.size(), _trial_var_names.size());
     420        2180 :   _jacobian_blocks = nullptr;
     421             : 
     422        2180 :   const mfem::BlockVector update_vector(const_cast<mfem::Vector &>(u), _block_true_offsets);
     423        4360 :   for (const auto i : index_range(_test_var_names))
     424             :   {
     425        2180 :     auto test_var_name = _test_var_names.at(i);
     426        2180 :     if (_nlfs.Has(test_var_name))
     427             :     {
     428        2180 :       auto nlf = _nlfs.Get(test_var_name);
     429             :       mfem::HypreParMatrix * nlf_jac =
     430        2180 :           dynamic_cast<mfem::HypreParMatrix *>(&nlf->GetGradient(update_vector.GetBlock(i)));
     431             :       mooseAssert(nlf_jac,
     432             :                   "Jacobian contribution of nonlinear form associated with " + test_var_name +
     433             :                       " is not castable into a HypreParMatrix");
     434        2180 :       _jacobian_blocks(i, i) = mfem::ParAdd(_h_blocks(i, i), nlf_jac);
     435             :     }
     436             :     else
     437           0 :       _jacobian_blocks(i, i) = _h_blocks(i, i);
     438        4360 :     for (const auto j : index_range(_trial_var_names))
     439        2180 :       if (i != j) // nlf->GetGradient only contributes to on-diagonal blocks
     440           0 :         _jacobian_blocks(i, j) = _h_blocks(i, j);
     441        2180 :   }
     442             :   // Create monolithic matrix
     443        2180 :   _jacobian.Reset(mfem::HypreParMatrixFromBlocks(_jacobian_blocks));
     444        2180 : }
     445             : 
     446             : mfem::Operator &
     447        3674 : EquationSystem::GetGradient(const mfem::Vector & u) const
     448             : {
     449        3674 :   if (_non_linear)
     450        2180 :     const_cast<EquationSystem *>(this)->FormJacobianMatrix(u);
     451             :   else
     452        1494 :     _jacobian = _linear_operator;
     453             : 
     454        3674 :   return *_jacobian;
     455             : }
     456             : 
     457             : void
     458        6179 : EquationSystem::SetTrialVariablesFromTrueVectors(const mfem::BlockVector & trueX) const
     459             : {
     460       12466 :   for (const auto i : index_range(_trial_var_names))
     461             :   {
     462        6287 :     auto & trial_var_name = _trial_var_names.at(i);
     463        6287 :     trueX.GetBlock(i).SyncAliasMemory(trueX);
     464        6287 :     _gfuncs->Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
     465             :   }
     466        6179 : }
     467             : 
     468             : void
     469        1823 : EquationSystem::BuildLinearForms()
     470             : {
     471             :   // Register linear forms
     472        3688 :   for (const auto i : index_range(_test_var_names))
     473             :   {
     474        1865 :     auto test_var_name = _test_var_names.at(i);
     475        1865 :     _lfs.Register(test_var_name, std::make_shared<mfem::ParLinearForm>(_test_pfespaces.at(i)));
     476        1865 :     _lfs.GetRef(test_var_name) = 0.0;
     477        1865 :   }
     478             : 
     479        3688 :   for (auto & test_var_name : _test_var_names)
     480             :   {
     481             :     // Apply kernels
     482        1865 :     auto lf = _lfs.GetShared(test_var_name);
     483        1865 :     ApplyDomainLFIntegrators(test_var_name, lf, _kernels_map);
     484        1865 :     ApplyBoundaryLFIntegrators(test_var_name, lf, _integrated_bc_map);
     485        1865 :     lf->Assemble();
     486        1865 :   }
     487             : 
     488             :   // Apply essential boundary conditions
     489        1823 :   ApplyEssentialBCs();
     490             : 
     491             :   // Eliminate trivially eliminated variables by subtracting contributions from linear forms
     492        1823 :   EliminateCoupledVariables();
     493        1823 : }
     494             : 
     495             : void
     496         775 : EquationSystem::BuildNonlinearForms()
     497             : {
     498             :   // Register non-linear Action forms
     499        1574 :   for (const auto i : index_range(_test_var_names))
     500             :   {
     501         799 :     auto test_var_name = _test_var_names.at(i);
     502         799 :     _nlfs.Register(test_var_name, std::make_shared<mfem::ParNonlinearForm>(_test_pfespaces.at(i)));
     503             :     // Apply kernels
     504         799 :     auto nlf = _nlfs.GetShared(test_var_name);
     505         799 :     nlf->SetEssentialTrueDofs(_ess_tdof_lists.at(i));
     506         799 :     ApplyDomainNLFIntegrators(test_var_name, nlf, _kernels_map);
     507         799 :     ApplyBoundaryNLFIntegrators(test_var_name, nlf, _integrated_bc_map);
     508         799 :   }
     509         775 : }
     510             : 
     511             : void
     512         775 : EquationSystem::BuildBilinearForms()
     513             : {
     514             :   // Register bilinear forms
     515        1574 :   for (const auto i : index_range(_test_var_names))
     516             :   {
     517         799 :     auto test_var_name = _test_var_names.at(i);
     518         799 :     _blfs.Register(test_var_name, std::make_shared<mfem::ParBilinearForm>(_test_pfespaces.at(i)));
     519             : 
     520             :     // Apply kernels
     521         799 :     auto blf = _blfs.GetShared(test_var_name);
     522         799 :     blf->SetAssemblyLevel(_assembly_level);
     523        1598 :     ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(
     524         799 :         test_var_name, test_var_name, blf, _integrated_bc_map);
     525        1598 :     ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(
     526         799 :         test_var_name, test_var_name, blf, _kernels_map);
     527             :     // Assemble
     528         799 :     blf->Assemble();
     529         799 :   }
     530         775 : }
     531             : 
     532             : void
     533         775 : EquationSystem::BuildMixedBilinearForms()
     534             : {
     535             :   // Register mixed bilinear forms. Note that not all combinations may
     536             :   // have a kernel.
     537             : 
     538             :   // Create mblf for each test/coupled variable pair with an added kernel.
     539             :   // Mixed bilinear forms with coupled variables that are not trial variables are
     540             :   // associated with contributions from eliminated variables.
     541        1574 :   for (const auto i : index_range(_test_var_names))
     542             :   {
     543         799 :     auto test_var_name = _test_var_names.at(i);
     544             :     auto test_mblfs =
     545         799 :         std::make_shared<Moose::MFEM::NamedFieldsMap<Moose::MFEM::ParMixedBilinearForm>>();
     546        1728 :     for (const auto j : index_range(_coupled_var_names))
     547             :     {
     548         929 :       const auto & coupled_var_name = _coupled_var_names.at(j);
     549        1858 :       auto mblf = std::make_shared<Moose::MFEM::ParMixedBilinearForm>(_coupled_pfespaces.at(j),
     550         929 :                                                                       _test_pfespaces.at(i));
     551             :       // Register MixedBilinearForm if kernels exist for it, and assemble kernels
     552         929 :       if (_kernels_map.Has(test_var_name) &&
     553        1834 :           _kernels_map.Get(test_var_name)->Has(coupled_var_name) &&
     554         905 :           test_var_name != coupled_var_name)
     555             :       {
     556         119 :         mblf->SetAssemblyLevel(_assembly_level);
     557             :         // Apply all mixed kernels with this test/trial pair
     558         238 :         ApplyDomainBLFIntegrators<Moose::MFEM::ParMixedBilinearForm>(
     559         119 :             coupled_var_name, test_var_name, mblf, _kernels_map);
     560             :         // Assemble mixed bilinear forms
     561         119 :         mblf->Assemble();
     562             :         // Register mixed bilinear forms associated with a single trial variable
     563             :         // for the current test variable
     564         119 :         test_mblfs->Register(coupled_var_name, mblf);
     565             :       }
     566         929 :     }
     567             :     // Register all mixed bilinear form sets associated with a single test variable
     568         799 :     _mblfs.Register(test_var_name, test_mblfs);
     569         799 :   }
     570         775 : }
     571             : 
     572             : void
     573        1823 : EquationSystem::BuildEquationSystem()
     574             : {
     575        1823 :   BuildBilinearForms();
     576        1823 :   BuildMixedBilinearForms();
     577        1823 :   BuildLinearForms();
     578        1823 :   BuildNonlinearForms();
     579        1823 : }
     580             : 
     581             : } // namespace Moose::MFEM
     582             : 
     583             : #endif

Generated by: LCOV version 1.14