https://mooseframework.inl.gov
ThermalContactAction.C
Go to the documentation of this file.
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 
41 {
43  params.addClassDescription(
44  "Action that controls the creation of all of the necessary objects for "
45  "calculation of Thermal Contact");
46 
47  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  params.addRequiredParam<NonlinearVariableName>("variable", "The variable for thermal contact");
52  params.addParam<std::vector<BoundaryName>>(
53  "primary", "The list of boundary IDs referring to primary sidesets");
54  params.addRequiredParam<std::vector<BoundaryName>>(
55  "secondary", "The list of boundary IDs referring to secondary sidesets");
56  params.addRangeCheckedParam<Real>("tangential_tolerance",
57  "tangential_tolerance>=0",
58  "Tangential distance to extend edges of contact surfaces");
59  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  params.addParam<std::string>("normal_smoothing_method",
64  "Method to use to smooth normals (edge_based|nodal_normal_based)");
65 
67  params.addParam<MooseEnum>("order", orders, "The finite element order");
68 
69  params.addParam<bool>(
70  "warnings", false, "Whether to output warning messages concerning nodes not being found");
71  params.addParam<bool>(
72  "quadrature", false, "Whether or not to use quadrature point based gap heat transfer");
73  params.addRangeCheckedParam<Real>("penalty",
74  1e3,
75  "penalty>0",
76  "The penalty used in the residual and Jacobian calculations "
77  "when using the GapPerfectConductance model");
78  params.addParam<std::string>(
79  "appended_property_name", "", "Name appended to material properties to make them unique");
80  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  params.addParam<std::vector<VariableName>>(
85  "displacements",
86  "The displacements appropriate for the simulation geometry and coordinate system");
87 
88  params.addParam<std::vector<AuxVariableName>>(
89  "save_in", {}, "The Auxiliary Variable to (optionally) save the boundary flux in");
90  params.addRangeCheckedParam<Real>("gap_conductivity",
91  1.0,
92  "gap_conductivity>0",
93  "The thermal conductivity of the gap material");
94  params.addParam<FunctionName>(
95  "gap_conductivity_function",
96  "Thermal conductivity of the gap material as a function. Multiplied by gap_conductivity.");
97  params.addParam<std::vector<VariableName>>(
98  "gap_conductivity_function_variable",
99  "Variable to be used in gap_conductivity_function in place of time");
100  params.addParam<VariableName>("secondary_gap_offset",
101  "Offset to gap distance from secondary side");
102  params.addParam<VariableName>("mapped_primary_gap_offset",
103  "Offset to gap distance mapped from primary side");
104  params.addParam<bool>(
105  "check_boundary_restricted",
106  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 
115 
116  params.addParamNamesToGroup("primary secondary", "Gap surface definition");
117  params.addParamNamesToGroup(
118  "tangential_tolerance normal_smoothing_distance normal_smoothing_method",
119  "Gap edge and edge normal smoothing");
120  params.addParamNamesToGroup("gap_aux_type secondary_gap_offset mapped_primary_gap_offset",
121  "Gap size");
122  params.addParamNamesToGroup("order quadrature", "Integration");
123  params.addParamNamesToGroup(
124  "gap_conductivity gap_conductivity_function gap_conductivity_function_variable",
125  "Gap conductivity");
126  params.addParamNamesToGroup("save_in check_boundary_restricted warnings",
127  "Diagnostics and debug");
128 
129  return params;
130 }
131 
133  : Action(params),
134  _quadrature(getParam<bool>("quadrature")),
135  _order(getParam<MooseEnum>("order")),
136  _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
137  _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
138  _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable")),
139  _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary"))
140 {
141  if (!params.get<bool>("check_boundary_restricted"))
142  {
143  if (_quadrature)
144  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  paramError("check_boundary_restricted",
152  "This parameter cannot be 'false' when 'quadrature=false'");
153  }
154  if (params.isParamSetByUser("penalty") &&
155  getParam<std::string>("type") != "GapPerfectConductance")
156  paramError("penalty",
157  "This parameter should only be set by the user when 'type=GapPerfectConductance'.");
158 }
159 
160 void
162 {
163  if (_current_task == "add_aux_kernel")
164  addAuxKernels();
165  else if (_current_task == "add_aux_variable")
166  addAuxVariables();
167  else if (_current_task == "add_bc")
168  addBCs();
169  else if (_current_task == "add_dirac_kernel")
170  addDiracKernels();
171  else if (_current_task == "add_material")
172  addMaterials();
173  else if (_current_task == "add_secondary_flux_vector")
175 }
176 
177 void
179 {
180  for (const auto & contact_pair : _boundary_pairs)
181  {
182  // Add gap aux kernel
183  {
184  InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));
185 
187  {"tangential_tolerance",
188  "normal_smoothing_distance",
189  "normal_smoothing_method",
190  "order",
191  "warnings",
192  "check_boundary_restricted"});
193  params.set<AuxVariableName>("variable") = _gap_value_name;
194  params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
195 
196  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
197  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
198  params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");
199 
200  _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
201  "gap_value_" + name() + "_" + Moose::stringify(aux_kenels_counter),
202  params);
203 
204  if (_quadrature)
205  {
206  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
207  params.set<BoundaryName>("paired_boundary") = contact_pair.second;
208 
209  _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
210  "gap_value_primary_" + name() + "_" +
212  params);
213  }
214  }
215 
216  // Add penetration aux kernel
217  {
218  InputParameters params = _factory.getValidParams("PenetrationAux");
219 
221  {"tangential_tolerance",
222  "normal_smoothing_distance",
223  "normal_smoothing_method",
224  "order",
225  "check_boundary_restricted"});
226  params.set<AuxVariableName>("variable") = _penetration_var_name;
227  if (isParamValid("secondary_gap_offset"))
228  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
229  getParam<VariableName>("secondary_gap_offset")};
230  if (isParamValid("mapped_primary_gap_offset"))
231  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
232  getParam<VariableName>("mapped_primary_gap_offset")};
233  params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
234  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
235  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
236 
237  _problem->addAuxKernel("PenetrationAux",
238  "penetration_" + name() + "_" + Moose::stringify(aux_kenels_counter++),
239  params);
240  }
241  }
242 }
243 
244 void
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  auto order = getParam<MooseEnum>("order");
251  std::string family = "LAGRANGE";
252 
253  if (_quadrature)
254  {
255  order = "CONSTANT";
256  family = "MONOMIAL";
257  }
258 
259  auto var_type =
260  AddVariableAction::variableType(FEType(order, Utility::string_to_enum<FEFamily>(family)));
261  auto var_params = _factory.getValidParams(var_type);
262  var_params.set<MooseEnum>("order") = order;
263  var_params.set<MooseEnum>("family") = family;
264 
265  _problem->addAuxVariable(var_type, _penetration_var_name, var_params);
266  _problem->addAuxVariable(var_type, _gap_value_name, var_params);
267 }
268 
269 void
271 {
272  for (const auto & contact_pair : _boundary_pairs)
273  {
274  const std::string object_name = getParam<std::string>("type");
275  InputParameters params = _factory.getValidParams(object_name);
276  params.applyParameters(parameters());
277 
278  if (object_name == "GapPerfectConductance")
279  {
280  params.set<Real>("penalty") = getParam<Real>("penalty");
281  params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
282  params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
283  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
284  _problem->addBoundaryCondition(
285  object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
286  }
287  else
288  {
289  if (_quadrature)
290  {
291  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
292  params.set<bool>("use_displaced_mesh") = true;
293  }
294  else
295  {
296  params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
297  params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
298  }
299 
300  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
301 
302  _problem->addBoundaryCondition(
303  object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
304 
305  if (_quadrature)
306  {
307  // Swap primary and secondary for this one
308  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
309  params.set<BoundaryName>("paired_boundary") = contact_pair.second;
310 
311  _problem->addBoundaryCondition(
312  object_name, "gap_bc_primary_" + name() + "_" + Moose::stringify(bcs_counter), params);
313  }
314  }
315  bcs_counter++;
316  }
317 }
318 
319 void
321 {
322  if (_quadrature)
323  return;
324 
325  for (const auto & contact_pair : _boundary_pairs)
326  {
327  const std::string object_name = "GapHeatPointSourceMaster";
328  InputParameters params = _factory.getValidParams(object_name);
330  {"tangential_tolerance",
331  "normal_smoothing_distance",
332  "normal_smoothing_method",
333  "order",
334  "variable"});
335  params.set<BoundaryName>("boundary") = contact_pair.first;
336  params.set<BoundaryName>("secondary") = contact_pair.second;
337 
338  _problem->addDiracKernel(
339  object_name, object_name + "_" + name() + "_" + Moose::stringify(dirac_counter++), params);
340  }
341 }
342 
343 void
345 {
346  if (getParam<std::string>("type") != "GapHeatTransfer")
347  return;
348 
349  if (parameters().isParamSetByUser("gap_conductance"))
350  {
351  if (parameters().isParamSetByUser("gap_conductivity") ||
352  parameters().isParamSetByUser("gap_conductivity_function"))
353  mooseError(
354  "Cannot specify both gap_conductance and gap_conductivity or gap_conductivity_function");
355 
356  for (const auto & contact_pair : _boundary_pairs)
357  {
358  const std::string object_type = "GapConductanceConstant";
359  InputParameters params = _factory.getValidParams(object_type);
360  params.applyParameters(parameters());
361  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
362  _problem->addMaterial(object_type,
363  name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
364  params);
365 
366  if (_quadrature)
367  {
368  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
369  _problem->addMaterial(object_type,
370  name() + "_" + "gap_value_primary" + "_" +
372  params);
373  }
375  }
376  }
377  else
378  {
379  const std::string object_type = "GapConductance";
380 
381  for (const auto & contact_pair : _boundary_pairs)
382  {
383  InputParameters params = _factory.getValidParams(object_type);
384  params.applyParameters(parameters(), {"variable"});
385 
386  params.set<std::vector<VariableName>>("variable") = {
387  getParam<NonlinearVariableName>("variable")};
388  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
389 
390  if (_quadrature)
391  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
392  else
393  {
394  params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
395  params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
396  }
397 
398  _problem->addMaterial(object_type,
399  name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
400  params);
401 
402  if (_quadrature)
403  {
404  params.set<BoundaryName>("paired_boundary") = contact_pair.second;
405  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
406 
407  _problem->addMaterial(object_type,
408  name() + "_" + "gap_value_primary" + "_" +
410  params);
411  }
413  }
414  }
415 }
416 
417 void
419 {
420  _problem->getNonlinearSystemBase(/*nl_sys_num=*/0)
421  .addVector("secondary_flux", false, libMesh::GHOSTED);
422  _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  if (!_problem->isSNESMFReuseBaseSetbyUser())
429  _problem->setSNESMFReuseBase(false, false);
430 }
431 
432 void
434 {
435  if (!_quadrature)
436  return;
437 
438  for (const auto & contact_pair : _boundary_pairs)
439  {
440  const auto & object_name = getParam<std::string>("type");
441  auto params = _factory.getValidParams(object_name);
442  params.applyParameters(parameters());
443 
444  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
445  params.set<bool>("use_displaced_mesh") = true;
446  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
447  addRelationshipManagers(input_rm_type, params);
448  }
449 }
static InputParameters actionParameters()
virtual void addAuxVariables()
RelationshipManagerType
static InputParameters actionParameters()
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void applySpecificParameters(const InputParameters &common, const std::vector< std::string > &include, bool allow_private=false)
std::vector< std::pair< R1, R2 > > get(const std::string &param1, const std::string &param2) const
T & set(const std::string &name, bool quiet_mode=false)
InputParameters getValidParams(const std::string &name) const
void applyParameters(const InputParameters &common, const std::vector< std::string > &exclude={}, const bool allow_private=false)
static unsigned int materials_counter
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
virtual void addSecondaryFluxVector()
static unsigned int dirac_counter
bool isParamValid(const std::string &name) const
Factory & _factory
const std::vector< std::pair< BoundaryName, BoundaryName > > _boundary_pairs
Primary/Secondary boundary name pairs for thermal contact.
virtual void addDiracKernels()
virtual void act() override
static InputParameters validParams()
static MooseEnum getNonlinearVariableOrders()
const std::string & _current_task
ThermalContactAction(const InputParameters &params)
static std::string variableType(const libMesh::FEType &fe_type, const bool is_fv=false, const bool is_array=false)
void paramError(const std::string &param, Args... args) const
const ExecFlagType EXEC_LINEAR
std::string stringify(const T &t)
const AuxVariableName _gap_value_name
bool isParamSetByUser(const std::string &name) const
bool isParamSetByUser(const std::string &nm) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static InputParameters validParams()
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
std::shared_ptr< FEProblemBase > & _problem
const InputParameters & parameters() const
static unsigned int bcs_counter
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
virtual void addRelationshipManagers(Moose::RelationshipManagerType input_rm) override
void paramInfo(const std::string &param, Args... args) const
const AuxVariableName _penetration_var_name
registerMooseAction("HeatTransferApp", ThermalContactAction, "add_aux_kernel")
static unsigned int aux_kenels_counter
const ExecFlagType EXEC_INITIAL