LCOV - code coverage report
Current view: top level - src/transfers - MultiAppDofCopyTransfer.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 116 124 93.5 %
Date: 2025-07-17 01:28:37 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       15405 : MultiAppDofCopyTransfer::validParams()
      23             : {
      24       15405 :   InputParameters params = MultiAppFieldTransfer::validParams();
      25             : 
      26       15405 :   params.addParam<TagName>(
      27             :       "from_solution_tag",
      28             :       "The tag of the solution vector to be transferred (default to the solution)");
      29       15405 :   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       15405 :   params.addParam<std::vector<SubdomainName>>(
      35             :       "from_blocks",
      36             :       {},
      37             :       "Subdomain restriction to transfer from (defaults to all the origin app domain)");
      38       15405 :   params.addParam<std::vector<SubdomainName>>(
      39             :       "to_blocks",
      40             :       {},
      41             :       "Subdomain restriction to transfer to, (defaults to all the target app domain)");
      42             : 
      43       15405 :   params.addClassDescription(
      44             :       "Base class for copying degrees-of-freedom values (nonlinear and auxiliary) between apps "
      45             :       "that have identical meshes.");
      46       15405 :   return params;
      47           0 : }
      48             : 
      49         576 : MultiAppDofCopyTransfer::MultiAppDofCopyTransfer(const InputParameters & parameters)
      50             :   : MultiAppFieldTransfer(parameters),
      51        1652 :     _has_block_restrictions(!getParam<std::vector<SubdomainName>>("from_blocks").empty() ||
      52        2228 :                             !getParam<std::vector<SubdomainName>>("to_blocks").empty())
      53             : {
      54         564 : }
      55             : 
      56             : void
      57         528 : MultiAppDofCopyTransfer::initialSetup()
      58             : {
      59         528 :   MultiAppFieldTransfer::initialSetup();
      60             : 
      61             :   const FEProblemBase * from_problem;
      62             :   const FEProblemBase * to_problem;
      63             : 
      64         520 :   if (_current_direction == FROM_MULTIAPP)
      65             :   {
      66             :     // Subdomain and variable type information is shared on all subapps
      67         268 :     from_problem = &getFromMultiApp()->appProblemBase(getFromMultiApp()->firstLocalApp());
      68         268 :     to_problem = &getFromMultiApp()->problemBase();
      69             :   }
      70         252 :   else if (_current_direction == TO_MULTIAPP)
      71             :   {
      72         242 :     from_problem = &getToMultiApp()->problemBase();
      73         242 :     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         520 :   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         520 :   if (_has_block_restrictions)
      86             :   {
      87          76 :     const auto & from_block_names = getParam<std::vector<SubdomainName>>("from_blocks");
      88         108 :     for (const auto & b : from_block_names)
      89          40 :       if (!MooseMeshUtils::hasSubdomainName(const_cast<MeshBase &>(from_problem->mesh().getMesh()),
      90             :                                             b))
      91           8 :         paramError("from_blocks", "The block '", b, "' was not found in the mesh");
      92             : 
      93          68 :     if (from_block_names.size())
      94             :     {
      95          32 :       if (from_problem)
      96             :       {
      97          32 :         const auto block_vec = from_problem->mesh().getSubdomainIDs(from_block_names);
      98          32 :         _from_blocks = std::set<SubdomainID>(block_vec.begin(), block_vec.end());
      99          32 :       }
     100             :       // We dont even own any of these subapps
     101             :       else
     102           0 :         _from_blocks = {Moose::INVALID_BLOCK_ID};
     103             :     }
     104             :     else
     105          36 :       _from_blocks = from_problem->mesh().meshSubdomains();
     106             : 
     107          68 :     const auto & to_block_names = getParam<std::vector<SubdomainName>>("to_blocks");
     108          96 :     for (const auto & b : to_block_names)
     109          36 :       if (!MooseMeshUtils::hasSubdomainName(const_cast<MeshBase &>(to_problem->mesh().getMesh()),
     110             :                                             b))
     111           8 :         paramError("to_blocks", "The block '", b, "' was not found in the mesh");
     112             : 
     113          60 :     if (to_block_names.size())
     114             :     {
     115          28 :       if (to_problem)
     116             :       {
     117          28 :         const auto block_vec = to_problem->mesh().getSubdomainIDs(to_block_names);
     118          28 :         _to_blocks = std::set<SubdomainID>(block_vec.begin(), block_vec.end());
     119          28 :       }
     120             :       // We dont even own any of these subapps
     121             :       else
     122           0 :         _from_blocks = {Moose::INVALID_BLOCK_ID};
     123             :     }
     124             :     else
     125          32 :       _to_blocks = to_problem->mesh().meshSubdomains();
     126             :   }
     127             : 
     128             :   // Forbid block restriction on nodal variables as currently not supported
     129         504 :   if (_from_blocks.size())
     130         112 :     for (auto & from_var : getFromVarNames())
     131          60 :       if (from_problem
     132          60 :               ->getVariable(
     133             :                   0, from_var, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY)
     134          60 :               .hasDoFsOnNodes())
     135          60 :         paramError("from_blocks", "Block restriction is not implemented for nodal variables");
     136         496 :   if (_to_blocks.size())
     137         104 :     for (auto & to_var : getToVarNames())
     138          52 :       if (to_problem
     139          52 :               ->getVariable(
     140             :                   0, to_var, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY)
     141          52 :               .hasDoFsOnNodes())
     142          52 :         paramError("to_blocks", "Block restriction is not implemented for nodal variables");
     143         496 : }
     144             : 
     145             : void
     146        1873 : MultiAppDofCopyTransfer::transfer(FEProblemBase & to_problem, FEProblemBase & from_problem)
     147             : {
     148             :   // Perform error checking
     149        1873 :   if (!getToVarNames().size())
     150           0 :     mooseError("No transferred variables were specified, neither programmatically or through the "
     151             :                "'source_variable' parameter");
     152        1873 :   if (getToVarNames().size() != getFromVarNames().size())
     153           0 :     mooseError("Number of variables transferred must be same in both systems.");
     154        3757 :   for (auto & to_var : getToVarNames())
     155        3757 :     checkVariable(to_problem, to_var);
     156        3753 :   for (auto & from_var : getFromVarNames())
     157        3753 :     checkVariable(from_problem, from_var);
     158             : 
     159        3741 :   for (unsigned int v = 0; v < getToVarNames().size(); ++v)
     160             :   {
     161             :     // Populate the to/from variables needed to perform the transfer
     162        1880 :     MooseVariableFEBase & to_var = to_problem.getVariable(
     163        3760 :         0, getToVarNames()[v], Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
     164        1880 :     MeshBase & to_mesh = to_problem.mesh().getMesh();
     165             : 
     166        1880 :     MooseVariableFEBase & from_var = from_problem.getVariable(
     167        3760 :         0, getFromVarNames()[v], Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
     168        1880 :     MeshBase & from_mesh = from_problem.mesh().getMesh();
     169             : 
     170        3760 :     auto & to_solution = isParamValid("to_solution_tag")
     171        3770 :                              ? to_var.sys().getVector(
     172          10 :                                    to_problem.getVectorTagID(getParam<TagName>("to_solution_tag")))
     173        1880 :                              : to_var.sys().solution();
     174        3760 :     auto & from_solution = isParamValid("from_solution_tag")
     175        3760 :                                ? from_var.sys().getVector(from_problem.getVectorTagID(
     176             :                                      getParam<TagName>("from_solution_tag")))
     177        1880 :                                : from_var.sys().solution();
     178             : 
     179             :     // Check integrity
     180        1880 :     if (to_var.feType() != from_var.feType())
     181          20 :       mooseError("MultiAppFieldTransfer '",
     182           4 :                  name(),
     183             :                  "'requires that the target variable '",
     184           4 :                  to_var.name(),
     185             :                  "' and the source variable'",
     186           4 :                  from_var.name(),
     187             :                  "' must be the same type "
     188             :                  "(order and family): ",
     189           4 :                  libMesh::Utility::enum_to_string<FEFamily>(to_var.feType().family),
     190           4 :                  moose::internal::incompatVarMsg(to_var, from_var));
     191        1876 :     if (to_var.fieldType() != from_var.fieldType())
     192           0 :       mooseError(
     193             :           "Corresponding transfer variables must be same field type (STANDARD | VECTOR | ARRAY).");
     194        1876 :     if (to_var.count() != from_var.count())
     195           0 :       mooseError("Corresponding transfer variables must have same number of components.");
     196             : 
     197        1876 :     if ((to_mesh.n_nodes() != from_mesh.n_nodes()) || (to_mesh.n_elem() != from_mesh.n_elem()))
     198           4 :       mooseError("The meshes must be identical to utilize MultiAppDofCopyTransfer::transfer.");
     199             : 
     200             :     // Transfer node dofs. Block restriction is not supported, forbidden in initialSetup
     201      233206 :     for (const auto & node : as_range(to_mesh.local_nodes_begin(), to_mesh.local_nodes_end()))
     202      231334 :       transferDofObject(
     203      233206 :           node, from_mesh.node_ptr(node->id()), to_var, from_var, to_solution, from_solution);
     204             : 
     205             :     // Transfer elem dofs
     206      181884 :     for (auto & to_elem : as_range(to_mesh.local_elements_begin(), to_mesh.local_elements_end()))
     207             :     {
     208       90006 :       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       90006 :       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       89334 :       transferDofObject(to_elem, from_elem, to_var, from_var, to_solution, from_solution);
     224        1872 :     }
     225             : 
     226        1872 :     to_solution.close();
     227        1872 :     to_var.sys().update();
     228             :   }
     229        1861 : }
     230             : 
     231             : void
     232      205001 : 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      563818 :   for (unsigned int vc = 0; vc < to_var.count(); ++vc)
     240             :     // Transfer from one solution vector to another
     241      358817 :     if (to_object->n_dofs(to_var.sys().number(), to_var.number() + vc) >
     242             :         0) // If this variable has dofs at this node
     243      413486 :       for (unsigned int comp = 0;
     244      413486 :            comp < to_object->n_comp(to_var.sys().number(), to_var.number() + vc);
     245             :            ++comp)
     246             :       {
     247      215671 :         dof_id_type dof = to_object->dof_number(to_var.sys().number(), to_var.number() + vc, comp);
     248             :         dof_id_type from_dof =
     249      215671 :             from_object->dof_number(from_var.sys().number(), from_var.number() + vc, comp);
     250      215671 :         Real from_value = from_solution(from_dof);
     251      215671 :         to_solution.set(dof, from_value);
     252             :       }
     253      205001 : }

Generated by: LCOV version 1.14