LCOV - code coverage report
Current view: top level - src/actions - ThermalContactAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose heat_transfer: #31653 (2d163b) with base 0cc44f Lines: 209 214 97.7 %
Date: 2025-11-04 20:39:44 Functions: 10 10 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 "ThermalContactAction.h"
      11             : 
      12             : #include "AddVariableAction.h"
      13             : #include "FEProblem.h"
      14             : #include "GapHeatTransfer.h"
      15             : #include "libmesh/string_to_enum.h"
      16             : #include "GapConductance.h"
      17             : #include "GapConductanceConstant.h"
      18             : #include "NonlinearSystem.h"
      19             : 
      20             : // Counter for naming materials
      21             : static unsigned int materials_counter = 0;
      22             : 
      23             : // Counter for naming dirac kernels
      24             : static unsigned int dirac_counter = 0;
      25             : 
      26             : // Counter for naming BCs
      27             : static unsigned int bcs_counter = 0;
      28             : 
      29             : // Counter for naming aux kernels
      30             : static unsigned int aux_kenels_counter = 0;
      31             : 
      32             : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_aux_kernel");
      33             : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_aux_variable");
      34             : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_bc");
      35             : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_dirac_kernel");
      36             : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_material");
      37             : registerMooseAction("HeatTransferApp", ThermalContactAction, "add_secondary_flux_vector");
      38             : 
      39             : InputParameters
      40        6508 : ThermalContactAction::validParams()
      41             : {
      42        6508 :   InputParameters params = Action::validParams();
      43        6508 :   params.addClassDescription(
      44             :       "Action that controls the creation of all of the necessary objects for "
      45             :       "calculation of Thermal Contact");
      46             : 
      47       13016 :   params.addParam<std::string>(
      48             :       "gap_aux_type",
      49             :       "GapValueAux",
      50             :       "A string representing the Moose object that will be used for computing the gap size");
      51       13016 :   params.addRequiredParam<NonlinearVariableName>("variable", "The variable for thermal contact");
      52       13016 :   params.addParam<std::vector<BoundaryName>>(
      53             :       "primary", "The list of boundary IDs referring to primary sidesets");
      54       13016 :   params.addRequiredParam<std::vector<BoundaryName>>(
      55             :       "secondary", "The list of boundary IDs referring to secondary sidesets");
      56       13016 :   params.addRangeCheckedParam<Real>("tangential_tolerance",
      57             :                                     "tangential_tolerance>=0",
      58             :                                     "Tangential distance to extend edges of contact surfaces");
      59       13016 :   params.addRangeCheckedParam<Real>(
      60             :       "normal_smoothing_distance",
      61             :       "normal_smoothing_distance>=0 & normal_smoothing_distance<=1",
      62             :       "Distance from edge in parametric coordinates over which to smooth contact normal");
      63       13016 :   params.addParam<std::string>("normal_smoothing_method",
      64             :                                "Method to use to smooth normals (edge_based|nodal_normal_based)");
      65             : 
      66        6508 :   MooseEnum orders(AddVariableAction::getNonlinearVariableOrders());
      67       13016 :   params.addParam<MooseEnum>("order", orders, "The finite element order");
      68             : 
      69       13016 :   params.addParam<bool>(
      70       13016 :       "warnings", false, "Whether to output warning messages concerning nodes not being found");
      71       13016 :   params.addParam<bool>(
      72       13016 :       "quadrature", false, "Whether or not to use quadrature point based gap heat transfer");
      73       19524 :   params.addRangeCheckedParam<Real>("penalty",
      74       13016 :                                     1e3,
      75             :                                     "penalty>0",
      76             :                                     "The penalty used in the residual and Jacobian calculations "
      77             :                                     "when using the GapPerfectConductance model");
      78       13016 :   params.addParam<std::string>(
      79             :       "appended_property_name", "", "Name appended to material properties to make them unique");
      80       13016 :   params.addRequiredParam<std::string>(
      81             :       "type",
      82             :       "A string representing the Moose object that will be used for heat conduction over the gap");
      83             : 
      84       13016 :   params.addParam<std::vector<VariableName>>(
      85             :       "displacements",
      86             :       "The displacements appropriate for the simulation geometry and coordinate system");
      87             : 
      88       13016 :   params.addParam<std::vector<AuxVariableName>>(
      89             :       "save_in", {}, "The Auxiliary Variable to (optionally) save the boundary flux in");
      90       19524 :   params.addRangeCheckedParam<Real>("gap_conductivity",
      91       13016 :                                     1.0,
      92             :                                     "gap_conductivity>0",
      93             :                                     "The thermal conductivity of the gap material");
      94       13016 :   params.addParam<FunctionName>(
      95             :       "gap_conductivity_function",
      96             :       "Thermal conductivity of the gap material as a function.  Multiplied by gap_conductivity.");
      97       13016 :   params.addParam<std::vector<VariableName>>(
      98             :       "gap_conductivity_function_variable",
      99             :       "Variable to be used in gap_conductivity_function in place of time");
     100       13016 :   params.addParam<VariableName>("secondary_gap_offset",
     101             :                                 "Offset to gap distance from secondary side");
     102       13016 :   params.addParam<VariableName>("mapped_primary_gap_offset",
     103             :                                 "Offset to gap distance mapped from primary side");
     104       13016 :   params.addParam<bool>(
     105             :       "check_boundary_restricted",
     106       13016 :       true,
     107             :       "Whether to check for multiple element sides on the boundary for the boundary restricted, "
     108             :       "element aux variable set up for thermal contact enforcement. Setting this to false will "
     109             :       "allow contribution to a single element's elemental value(s) from multiple boundary sides "
     110             :       "on the same element (example: when the restricted boundary exists on two or more sides "
     111             :       "of an element, such as at a corner of a mesh");
     112             : 
     113        6508 :   params += GapConductance::actionParameters();
     114        6508 :   params += GapConductanceConstant::actionParameters();
     115             : 
     116        6508 :   params += GeometricSearchInterface::validParams();
     117             : 
     118       13016 :   params.addParamNamesToGroup("primary secondary", "Gap surface definition");
     119       13016 :   params.addParamNamesToGroup(
     120             :       "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
     121             :       "Gap edge and edge normal smoothing");
     122       13016 :   params.addParamNamesToGroup("gap_aux_type secondary_gap_offset mapped_primary_gap_offset",
     123             :                               "Gap size");
     124       13016 :   params.addParamNamesToGroup("order quadrature", "Integration");
     125       13016 :   params.addParamNamesToGroup(
     126             :       "gap_conductivity gap_conductivity_function gap_conductivity_function_variable",
     127             :       "Gap conductivity");
     128       13016 :   params.addParamNamesToGroup("save_in check_boundary_restricted warnings",
     129             :                               "Diagnostics and debug");
     130             : 
     131        6508 :   return params;
     132        6508 : }
     133             : 
     134        6508 : ThermalContactAction::ThermalContactAction(const InputParameters & params)
     135             :   : Action(params),
     136        6508 :     _quadrature(getParam<bool>("quadrature")),
     137       13016 :     _order(getParam<MooseEnum>("order")),
     138        6508 :     _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
     139       13016 :     _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
     140       13016 :     _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable")),
     141       19524 :     _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary"))
     142             : {
     143        6508 :   if (!params.get<bool>("check_boundary_restricted"))
     144             :   {
     145          50 :     if (_quadrature)
     146          96 :       paramInfo(
     147             :           "check_boundary_restricted",
     148             :           "This parameter is set to 'false'. Although thermal contact ",
     149             :           "will be correctly enforced, the contact-related output may have issues ",
     150             :           "in cases where where more than one face of an element belongs to a contact surface ",
     151             :           "because the values from only one of the faces will be reported.");
     152             :     else
     153           2 :       paramError("check_boundary_restricted",
     154             :                  "This parameter cannot be 'false' when 'quadrature=false'");
     155             :   }
     156       13128 :   if (params.isParamSetByUser("penalty") &&
     157        6738 :       getParam<std::string>("type") != "GapPerfectConductance")
     158           2 :     paramError("penalty",
     159             :                "This parameter should only be set by the user when 'type=GapPerfectConductance'.");
     160        6504 : }
     161             : 
     162             : void
     163        6464 : ThermalContactAction::act()
     164             : {
     165        6464 :   if (_current_task == "add_aux_kernel")
     166        1077 :     addAuxKernels();
     167        5387 :   else if (_current_task == "add_aux_variable")
     168        1079 :     addAuxVariables();
     169        4308 :   else if (_current_task == "add_bc")
     170        1075 :     addBCs();
     171        3233 :   else if (_current_task == "add_dirac_kernel")
     172        1075 :     addDiracKernels();
     173        2158 :   else if (_current_task == "add_material")
     174        1079 :     addMaterials();
     175        1079 :   else if (_current_task == "add_secondary_flux_vector")
     176        1079 :     addSecondaryFluxVector();
     177        6460 : }
     178             : 
     179             : void
     180        1077 : ThermalContactAction::addAuxKernels()
     181             : {
     182        2171 :   for (const auto & contact_pair : _boundary_pairs)
     183             :   {
     184             :     // Add gap aux kernel
     185             :     {
     186        2192 :       InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));
     187             : 
     188        1096 :       params.applySpecificParameters(parameters(),
     189             :                                      {"tangential_tolerance",
     190             :                                       "normal_smoothing_distance",
     191             :                                       "normal_smoothing_method",
     192             :                                       "order",
     193             :                                       "warnings",
     194             :                                       "search_method",
     195             :                                       "check_boundary_restricted"});
     196        1096 :       params.set<AuxVariableName>("variable") = _gap_value_name;
     197        4384 :       params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
     198             : 
     199        3288 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     200        1096 :       params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     201        3288 :       params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");
     202             : 
     203        4382 :       _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
     204        3286 :                              "gap_value_" + name() + "_" + Moose::stringify(aux_kenels_counter),
     205             :                              params);
     206             : 
     207        1094 :       if (_quadrature)
     208             :       {
     209        1932 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     210         644 :         params.set<BoundaryName>("paired_boundary") = contact_pair.second;
     211             : 
     212        2576 :         _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
     213        1932 :                                "gap_value_primary_" + name() + "_" +
     214        1288 :                                    Moose::stringify(aux_kenels_counter),
     215             :                                params);
     216             :       }
     217        1094 :     }
     218             : 
     219             :     // Add penetration aux kernel
     220             :     {
     221        1094 :       InputParameters params = _factory.getValidParams("PenetrationAux");
     222             : 
     223        1094 :       params.applySpecificParameters(parameters(),
     224             :                                      {"tangential_tolerance",
     225             :                                       "normal_smoothing_distance",
     226             :                                       "normal_smoothing_method",
     227             :                                       "order",
     228             :                                       "search_method",
     229             :                                       "check_boundary_restricted"});
     230        1094 :       params.set<AuxVariableName>("variable") = _penetration_var_name;
     231        2188 :       if (isParamValid("secondary_gap_offset"))
     232           0 :         params.set<std::vector<VariableName>>("secondary_gap_offset") = {
     233           0 :             getParam<VariableName>("secondary_gap_offset")};
     234        2188 :       if (isParamValid("mapped_primary_gap_offset"))
     235           0 :         params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
     236           0 :             getParam<VariableName>("mapped_primary_gap_offset")};
     237        4376 :       params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
     238        3282 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     239        1094 :       params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     240             : 
     241        3282 :       _problem->addAuxKernel("PenetrationAux",
     242        3282 :                              "penetration_" + name() + "_" + Moose::stringify(aux_kenels_counter++),
     243             :                              params);
     244        1094 :     }
     245             :   }
     246        3265 : }
     247             : 
     248             : void
     249        1079 : ThermalContactAction::addAuxVariables()
     250             : {
     251             :   // We need to add variables only once per variable name.  However, we don't know how many unique
     252             :   // variable names we will have.  So, we'll always add them.
     253             : 
     254        2158 :   auto order = getParam<MooseEnum>("order");
     255        1079 :   std::string family = "LAGRANGE";
     256             : 
     257        1079 :   if (_quadrature)
     258             :   {
     259        1296 :     order = "CONSTANT";
     260             :     family = "MONOMIAL";
     261             :   }
     262             : 
     263             :   auto var_type =
     264        1079 :       AddVariableAction::variableType(FEType(order, Utility::string_to_enum<FEFamily>(family)));
     265        1079 :   auto var_params = _factory.getValidParams(var_type);
     266        1079 :   var_params.set<MooseEnum>("order") = order;
     267        1079 :   var_params.set<MooseEnum>("family") = family;
     268             : 
     269        1079 :   _problem->addAuxVariable(var_type, _penetration_var_name, var_params);
     270        1079 :   _problem->addAuxVariable(var_type, _gap_value_name, var_params);
     271        2158 : }
     272             : 
     273             : void
     274        1075 : ThermalContactAction::addBCs()
     275             : {
     276        2169 :   for (const auto & contact_pair : _boundary_pairs)
     277             :   {
     278        2188 :     const std::string object_name = getParam<std::string>("type");
     279        1094 :     InputParameters params = _factory.getValidParams(object_name);
     280        1094 :     params.applyParameters(parameters());
     281             : 
     282        1094 :     if (object_name == "GapPerfectConductance")
     283             :     {
     284          38 :       params.set<Real>("penalty") = getParam<Real>("penalty");
     285          57 :       params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
     286          57 :       params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
     287          57 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     288          38 :       _problem->addBoundaryCondition(
     289          57 :           object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
     290             :     }
     291             :     else
     292             :     {
     293        1075 :       if (_quadrature)
     294             :       {
     295         644 :         params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     296         644 :         params.set<bool>("use_displaced_mesh") = true;
     297             :       }
     298             :       else
     299             :       {
     300        1293 :         params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
     301        1293 :         params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
     302             :       }
     303             : 
     304        3225 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     305             : 
     306        2150 :       _problem->addBoundaryCondition(
     307        3225 :           object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
     308             : 
     309        1075 :       if (_quadrature)
     310             :       {
     311             :         // Swap primary and secondary for this one
     312        1932 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     313         644 :         params.set<BoundaryName>("paired_boundary") = contact_pair.second;
     314             : 
     315        1288 :         _problem->addBoundaryCondition(
     316        1932 :             object_name, "gap_bc_primary_" + name() + "_" + Moose::stringify(bcs_counter), params);
     317             :       }
     318             :     }
     319        1094 :     bcs_counter++;
     320        1094 :   }
     321        1525 : }
     322             : 
     323             : void
     324        1075 : ThermalContactAction::addDiracKernels()
     325             : {
     326        1075 :   if (_quadrature)
     327             :     return;
     328             : 
     329         881 :   for (const auto & contact_pair : _boundary_pairs)
     330             :   {
     331         450 :     const std::string object_name = "GapHeatPointSourceMaster";
     332         450 :     InputParameters params = _factory.getValidParams(object_name);
     333         450 :     params.applySpecificParameters(parameters(),
     334             :                                    {"tangential_tolerance",
     335             :                                     "normal_smoothing_distance",
     336             :                                     "normal_smoothing_method",
     337             :                                     "order",
     338             :                                     "search_method",
     339             :                                     "variable"});
     340         450 :     params.set<BoundaryName>("boundary") = contact_pair.first;
     341         450 :     params.set<BoundaryName>("secondary") = contact_pair.second;
     342             : 
     343         900 :     _problem->addDiracKernel(
     344        1350 :         object_name, object_name + "_" + name() + "_" + Moose::stringify(dirac_counter++), params);
     345         450 :   }
     346             : }
     347             : 
     348             : void
     349        1079 : ThermalContactAction::addMaterials()
     350             : {
     351        2158 :   if (getParam<std::string>("type") != "GapHeatTransfer")
     352             :     return;
     353             : 
     354        2120 :   if (parameters().isParamSetByUser("gap_conductance"))
     355             :   {
     356         114 :     if (parameters().isParamSetByUser("gap_conductivity") ||
     357         114 :         parameters().isParamSetByUser("gap_conductivity_function"))
     358           0 :       mooseError(
     359             :           "Cannot specify both gap_conductance and gap_conductivity or gap_conductivity_function");
     360             : 
     361         133 :     for (const auto & contact_pair : _boundary_pairs)
     362             :     {
     363          76 :       const std::string object_type = "GapConductanceConstant";
     364          76 :       InputParameters params = _factory.getValidParams(object_type);
     365          76 :       params.applyParameters(parameters());
     366         228 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     367         152 :       _problem->addMaterial(object_type,
     368         228 :                             name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
     369             :                             params);
     370             : 
     371          76 :       if (_quadrature)
     372             :       {
     373          57 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     374          38 :         _problem->addMaterial(object_type,
     375          57 :                               name() + "_" + "gap_value_primary" + "_" +
     376          38 :                                   Moose::stringify(materials_counter),
     377             :                               params);
     378             :       }
     379          76 :       materials_counter++;
     380          76 :     }
     381             :   }
     382             :   else
     383             :   {
     384        1003 :     const std::string object_type = "GapConductance";
     385             : 
     386        2004 :     for (const auto & contact_pair : _boundary_pairs)
     387             :     {
     388        1003 :       InputParameters params = _factory.getValidParams(object_type);
     389        1003 :       params.applyParameters(parameters(), {"variable"});
     390             : 
     391        2006 :       params.set<std::vector<VariableName>>("variable") = {
     392        6018 :           getParam<NonlinearVariableName>("variable")};
     393        3009 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     394             : 
     395        1003 :       if (_quadrature)
     396        1258 :         params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     397             :       else
     398             :       {
     399        1122 :         params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
     400        1122 :         params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
     401             :       }
     402             : 
     403        2006 :       _problem->addMaterial(object_type,
     404        3007 :                             name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
     405             :                             params);
     406             : 
     407        1001 :       if (_quadrature)
     408             :       {
     409        1254 :         params.set<BoundaryName>("paired_boundary") = contact_pair.second;
     410        1881 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     411             : 
     412        1254 :         _problem->addMaterial(object_type,
     413        1881 :                               name() + "_" + "gap_value_primary" + "_" +
     414        1254 :                                   Moose::stringify(materials_counter),
     415             :                               params);
     416             :       }
     417        1001 :       materials_counter++;
     418        1001 :     }
     419             :   }
     420        1377 : }
     421             : 
     422             : void
     423        1079 : ThermalContactAction::addSecondaryFluxVector()
     424             : {
     425        1079 :   _problem->getNonlinearSystemBase(/*nl_sys_num=*/0)
     426        1079 :       .addVector("secondary_flux", false, libMesh::GHOSTED);
     427        1079 :   _problem->getNonlinearSystemBase(/*nl_sys_num=*/0).zeroVectorForResidual("secondary_flux");
     428             : 
     429             :   // It is risky to apply this optimization to contact problems
     430             :   // since the problem configuration may be changed during Jacobian
     431             :   // evaluation. We therefore turn it off for all contact problems so that
     432             :   // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
     433        1079 :   if (!_problem->isSNESMFReuseBaseSetbyUser())
     434             :     _problem->setSNESMFReuseBase(false, false);
     435        1079 : }
     436             : 
     437             : void
     438       19404 : ThermalContactAction::addRelationshipManagers(Moose::RelationshipManagerType input_rm_type)
     439             : {
     440       19404 :   if (!_quadrature)
     441             :     return;
     442             : 
     443       23292 :   for (const auto & contact_pair : _boundary_pairs)
     444             :   {
     445       11646 :     const auto & object_name = getParam<std::string>("type");
     446       11646 :     auto params = _factory.getValidParams(object_name);
     447       11646 :     params.applyParameters(parameters());
     448             : 
     449       11646 :     params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     450       11646 :     params.set<bool>("use_displaced_mesh") = true;
     451       34938 :     params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     452       11646 :     addRelationshipManagers(input_rm_type, params);
     453       11646 :   }
     454             : }

Generated by: LCOV version 1.14