LCOV - code coverage report
Current view: top level - src/transfers - MultiAppDofCopyTransfer.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 116 124 93.5 %
Date: 2026-05-29 20:35:17 Functions: 5 5 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             : // MOOSE includes
      11             : #include "MultiAppDofCopyTransfer.h"
      12             : #include "FEProblemBase.h"
      13             : #include "MultiApp.h"
      14             : #include "SystemBase.h"
      15             : 
      16             : #include "libmesh/id_types.h"
      17             : #include "libmesh/string_to_enum.h"
      18             : 
      19             : using namespace libMesh;
      20             : 
      21             : InputParameters
      22        4250 : MultiAppDofCopyTransfer::validParams()
      23             : {
      24        4250 :   InputParameters params = MultiAppFieldTransfer::validParams();
      25             : 
      26       17000 :   params.addParam<TagName>(
      27             :       "from_solution_tag",
      28             :       "The tag of the solution vector to be transferred (default to the solution)");
      29       17000 :   params.addParam<TagName>(
      30             :       "to_solution_tag",
      31             :       "The tag of the solution vector to be transferred to (default to the solution)");
      32             : 
      33             :   // Block restrictions
      34       17000 :   params.addParam<std::vector<SubdomainName>>(
      35             :       "from_blocks",
      36             :       {},
      37             :       "Subdomain restriction to transfer from (defaults to all the origin app domain)");
      38       17000 :   params.addParam<std::vector<SubdomainName>>(
      39             :       "to_blocks",
      40             :       {},
      41             :       "Subdomain restriction to transfer to, (defaults to all the target app domain)");
      42             : 
      43        4250 :   params.addClassDescription(
      44             :       "Base class for copying degrees-of-freedom values (nonlinear and auxiliary) between apps "
      45             :       "that have identical meshes.");
      46        4250 :   return params;
      47           0 : }
      48             : 
      49         599 : MultiAppDofCopyTransfer::MultiAppDofCopyTransfer(const InputParameters & parameters)
      50             :   : MultiAppFieldTransfer(parameters),
      51        1734 :     _has_block_restrictions(!getParam<std::vector<SubdomainName>>("from_blocks").empty() ||
      52        3441 :                             !getParam<std::vector<SubdomainName>>("to_blocks").empty())
      53             : {
      54         590 : }
      55             : 
      56             : void
      57         563 : MultiAppDofCopyTransfer::initialSetup()
      58             : {
      59         563 :   MultiAppFieldTransfer::initialSetup();
      60             : 
      61             :   const FEProblemBase * from_problem;
      62             :   const FEProblemBase * to_problem;
      63             : 
      64         557 :   if (_current_direction == FROM_MULTIAPP)
      65             :   {
      66             :     // Subdomain and variable type information is shared on all subapps
      67         289 :     from_problem = &getFromMultiApp()->appProblemBase(getFromMultiApp()->firstLocalApp());
      68         289 :     to_problem = &getFromMultiApp()->problemBase();
      69             :   }
      70         268 :   else if (_current_direction == TO_MULTIAPP)
      71             :   {
      72         258 :     from_problem = &getToMultiApp()->problemBase();
      73         258 :     to_problem = &getToMultiApp()->appProblemBase(getToMultiApp()->firstLocalApp());
      74             :   }
      75             :   else
      76             :   {
      77          10 :     from_problem = &getFromMultiApp()->appProblemBase(getFromMultiApp()->firstLocalApp());
      78          10 :     to_problem = &getToMultiApp()->appProblemBase(getToMultiApp()->firstLocalApp());
      79             :   }
      80             : 
      81         557 :   if (from_problem->mesh().getParallelType() != to_problem->mesh().getParallelType())
      82           0 :     mooseError("The parallel types (distributed or replicated) of the meshes are not the same.");
      83             : 
      84             :   // Convert block names to block IDs, fill with all blocks if unspecified
      85         557 :   if (_has_block_restrictions)
      86             :   {
      87         138 :     const auto & from_block_names = getParam<std::vector<SubdomainName>>("from_blocks");
      88          99 :     for (const auto & b : from_block_names)
      89          36 :       if (!MooseMeshUtils::hasSubdomainName(const_cast<MeshBase &>(from_problem->mesh().getMesh()),
      90             :                                             b))
      91          12 :         paramError("from_blocks", "The block '", b, "' was not found in the mesh");
      92             : 
      93          63 :     if (from_block_names.size())
      94             :     {
      95          30 :       if (from_problem)
      96             :       {
      97          30 :         const auto block_vec = from_problem->mesh().getSubdomainIDs(from_block_names);
      98          30 :         _from_blocks = std::set<SubdomainID>(block_vec.begin(), block_vec.end());
      99          30 :       }
     100             :       // We dont even own any of these subapps
     101             :       else
     102           0 :         _from_blocks = {Moose::INVALID_BLOCK_ID};
     103             :     }
     104             :     else
     105          33 :       _from_blocks = from_problem->mesh().meshSubdomains();
     106             : 
     107         126 :     const auto & to_block_names = getParam<std::vector<SubdomainName>>("to_blocks");
     108          90 :     for (const auto & b : to_block_names)
     109          33 :       if (!MooseMeshUtils::hasSubdomainName(const_cast<MeshBase &>(to_problem->mesh().getMesh()),
     110             :                                             b))
     111          12 :         paramError("to_blocks", "The block '", b, "' was not found in the mesh");
     112             : 
     113          57 :     if (to_block_names.size())
     114             :     {
     115          27 :       if (to_problem)
     116             :       {
     117          27 :         const auto block_vec = to_problem->mesh().getSubdomainIDs(to_block_names);
     118          27 :         _to_blocks = std::set<SubdomainID>(block_vec.begin(), block_vec.end());
     119          27 :       }
     120             :       // We dont even own any of these subapps
     121             :       else
     122           0 :         _to_blocks = {Moose::INVALID_BLOCK_ID};
     123             :     }
     124             :     else
     125          30 :       _to_blocks = to_problem->mesh().meshSubdomains();
     126             :   }
     127             : 
     128             :   // Forbid block restriction on nodal variables as currently not supported
     129         545 :   if (_from_blocks.size())
     130         108 :     for (auto & from_var : getFromVarNames())
     131          57 :       if (from_problem
     132          57 :               ->getVariable(
     133             :                   0, from_var, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY)
     134          57 :               .hasDoFsOnNodes())
     135          63 :         paramError("from_blocks", "Block restriction is not implemented for nodal variables");
     136         539 :   if (_to_blocks.size())
     137         102 :     for (auto & to_var : getToVarNames())
     138          51 :       if (to_problem
     139          51 :               ->getVariable(
     140             :                   0, to_var, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY)
     141          51 :               .hasDoFsOnNodes())
     142          51 :         paramError("to_blocks", "Block restriction is not implemented for nodal variables");
     143         539 : }
     144             : 
     145             : void
     146        2045 : MultiAppDofCopyTransfer::transfer(FEProblemBase & to_problem, FEProblemBase & from_problem)
     147             : {
     148             :   // Perform error checking
     149        2045 :   if (!getToVarNames().size())
     150           0 :     mooseError("No transferred variables were specified, neither programmatically or through the "
     151             :                "'source_variable' parameter");
     152        2045 :   if (getToVarNames().size() != getFromVarNames().size())
     153           0 :     mooseError("Number of variables transferred must be same in both systems.");
     154        4101 :   for (auto & to_var : getToVarNames())
     155        8213 :     checkVariable(to_problem, to_var);
     156        4098 :   for (auto & from_var : getFromVarNames())
     157        8207 :     checkVariable(from_problem, from_var);
     158             : 
     159        4089 :   for (unsigned int v = 0; v < getToVarNames().size(); ++v)
     160             :   {
     161             :     // Populate the to/from variables needed to perform the transfer
     162        2053 :     MooseVariableFEBase & to_var = to_problem.getVariable(
     163        4106 :         0, getToVarNames()[v], Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
     164        2053 :     MeshBase & to_mesh = to_problem.mesh().getMesh();
     165             : 
     166        2053 :     MooseVariableFEBase & from_var = from_problem.getVariable(
     167        4106 :         0, getFromVarNames()[v], Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
     168        2053 :     MeshBase & from_mesh = from_problem.mesh().getMesh();
     169             : 
     170        4106 :     auto & to_solution = isParamValid("to_solution_tag")
     171        4126 :                              ? to_var.sys().getVector(
     172          10 :                                    to_problem.getVectorTagID(getParam<TagName>("to_solution_tag")))
     173        2053 :                              : to_var.sys().solution();
     174        4106 :     auto & from_solution = isParamValid("from_solution_tag")
     175        4106 :                                ? from_var.sys().getVector(from_problem.getVectorTagID(
     176             :                                      getParam<TagName>("from_solution_tag")))
     177        2053 :                                : from_var.sys().solution();
     178             : 
     179             :     // Check integrity
     180        2053 :     if (to_var.feType() != from_var.feType())
     181           3 :       mooseError("MultiAppFieldTransfer '",
     182           3 :                  name(),
     183             :                  "'requires that the target variable '",
     184           3 :                  to_var.name(),
     185             :                  "' and the source variable'",
     186           3 :                  from_var.name(),
     187             :                  "' must be the same type "
     188             :                  "(order and family): ",
     189           3 :                  libMesh::Utility::enum_to_string<FEFamily>(to_var.feType().family),
     190           3 :                  moose::internal::incompatVarMsg(to_var, from_var));
     191        2050 :     if (to_var.fieldType() != from_var.fieldType())
     192           0 :       mooseError(
     193             :           "Corresponding transfer variables must be same field type (STANDARD | VECTOR | ARRAY).");
     194        2050 :     if (to_var.count() != from_var.count())
     195           0 :       mooseError("Corresponding transfer variables must have same number of components.");
     196             : 
     197        2050 :     if ((to_mesh.n_nodes() != from_mesh.n_nodes()) || (to_mesh.n_elem() != from_mesh.n_elem()))
     198           3 :       mooseError("The meshes must be identical to utilize MultiAppDofCopyTransfer::transfer.");
     199             : 
     200             :     // Transfer node dofs. Block restriction is not supported, forbidden in initialSetup
     201      126649 :     for (const auto & node : as_range(to_mesh.local_nodes_begin(), to_mesh.local_nodes_end()))
     202      249204 :       transferDofObject(
     203      251251 :           node, from_mesh.node_ptr(node->id()), to_var, from_var, to_solution, from_solution);
     204             : 
     205             :     // Transfer elem dofs
     206       98488 :     for (auto & to_elem : as_range(to_mesh.local_elements_begin(), to_mesh.local_elements_end()))
     207             :     {
     208       96441 :       Elem * from_elem = from_mesh.elem_ptr(to_elem->id());
     209             :       mooseAssert(to_elem->type() == from_elem->type(), "The elements must be the same type.");
     210             : 
     211             :       // Examine block restriction
     212       96441 :       if (_has_block_restrictions)
     213             :       {
     214        1024 :         SubdomainID from_block = from_elem->subdomain_id();
     215        1024 :         if (std::find(_from_blocks.begin(), _from_blocks.end(), from_block) == _from_blocks.end())
     216         672 :           continue;
     217             : 
     218         688 :         SubdomainID to_block = to_elem->subdomain_id();
     219         688 :         if (std::find(_to_blocks.begin(), _to_blocks.end(), to_block) == _to_blocks.end())
     220         336 :           continue;
     221             :       }
     222             : 
     223       95769 :       transferDofObject(to_elem, from_elem, to_var, from_var, to_solution, from_solution);
     224        2047 :     }
     225             : 
     226        2047 :     to_solution.close();
     227        2047 :     to_var.sys().update();
     228             :   }
     229        2036 : }
     230             : 
     231             : void
     232      220371 : MultiAppDofCopyTransfer::transferDofObject(libMesh::DofObject * to_object,
     233             :                                            libMesh::DofObject * from_object,
     234             :                                            MooseVariableFEBase & to_var,
     235             :                                            MooseVariableFEBase & from_var,
     236             :                                            NumericVector<Number> & to_solution,
     237             :                                            NumericVector<Number> & from_solution)
     238             : {
     239      599420 :   for (unsigned int vc = 0; vc < to_var.count(); ++vc)
     240             :     // Transfer from one solution vector to another
     241      379049 :     if (to_object->n_dofs(to_var.sys().number(), to_var.number() + vc) >
     242             :         0) // If this variable has dofs at this node
     243      437538 :       for (unsigned int comp = 0;
     244      437538 :            comp < to_object->n_comp(to_var.sys().number(), to_var.number() + vc);
     245             :            ++comp)
     246             :       {
     247      228147 :         dof_id_type dof = to_object->dof_number(to_var.sys().number(), to_var.number() + vc, comp);
     248             :         dof_id_type from_dof =
     249      228147 :             from_object->dof_number(from_var.sys().number(), from_var.number() + vc, comp);
     250      228147 :         Real from_value = from_solution(from_dof);
     251      228147 :         to_solution.set(dof, from_value);
     252             :       }
     253      220371 : }

Generated by: LCOV version 1.14