LCOV - code coverage report
Current view: top level - src/userobjects - PorousFlowAdvectiveFluxCalculatorBase.C (source / functions) Hit Total Coverage
Test: idaholab/moose porous_flow: #32971 (54bef8) with base c6cf66 Lines: 221 226 97.8 %
Date: 2026-05-29 20:38:56 Functions: 16 16 100.0 %
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 "PorousFlowAdvectiveFluxCalculatorBase.h"
      11             : #include "Assembly.h"
      12             : #include "libmesh/string_to_enum.h"
      13             : #include "libmesh/parallel_sync.h"
      14             : 
      15             : InputParameters
      16        1433 : PorousFlowAdvectiveFluxCalculatorBase::validParams()
      17             : {
      18        1433 :   InputParameters params = AdvectiveFluxCalculatorBase::validParams();
      19        1433 :   params.addClassDescription(
      20             :       "Base class to compute the advective flux of fluid in PorousFlow situations.  The velocity "
      21             :       "is U * (-permeability * (grad(P) - density * gravity)), while derived classes define U.  "
      22             :       "The Kuzmin-Turek FEM-TVD multidimensional stabilization scheme is used");
      23        2866 :   params.addRequiredParam<RealVectorValue>("gravity",
      24             :                                            "Gravitational acceleration vector downwards (m/s^2)");
      25        2866 :   params.addRequiredParam<UserObjectName>(
      26             :       "PorousFlowDictator", "The UserObject that holds the list of PorousFlow variable names");
      27        2866 :   params.addParam<unsigned int>(
      28        2866 :       "phase", 0, "The index corresponding to the phase for this UserObject");
      29        2866 :   MooseEnum families("LAGRANGE MONOMIAL HERMITE SCALAR HIERARCHIC CLOUGH XYZ SZABAB BERNSTEIN");
      30        2866 :   params.addParam<MooseEnum>(
      31             :       "fe_family",
      32             :       families,
      33             :       "FE Family to use (eg Lagrange).  You only need to specify this is your porous_flow_vars in "
      34             :       "your PorousFlowDictator have different families or orders");
      35        2866 :   MooseEnum orders("CONSTANT FIRST SECOND THIRD FOURTH");
      36        2866 :   params.addParam<MooseEnum>(
      37             :       "fe_order",
      38             :       orders,
      39             :       "FE Order to use (eg First).  You only need to specify this is your porous_flow_vars in your "
      40             :       "PorousFlowDictator have different families or orders");
      41        1433 :   return params;
      42        1433 : }
      43             : 
      44         561 : PorousFlowAdvectiveFluxCalculatorBase::PorousFlowAdvectiveFluxCalculatorBase(
      45         561 :     const InputParameters & parameters)
      46             :   : AdvectiveFluxCalculatorBase(parameters),
      47         561 :     _dictator(getUserObject<PorousFlowDictator>("PorousFlowDictator")),
      48         561 :     _num_vars(_dictator.numVariables()),
      49        1122 :     _gravity(getParam<RealVectorValue>("gravity")),
      50        1122 :     _phase(getParam<unsigned int>("phase")),
      51        1122 :     _permeability(getMaterialProperty<RealTensorValue>("PorousFlow_permeability_qp")),
      52         561 :     _dpermeability_dvar(
      53         561 :         getMaterialProperty<std::vector<RealTensorValue>>("dPorousFlow_permeability_qp_dvar")),
      54        1122 :     _dpermeability_dgradvar(getMaterialProperty<std::vector<std::vector<RealTensorValue>>>(
      55             :         "dPorousFlow_permeability_qp_dgradvar")),
      56        1122 :     _fluid_density_qp(getMaterialProperty<std::vector<Real>>("PorousFlow_fluid_phase_density_qp")),
      57        1122 :     _dfluid_density_qp_dvar(getMaterialProperty<std::vector<std::vector<Real>>>(
      58             :         "dPorousFlow_fluid_phase_density_qp_dvar")),
      59        1122 :     _grad_p(getMaterialProperty<std::vector<RealGradient>>("PorousFlow_grad_porepressure_qp")),
      60        1122 :     _dgrad_p_dgrad_var(getMaterialProperty<std::vector<std::vector<Real>>>(
      61             :         "dPorousFlow_grad_porepressure_qp_dgradvar")),
      62        1122 :     _dgrad_p_dvar(getMaterialProperty<std::vector<std::vector<RealGradient>>>(
      63             :         "dPorousFlow_grad_porepressure_qp_dvar")),
      64        1126 :     _fe_type(isParamValid("fe_family") && isParamValid("fe_order")
      65        1122 :                  ? FEType(Utility::string_to_enum<Order>(getParam<MooseEnum>("fe_order")),
      66         561 :                           Utility::string_to_enum<FEFamily>(getParam<MooseEnum>("fe_family")))
      67         561 :                  : _dictator.feType()),
      68         561 :     _phi(_assembly.fePhi<Real>(_fe_type)),
      69         561 :     _grad_phi(_assembly.feGradPhi<Real>(_fe_type)),
      70             :     _du_dvar(),
      71             :     _du_dvar_computed_by_thread(),
      72             :     _dkij_dvar(),
      73             :     _dflux_out_dvars(),
      74             :     _triples_to_receive(),
      75             :     _triples_to_send(),
      76        1122 :     _perm_derivs(_dictator.usePermDerivs())
      77             : {
      78         561 :   if (_phase >= _dictator.numPhases())
      79           2 :     paramError("phase",
      80             :                "Phase number entered is greater than the number of phases specified in the "
      81             :                "Dictator. Remember that indexing starts at 0");
      82             : 
      83        1122 :   if (isParamValid("fe_family") && !isParamValid("fe_order"))
      84           2 :     paramError("fe_order", "If you specify fe_family you must also specify fe_order");
      85        1118 :   if (isParamValid("fe_order") && !isParamValid("fe_family"))
      86           2 :     paramError("fe_family", "If you specify fe_order you must also specify fe_family");
      87         559 :   if (!_dictator.consistentFEType() && !isParamValid("fe_family"))
      88           2 :     paramError("fe_family",
      89             :                "The PorousFlowDictator cannot determine the appropriate FE type to use because "
      90             :                "your porous_flow_vars are of different types.  You must specify the appropriate "
      91             :                "fe_family and fe_order to use.");
      92         553 : }
      93             : 
      94             : Real
      95     9970288 : PorousFlowAdvectiveFluxCalculatorBase::computeVelocity(unsigned i, unsigned j, unsigned qp) const
      96             : {
      97             :   // The following is but one choice for PorousFlow situations
      98             :   // If you change this, you will probably have to change
      99             :   // - the derivative in executeOnElement
     100             :   // - computeU
     101             :   // - computedU_dvar
     102     9970288 :   return -_grad_phi[i][qp] *
     103     9970288 :          (_permeability[qp] * (_grad_p[qp][_phase] - _fluid_density_qp[qp][_phase] * _gravity)) *
     104     9970288 :          _phi[j][qp];
     105             : }
     106             : 
     107             : void
     108     9970288 : PorousFlowAdvectiveFluxCalculatorBase::executeOnElement(
     109             :     dof_id_type global_i, dof_id_type global_j, unsigned local_i, unsigned local_j, unsigned qp)
     110             : {
     111     9970288 :   AdvectiveFluxCalculatorBase::executeOnElement(global_i, global_j, local_i, local_j, qp);
     112     9970288 :   const dof_id_type sequential_i = _connections.sequentialID(global_i);
     113     9970288 :   const unsigned j = _connections.indexOfGlobalConnection(global_i, global_j);
     114             : 
     115             :   // compute d(Kij)/d(porous_flow_variables)
     116    42384208 :   for (unsigned local_k = 0; local_k < _current_elem->n_nodes(); ++local_k)
     117             :   {
     118    32413920 :     const dof_id_type global_k = _current_elem->node_id(local_k);
     119   109200032 :     for (unsigned pvar = 0; pvar < _num_vars; ++pvar)
     120             :     {
     121             :       RealVectorValue deriv =
     122    76786112 :           _permeability[qp] *
     123    76786112 :           (_grad_phi[local_k][qp] * _dgrad_p_dgrad_var[qp][_phase][pvar] -
     124    76786112 :            _phi[local_k][qp] * _dfluid_density_qp_dvar[qp][_phase][pvar] * _gravity);
     125    76786112 :       deriv += _permeability[qp] * (_dgrad_p_dvar[qp][_phase][pvar] * _phi[local_k][qp]);
     126             : 
     127    76786112 :       if (_perm_derivs)
     128             :       {
     129           0 :         deriv += _dpermeability_dvar[qp][pvar] * _phi[local_k][qp] *
     130           0 :                  (_grad_p[qp][_phase] - _fluid_density_qp[qp][_phase] * _gravity);
     131           0 :         for (unsigned i = 0; i < LIBMESH_DIM; ++i)
     132           0 :           deriv += _dpermeability_dgradvar[qp][i][pvar] * _grad_phi[local_k][qp](i) *
     133           0 :                    (_grad_p[qp][_phase] - _fluid_density_qp[qp][_phase] * _gravity);
     134             :       }
     135             : 
     136    76786112 :       _dkij_dvar[sequential_i][j][global_k][pvar] +=
     137    76786112 :           _JxW[qp] * _coord[qp] * (-_grad_phi[local_i][qp] * deriv * _phi[local_j][qp]);
     138             :     }
     139             :   }
     140     9970288 : }
     141             : 
     142             : void
     143       14607 : PorousFlowAdvectiveFluxCalculatorBase::timestepSetup()
     144             : {
     145       14607 :   const bool resizing_was_needed =
     146             :       _resizing_needed; // _resizing_needed gets set to false at the end of
     147             :                         // AdvectiveFluxCalculatorBase::timestepSetup()
     148       14607 :   AdvectiveFluxCalculatorBase::timestepSetup();
     149             : 
     150             :   // clear and appropriately size all the derivative info
     151             :   // d(U)/d(porous_flow_variables) and
     152             :   // d(Kij)/d(porous_flow_variables) and
     153             :   // d(flux_out)/d(porous_flow_variables)
     154       14607 :   if (resizing_was_needed)
     155             :   {
     156         781 :     const std::size_t num_nodes = _connections.numNodes();
     157        1562 :     _du_dvar.assign(num_nodes, std::vector<Real>(_num_vars, 0.0));
     158         781 :     _du_dvar_computed_by_thread.assign(num_nodes, false);
     159         781 :     _dflux_out_dvars.assign(num_nodes, std::map<dof_id_type, std::vector<Real>>());
     160         781 :     _dkij_dvar.resize(num_nodes);
     161       18199 :     for (dof_id_type sequential_i = 0; sequential_i < num_nodes; ++sequential_i)
     162             :     {
     163             :       const std::vector<dof_id_type> con_i =
     164       17418 :           _connections.globalConnectionsToSequentialID(sequential_i);
     165             :       const std::size_t num_con_i = con_i.size();
     166       17418 :       _dkij_dvar[sequential_i].assign(num_con_i, std::map<dof_id_type, std::vector<Real>>());
     167       97296 :       for (unsigned j = 0; j < num_con_i; ++j)
     168      558036 :         for (const auto & global_neighbor_to_i : con_i)
     169      956316 :           _dkij_dvar[sequential_i][j][global_neighbor_to_i] = std::vector<Real>(_num_vars, 0.0);
     170       17418 :     }
     171             :   }
     172       14607 : }
     173             : 
     174             : void
     175       59874 : PorousFlowAdvectiveFluxCalculatorBase::initialize()
     176             : {
     177       59874 :   AdvectiveFluxCalculatorBase::initialize();
     178       59874 :   const std::size_t num_nodes = _connections.numNodes();
     179       59874 :   _du_dvar_computed_by_thread.assign(num_nodes, false);
     180     1609334 :   for (dof_id_type sequential_i = 0; sequential_i < num_nodes; ++sequential_i)
     181             :   {
     182             :     const std::vector<dof_id_type> & con_i =
     183     1549460 :         _connections.globalConnectionsToSequentialID(sequential_i);
     184             :     const std::size_t num_con_i = con_i.size();
     185     6729772 :     for (unsigned j = 0; j < num_con_i; ++j)
     186    26015680 :       for (const auto & global_neighbor_to_i : con_i)
     187    41670736 :         _dkij_dvar[sequential_i][j][global_neighbor_to_i] = std::vector<Real>(_num_vars, 0.0);
     188             :   }
     189       59874 : }
     190             : 
     191             : void
     192      793260 : PorousFlowAdvectiveFluxCalculatorBase::execute()
     193             : {
     194      793260 :   AdvectiveFluxCalculatorBase::execute();
     195             : 
     196             :   // compute d(U)/d(porous_flow_variables) for nodes in _current_elem and for this
     197             :   // execution thread.  In threadJoin all these computations get gathered
     198             :   // using _du_dvar_computed_by_thread
     199     2483032 :   for (unsigned i = 0; i < _current_elem->n_nodes(); ++i)
     200             :   {
     201     1689772 :     const dof_id_type global_i = _current_elem->node_id(i);
     202     1689772 :     const dof_id_type sequential_i = _connections.sequentialID(global_i);
     203     1689772 :     if (_du_dvar_computed_by_thread[sequential_i])
     204      803572 :       continue;
     205     2717376 :     for (unsigned pvar = 0; pvar < _num_vars; ++pvar)
     206     1831176 :       _du_dvar[sequential_i][pvar] = computedU_dvar(i, pvar);
     207             :     _du_dvar_computed_by_thread[sequential_i] = true;
     208             :   }
     209      793260 : }
     210             : 
     211             : void
     212       24584 : PorousFlowAdvectiveFluxCalculatorBase::threadJoin(const UserObject & uo)
     213             : {
     214       24584 :   AdvectiveFluxCalculatorBase::threadJoin(uo);
     215             :   const auto & pfafc = static_cast<const PorousFlowAdvectiveFluxCalculatorBase &>(uo);
     216             :   // add the values of _dkij_dvar computed by different threads
     217       24584 :   const std::size_t num_nodes = _connections.numNodes();
     218      675142 :   for (dof_id_type sequential_i = 0; sequential_i < num_nodes; ++sequential_i)
     219             :   {
     220             :     const std::vector<dof_id_type> & con_i =
     221      650558 :         _connections.globalConnectionsToSequentialID(sequential_i);
     222             :     const std::size_t num_con_i = con_i.size();
     223     2777476 :     for (unsigned j = 0; j < num_con_i; ++j)
     224    10238908 :       for (const auto & global_derivs : pfafc._dkij_dvar[sequential_i][j])
     225    25026170 :         for (unsigned pvar = 0; pvar < _num_vars; ++pvar)
     226    16914180 :           _dkij_dvar[sequential_i][j][global_derivs.first][pvar] += global_derivs.second[pvar];
     227             :   }
     228             : 
     229             :   // gather the values of _du_dvar computed by different threads
     230      675142 :   for (dof_id_type sequential_i = 0; sequential_i < _number_of_nodes; ++sequential_i)
     231      650558 :     if (!_du_dvar_computed_by_thread[sequential_i] &&
     232             :         pfafc._du_dvar_computed_by_thread[sequential_i])
     233      231350 :       _du_dvar[sequential_i] = pfafc._du_dvar[sequential_i];
     234       24584 : }
     235             : 
     236             : const std::map<dof_id_type, std::vector<Real>> &
     237    12723378 : PorousFlowAdvectiveFluxCalculatorBase::getdK_dvar(dof_id_type node_i, dof_id_type node_j) const
     238             : {
     239    12723378 :   const dof_id_type sequential_i = _connections.sequentialID(node_i);
     240    12723378 :   const unsigned j = _connections.indexOfGlobalConnection(node_i, node_j);
     241    12723378 :   return _dkij_dvar[sequential_i][j];
     242             : }
     243             : 
     244             : const std::map<dof_id_type, std::vector<Real>> &
     245     1233788 : PorousFlowAdvectiveFluxCalculatorBase::getdFluxOut_dvars(unsigned node_id) const
     246             : {
     247     1233788 :   return _dflux_out_dvars[_connections.sequentialID(node_id)];
     248             : }
     249             : 
     250             : void
     251       35290 : PorousFlowAdvectiveFluxCalculatorBase::finalize()
     252             : {
     253       35290 :   AdvectiveFluxCalculatorBase::finalize();
     254             : 
     255             :   // compute d(flux_out)/d(porous flow variable)
     256             :   /// _dflux_out_dvars[sequential_i][global_j][pvar] = d(flux_out[global version of sequential_i])/d(porous_flow_variable pvar at global node j)
     257      934192 :   for (const auto & node_i : _connections.globalIDs())
     258             :   {
     259      898902 :     const dof_id_type sequential_i = _connections.sequentialID(node_i);
     260             :     _dflux_out_dvars[sequential_i].clear();
     261             : 
     262             :     const std::map<dof_id_type, Real> & dflux_out_du =
     263      898902 :         AdvectiveFluxCalculatorBase::getdFluxOutdu(node_i);
     264     6205360 :     for (const auto & node_du : dflux_out_du)
     265             :     {
     266     5306458 :       const dof_id_type j = node_du.first;
     267     5306458 :       const Real dflux_out_du_j = node_du.second;
     268     5306458 :       _dflux_out_dvars[sequential_i][j] = _du_dvar[_connections.sequentialID(j)];
     269    16364526 :       for (unsigned pvar = 0; pvar < _num_vars; ++pvar)
     270    11058068 :         _dflux_out_dvars[sequential_i][j][pvar] *= dflux_out_du_j;
     271             :     }
     272             : 
     273             :     // _dflux_out_dvars is now sized correctly, because getdFluxOutdu(i) contains all nodes
     274             :     // connected to i and all nodes connected to nodes connected to i.  The
     275             :     // getdFluxOutdKij contains no extra nodes, so just += the dflux/dK terms
     276             :     const std::vector<std::vector<Real>> & dflux_out_dKjk =
     277      898902 :         AdvectiveFluxCalculatorBase::getdFluxOutdKjk(node_i);
     278      898902 :     const std::vector<dof_id_type> & con_i = _connections.globalConnectionsToGlobalID(node_i);
     279     3952296 :     for (std::size_t index_j = 0; index_j < con_i.size(); ++index_j)
     280             :     {
     281     3053394 :       const dof_id_type node_j = con_i[index_j];
     282     3053394 :       const std::vector<dof_id_type> & con_j = _connections.globalConnectionsToGlobalID(node_j);
     283    15776772 :       for (std::size_t index_k = 0; index_k < con_j.size(); ++index_k)
     284             :       {
     285    12723378 :         const dof_id_type node_k = con_j[index_k];
     286    12723378 :         const Real dflux_out_dK_jk = dflux_out_dKjk[index_j][index_k];
     287    12723378 :         const std::map<dof_id_type, std::vector<Real>> & dkj_dvarl = getdK_dvar(node_j, node_k);
     288    84398604 :         for (const auto & nodel_deriv : dkj_dvarl)
     289             :         {
     290    71675226 :           const dof_id_type l = nodel_deriv.first;
     291   236533038 :           for (unsigned pvar = 0; pvar < _num_vars; ++pvar)
     292   164857812 :             _dflux_out_dvars[sequential_i][l][pvar] += dflux_out_dK_jk * nodel_deriv.second[pvar];
     293             :         }
     294             :       }
     295             :     }
     296             :   }
     297       35290 : }
     298             : 
     299             : void
     300         384 : PorousFlowAdvectiveFluxCalculatorBase::buildCommLists()
     301             : {
     302             :   // build nodes and pairs to exchange
     303         384 :   AdvectiveFluxCalculatorBase::buildCommLists();
     304             : 
     305             :   // Build _triples_to_receive
     306             :   // tpr_global is essentially _triples_to_receive, but its key-pairs have global nodal IDs: later
     307             :   // we build _triples_to_receive by flattening the data structure and making these key-pairs into
     308             :   // sequential nodal IDs
     309             :   std::map<processor_id_type,
     310             :            std::map<std::pair<dof_id_type, dof_id_type>, std::vector<dof_id_type>>>
     311             :       tpr_global;
     312        5512 :   for (const auto & elem : _fe_problem.getNonlinearEvaluableElementRange())
     313        5128 :     if (this->hasBlocks(elem->subdomain_id()))
     314             :     {
     315        5128 :       const processor_id_type elem_pid = elem->processor_id();
     316        5128 :       if (elem_pid != _my_pid)
     317             :       {
     318        1098 :         if (tpr_global.find(elem_pid) == tpr_global.end())
     319         376 :           tpr_global[elem_pid] =
     320         376 :               std::map<std::pair<dof_id_type, dof_id_type>, std::vector<dof_id_type>>();
     321        4266 :         for (unsigned i = 0; i < elem->n_nodes(); ++i)
     322       13824 :           for (unsigned j = 0; j < elem->n_nodes(); ++j)
     323             :           {
     324       10656 :             std::pair<dof_id_type, dof_id_type> the_pair(elem->node_id(i), elem->node_id(j));
     325       10656 :             if (tpr_global[elem_pid].find(the_pair) == tpr_global[elem_pid].end())
     326       16280 :               tpr_global[elem_pid][the_pair] = std::vector<dof_id_type>();
     327             : 
     328       10656 :             for (const auto & global_neighbor_to_i :
     329       94360 :                  _connections.globalConnectionsToGlobalID(elem->node_id(i)))
     330       73048 :               if (std::find(tpr_global[elem_pid][the_pair].begin(),
     331       73048 :                             tpr_global[elem_pid][the_pair].end(),
     332       73048 :                             global_neighbor_to_i) == tpr_global[elem_pid][the_pair].end())
     333       53532 :                 tpr_global[elem_pid][the_pair].push_back(global_neighbor_to_i);
     334             :           }
     335             :       }
     336             :     }
     337             : 
     338             :   // flattening makes later manipulations a lot more concise.  Store the result in
     339             :   // _triples_to_receive
     340             :   _triples_to_receive.clear();
     341         760 :   for (const auto & kv : tpr_global)
     342             :   {
     343         376 :     const processor_id_type pid = kv.first;
     344         752 :     _triples_to_receive[pid] = std::vector<dof_id_type>();
     345        8516 :     for (const auto & pr_vec : kv.second)
     346             :     {
     347        8140 :       const dof_id_type i = pr_vec.first.first;
     348        8140 :       const dof_id_type j = pr_vec.first.second;
     349       61672 :       for (const auto & global_nd : pr_vec.second)
     350             :       {
     351       53532 :         _triples_to_receive[pid].push_back(i);
     352       53532 :         _triples_to_receive[pid].push_back(j);
     353       53532 :         _triples_to_receive[pid].push_back(global_nd);
     354             :       }
     355             :     }
     356             :   }
     357             : 
     358             :   _triples_to_send.clear();
     359         376 :   auto triples_action_functor = [this](processor_id_type pid, const std::vector<dof_id_type> & tts)
     360         376 :   { _triples_to_send[pid] = tts; };
     361         384 :   Parallel::push_parallel_vector_data(this->comm(), _triples_to_receive, triples_action_functor);
     362             : 
     363             :   // _triples_to_send and _triples_to_receive have been built using global node IDs
     364             :   // since all processors know about that.  However, using global IDs means
     365             :   // that every time we send/receive, we keep having to do things like
     366             :   // _dkij_dvar[_connections.sequentialID(_triples_to_send[pid][i])][_connections.indexOfGlobalConnection(_triples_to_send[pid][i],
     367             :   // _triples_to_send[pid][i + 1])] which is quite inefficient.  So:
     368         760 :   for (auto & kv : _triples_to_send)
     369             :   {
     370         376 :     const processor_id_type pid = kv.first;
     371             :     const std::size_t num = kv.second.size();
     372       53908 :     for (std::size_t i = 0; i < num; i += 3)
     373             :     {
     374       53532 :       _triples_to_send[pid][i + 1] = _connections.indexOfGlobalConnection(
     375       53532 :           _triples_to_send[pid][i], _triples_to_send[pid][i + 1]);
     376       53532 :       _triples_to_send[pid][i] = _connections.sequentialID(_triples_to_send[pid][i]);
     377             :     }
     378             :   }
     379         760 :   for (auto & kv : _triples_to_receive)
     380             :   {
     381         376 :     const processor_id_type pid = kv.first;
     382             :     const std::size_t num = kv.second.size();
     383       53908 :     for (std::size_t i = 0; i < num; i += 3)
     384             :     {
     385       53532 :       _triples_to_receive[pid][i + 1] = _connections.indexOfGlobalConnection(
     386       53532 :           _triples_to_receive[pid][i], _triples_to_receive[pid][i + 1]);
     387       53532 :       _triples_to_receive[pid][i] = _connections.sequentialID(_triples_to_receive[pid][i]);
     388             :     }
     389             :   }
     390         384 : }
     391             : 
     392             : void
     393       18792 : PorousFlowAdvectiveFluxCalculatorBase::exchangeGhostedInfo()
     394             : {
     395             :   // Exchange u_nodal and k_ij
     396       18792 :   AdvectiveFluxCalculatorBase::exchangeGhostedInfo();
     397             : 
     398             :   // Exchange _du_dvar
     399             :   std::map<processor_id_type, std::vector<std::vector<Real>>> du_dvar_to_send;
     400       37384 :   for (const auto & kv : _nodes_to_send)
     401             :   {
     402       18592 :     const processor_id_type pid = kv.first;
     403       37184 :     du_dvar_to_send[pid] = std::vector<std::vector<Real>>();
     404       87952 :     for (const auto & nd : kv.second)
     405       69360 :       du_dvar_to_send[pid].push_back(_du_dvar[nd]);
     406             :   }
     407             : 
     408             :   auto du_action_functor =
     409       18592 :       [this](processor_id_type pid, const std::vector<std::vector<Real>> & du_dvar_received)
     410             :   {
     411             :     const std::size_t msg_size = du_dvar_received.size();
     412             :     mooseAssert(
     413             :         msg_size == _nodes_to_receive[pid].size(),
     414             :         "Message size, "
     415             :             << msg_size
     416             :             << ", in du_dvar communication is incompatible with nodes_to_receive, which has size "
     417             :             << _nodes_to_receive[pid].size());
     418       87952 :     for (unsigned i = 0; i < msg_size; ++i)
     419       69360 :       _du_dvar[_nodes_to_receive[pid][i]] = du_dvar_received[i];
     420       18792 :   };
     421       18792 :   Parallel::push_parallel_vector_data(this->comm(), du_dvar_to_send, du_action_functor);
     422             : 
     423             :   // Exchange _dkij_dvar
     424             :   std::map<processor_id_type, std::vector<std::vector<Real>>> dkij_dvar_to_send;
     425       37384 :   for (const auto & kv : _triples_to_send)
     426             :   {
     427       18592 :     const processor_id_type pid = kv.first;
     428       37184 :     dkij_dvar_to_send[pid] = std::vector<std::vector<Real>>();
     429             :     const std::size_t num = kv.second.size();
     430     1444720 :     for (std::size_t i = 0; i < num; i += 3)
     431             :     {
     432     1426128 :       const dof_id_type sequential_id = kv.second[i];
     433     1426128 :       const unsigned index_to_seq = kv.second[i + 1];
     434     1426128 :       const dof_id_type global_id = kv.second[i + 2];
     435     1426128 :       dkij_dvar_to_send[pid].push_back(_dkij_dvar[sequential_id][index_to_seq][global_id]);
     436             :     }
     437             :   }
     438             : 
     439             :   auto dk_action_functor =
     440       18592 :       [this](processor_id_type pid, const std::vector<std::vector<Real>> & dkij_dvar_received)
     441             :   {
     442       18592 :     const std::size_t num = _triples_to_receive[pid].size();
     443             :     mooseAssert(dkij_dvar_received.size() == num / 3,
     444             :                 "Message size, " << dkij_dvar_received.size()
     445             :                                  << ", in dkij_dvar communication is incompatible with "
     446             :                                     "triples_to_receive, which has size "
     447             :                                  << _triples_to_receive[pid].size());
     448     1444720 :     for (std::size_t i = 0; i < num; i += 3)
     449             :     {
     450     1426128 :       const dof_id_type sequential_id = _triples_to_receive[pid][i];
     451     1426128 :       const unsigned index_to_seq = _triples_to_receive[pid][i + 1];
     452     1426128 :       const dof_id_type global_id = _triples_to_receive[pid][i + 2];
     453     4914608 :       for (unsigned pvar = 0; pvar < _num_vars; ++pvar)
     454     3488480 :         _dkij_dvar[sequential_id][index_to_seq][global_id][pvar] += dkij_dvar_received[i / 3][pvar];
     455             :     }
     456       18792 :   };
     457       18792 :   Parallel::push_parallel_vector_data(this->comm(), dkij_dvar_to_send, dk_action_functor);
     458       18792 : }

Generated by: LCOV version 1.14