LCOV - code coverage report
Current view: top level - src/mfem/equation_systems - EquationSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 300 307 97.7 %
Date: 2026-05-29 20:35:17 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        1361 : EquationSystem::~EquationSystem()
      19             : {
      20        1361 :   DeleteHBlocks();
      21        1361 :   DeleteJacobianBlocks();
      22        1361 : }
      23             : 
      24             : void
      25        3152 : EquationSystem::DeleteHBlocks()
      26             : {
      27        4974 :   for (const auto i : make_range(_h_blocks.NumRows()))
      28        3706 :     for (const auto j : make_range(_h_blocks.NumCols()))
      29             :     {
      30        1884 :       if (_jacobian_blocks.NumRows() && _jacobian_blocks(i, j) == _h_blocks(i, j))
      31           0 :         _jacobian_blocks(i, j) = nullptr;
      32        1884 :       delete _h_blocks(i, j);
      33             :     }
      34        3152 :   _h_blocks.DeleteAll();
      35        3152 : }
      36             : 
      37             : void
      38        3541 : EquationSystem::DeleteJacobianBlocks()
      39             : {
      40        5721 :   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        3541 :   _jacobian_blocks.DeleteAll();
      45        3541 : }
      46             : 
      47             : bool
      48        6752 : EquationSystem::VectorContainsName(const std::vector<std::string> & the_vector,
      49             :                                    const std::string & name) const
      50             : {
      51        6752 :   return std::find(the_vector.begin(), the_vector.end(), name) != the_vector.end();
      52             : }
      53             : 
      54             : void
      55        1620 : EquationSystem::AddCoupledVariableNameIfMissing(const std::string & coupled_var_name)
      56             : {
      57        1620 :   if (!VectorContainsName(_coupled_var_names, coupled_var_name))
      58        1019 :     _coupled_var_names.push_back(coupled_var_name);
      59        1620 : }
      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        2913 : EquationSystem::AddTestVariableNameIfMissing(const std::string & test_var_name)
      70             : {
      71        2913 :   if (!VectorContainsName(_test_var_names, test_var_name))
      72         937 :     _test_var_names.push_back(test_var_name);
      73        2913 : }
      74             : 
      75             : void
      76        1361 : EquationSystem::SetTrialVariableNames()
      77             : {
      78             :   // If a coupled variable has an equation associated with it,
      79             :   // add it to the set of trial variables.
      80        2298 :   for (const auto & test_var_name : _test_var_names)
      81         937 :     if (VectorContainsName(_coupled_var_names, test_var_name))
      82         937 :       _trial_var_names.push_back(test_var_name);
      83             : 
      84             :   // Otherwise, add it to the set of eliminated variables.
      85        2380 :   for (const auto & coupled_var_name : _coupled_var_names)
      86        1019 :     if (!VectorContainsName(_test_var_names, coupled_var_name))
      87          82 :       _eliminated_var_names.push_back(coupled_var_name);
      88        1361 : }
      89             : 
      90             : void
      91        1491 : EquationSystem::AddKernel(std::shared_ptr<MFEMKernel> kernel)
      92             : {
      93        1491 :   const auto & trial_var_name = kernel->getTrialVariableName();
      94        1491 :   const auto & test_var_name = kernel->getTestVariableName();
      95        1491 :   AddCoupledVariableNameIfMissing(trial_var_name);
      96        1491 :   AddTestVariableNameIfMissing(test_var_name);
      97             :   // Register new kernels map if not present for the test variable
      98        1491 :   if (!_kernels_map.Has(test_var_name))
      99             :   {
     100             :     auto kernel_field_map =
     101         890 :         std::make_shared<Moose::MFEM::NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>>();
     102         890 :     _kernels_map.Register(test_var_name, std::move(kernel_field_map));
     103         890 :   }
     104             :   // Register new kernels map if not present for the test/trial variable pair
     105        1491 :   if (!_kernels_map.Get(test_var_name)->Has(trial_var_name))
     106             :   {
     107         985 :     auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMKernel>>>();
     108         985 :     _kernels_map.Get(test_var_name)->Register(trial_var_name, std::move(kernels));
     109         985 :   }
     110        1491 :   _kernels_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(kernel));
     111        1491 : }
     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        1086 : EquationSystem::AddEssentialBC(std::shared_ptr<MFEMEssentialBC> bc)
     138             : {
     139        1086 :   const auto & test_var_name = bc->getTestVariableName();
     140        1086 :   AddTestVariableNameIfMissing(test_var_name);
     141             :   // Register new essential bc map if not present for the test variable
     142        1086 :   if (!_essential_bc_map.Has(test_var_name))
     143             :   {
     144         814 :     auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMEssentialBC>>>();
     145         814 :     _essential_bc_map.Register(test_var_name, std::move(bcs));
     146         814 :   }
     147        1086 :   _essential_bc_map.GetRef(test_var_name).push_back(std::move(bc));
     148        1086 : }
     149             : 
     150             : void
     151        1299 : EquationSystem::Init(Moose::MFEM::GridFunctions & gridfunctions,
     152             :                      Moose::MFEM::ComplexGridFunctions & cmplx_gridfunctions,
     153             :                      mfem::AssemblyLevel assembly_level)
     154             : {
     155        1299 :   _assembly_level = assembly_level;
     156             : 
     157        1299 :   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        1299 :   SetTrialVariableNames();
     163             : 
     164        2195 :   for (auto & test_var_name : _test_var_names)
     165             :   {
     166         896 :     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         896 :     _test_pfespaces.push_back(gridfunctions.Get(test_var_name)->ParFESpace());
     175             :   }
     176             : 
     177        2195 :   for (auto & trial_var_name : _trial_var_names)
     178             :   {
     179         896 :     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         896 :     _var_ess_constraints.emplace_back(
     188        1792 :         std::make_unique<mfem::ParGridFunction>(gridfunctions.Get(trial_var_name)->ParFESpace()));
     189             :   }
     190             : 
     191             :   // Store pointers to FESpaces of all coupled variables
     192        2277 :   for (auto & coupled_var_name : _coupled_var_names)
     193         978 :     _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        1520 :   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        1299 :   _gfuncs = &gridfunctions;
     203        1299 : }
     204             : 
     205             : void
     206        1817 : EquationSystem::ApplyEssentialBC(const std::string & var_name,
     207             :                                  mfem::ParGridFunction & trial_gf,
     208             :                                  mfem::Array<int> & global_ess_markers)
     209             : {
     210        1817 :   if (_essential_bc_map.Has(var_name))
     211             :   {
     212        1405 :     auto & bcs = _essential_bc_map.GetRef(var_name);
     213        3627 :     for (auto & bc : bcs)
     214             :     {
     215             :       // Set constrained DoFs values on essential boundaries
     216        2222 :       bc->ApplyBC(trial_gf);
     217             :       // Fetch marker array labelling essential boundaries of current BC
     218        2222 :       mfem::Array<int> ess_bdrs(bc->getBoundaryMarkers());
     219             :       // Add these boundary markers to the set of markers labelling all essential boundaries
     220       11060 :       for (const auto i : make_range(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max()))
     221        8838 :         global_ess_markers[i] = std::max(global_ess_markers[i], ess_bdrs[i]);
     222        2222 :     }
     223             :   }
     224        1817 : }
     225             : 
     226             : void
     227        1786 : EquationSystem::ApplyEssentialBCs()
     228             : {
     229        1786 :   _ess_tdof_lists.resize(_trial_var_names.size());
     230        3603 :   for (const auto i : index_range(_trial_var_names))
     231             :   {
     232        1817 :     const auto & trial_var_name = _trial_var_names.at(i);
     233        1817 :     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        1817 :     trial_gf.Update();
     237             : 
     238             :     // Initial guess for non-linear problems (initial condition or the previous time step solution)
     239        1817 :     trial_gf = _gfuncs->GetRef(trial_var_name);
     240             : 
     241        1817 :     mfem::Array<int> global_ess_markers(trial_gf.ParFESpace()->GetParMesh()->bdr_attributes.Max());
     242        1817 :     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        1817 :     ApplyEssentialBC(trial_var_name, trial_gf, global_ess_markers);
     246        1817 :     trial_gf.ParFESpace()->GetEssentialTrueDofs(global_ess_markers, _ess_tdof_lists.at(i));
     247        1817 :   }
     248        1786 : }
     249             : 
     250             : void
     251        1812 : EquationSystem::EliminateCoupledVariables()
     252             : {
     253        3655 :   for (const auto & test_var_name : _test_var_names)
     254        3021 :     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        1812 : }
     262             : 
     263             : void
     264        1827 : 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        1827 :   if (_assembly_level == mfem::AssemblyLevel::LEGACY)
     272        1791 :     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        1827 : }
     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        1750 : EquationSystem::FormSystemMatrix(mfem::OperatorHandle & op,
     310             :                                  mfem::BlockVector & trueX,
     311             :                                  mfem::BlockVector & trueRHS)
     312             : {
     313             :   // Allocate block operator
     314        1750 :   DeleteHBlocks();
     315        1750 :   _h_blocks.SetSize(_test_var_names.size(), _trial_var_names.size());
     316        1750 :   _h_blocks = nullptr;
     317             :   // Zero out RHS and sync memory
     318        1750 :   trueRHS = 0.0;
     319        1750 :   trueRHS.SyncToBlocks();
     320             : 
     321        3531 :   for (const auto i : index_range(_test_var_names))
     322             :   {
     323        1781 :     auto test_var_name = _test_var_names.at(i);
     324             : 
     325        3624 :     for (const auto j : index_range(_trial_var_names))
     326             :     {
     327        1843 :       auto trial_var_name = _trial_var_names.at(j);
     328             : 
     329        1843 :       mfem::Vector aux_x, aux_rhs;
     330        1843 :       mfem::ParLinearForm aux_lf(_test_pfespaces.at(i));
     331        1843 :       mfem::HypreParMatrix * aux_a = new mfem::HypreParMatrix;
     332             : 
     333        1843 :       if (test_var_name == trial_var_name)
     334             :       {
     335             :         mooseAssert(i == j, "Trial and test variables must have the same ordering.");
     336        1781 :         auto blf = _blfs.Get(test_var_name);
     337        1781 :         blf->FormLinearSystem(_ess_tdof_lists.at(j),
     338        1781 :                               *_var_ess_constraints.at(j),
     339        1781 :                               *_lfs.Get(test_var_name),
     340             :                               *aux_a,
     341             :                               aux_x,
     342             :                               aux_rhs,
     343             :                               /*copy_interior=*/true);
     344        1781 :         trueX.GetBlock(j) = aux_x;
     345             :       }
     346          62 :       else if (_mblfs.Has(test_var_name) && _mblfs.Get(test_var_name)->Has(trial_var_name))
     347             :       {
     348          62 :         auto mblf = _mblfs.Get(test_var_name)->Get(trial_var_name);
     349          62 :         mblf->FormRectangularLinearSystem(_ess_tdof_lists.at(j),
     350          62 :                                           _ess_tdof_lists.at(i),
     351          62 :                                           *_var_ess_constraints.at(j),
     352          62 :                                           aux_lf = 0,
     353             :                                           *aux_a,
     354             :                                           aux_x,
     355             :                                           aux_rhs);
     356             :       }
     357             :       else
     358           0 :         continue;
     359             : 
     360        1843 :       trueRHS.GetBlock(i) += aux_rhs;
     361        1843 :       _h_blocks(i, j) = aux_a;
     362        1843 :     }
     363        1781 :   }
     364             :   // Sync memory
     365        1750 :   trueX.SyncFromBlocks();
     366        1750 :   trueRHS.SyncFromBlocks();
     367             : 
     368             :   // Create monolithic matrix
     369        1750 :   op.Reset(mfem::HypreParMatrixFromBlocks(_h_blocks));
     370        1750 : }
     371             : 
     372             : void
     373        1827 : EquationSystem::FormSystem(mfem::BlockVector & trueX, mfem::BlockVector & trueRHS)
     374             : {
     375        1827 :   height = trueX.Size();
     376        1827 :   width = trueRHS.Size();
     377             :   // Store block offsets
     378        1827 :   _block_true_offsets.SetSize(trueX.NumBlocks() + 1);
     379        1827 :   _block_true_offsets[0] = 0;
     380        3685 :   for (unsigned i = 0; i < _trial_var_names.size(); i++)
     381        1858 :     _block_true_offsets[i + 1] = trueX.BlockSize(i);
     382        1827 :   _block_true_offsets.PartialSum();
     383        1827 :   FormLinearSystem(_linear_operator, trueX, trueRHS);
     384        1827 : }
     385             : 
     386             : void
     387        5408 : EquationSystem::Mult(const mfem::Vector & sol, mfem::Vector & residual) const
     388             : {
     389             :   // Update gridfunctions that may be referenced by coefficients within nonlinear integrators
     390        5408 :   const mfem::BlockVector blockSolution(const_cast<mfem::Vector &>(sol), _block_true_offsets);
     391        5408 :   SetTrialVariablesFromTrueVectors(blockSolution);
     392             : 
     393        5408 :   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        2884 :     residual = 0.0;
     408        2884 :     _linear_operator->Mult(sol, residual);
     409             :   }
     410             : 
     411        5408 :   sol.HostRead();
     412        5408 :   residual.HostRead();
     413        5408 : }
     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        3663 : EquationSystem::GetGradient(const mfem::Vector & u) const
     448             : {
     449        3663 :   if (_non_linear)
     450        2180 :     const_cast<EquationSystem *>(this)->FormJacobianMatrix(u);
     451             :   else
     452        1483 :     _jacobian = _linear_operator;
     453             : 
     454        3663 :   return *_jacobian;
     455             : }
     456             : 
     457             : void
     458        6146 : EquationSystem::SetTrialVariablesFromTrueVectors(const mfem::BlockVector & trueX) const
     459             : {
     460       12367 :   for (const auto i : index_range(_trial_var_names))
     461             :   {
     462        6221 :     auto & trial_var_name = _trial_var_names.at(i);
     463        6221 :     trueX.GetBlock(i).SyncAliasMemory(trueX);
     464        6221 :     _gfuncs->Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
     465             :   }
     466        6146 : }
     467             : 
     468             : void
     469        1812 : EquationSystem::BuildLinearForms()
     470             : {
     471             :   // Register linear forms
     472        3655 :   for (const auto i : index_range(_test_var_names))
     473             :   {
     474        1843 :     auto test_var_name = _test_var_names.at(i);
     475        1843 :     _lfs.Register(test_var_name, std::make_shared<mfem::ParLinearForm>(_test_pfespaces.at(i)));
     476        1843 :     _lfs.GetRef(test_var_name) = 0.0;
     477        1843 :   }
     478             : 
     479        3655 :   for (auto & test_var_name : _test_var_names)
     480             :   {
     481             :     // Apply kernels
     482        1843 :     auto lf = _lfs.GetShared(test_var_name);
     483        1843 :     ApplyDomainLFIntegrators(test_var_name, lf, _kernels_map);
     484        1843 :     ApplyBoundaryLFIntegrators(test_var_name, lf, _integrated_bc_map);
     485        1843 :     lf->Assemble();
     486        1843 :   }
     487             : 
     488             :   // Apply essential boundary conditions
     489        1812 :   ApplyEssentialBCs();
     490             : 
     491             :   // Eliminate trivially eliminated variables by subtracting contributions from linear forms
     492        1812 :   EliminateCoupledVariables();
     493        1812 : }
     494             : 
     495             : void
     496         764 : EquationSystem::BuildNonlinearForms()
     497             : {
     498             :   // Register non-linear Action forms
     499        1541 :   for (const auto i : index_range(_test_var_names))
     500             :   {
     501         777 :     auto test_var_name = _test_var_names.at(i);
     502         777 :     _nlfs.Register(test_var_name, std::make_shared<mfem::ParNonlinearForm>(_test_pfespaces.at(i)));
     503             :     // Apply kernels
     504         777 :     auto nlf = _nlfs.GetShared(test_var_name);
     505         777 :     nlf->SetEssentialTrueDofs(_ess_tdof_lists.at(i));
     506         777 :     ApplyDomainNLFIntegrators(test_var_name, nlf, _kernels_map);
     507         777 :     ApplyBoundaryNLFIntegrators(test_var_name, nlf, _integrated_bc_map);
     508         777 :   }
     509         764 : }
     510             : 
     511             : void
     512         764 : EquationSystem::BuildBilinearForms()
     513             : {
     514             :   // Register bilinear forms
     515        1541 :   for (const auto i : index_range(_test_var_names))
     516             :   {
     517         777 :     auto test_var_name = _test_var_names.at(i);
     518         777 :     _blfs.Register(test_var_name, std::make_shared<mfem::ParBilinearForm>(_test_pfespaces.at(i)));
     519             : 
     520             :     // Apply kernels
     521         777 :     auto blf = _blfs.GetShared(test_var_name);
     522         777 :     blf->SetAssemblyLevel(_assembly_level);
     523        1554 :     ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(
     524         777 :         test_var_name, test_var_name, blf, _integrated_bc_map);
     525        1554 :     ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(
     526         777 :         test_var_name, test_var_name, blf, _kernels_map);
     527             :     // Assemble
     528         777 :     blf->Assemble();
     529         777 :   }
     530         764 : }
     531             : 
     532             : void
     533         764 : 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        1541 :   for (const auto i : index_range(_test_var_names))
     542             :   {
     543         777 :     auto test_var_name = _test_var_names.at(i);
     544         777 :     auto test_mblfs = std::make_shared<Moose::MFEM::NamedFieldsMap<mfem::ParMixedBilinearForm>>();
     545        1662 :     for (const auto j : index_range(_coupled_var_names))
     546             :     {
     547         885 :       const auto & coupled_var_name = _coupled_var_names.at(j);
     548        1770 :       auto mblf = std::make_shared<mfem::ParMixedBilinearForm>(_coupled_pfespaces.at(j),
     549         885 :                                                                _test_pfespaces.at(i));
     550             :       // Register MixedBilinearForm if kernels exist for it, and assemble kernels
     551         885 :       if (_kernels_map.Has(test_var_name) &&
     552        1757 :           _kernels_map.Get(test_var_name)->Has(coupled_var_name) &&
     553         872 :           test_var_name != coupled_var_name)
     554             :       {
     555         108 :         mblf->SetAssemblyLevel(_assembly_level);
     556             :         // Apply all mixed kernels with this test/trial pair
     557         216 :         ApplyDomainBLFIntegrators<mfem::ParMixedBilinearForm>(
     558         108 :             coupled_var_name, test_var_name, mblf, _kernels_map);
     559             :         // Assemble mixed bilinear forms
     560         108 :         mblf->Assemble();
     561             :         // Register mixed bilinear forms associated with a single trial variable
     562             :         // for the current test variable
     563         108 :         test_mblfs->Register(coupled_var_name, mblf);
     564             :       }
     565         885 :     }
     566             :     // Register all mixed bilinear form sets associated with a single test variable
     567         777 :     _mblfs.Register(test_var_name, test_mblfs);
     568         777 :   }
     569         764 : }
     570             : 
     571             : void
     572        1812 : EquationSystem::BuildEquationSystem()
     573             : {
     574        1812 :   BuildBilinearForms();
     575        1812 :   BuildMixedBilinearForms();
     576        1812 :   BuildLinearForms();
     577        1812 :   BuildNonlinearForms();
     578        1812 : }
     579             : 
     580             : } // namespace Moose::MFEM
     581             : 
     582             : #endif

Generated by: LCOV version 1.14