LCOV - code coverage report
Current view: top level - src/mfem/equation_systems - EquationSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 313 326 96.0 %
Date: 2025-07-17 01:28:37 Functions: 29 30 96.7 %
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 MFEM_ENABLED
      11             : 
      12             : #include "EquationSystem.h"
      13             : #include "libmesh/int_range.h"
      14             : 
      15             : namespace Moose::MFEM
      16             : {
      17             : 
      18         134 : EquationSystem::~EquationSystem() { DeleteAllBlocks(); }
      19             : 
      20             : void
      21         260 : EquationSystem::DeleteAllBlocks()
      22             : {
      23         386 :   for (const auto i : make_range(_h_blocks.NumRows()))
      24         252 :     for (const auto j : make_range(_h_blocks.NumCols()))
      25         126 :       delete _h_blocks(i, j);
      26         260 :   _h_blocks.DeleteAll();
      27         260 : }
      28             : 
      29             : bool
      30         502 : EquationSystem::VectorContainsName(const std::vector<std::string> & the_vector,
      31             :                                    const std::string & name) const
      32             : {
      33             : 
      34         502 :   auto iter = std::find(the_vector.begin(), the_vector.end(), name);
      35             : 
      36         502 :   return (iter != the_vector.end());
      37             : }
      38             : 
      39             : void
      40         122 : EquationSystem::AddTrialVariableNameIfMissing(const std::string & trial_var_name)
      41             : {
      42         122 :   if (!VectorContainsName(_trial_var_names, trial_var_name))
      43             :   {
      44          78 :     _trial_var_names.push_back(trial_var_name);
      45             :   }
      46         122 : }
      47             : 
      48             : void
      49         332 : EquationSystem::AddTestVariableNameIfMissing(const std::string & test_var_name)
      50             : {
      51         332 :   if (!VectorContainsName(_test_var_names, test_var_name))
      52             :   {
      53         102 :     _test_var_names.push_back(test_var_name);
      54             :   }
      55         332 : }
      56             : 
      57             : void
      58         142 : EquationSystem::AddKernel(std::shared_ptr<MFEMKernel> kernel)
      59             : {
      60         142 :   AddTestVariableNameIfMissing(kernel->getTestVariableName());
      61         142 :   AddTrialVariableNameIfMissing(kernel->getTrialVariableName());
      62         142 :   auto trial_var_name = kernel->getTrialVariableName();
      63         142 :   auto test_var_name = kernel->getTestVariableName();
      64         142 :   if (!_kernels_map.Has(test_var_name))
      65             :   {
      66             :     auto kernel_field_map =
      67         102 :         std::make_shared<Moose::MFEM::NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>>();
      68         102 :     _kernels_map.Register(test_var_name, std::move(kernel_field_map));
      69         102 :   }
      70             :   // Register new kernels map if not present for the test/trial variable
      71             :   // pair
      72         142 :   if (!_kernels_map.Get(test_var_name)->Has(trial_var_name))
      73             :   {
      74         102 :     auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMKernel>>>();
      75         102 :     _kernels_map.Get(test_var_name)->Register(trial_var_name, std::move(kernels));
      76         102 :   }
      77         142 :   _kernels_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(kernel));
      78         142 : }
      79             : 
      80             : void
      81           8 : EquationSystem::AddIntegratedBC(std::shared_ptr<MFEMIntegratedBC> bc)
      82             : {
      83           8 :   AddTestVariableNameIfMissing(bc->getTestVariableName());
      84           8 :   AddTrialVariableNameIfMissing(bc->getTrialVariableName());
      85           8 :   auto trial_var_name = bc->getTrialVariableName();
      86           8 :   auto test_var_name = bc->getTestVariableName();
      87           8 :   if (!_integrated_bc_map.Has(test_var_name))
      88             :   {
      89             :     auto integrated_bc_field_map = std::make_shared<
      90           8 :         Moose::MFEM::NamedFieldsMap<std::vector<std::shared_ptr<MFEMIntegratedBC>>>>();
      91           8 :     _integrated_bc_map.Register(test_var_name, std::move(integrated_bc_field_map));
      92           8 :   }
      93             :   // Register new integrated bc map if not present for the test/trial variable
      94             :   // pair
      95           8 :   if (!_integrated_bc_map.Get(test_var_name)->Has(trial_var_name))
      96             :   {
      97           8 :     auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMIntegratedBC>>>();
      98           8 :     _integrated_bc_map.Get(test_var_name)->Register(trial_var_name, std::move(bcs));
      99           8 :   }
     100           8 :   _integrated_bc_map.GetRef(test_var_name).Get(trial_var_name)->push_back(std::move(bc));
     101           8 : }
     102             : 
     103             : void
     104         162 : EquationSystem::AddEssentialBC(std::shared_ptr<MFEMEssentialBC> bc)
     105             : {
     106         162 :   AddTestVariableNameIfMissing(bc->getTestVariableName());
     107         162 :   auto test_var_name = bc->getTestVariableName();
     108         162 :   if (!_essential_bc_map.Has(test_var_name))
     109             :   {
     110          98 :     auto bcs = std::make_shared<std::vector<std::shared_ptr<MFEMEssentialBC>>>();
     111          98 :     _essential_bc_map.Register(test_var_name, std::move(bcs));
     112          98 :   }
     113         162 :   _essential_bc_map.GetRef(test_var_name).push_back(std::move(bc));
     114         162 : }
     115             : 
     116             : void
     117         202 : EquationSystem::ApplyEssentialBCs()
     118             : {
     119         202 :   _ess_tdof_lists.resize(_test_var_names.size());
     120         372 :   for (const auto i : index_range(_test_var_names))
     121             :   {
     122         170 :     auto test_var_name = _test_var_names.at(i);
     123         170 :     if (!_essential_bc_map.Has(test_var_name))
     124           4 :       continue;
     125             : 
     126             :     // Set default value of gridfunction used in essential BC. Values
     127             :     // overwritten in applyEssentialBCs
     128         166 :     mfem::ParGridFunction & trial_gf(*(_xs.at(i)));
     129         166 :     auto * const pmesh = _test_pfespaces.at(i)->GetParMesh();
     130             :     mooseAssert(pmesh, "parallel mesh is null");
     131             : 
     132         166 :     auto bcs = _essential_bc_map.GetRef(test_var_name);
     133         166 :     mfem::Array<int> global_ess_markers(pmesh->bdr_attributes.Max());
     134         166 :     global_ess_markers = 0;
     135         452 :     for (auto & bc : bcs)
     136             :     {
     137         286 :       bc->ApplyBC(trial_gf);
     138             : 
     139         286 :       mfem::Array<int> ess_bdrs(bc->getBoundaryMarkers());
     140        1236 :       for (auto it = 0; it != pmesh->bdr_attributes.Max(); ++it)
     141             :       {
     142         950 :         global_ess_markers[it] = std::max(global_ess_markers[it], ess_bdrs[it]);
     143             :       }
     144         286 :     }
     145         166 :     trial_gf.FESpace()->GetEssentialTrueDofs(global_ess_markers, _ess_tdof_lists.at(i));
     146         170 :   }
     147         202 : }
     148             : 
     149             : void
     150         146 : EquationSystem::FormLinearSystem(mfem::OperatorHandle & op,
     151             :                                  mfem::BlockVector & trueX,
     152             :                                  mfem::BlockVector & trueRHS)
     153             : {
     154             : 
     155         146 :   switch (_assembly_level)
     156             :   {
     157         126 :     case mfem::AssemblyLevel::LEGACY:
     158         126 :       FormLegacySystem(op, trueX, trueRHS);
     159         126 :       break;
     160          20 :     default:
     161             :       mooseAssert(_test_var_names.size() == 1,
     162             :                   "Non-legacy assembly is only supported for single-variable systems");
     163             :       mooseAssert(
     164             :           _test_var_names.size() == _trial_var_names.size(),
     165             :           "Non-legacy assembly is only supported for single test and trial variable systems");
     166          20 :       FormSystem(op, trueX, trueRHS);
     167             :   }
     168         146 : }
     169             : 
     170             : void
     171           4 : EquationSystem::FormSystem(mfem::OperatorHandle & op,
     172             :                            mfem::BlockVector & trueX,
     173             :                            mfem::BlockVector & trueRHS)
     174             : {
     175           4 :   auto & test_var_name = _test_var_names.at(0);
     176           4 :   auto blf = _blfs.Get(test_var_name);
     177           4 :   auto lf = _lfs.Get(test_var_name);
     178           4 :   mfem::BlockVector aux_x, aux_rhs;
     179           4 :   mfem::OperatorPtr aux_a;
     180             : 
     181           4 :   blf->FormLinearSystem(_ess_tdof_lists.at(0), *(_xs.at(0)), *lf, aux_a, aux_x, aux_rhs);
     182             : 
     183           4 :   trueX.GetBlock(0) = aux_x;
     184           4 :   trueRHS.GetBlock(0) = aux_rhs;
     185           4 :   trueX.SyncFromBlocks();
     186           4 :   trueRHS.SyncFromBlocks();
     187             : 
     188           4 :   op.Reset(aux_a.Ptr());
     189           4 :   aux_a.SetOperatorOwner(false);
     190           4 : }
     191             : 
     192             : void
     193          74 : EquationSystem::FormLegacySystem(mfem::OperatorHandle & op,
     194             :                                  mfem::BlockVector & trueX,
     195             :                                  mfem::BlockVector & trueRHS)
     196             : {
     197             : 
     198             :   // Allocate block operator
     199          74 :   DeleteAllBlocks();
     200          74 :   _h_blocks.SetSize(_test_var_names.size(), _test_var_names.size());
     201             :   // Form diagonal blocks.
     202         148 :   for (const auto i : index_range(_test_var_names))
     203             :   {
     204          74 :     auto & test_var_name = _test_var_names.at(i);
     205          74 :     auto blf = _blfs.Get(test_var_name);
     206          74 :     auto lf = _lfs.Get(test_var_name);
     207          74 :     mfem::Vector aux_x, aux_rhs;
     208          74 :     mfem::HypreParMatrix * aux_a = new mfem::HypreParMatrix;
     209          74 :     blf->FormLinearSystem(_ess_tdof_lists.at(i), *(_xs.at(i)), *lf, *aux_a, aux_x, aux_rhs);
     210          74 :     _h_blocks(i, i) = aux_a;
     211          74 :     trueX.GetBlock(i) = aux_x;
     212          74 :     trueRHS.GetBlock(i) = aux_rhs;
     213          74 :   }
     214             : 
     215             :   // Form off-diagonal blocks
     216         148 :   for (const auto i : index_range(_test_var_names))
     217             :   {
     218          74 :     auto test_var_name = _test_var_names.at(i);
     219         148 :     for (const auto j : index_range(_test_var_names))
     220             :     {
     221          74 :       auto trial_var_name = _trial_var_names.at(j);
     222             : 
     223          74 :       mfem::Vector aux_x, aux_rhs;
     224          74 :       mfem::ParLinearForm aux_lf(_test_pfespaces.at(i));
     225          74 :       aux_lf = 0.0;
     226          74 :       if (_mblfs.Has(test_var_name) && _mblfs.Get(test_var_name)->Has(trial_var_name))
     227             :       {
     228           0 :         auto mblf = _mblfs.Get(test_var_name)->Get(trial_var_name);
     229           0 :         mfem::HypreParMatrix * aux_a = new mfem::HypreParMatrix;
     230           0 :         mblf->FormRectangularLinearSystem(_ess_tdof_lists.at(j),
     231           0 :                                           _ess_tdof_lists.at(i),
     232           0 :                                           *(_xs.at(j)),
     233             :                                           aux_lf,
     234             :                                           *aux_a,
     235             :                                           aux_x,
     236             :                                           aux_rhs);
     237           0 :         _h_blocks(i, j) = aux_a;
     238           0 :         trueRHS.GetBlock(i) += aux_rhs;
     239             :       }
     240          74 :     }
     241          74 :   }
     242             :   // Sync memory
     243         148 :   for (const auto i : index_range(_test_var_names))
     244             :   {
     245          74 :     trueX.GetBlock(i).SyncAliasMemory(trueX);
     246          74 :     trueRHS.GetBlock(i).SyncAliasMemory(trueRHS);
     247             :   }
     248             : 
     249             :   // Create monolithic matrix
     250          74 :   op.Reset(mfem::HypreParMatrixFromBlocks(_h_blocks));
     251          74 : }
     252             : 
     253             : void
     254         146 : EquationSystem::BuildJacobian(mfem::BlockVector & trueX, mfem::BlockVector & trueRHS)
     255             : {
     256         146 :   height = trueX.Size();
     257         146 :   width = trueRHS.Size();
     258         146 :   FormLinearSystem(_jacobian, trueX, trueRHS);
     259         146 : }
     260             : 
     261             : void
     262         292 : EquationSystem::Mult(const mfem::Vector & x, mfem::Vector & residual) const
     263             : {
     264         292 :   _jacobian->Mult(x, residual);
     265         292 :   x.HostRead();
     266         292 :   residual.HostRead();
     267         292 : }
     268             : 
     269             : mfem::Operator &
     270         146 : EquationSystem::GetGradient(const mfem::Vector &) const
     271             : {
     272         146 :   return *_jacobian;
     273             : }
     274             : 
     275             : void
     276          78 : EquationSystem::RecoverFEMSolution(mfem::BlockVector & trueX,
     277             :                                    Moose::MFEM::GridFunctions & gridfunctions)
     278             : {
     279         156 :   for (const auto i : index_range(_trial_var_names))
     280             :   {
     281          78 :     auto & trial_var_name = _trial_var_names.at(i);
     282          78 :     trueX.GetBlock(i).SyncAliasMemory(trueX);
     283          78 :     gridfunctions.Get(trial_var_name)->Distribute(&(trueX.GetBlock(i)));
     284             :   }
     285          78 : }
     286             : 
     287             : void
     288         134 : EquationSystem::Init(Moose::MFEM::GridFunctions & gridfunctions,
     289             :                      const Moose::MFEM::FESpaces & /*fespaces*/,
     290             :                      mfem::AssemblyLevel assembly_level)
     291             : {
     292         134 :   _assembly_level = assembly_level;
     293             : 
     294         236 :   for (auto & test_var_name : _test_var_names)
     295             :   {
     296         102 :     if (!gridfunctions.Has(test_var_name))
     297             :     {
     298           0 :       MFEM_ABORT("Test variable " << test_var_name
     299             :                                   << " requested by equation system during initialisation was "
     300             :                                      "not found in gridfunctions");
     301             :     }
     302             :     // Store pointers to variable FESpaces
     303         102 :     _test_pfespaces.push_back(gridfunctions.Get(test_var_name)->ParFESpace());
     304             :     // Create auxiliary gridfunctions for applying Dirichlet conditions
     305         102 :     _xs.emplace_back(
     306         204 :         std::make_unique<mfem::ParGridFunction>(gridfunctions.Get(test_var_name)->ParFESpace()));
     307         102 :     _dxdts.emplace_back(
     308         204 :         std::make_unique<mfem::ParGridFunction>(gridfunctions.Get(test_var_name)->ParFESpace()));
     309         102 :     _trial_variables.Register(test_var_name, gridfunctions.GetShared(test_var_name));
     310             :   }
     311         134 : }
     312             : 
     313             : void
     314         202 : EquationSystem::BuildLinearForms()
     315             : {
     316             :   // Register linear forms
     317         372 :   for (const auto i : index_range(_test_var_names))
     318             :   {
     319         170 :     auto test_var_name = _test_var_names.at(i);
     320         170 :     _lfs.Register(test_var_name, std::make_shared<mfem::ParLinearForm>(_test_pfespaces.at(i)));
     321         170 :     _lfs.GetRef(test_var_name) = 0.0;
     322         170 :   }
     323             :   // Apply boundary conditions
     324         202 :   ApplyEssentialBCs();
     325             : 
     326         372 :   for (auto & test_var_name : _test_var_names)
     327             :   {
     328             :     // Apply kernels
     329         170 :     auto lf = _lfs.GetShared(test_var_name);
     330         170 :     ApplyDomainLFIntegrators(test_var_name, lf, _kernels_map);
     331         170 :     ApplyBoundaryLFIntegrators(test_var_name, lf, _integrated_bc_map);
     332         170 :     lf->Assemble();
     333         170 :   }
     334         202 : }
     335             : 
     336             : void
     337         202 : EquationSystem::BuildBilinearForms()
     338             : {
     339             :   // Register bilinear forms
     340         372 :   for (const auto i : index_range(_test_var_names))
     341             :   {
     342         170 :     auto test_var_name = _test_var_names.at(i);
     343         170 :     _blfs.Register(test_var_name, std::make_shared<mfem::ParBilinearForm>(_test_pfespaces.at(i)));
     344             : 
     345             :     // Apply kernels
     346         170 :     auto blf = _blfs.GetShared(test_var_name);
     347         170 :     blf->SetAssemblyLevel(_assembly_level);
     348         170 :     ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(
     349         170 :         test_var_name, test_var_name, blf, _integrated_bc_map);
     350         170 :     ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(
     351         170 :         test_var_name, test_var_name, blf, _kernels_map);
     352             :     // Assemble
     353         170 :     blf->Assemble();
     354         170 :   }
     355         202 : }
     356             : 
     357             : void
     358         202 : EquationSystem::BuildMixedBilinearForms()
     359             : {
     360             :   // Register mixed bilinear forms. Note that not all combinations may
     361             :   // have a kernel
     362             : 
     363             :   // Create mblf for each test/trial pair
     364         372 :   for (const auto i : index_range(_test_var_names))
     365             :   {
     366         170 :     auto test_var_name = _test_var_names.at(i);
     367         170 :     auto test_mblfs = std::make_shared<Moose::MFEM::NamedFieldsMap<mfem::ParMixedBilinearForm>>();
     368         340 :     for (const auto j : index_range(_test_var_names))
     369             :     {
     370         170 :       auto trial_var_name = _trial_var_names.at(j);
     371         340 :       auto mblf = std::make_shared<mfem::ParMixedBilinearForm>(_test_pfespaces.at(j),
     372         170 :                                                                _test_pfespaces.at(i));
     373             :       // Register MixedBilinearForm if kernels exist for it, and assemble
     374             :       // kernels
     375         248 :       if (_kernels_map.Has(test_var_name) && _kernels_map.Get(test_var_name)->Has(trial_var_name) &&
     376          78 :           test_var_name != trial_var_name)
     377             :       {
     378           0 :         mblf->SetAssemblyLevel(_assembly_level);
     379             :         // Apply all mixed kernels with this test/trial pair
     380           0 :         ApplyDomainBLFIntegrators<mfem::ParMixedBilinearForm>(
     381           0 :             trial_var_name, test_var_name, mblf, _kernels_map);
     382             :         // Assemble mixed bilinear forms
     383           0 :         mblf->Assemble();
     384             :         // Register mixed bilinear forms associated with a single trial variable
     385             :         // for the current test variable
     386           0 :         test_mblfs->Register(trial_var_name, mblf);
     387             :       }
     388         170 :     }
     389             :     // Register all mixed bilinear form sets associated with a single test
     390             :     // variable
     391         170 :     _mblfs.Register(test_var_name, test_mblfs);
     392         170 :   }
     393         202 : }
     394             : 
     395             : void
     396         134 : EquationSystem::BuildEquationSystem()
     397             : {
     398         134 :   BuildBilinearForms();
     399         134 :   BuildMixedBilinearForms();
     400         134 :   BuildLinearForms();
     401         134 : }
     402             : 
     403          24 : TimeDependentEquationSystem::TimeDependentEquationSystem() : _dt_coef(1.0) {}
     404             : 
     405             : void
     406          48 : TimeDependentEquationSystem::AddTrialVariableNameIfMissing(const std::string & var_name)
     407             : {
     408             :   // The TimeDependentEquationSystem operator expects to act on a vector of variable time
     409             :   // derivatives
     410          48 :   std::string var_time_derivative_name = GetTimeDerivativeName(var_name);
     411             : 
     412          48 :   if (!VectorContainsName(_trial_var_names, var_time_derivative_name))
     413             :   {
     414          24 :     _trial_var_names.push_back(var_time_derivative_name);
     415          24 :     _trial_var_time_derivative_names.push_back(var_time_derivative_name);
     416             :   }
     417          48 : }
     418             : 
     419             : void
     420          68 : TimeDependentEquationSystem::SetTimeStep(double dt)
     421             : {
     422          68 :   if (fabs(dt - _dt_coef.constant) > 1.0e-12 * dt)
     423             :   {
     424          20 :     _dt_coef.constant = dt;
     425          40 :     for (auto test_var_name : _test_var_names)
     426             :     {
     427          20 :       auto blf = _blfs.Get(test_var_name);
     428          20 :       blf->Update();
     429          20 :       blf->Assemble();
     430          20 :     }
     431             :   }
     432          68 : }
     433             : 
     434             : void
     435          44 : TimeDependentEquationSystem::AddKernel(std::shared_ptr<MFEMKernel> kernel)
     436             : {
     437          44 :   if (kernel->getTrialVariableName() == GetTimeDerivativeName(kernel->getTestVariableName()))
     438             :   {
     439          20 :     auto trial_var_name = kernel->getTrialVariableName();
     440          20 :     auto test_var_name = kernel->getTestVariableName();
     441          20 :     AddTestVariableNameIfMissing(test_var_name);
     442          20 :     AddTrialVariableNameIfMissing(test_var_name);
     443          20 :     if (!_td_kernels_map.Has(test_var_name))
     444             :     {
     445             :       auto kernel_field_map =
     446          20 :           std::make_shared<Moose::MFEM::NamedFieldsMap<std::vector<std::shared_ptr<MFEMKernel>>>>();
     447          20 :       _td_kernels_map.Register(test_var_name, std::move(kernel_field_map));
     448          20 :     }
     449             :     // Register new kernels map if not present for the test variable
     450          20 :     if (!_td_kernels_map.Get(test_var_name)->Has(test_var_name))
     451             :     {
     452          20 :       auto kernels = std::make_shared<std::vector<std::shared_ptr<MFEMKernel>>>();
     453          20 :       _td_kernels_map.Get(test_var_name)->Register(test_var_name, std::move(kernels));
     454          20 :     }
     455          20 :     _td_kernels_map.GetRef(test_var_name).Get(test_var_name)->push_back(std::move(kernel));
     456          20 :   }
     457             :   else
     458             :   {
     459          24 :     EquationSystem::AddKernel(kernel);
     460             :   }
     461          44 : }
     462             : 
     463             : void
     464          92 : TimeDependentEquationSystem::BuildBilinearForms()
     465             : {
     466          92 :   EquationSystem::BuildBilinearForms();
     467             : 
     468             :   // Build and assemble bilinear forms acting on time derivatives
     469         184 :   for (const auto i : index_range(_test_var_names))
     470             :   {
     471          92 :     auto test_var_name = _test_var_names.at(i);
     472             : 
     473          92 :     _td_blfs.Register(test_var_name,
     474         184 :                       std::make_shared<mfem::ParBilinearForm>(_test_pfespaces.at(i)));
     475             : 
     476             :     // Apply kernels to td_blf
     477          92 :     auto td_blf = _td_blfs.GetShared(test_var_name);
     478          92 :     td_blf->SetAssemblyLevel(_assembly_level);
     479          92 :     ApplyBoundaryBLFIntegrators<mfem::ParBilinearForm>(
     480          92 :         test_var_name, test_var_name, td_blf, _integrated_bc_map);
     481          92 :     ApplyDomainBLFIntegrators<mfem::ParBilinearForm>(
     482          92 :         test_var_name, test_var_name, td_blf, _td_kernels_map);
     483             : 
     484             :     // Recover and scale integrators from blf. This is to apply the dt*du/dt contributions from the
     485             :     // operator on the trial variable in the implicit integration scheme
     486          92 :     auto blf = _blfs.Get(test_var_name);
     487          92 :     auto integs = blf->GetDBFI();
     488          92 :     auto b_integs = blf->GetBBFI();
     489          92 :     auto markers = blf->GetBBFI_Marker();
     490             : 
     491          92 :     mfem::SumIntegrator * sum = new mfem::SumIntegrator(false);
     492          92 :     ScaleIntegrator * scaled_sum = new ScaleIntegrator(sum, _dt_coef.constant, true);
     493             : 
     494         184 :     for (int i = 0; i < integs->Size(); ++i)
     495             :     {
     496          92 :       sum->AddIntegrator(*integs[i]);
     497             :     }
     498             : 
     499         108 :     for (int i = 0; i < b_integs->Size(); ++i)
     500             :     {
     501          32 :       td_blf->AddBoundaryIntegrator(new ScaleIntegrator(*b_integs[i], _dt_coef.constant, false),
     502          16 :                                     *(*markers[i]));
     503             :     }
     504             : 
     505             :     // scaled_sum is owned by td_blf
     506          92 :     td_blf->AddDomainIntegrator(scaled_sum);
     507             : 
     508             :     // Assemble form
     509          92 :     td_blf->Assemble();
     510          92 :   }
     511          92 : }
     512             : 
     513             : void
     514          52 : TimeDependentEquationSystem::FormLegacySystem(mfem::OperatorHandle & op,
     515             :                                               mfem::BlockVector & truedXdt,
     516             :                                               mfem::BlockVector & trueRHS)
     517             : {
     518             : 
     519             :   // Allocate block operator
     520          52 :   DeleteAllBlocks();
     521          52 :   _h_blocks.SetSize(_test_var_names.size(), _test_var_names.size());
     522             :   // Form diagonal blocks.
     523         104 :   for (const auto i : index_range(_test_var_names))
     524             :   {
     525          52 :     auto & test_var_name = _test_var_names.at(i);
     526          52 :     auto td_blf = _td_blfs.Get(test_var_name);
     527          52 :     auto blf = _blfs.Get(test_var_name);
     528          52 :     auto lf = _lfs.Get(test_var_name);
     529             :     // if implicit, add contribution to linear form from terms involving state
     530             :     // variable at previous timestep: {
     531          52 :     blf->AddMult(*_trial_variables.Get(test_var_name), *lf, -1.0);
     532             :     // }
     533          52 :     mfem::Vector aux_x, aux_rhs;
     534             :     // Update solution values on Dirichlet values to be in terms of du/dt instead of u
     535          52 :     mfem::Vector bc_x = *(_xs.at(i).get());
     536          52 :     bc_x -= *_trial_variables.Get(test_var_name);
     537          52 :     bc_x /= _dt_coef.constant;
     538             : 
     539             :     // Form linear system for operator acting on vector of du/dt
     540          52 :     mfem::HypreParMatrix * aux_a = new mfem::HypreParMatrix;
     541          52 :     td_blf->FormLinearSystem(_ess_tdof_lists.at(i), bc_x, *lf, *aux_a, aux_x, aux_rhs);
     542          52 :     _h_blocks(i, i) = aux_a;
     543          52 :     truedXdt.GetBlock(i) = aux_x;
     544          52 :     trueRHS.GetBlock(i) = aux_rhs;
     545          52 :   }
     546             : 
     547          52 :   truedXdt.SyncFromBlocks();
     548          52 :   trueRHS.SyncFromBlocks();
     549             : 
     550             :   // Create monolithic matrix
     551          52 :   op.Reset(mfem::HypreParMatrixFromBlocks(_h_blocks));
     552          52 : }
     553             : 
     554             : void
     555          16 : TimeDependentEquationSystem::FormSystem(mfem::OperatorHandle & op,
     556             :                                         mfem::BlockVector & truedXdt,
     557             :                                         mfem::BlockVector & trueRHS)
     558             : {
     559          16 :   auto & test_var_name = _test_var_names.at(0);
     560          16 :   auto td_blf = _td_blfs.Get(test_var_name);
     561          16 :   auto blf = _blfs.Get(test_var_name);
     562          16 :   auto lf = _lfs.Get(test_var_name);
     563             :   // if implicit, add contribution to linear form from terms involving state
     564             :   // variable at previous timestep: {
     565             : 
     566             :   // The AddMult method in mfem::BilinearForm is not defined for non-legacy assembly
     567          16 :   mfem::Vector lf_prev(lf->Size());
     568          16 :   blf->Mult(*_trial_variables.Get(test_var_name), lf_prev);
     569          16 :   *lf -= lf_prev;
     570             :   // }
     571          16 :   mfem::Vector aux_x, aux_rhs;
     572             :   // Update solution values on Dirichlet values to be in terms of du/dt instead of u
     573          16 :   mfem::Vector bc_x = *(_xs.at(0).get());
     574          16 :   bc_x -= *_trial_variables.Get(test_var_name);
     575          16 :   bc_x /= _dt_coef.constant;
     576             : 
     577             :   // Form linear system for operator acting on vector of du/dt
     578          16 :   mfem::OperatorPtr aux_a;
     579          16 :   td_blf->FormLinearSystem(_ess_tdof_lists.at(0), bc_x, *lf, aux_a, aux_x, aux_rhs);
     580             : 
     581          16 :   truedXdt.GetBlock(0) = aux_x;
     582          16 :   trueRHS.GetBlock(0) = aux_rhs;
     583          16 :   truedXdt.SyncFromBlocks();
     584          16 :   trueRHS.SyncFromBlocks();
     585             : 
     586             :   // Create monolithic matrix
     587          16 :   op.Reset(aux_a.Ptr());
     588          16 :   aux_a.SetOperatorOwner(false);
     589          16 : }
     590             : 
     591             : void
     592          68 : TimeDependentEquationSystem::UpdateEquationSystem()
     593             : {
     594          68 :   BuildBilinearForms();
     595          68 :   BuildMixedBilinearForms();
     596          68 :   BuildLinearForms();
     597          68 : }
     598             : 
     599             : } // namespace Moose::MFEM
     600             : 
     601             : #endif

Generated by: LCOV version 1.14