LCOV - code coverage report
Current view: top level - src/actions - ThermalContactAction.C (source / functions) Hit Total Coverage
Test: idaholab/moose heat_transfer: #31405 (292dce) with base fef103 Lines: 208 213 97.7 %
Date: 2025-09-04 07:53:51 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       13016 :   params.addParamNamesToGroup("primary secondary", "Gap surface definition");
     117       13016 :   params.addParamNamesToGroup(
     118             :       "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
     119             :       "Gap edge and edge normal smoothing");
     120       13016 :   params.addParamNamesToGroup("gap_aux_type secondary_gap_offset mapped_primary_gap_offset",
     121             :                               "Gap size");
     122       13016 :   params.addParamNamesToGroup("order quadrature", "Integration");
     123       13016 :   params.addParamNamesToGroup(
     124             :       "gap_conductivity gap_conductivity_function gap_conductivity_function_variable",
     125             :       "Gap conductivity");
     126       13016 :   params.addParamNamesToGroup("save_in check_boundary_restricted warnings",
     127             :                               "Diagnostics and debug");
     128             : 
     129        6508 :   return params;
     130        6508 : }
     131             : 
     132        6508 : ThermalContactAction::ThermalContactAction(const InputParameters & params)
     133             :   : Action(params),
     134        6508 :     _quadrature(getParam<bool>("quadrature")),
     135       13016 :     _order(getParam<MooseEnum>("order")),
     136        6508 :     _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
     137       13016 :     _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
     138       13016 :     _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable")),
     139       19524 :     _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary"))
     140             : {
     141        6508 :   if (!params.get<bool>("check_boundary_restricted"))
     142             :   {
     143          50 :     if (_quadrature)
     144          96 :       paramInfo(
     145             :           "check_boundary_restricted",
     146             :           "This parameter is set to 'false'. Although thermal contact ",
     147             :           "will be correctly enforced, the contact-related output may have issues ",
     148             :           "in cases where where more than one face of an element belongs to a contact surface ",
     149             :           "because the values from only one of the faces will be reported.");
     150             :     else
     151           2 :       paramError("check_boundary_restricted",
     152             :                  "This parameter cannot be 'false' when 'quadrature=false'");
     153             :   }
     154       13128 :   if (params.isParamSetByUser("penalty") &&
     155        6738 :       getParam<std::string>("type") != "GapPerfectConductance")
     156           2 :     paramError("penalty",
     157             :                "This parameter should only be set by the user when 'type=GapPerfectConductance'.");
     158        6504 : }
     159             : 
     160             : void
     161        6464 : ThermalContactAction::act()
     162             : {
     163        6464 :   if (_current_task == "add_aux_kernel")
     164        1077 :     addAuxKernels();
     165        5387 :   else if (_current_task == "add_aux_variable")
     166        1079 :     addAuxVariables();
     167        4308 :   else if (_current_task == "add_bc")
     168        1075 :     addBCs();
     169        3233 :   else if (_current_task == "add_dirac_kernel")
     170        1075 :     addDiracKernels();
     171        2158 :   else if (_current_task == "add_material")
     172        1079 :     addMaterials();
     173        1079 :   else if (_current_task == "add_secondary_flux_vector")
     174        1079 :     addSecondaryFluxVector();
     175        6460 : }
     176             : 
     177             : void
     178        1077 : ThermalContactAction::addAuxKernels()
     179             : {
     180        2171 :   for (const auto & contact_pair : _boundary_pairs)
     181             :   {
     182             :     // Add gap aux kernel
     183             :     {
     184        2192 :       InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));
     185             : 
     186        1096 :       params.applySpecificParameters(parameters(),
     187             :                                      {"tangential_tolerance",
     188             :                                       "normal_smoothing_distance",
     189             :                                       "normal_smoothing_method",
     190             :                                       "order",
     191             :                                       "warnings",
     192             :                                       "check_boundary_restricted"});
     193        1096 :       params.set<AuxVariableName>("variable") = _gap_value_name;
     194        4384 :       params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
     195             : 
     196        3288 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     197        1096 :       params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     198        3288 :       params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");
     199             : 
     200        4382 :       _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
     201        3286 :                              "gap_value_" + name() + "_" + Moose::stringify(aux_kenels_counter),
     202             :                              params);
     203             : 
     204        1094 :       if (_quadrature)
     205             :       {
     206        1932 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     207         644 :         params.set<BoundaryName>("paired_boundary") = contact_pair.second;
     208             : 
     209        2576 :         _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
     210        1932 :                                "gap_value_primary_" + name() + "_" +
     211        1288 :                                    Moose::stringify(aux_kenels_counter),
     212             :                                params);
     213             :       }
     214        1094 :     }
     215             : 
     216             :     // Add penetration aux kernel
     217             :     {
     218        1094 :       InputParameters params = _factory.getValidParams("PenetrationAux");
     219             : 
     220        1094 :       params.applySpecificParameters(parameters(),
     221             :                                      {"tangential_tolerance",
     222             :                                       "normal_smoothing_distance",
     223             :                                       "normal_smoothing_method",
     224             :                                       "order",
     225             :                                       "check_boundary_restricted"});
     226        1094 :       params.set<AuxVariableName>("variable") = _penetration_var_name;
     227        2188 :       if (isParamValid("secondary_gap_offset"))
     228           0 :         params.set<std::vector<VariableName>>("secondary_gap_offset") = {
     229           0 :             getParam<VariableName>("secondary_gap_offset")};
     230        2188 :       if (isParamValid("mapped_primary_gap_offset"))
     231           0 :         params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
     232           0 :             getParam<VariableName>("mapped_primary_gap_offset")};
     233        4376 :       params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
     234        3282 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     235        1094 :       params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     236             : 
     237        3282 :       _problem->addAuxKernel("PenetrationAux",
     238        3282 :                              "penetration_" + name() + "_" + Moose::stringify(aux_kenels_counter++),
     239             :                              params);
     240        1094 :     }
     241             :   }
     242        3265 : }
     243             : 
     244             : void
     245        1079 : ThermalContactAction::addAuxVariables()
     246             : {
     247             :   // We need to add variables only once per variable name.  However, we don't know how many unique
     248             :   // variable names we will have.  So, we'll always add them.
     249             : 
     250        2158 :   auto order = getParam<MooseEnum>("order");
     251        1079 :   std::string family = "LAGRANGE";
     252             : 
     253        1079 :   if (_quadrature)
     254             :   {
     255        1296 :     order = "CONSTANT";
     256             :     family = "MONOMIAL";
     257             :   }
     258             : 
     259             :   auto var_type =
     260        1079 :       AddVariableAction::variableType(FEType(order, Utility::string_to_enum<FEFamily>(family)));
     261        1079 :   auto var_params = _factory.getValidParams(var_type);
     262        1079 :   var_params.set<MooseEnum>("order") = order;
     263        1079 :   var_params.set<MooseEnum>("family") = family;
     264             : 
     265        1079 :   _problem->addAuxVariable(var_type, _penetration_var_name, var_params);
     266        1079 :   _problem->addAuxVariable(var_type, _gap_value_name, var_params);
     267        2158 : }
     268             : 
     269             : void
     270        1075 : ThermalContactAction::addBCs()
     271             : {
     272        2169 :   for (const auto & contact_pair : _boundary_pairs)
     273             :   {
     274        2188 :     const std::string object_name = getParam<std::string>("type");
     275        1094 :     InputParameters params = _factory.getValidParams(object_name);
     276        1094 :     params.applyParameters(parameters());
     277             : 
     278        1094 :     if (object_name == "GapPerfectConductance")
     279             :     {
     280          38 :       params.set<Real>("penalty") = getParam<Real>("penalty");
     281          57 :       params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
     282          57 :       params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
     283          57 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     284          38 :       _problem->addBoundaryCondition(
     285          57 :           object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
     286             :     }
     287             :     else
     288             :     {
     289        1075 :       if (_quadrature)
     290             :       {
     291         644 :         params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     292         644 :         params.set<bool>("use_displaced_mesh") = true;
     293             :       }
     294             :       else
     295             :       {
     296        1293 :         params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
     297        1293 :         params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
     298             :       }
     299             : 
     300        3225 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     301             : 
     302        2150 :       _problem->addBoundaryCondition(
     303        3225 :           object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
     304             : 
     305        1075 :       if (_quadrature)
     306             :       {
     307             :         // Swap primary and secondary for this one
     308        1932 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     309         644 :         params.set<BoundaryName>("paired_boundary") = contact_pair.second;
     310             : 
     311        1288 :         _problem->addBoundaryCondition(
     312        1932 :             object_name, "gap_bc_primary_" + name() + "_" + Moose::stringify(bcs_counter), params);
     313             :       }
     314             :     }
     315        1094 :     bcs_counter++;
     316        1094 :   }
     317        1525 : }
     318             : 
     319             : void
     320        1075 : ThermalContactAction::addDiracKernels()
     321             : {
     322        1075 :   if (_quadrature)
     323             :     return;
     324             : 
     325         881 :   for (const auto & contact_pair : _boundary_pairs)
     326             :   {
     327         450 :     const std::string object_name = "GapHeatPointSourceMaster";
     328         450 :     InputParameters params = _factory.getValidParams(object_name);
     329         450 :     params.applySpecificParameters(parameters(),
     330             :                                    {"tangential_tolerance",
     331             :                                     "normal_smoothing_distance",
     332             :                                     "normal_smoothing_method",
     333             :                                     "order",
     334             :                                     "variable"});
     335         450 :     params.set<BoundaryName>("boundary") = contact_pair.first;
     336         450 :     params.set<BoundaryName>("secondary") = contact_pair.second;
     337             : 
     338         900 :     _problem->addDiracKernel(
     339        1350 :         object_name, object_name + "_" + name() + "_" + Moose::stringify(dirac_counter++), params);
     340         450 :   }
     341             : }
     342             : 
     343             : void
     344        1079 : ThermalContactAction::addMaterials()
     345             : {
     346        2158 :   if (getParam<std::string>("type") != "GapHeatTransfer")
     347             :     return;
     348             : 
     349        2120 :   if (parameters().isParamSetByUser("gap_conductance"))
     350             :   {
     351         114 :     if (parameters().isParamSetByUser("gap_conductivity") ||
     352         114 :         parameters().isParamSetByUser("gap_conductivity_function"))
     353           0 :       mooseError(
     354             :           "Cannot specify both gap_conductance and gap_conductivity or gap_conductivity_function");
     355             : 
     356         133 :     for (const auto & contact_pair : _boundary_pairs)
     357             :     {
     358          76 :       const std::string object_type = "GapConductanceConstant";
     359          76 :       InputParameters params = _factory.getValidParams(object_type);
     360          76 :       params.applyParameters(parameters());
     361         228 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     362         152 :       _problem->addMaterial(object_type,
     363         228 :                             name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
     364             :                             params);
     365             : 
     366          76 :       if (_quadrature)
     367             :       {
     368          57 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     369          38 :         _problem->addMaterial(object_type,
     370          57 :                               name() + "_" + "gap_value_primary" + "_" +
     371          38 :                                   Moose::stringify(materials_counter),
     372             :                               params);
     373             :       }
     374          76 :       materials_counter++;
     375          76 :     }
     376             :   }
     377             :   else
     378             :   {
     379        1003 :     const std::string object_type = "GapConductance";
     380             : 
     381        2004 :     for (const auto & contact_pair : _boundary_pairs)
     382             :     {
     383        1003 :       InputParameters params = _factory.getValidParams(object_type);
     384        1003 :       params.applyParameters(parameters(), {"variable"});
     385             : 
     386        2006 :       params.set<std::vector<VariableName>>("variable") = {
     387        6018 :           getParam<NonlinearVariableName>("variable")};
     388        3009 :       params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     389             : 
     390        1003 :       if (_quadrature)
     391        1258 :         params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     392             :       else
     393             :       {
     394        1122 :         params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
     395        1122 :         params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
     396             :       }
     397             : 
     398        2006 :       _problem->addMaterial(object_type,
     399        3007 :                             name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
     400             :                             params);
     401             : 
     402        1001 :       if (_quadrature)
     403             :       {
     404        1254 :         params.set<BoundaryName>("paired_boundary") = contact_pair.second;
     405        1881 :         params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
     406             : 
     407        1254 :         _problem->addMaterial(object_type,
     408        1881 :                               name() + "_" + "gap_value_primary" + "_" +
     409        1254 :                                   Moose::stringify(materials_counter),
     410             :                               params);
     411             :       }
     412        1001 :       materials_counter++;
     413        1001 :     }
     414             :   }
     415        1377 : }
     416             : 
     417             : void
     418        1079 : ThermalContactAction::addSecondaryFluxVector()
     419             : {
     420        1079 :   _problem->getNonlinearSystemBase(/*nl_sys_num=*/0)
     421        1079 :       .addVector("secondary_flux", false, libMesh::GHOSTED);
     422        1079 :   _problem->getNonlinearSystemBase(/*nl_sys_num=*/0).zeroVectorForResidual("secondary_flux");
     423             : 
     424             :   // It is risky to apply this optimization to contact problems
     425             :   // since the problem configuration may be changed during Jacobian
     426             :   // evaluation. We therefore turn it off for all contact problems so that
     427             :   // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
     428        1079 :   if (!_problem->isSNESMFReuseBaseSetbyUser())
     429             :     _problem->setSNESMFReuseBase(false, false);
     430        1079 : }
     431             : 
     432             : void
     433       19404 : ThermalContactAction::addRelationshipManagers(Moose::RelationshipManagerType input_rm_type)
     434             : {
     435       19404 :   if (!_quadrature)
     436             :     return;
     437             : 
     438       23292 :   for (const auto & contact_pair : _boundary_pairs)
     439             :   {
     440       11646 :     const auto & object_name = getParam<std::string>("type");
     441       11646 :     auto params = _factory.getValidParams(object_name);
     442       11646 :     params.applyParameters(parameters());
     443             : 
     444       11646 :     params.set<BoundaryName>("paired_boundary") = contact_pair.first;
     445       11646 :     params.set<bool>("use_displaced_mesh") = true;
     446       34938 :     params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
     447       11646 :     addRelationshipManagers(input_rm_type, params);
     448       11646 :   }
     449             : }

Generated by: LCOV version 1.14