LCOV - code coverage report
Current view: top level - src/loops - NonlinearThread.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 235 238 98.7 %
Date: 2025-07-17 01:28:37 Functions: 26 27 96.3 %
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             : #include "NonlinearThread.h"
      11             : #include "NonlinearSystem.h"
      12             : #include "Problem.h"
      13             : #include "FEProblem.h"
      14             : #include "KernelBase.h"
      15             : #include "IntegratedBCBase.h"
      16             : #include "DGKernelBase.h"
      17             : #include "InterfaceKernelBase.h"
      18             : #include "Material.h"
      19             : #include "TimeKernel.h"
      20             : #include "SwapBackSentinel.h"
      21             : #include "FVTimeKernel.h"
      22             : #include "ComputeJacobianThread.h"
      23             : 
      24             : #include "libmesh/threads.h"
      25             : 
      26     3521435 : NonlinearThread::NonlinearThread(FEProblemBase & fe_problem)
      27             :   : ThreadedElementLoop<ConstElemRange>(fe_problem),
      28     7042870 :     _nl(fe_problem.currentNonlinearSystem()),
      29     3521435 :     _num_cached(0),
      30     3521435 :     _integrated_bcs(_nl.getIntegratedBCWarehouse()),
      31     3521435 :     _dg_kernels(_nl.getDGKernelWarehouse()),
      32     3521435 :     _interface_kernels(_nl.getInterfaceKernelWarehouse()),
      33     3521435 :     _kernels(_nl.getKernelWarehouse()),
      34     3521435 :     _hdg_kernels(_nl.getHDGKernelWarehouse()),
      35     6848731 :     _has_active_objects(_integrated_bcs.hasActiveObjects() || _dg_kernels.hasActiveObjects() ||
      36     7076076 :                         _interface_kernels.hasActiveObjects() || _kernels.hasActiveObjects() ||
      37      227345 :                         _fe_problem.haveFV()),
      38     7042870 :     _should_execute_dg(false)
      39             : {
      40     3521435 : }
      41             : 
      42             : // Splitting Constructor
      43      334896 : NonlinearThread::NonlinearThread(NonlinearThread & x, Threads::split split)
      44             :   : ThreadedElementLoop<ConstElemRange>(x, split),
      45      334896 :     _nl(x._nl),
      46      334896 :     _num_cached(x._num_cached),
      47      334896 :     _integrated_bcs(x._integrated_bcs),
      48      334896 :     _dg_kernels(x._dg_kernels),
      49      334896 :     _interface_kernels(x._interface_kernels),
      50      334896 :     _kernels(x._kernels),
      51      334896 :     _tag_kernels(x._tag_kernels),
      52      334896 :     _hdg_kernels(x._hdg_kernels),
      53      334896 :     _has_active_objects(x._has_active_objects),
      54      334896 :     _should_execute_dg(x._should_execute_dg)
      55             : {
      56      334896 : }
      57             : 
      58     3856292 : NonlinearThread::~NonlinearThread() {}
      59             : 
      60             : void
      61     3855677 : NonlinearThread::operator()(const ConstElemRange & range, bool bypass_threading)
      62             : {
      63     3855677 :   if (_has_active_objects)
      64     3796798 :     ThreadedElementLoop<ConstElemRange>::operator()(range, bypass_threading);
      65     3855647 : }
      66             : 
      67             : void
      68     4484061 : NonlinearThread::subdomainChanged()
      69             : {
      70             :   // This should come first to setup the residual objects before we do dependency determination of
      71             :   // material properties and variables
      72     4484061 :   determineObjectWarehouses();
      73             : 
      74     4484061 :   _fe_problem.subdomainSetup(_subdomain, _tid);
      75             : 
      76             :   // Update variable Dependencies
      77     4484061 :   std::set<MooseVariableFEBase *> needed_moose_vars;
      78     4484061 :   _tag_kernels->updateBlockVariableDependency(_subdomain, needed_moose_vars, _tid);
      79     4484061 :   _ibc_warehouse->updateBoundaryVariableDependency(needed_moose_vars, _tid);
      80     4484061 :   _dg_warehouse->updateBlockVariableDependency(_subdomain, needed_moose_vars, _tid);
      81     4484061 :   _ik_warehouse->updateBoundaryVariableDependency(needed_moose_vars, _tid);
      82             : 
      83             :   // Update FE variable coupleable vector tags
      84     4484061 :   std::set<TagID> needed_fe_var_vector_tags;
      85     4484061 :   _tag_kernels->updateBlockFEVariableCoupledVectorTagDependency(
      86     4484061 :       _subdomain, needed_fe_var_vector_tags, _tid);
      87     4484061 :   _ibc_warehouse->updateBlockFEVariableCoupledVectorTagDependency(
      88     4484061 :       _subdomain, needed_fe_var_vector_tags, _tid);
      89     4484061 :   _fe_problem.getMaterialWarehouse().updateBlockFEVariableCoupledVectorTagDependency(
      90     4484061 :       _subdomain, needed_fe_var_vector_tags, _tid);
      91             : 
      92             :   // Update material dependencies
      93     4484061 :   std::unordered_set<unsigned int> needed_mat_props;
      94     4484061 :   _tag_kernels->updateBlockMatPropDependency(_subdomain, needed_mat_props, _tid);
      95     4484061 :   _ibc_warehouse->updateBoundaryMatPropDependency(needed_mat_props, _tid);
      96     4484061 :   _dg_warehouse->updateBlockMatPropDependency(_subdomain, needed_mat_props, _tid);
      97     4484061 :   _ik_warehouse->updateBoundaryMatPropDependency(needed_mat_props, _tid);
      98             : 
      99     4484061 :   if (_fe_problem.haveFV())
     100             :   {
     101             :     // Re-query the finite volume elemental kernels
     102      236726 :     _fv_kernels.clear();
     103      236726 :     _fe_problem.theWarehouse()
     104      236726 :         .query()
     105      473452 :         .template condition<AttribSysNum>(_nl.number())
     106      236726 :         .template condition<AttribSystem>("FVElementalKernel")
     107      236726 :         .template condition<AttribSubdomains>(_subdomain)
     108      236726 :         .template condition<AttribThread>(_tid)
     109      236726 :         .queryInto(_fv_kernels);
     110      519071 :     for (const auto fv_kernel : _fv_kernels)
     111             :     {
     112      282345 :       const auto & fv_mv_deps = fv_kernel->getMooseVariableDependencies();
     113      282345 :       needed_moose_vars.insert(fv_mv_deps.begin(), fv_mv_deps.end());
     114      282345 :       const auto & fv_mp_deps = fv_kernel->getMatPropDependencies();
     115      282345 :       needed_mat_props.insert(fv_mp_deps.begin(), fv_mp_deps.end());
     116             :     }
     117             :   }
     118             : 
     119     4484061 :   _fe_problem.setActiveElementalMooseVariables(needed_moose_vars, _tid);
     120     4484061 :   _fe_problem.setActiveFEVariableCoupleableVectorTags(needed_fe_var_vector_tags, _tid);
     121     4484061 :   _fe_problem.prepareMaterials(needed_mat_props, _subdomain, _tid);
     122     4484061 : }
     123             : 
     124             : void
     125   344434215 : NonlinearThread::onElement(const Elem * const elem)
     126             : {
     127             :   // Set up Sentinel class so that, even if reinitMaterials() throws in prepareElement, we
     128             :   // still remember to swap back during stack unwinding.
     129   344434215 :   SwapBackSentinel sentinel(_fe_problem, &FEProblemBase::swapBackMaterials, this->_tid);
     130             : 
     131   344434215 :   prepareElement(elem);
     132             : 
     133   344434129 :   if (dynamic_cast<ComputeJacobianThread *>(this))
     134    49371302 :     if (_nl.getScalarVariables(_tid).size() > 0)
     135      157470 :       _fe_problem.reinitOffDiagScalars(_tid);
     136             : 
     137   344434129 :   computeOnElement();
     138   344434189 : }
     139             : 
     140             : void
     141   328479495 : NonlinearThread::computeOnElement()
     142             : {
     143   328479495 :   if (_tag_kernels->hasActiveBlockObjects(_subdomain, _tid))
     144             :   {
     145   316094434 :     const auto & kernels = _tag_kernels->getActiveBlockObjects(_subdomain, _tid);
     146  1048079818 :     for (const auto & kernel : kernels)
     147   731985453 :       compute(*kernel);
     148             :   }
     149             : 
     150   328479426 :   if (_fe_problem.haveFV())
     151    27173306 :     for (auto kernel : _fv_kernels)
     152    14562426 :       compute(*kernel);
     153   328479426 : }
     154             : 
     155             : void
     156   104257922 : NonlinearThread::onBoundary(const Elem * const elem,
     157             :                             const unsigned int side,
     158             :                             const BoundaryID bnd_id,
     159             :                             const Elem * const lower_d_elem /*=nullptr*/)
     160             : {
     161   104257922 :   if (_ibc_warehouse->hasActiveBoundaryObjects(bnd_id, _tid))
     162             :   {
     163             :     // Set up Sentinel class so that, after we swap in reinitMaterialsFace in prepareFace, even if
     164             :     // one of our callees throws we remember to swap back during stack unwinding. We put our
     165             :     // sentinel here as opposed to in prepareFace because we certainly don't want our materials
     166             :     // swapped back before we proceed to residual/Jacobian computation
     167     2968845 :     SwapBackSentinel sentinel(_fe_problem, &FEProblem::swapBackMaterialsFace, _tid);
     168             : 
     169     2968845 :     prepareFace(elem, side, bnd_id, lower_d_elem);
     170     2968845 :     computeOnBoundary(bnd_id, lower_d_elem);
     171             : 
     172     2968841 :     if (lower_d_elem)
     173             :     {
     174       22356 :       Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     175       22356 :       accumulateLower();
     176       22356 :     }
     177     2968841 :   }
     178   104257918 : }
     179             : 
     180             : void
     181     2771210 : NonlinearThread::computeOnBoundary(BoundaryID bnd_id, const Elem * /*lower_d_elem*/)
     182             : {
     183     2771210 :   const auto & bcs = _ibc_warehouse->getActiveBoundaryObjects(bnd_id, _tid);
     184     5847932 :   for (const auto & bc : bcs)
     185     3076726 :     if (bc->shouldApply())
     186     3076558 :       compute(*bc);
     187     2771206 : }
     188             : 
     189             : void
     190      396096 : NonlinearThread::onInterface(const Elem * elem, unsigned int side, BoundaryID bnd_id)
     191             : {
     192      396096 :   if (_ik_warehouse->hasActiveBoundaryObjects(bnd_id, _tid))
     193             :   {
     194             : 
     195             :     // Pointer to the neighbor we are currently working on.
     196       51470 :     const Elem * neighbor = elem->neighbor_ptr(side);
     197             : 
     198       51470 :     if (neighbor->active())
     199             :     {
     200       51470 :       _fe_problem.reinitNeighbor(elem, side, _tid);
     201             : 
     202             :       // Set up Sentinels so that, even if one of the reinitMaterialsXXX() calls throws, we
     203             :       // still remember to swap back during stack unwinding. Note that face, boundary, and interface
     204             :       // all operate with the same MaterialData object
     205       51470 :       SwapBackSentinel face_sentinel(_fe_problem, &FEProblem::swapBackMaterialsFace, _tid);
     206       51470 :       _fe_problem.reinitMaterialsFace(elem->subdomain_id(), _tid);
     207       51470 :       _fe_problem.reinitMaterialsBoundary(bnd_id, _tid);
     208             : 
     209       51470 :       SwapBackSentinel neighbor_sentinel(_fe_problem, &FEProblem::swapBackMaterialsNeighbor, _tid);
     210       51470 :       _fe_problem.reinitMaterialsNeighbor(neighbor->subdomain_id(), _tid);
     211             : 
     212             :       // Has to happen after face and neighbor properties have been computed. Note that we don't use
     213             :       // a sentinel here because FEProblem::swapBackMaterialsFace is going to handle face materials,
     214             :       // boundary materials, and interface materials (e.g. it queries the boundary material data
     215             :       // with the current element and side
     216       51470 :       _fe_problem.reinitMaterialsInterface(bnd_id, _tid);
     217             : 
     218       51470 :       computeOnInterface(bnd_id);
     219             : 
     220             :       {
     221       51470 :         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     222       51470 :         accumulateNeighbor();
     223       51470 :       }
     224       51470 :     }
     225             :   }
     226      396096 : }
     227             : 
     228             : void
     229       44824 : NonlinearThread::computeOnInterface(BoundaryID bnd_id)
     230             : {
     231       44824 :   const auto & int_ks = _ik_warehouse->getActiveBoundaryObjects(bnd_id, _tid);
     232      122548 :   for (const auto & interface_kernel : int_ks)
     233       77724 :     compute(*interface_kernel);
     234       44824 : }
     235             : 
     236             : void
     237   652664700 : NonlinearThread::onInternalSide(const Elem * elem, unsigned int side)
     238             : {
     239   652664700 :   if (_should_execute_dg && _dg_warehouse->hasActiveBlockObjects(_subdomain, _tid))
     240             :   {
     241             :     // Pointer to the neighbor we are currently working on.
     242     2088139 :     const Elem * neighbor = elem->neighbor_ptr(side);
     243             : 
     244     2088139 :     _fe_problem.reinitElemNeighborAndLowerD(elem, side, _tid);
     245             : 
     246             :     // Set up Sentinels so that, even if one of the reinitMaterialsXXX() calls throws, we
     247             :     // still remember to swap back during stack unwinding.
     248     2088139 :     SwapBackSentinel face_sentinel(_fe_problem, &FEProblem::swapBackMaterialsFace, _tid);
     249     2088139 :     _fe_problem.reinitMaterialsFace(elem->subdomain_id(), _tid);
     250             : 
     251     2088139 :     SwapBackSentinel neighbor_sentinel(_fe_problem, &FEProblem::swapBackMaterialsNeighbor, _tid);
     252     2088139 :     _fe_problem.reinitMaterialsNeighbor(neighbor->subdomain_id(), _tid);
     253             : 
     254     2088139 :     computeOnInternalFace(neighbor);
     255             : 
     256             :     {
     257     2088139 :       Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     258     2088139 :       accumulateNeighborLower();
     259     2088139 :     }
     260     2088139 :   }
     261   652664700 :   if (_hdg_warehouse->hasActiveBlockObjects(_subdomain, _tid))
     262             :   {
     263             :     // Set up Sentinel class so that, after we swap in reinitMaterialsFace in prepareFace, even if
     264             :     // one of our callees throws we remember to swap back during stack unwinding. We put our
     265             :     // sentinel here as opposed to in prepareFace because we certainly don't want our materials
     266             :     // swapped back before we proceed to residual/Jacobian computation
     267     4124088 :     SwapBackSentinel sentinel(_fe_problem, &FEProblem::swapBackMaterialsFace, _tid);
     268             : 
     269     4124088 :     prepareFace(elem, side, Moose::INVALID_BOUNDARY_ID, nullptr);
     270     4124088 :     computeOnInternalFace();
     271     4124088 :   }
     272   652664700 : }
     273             : 
     274             : void
     275     2047029 : NonlinearThread::computeOnInternalFace(const Elem * neighbor)
     276             : {
     277     2047029 :   const auto & dgks = _dg_warehouse->getActiveBlockObjects(_subdomain, _tid);
     278     4700607 :   for (const auto & dg_kernel : dgks)
     279     2653578 :     if (dg_kernel->hasBlocks(neighbor->subdomain_id()))
     280     2651064 :       compute(*dg_kernel, neighbor);
     281     2047029 : }
     282             : 
     283             : void
     284   653601954 : NonlinearThread::compute(KernelBase & kernel)
     285             : {
     286   653601954 :   compute(static_cast<ResidualObject &>(kernel));
     287   653601908 : }
     288             : 
     289             : void
     290    14562426 : NonlinearThread::compute(FVElementalKernel & kernel)
     291             : {
     292    14562426 :   compute(static_cast<ResidualObject &>(kernel));
     293    14562426 : }
     294             : 
     295             : void
     296     2951830 : NonlinearThread::compute(IntegratedBCBase & bc)
     297             : {
     298     2951830 :   compute(static_cast<ResidualObject &>(bc));
     299     2951830 : }
     300             : 
     301             : void
     302     2553000 : NonlinearThread::compute(DGKernelBase & dg, const Elem * /*neighbor*/)
     303             : {
     304     2553000 :   compute(static_cast<ResidualObject &>(dg));
     305     2553000 : }
     306             : 
     307             : void
     308       74768 : NonlinearThread::compute(InterfaceKernelBase & ik)
     309             : {
     310       74768 :   compute(static_cast<ResidualObject &>(ik));
     311       74768 : }
     312             : 
     313             : void
     314   295062781 : NonlinearThread::postElement(const Elem * /*elem*/)
     315             : {
     316   295062781 :   accumulate();
     317   295062781 : }
     318             : 
     319             : void
     320     3797293 : NonlinearThread::post()
     321             : {
     322     3797293 :   clearVarsAndMaterials();
     323     3797293 : }
     324             : 
     325             : void
     326     3796798 : NonlinearThread::printGeneralExecutionInformation() const
     327             : {
     328     3796798 :   if (_fe_problem.shouldPrintExecution(_tid))
     329             :   {
     330        9373 :     const auto & console = _fe_problem.console();
     331        9373 :     const auto execute_on = _fe_problem.getCurrentExecuteOnFlag();
     332       18746 :     console << "[DBG] Beginning elemental loop to compute " + objectType() + " on " << execute_on
     333        9373 :             << std::endl;
     334        9373 :     mooseDoOnce(
     335             :         console << "[DBG] Execution order on each element:" << std::endl;
     336             :         console << "[DBG] - kernels on element quadrature points" << std::endl;
     337             :         console << "[DBG] - finite volume elemental kernels on element" << std::endl;
     338             :         console << "[DBG] - integrated boundary conditions on element side quadrature points"
     339             :                 << std::endl;
     340             :         console << "[DBG] - DG kernels on element side quadrature points" << std::endl;
     341             :         console << "[DBG] - interface kernels on element side quadrature points" << std::endl;);
     342        9373 :   }
     343     3796798 : }
     344             : 
     345             : void
     346     4483396 : NonlinearThread::printBlockExecutionInformation() const
     347             : {
     348             :   // Number of objects executing is approximated by size of warehouses
     349     4483396 :   const int num_objects = _kernels.size() + _fv_kernels.size() + _integrated_bcs.size() +
     350     4483396 :                           _dg_kernels.size() + _interface_kernels.size();
     351     4483396 :   const auto & console = _fe_problem.console();
     352     4483396 :   const auto block_name = _mesh.getSubdomainName(_subdomain);
     353             : 
     354     4483396 :   if (_fe_problem.shouldPrintExecution(_tid) && num_objects > 0)
     355             :   {
     356       78969 :     if (_blocks_exec_printed.count(_subdomain))
     357       62472 :       return;
     358       32994 :     console << "[DBG] Ordering of " + objectType() + " Objects on block " << block_name << " ("
     359       16497 :             << _subdomain << ")" << std::endl;
     360       16497 :     if (_kernels.hasActiveBlockObjects(_subdomain, _tid))
     361             :     {
     362       16385 :       console << "[DBG] Ordering of kernels:" << std::endl;
     363       16385 :       console << _kernels.activeObjectsToFormattedString() << std::endl;
     364             :     }
     365       16497 :     if (_fv_kernels.size())
     366             :     {
     367         112 :       console << "[DBG] Ordering of FV elemental kernels:" << std::endl;
     368             :       std::string fvkernels =
     369         112 :           std::accumulate(_fv_kernels.begin() + 1,
     370             :                           _fv_kernels.end(),
     371         112 :                           _fv_kernels[0]->name(),
     372          84 :                           [](const std::string & str_out, FVElementalKernel * kernel)
     373         392 :                           { return str_out + " " + kernel->name(); });
     374         112 :       console << ConsoleUtils::formatString(fvkernels, "[DBG]") << std::endl;
     375         112 :     }
     376       16497 :     if (_dg_kernels.hasActiveBlockObjects(_subdomain, _tid))
     377             :     {
     378        7424 :       console << "[DBG] Ordering of DG kernels:" << std::endl;
     379        7424 :       console << _dg_kernels.activeObjectsToFormattedString() << std::endl;
     380             :     }
     381             :   }
     382     4404427 :   else if (_fe_problem.shouldPrintExecution(_tid) && num_objects == 0 &&
     383           0 :            !_blocks_exec_printed.count(_subdomain))
     384           0 :     console << "[DBG] No Active " + objectType() + " Objects on block " << block_name << " ("
     385           0 :             << _subdomain << ")" << std::endl;
     386             : 
     387     4420924 :   _blocks_exec_printed.insert(_subdomain);
     388     4483396 : }
     389             : 
     390             : void
     391   104257922 : NonlinearThread::printBoundaryExecutionInformation(const unsigned int bid) const
     392             : {
     393   104360823 :   if (!_fe_problem.shouldPrintExecution(_tid) || _boundaries_exec_printed.count(bid) ||
     394      102901 :       (!_integrated_bcs.hasActiveBoundaryObjects(bid, _tid) &&
     395       80819 :        !_interface_kernels.hasActiveBoundaryObjects(bid, _tid)))
     396   104232624 :     return;
     397             : 
     398       25298 :   const auto & console = _fe_problem.console();
     399       25298 :   const auto b_name = _mesh.getBoundaryName(bid);
     400       50596 :   console << "[DBG] Ordering of " + objectType() + " Objects on boundary " << b_name << " (" << bid
     401       25298 :           << ")" << std::endl;
     402             : 
     403       25298 :   if (_integrated_bcs.hasActiveBoundaryObjects(bid, _tid))
     404             :   {
     405       22082 :     console << "[DBG] Ordering of integrated boundary conditions:" << std::endl;
     406       22082 :     console << _integrated_bcs.activeObjectsToFormattedString() << std::endl;
     407             :   }
     408             : 
     409             :   // We have not checked if we have a neighbor. This could be premature for saying we are executing
     410             :   // interface kernels. However, we should assume the execution will happen on another side of the
     411             :   // same boundary
     412       25298 :   if (_interface_kernels.hasActiveBoundaryObjects(bid, _tid))
     413             :   {
     414        3216 :     console << "[DBG] Ordering of interface kernels:" << std::endl;
     415        3216 :     console << _interface_kernels.activeObjectsToFormattedString() << std::endl;
     416             :   }
     417             : 
     418       25298 :   _boundaries_exec_printed.insert(bid);
     419       25298 : }
     420             : 
     421             : void
     422     7092933 : NonlinearThread::prepareFace(const Elem * const elem,
     423             :                              const unsigned int side,
     424             :                              const BoundaryID bnd_id,
     425             :                              const Elem * const lower_d_elem)
     426             : {
     427     7092933 :   _fe_problem.reinitElemFace(elem, side, _tid);
     428             : 
     429             :   // Needed to use lower-dimensional variables on Materials
     430     7092933 :   if (lower_d_elem)
     431       22356 :     _fe_problem.reinitLowerDElem(lower_d_elem, _tid);
     432             : 
     433     7092933 :   _fe_problem.reinitMaterialsFace(elem->subdomain_id(), _tid);
     434     7092933 :   if (bnd_id != Moose::INVALID_BOUNDARY_ID)
     435     2968845 :     _fe_problem.reinitMaterialsBoundary(bnd_id, _tid);
     436     7092933 : }
     437             : 
     438             : bool
     439  1299730007 : NonlinearThread::shouldComputeInternalSide(const Elem & elem, const Elem & neighbor) const
     440             : {
     441  1299730007 :   _should_execute_dg =
     442  1299730007 :       ThreadedElementLoop<ConstElemRange>::shouldComputeInternalSide(elem, neighbor);
     443  1299730007 :   return _should_execute_dg || _hdg_warehouse->hasActiveBlockObjects(_subdomain, _tid);
     444             : }

Generated by: LCOV version 1.14