www.mooseframework.org
ThermalContactAction.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
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 "libmesh/string_to_enum.h"
15 #include "GapConductance.h"
16 #include "GapConductanceConstant.h"
17 #include "NonlinearSystem.h"
18 
19 // Counter for naming materials
20 static unsigned int materials_counter = 0;
21 
22 // Counter for naming dirac kernels
23 static unsigned int dirac_counter = 0;
24 
25 // Counter for naming BCs
26 static unsigned int bcs_counter = 0;
27 
28 // Counter for naming aux kernels
29 static unsigned int aux_kenels_counter = 0;
30 
31 registerMooseAction("HeatTransferApp", ThermalContactAction, "add_aux_kernel");
32 registerMooseAction("HeatTransferApp", ThermalContactAction, "add_aux_variable");
33 registerMooseAction("HeatTransferApp", ThermalContactAction, "add_bc");
34 registerMooseAction("HeatTransferApp", ThermalContactAction, "add_dirac_kernel");
35 registerMooseAction("HeatTransferApp", ThermalContactAction, "add_material");
36 registerMooseAction("HeatTransferApp", ThermalContactAction, "add_secondary_flux_vector");
37 
40 {
42  params.addClassDescription(
43  "Action that controls the creation of all of the necessary objects for "
44  "calculation of Thermal Contact");
45 
46  params.addParam<std::string>(
47  "gap_aux_type",
48  "GapValueAux",
49  "A string representing the Moose object that will be used for computing the gap size");
50  params.addRequiredParam<NonlinearVariableName>("variable", "The variable for thermal contact");
51  params.addParam<std::vector<BoundaryName>>(
52  "primary", "The list of boundary IDs referring to primary sidesets");
53  params.addRequiredParam<std::vector<BoundaryName>>(
54  "secondary", "The list of boundary IDs referring to secondary sidesets");
55  params.addRangeCheckedParam<Real>("tangential_tolerance",
56  "tangential_tolerance>=0",
57  "Tangential distance to extend edges of contact surfaces");
58  params.addRangeCheckedParam<Real>(
59  "normal_smoothing_distance",
60  "normal_smoothing_distance>=0 & normal_smoothing_distance<=1",
61  "Distance from edge in parametric coordinates over which to smooth contact normal");
62  params.addParam<std::string>("normal_smoothing_method",
63  "Method to use to smooth normals (edge_based|nodal_normal_based)");
64 
66  params.addParam<MooseEnum>("order", orders, "The finite element order");
67 
68  params.addParam<bool>(
69  "warnings", false, "Whether to output warning messages concerning nodes not being found");
70  params.addParam<bool>(
71  "quadrature", false, "Whether or not to use quadrature point based gap heat transfer");
72 
73  params.addParam<std::string>(
74  "appended_property_name", "", "Name appended to material properties to make them unique");
75  params.addRequiredParam<std::string>(
76  "type",
77  "A string representing the Moose object that will be used for heat conduction over the gap");
78 
79  params.addParam<std::vector<VariableName>>(
80  "displacements",
81  "The displacements appropriate for the simulation geometry and coordinate system");
82 
83  params.addParam<std::vector<AuxVariableName>>(
84  "save_in", {}, "The Auxiliary Variable to (optionally) save the boundary flux in");
85  params.addRangeCheckedParam<Real>("gap_conductivity",
86  1.0,
87  "gap_conductivity>0",
88  "The thermal conductivity of the gap material");
89  params.addParam<FunctionName>(
90  "gap_conductivity_function",
91  "Thermal conductivity of the gap material as a function. Multiplied by gap_conductivity.");
92  params.addParam<std::vector<VariableName>>(
93  "gap_conductivity_function_variable",
94  "Variable to be used in gap_conductivity_function in place of time");
95  params.addParam<VariableName>("secondary_gap_offset",
96  "Offset to gap distance from secondary side");
97  params.addParam<VariableName>("mapped_primary_gap_offset",
98  "Offset to gap distance mapped from primary side");
99  params.addParam<bool>(
100  "check_boundary_restricted",
101  true,
102  "Whether to check for multiple element sides on the boundary for the boundary restricted, "
103  "element aux variable set up for thermal contact enforcement. Setting this to false will "
104  "allow contribution to a single element's elemental value(s) from multiple boundary sides "
105  "on the same element (example: when the restricted boundary exists on two or more sides "
106  "of an element, such as at a corner of a mesh");
107 
110 
111  return params;
112 }
113 
115  : Action(params),
116  _quadrature(getParam<bool>("quadrature")),
117  _order(getParam<MooseEnum>("order")),
118  _penetration_var_name(_quadrature ? "qpoint_penetration" : "penetration"),
119  _gap_value_name("paired_" + getParam<NonlinearVariableName>("variable")),
120  _gap_conductivity_name("paired_k_" + getParam<NonlinearVariableName>("variable")),
121  _boundary_pairs(getParam<BoundaryName, BoundaryName>("primary", "secondary"))
122 {
123  if (!params.get<bool>("check_boundary_restricted"))
124  {
125  if (_quadrature)
126  paramInfo(
127  "check_boundary_restricted",
128  "This parameter is set to 'false'. Although thermal contact ",
129  "will be correctly enforced, the contact-related output may have issues ",
130  "in cases where where more than one face of an element belongs to a contact surface ",
131  "because the values from only one of the faces will be reported.");
132  else
133  paramError("check_boundary_restricted",
134  "This parameter cannot be 'false' when 'quadrature=false'");
135  }
136 }
137 
138 void
140 {
141  if (_current_task == "add_aux_kernel")
142  addAuxKernels();
143  else if (_current_task == "add_aux_variable")
144  addAuxVariables();
145  else if (_current_task == "add_bc")
146  addBCs();
147  else if (_current_task == "add_dirac_kernel")
148  addDiracKernels();
149  else if (_current_task == "add_material")
150  addMaterials();
151  else if (_current_task == "add_secondary_flux_vector")
153 }
154 
155 void
157 {
158  for (const auto & contact_pair : _boundary_pairs)
159  {
160  // Add gap aux kernel
161  {
162  InputParameters params = _factory.getValidParams(getParam<std::string>("gap_aux_type"));
163 
165  {"tangential_tolerance",
166  "normal_smoothing_distance",
167  "normal_smoothing_method",
168  "order",
169  "warnings",
170  "check_boundary_restricted"});
171  params.set<AuxVariableName>("variable") = _gap_value_name;
172  params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
173 
174  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
175  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
176  params.set<VariableName>("paired_variable") = getParam<NonlinearVariableName>("variable");
177 
178  _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
179  "gap_value_" + name() + "_" + Moose::stringify(aux_kenels_counter),
180  params);
181 
182  if (_quadrature)
183  {
184  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
185  params.set<BoundaryName>("paired_boundary") = contact_pair.second;
186 
187  _problem->addAuxKernel(getParam<std::string>("gap_aux_type"),
188  "gap_value_primary_" + name() + "_" +
190  params);
191  }
192  }
193 
194  // Add penetration aux kernel
195  {
196  InputParameters params = _factory.getValidParams("PenetrationAux");
197 
199  {"tangential_tolerance",
200  "normal_smoothing_distance",
201  "normal_smoothing_method",
202  "order",
203  "check_boundary_restricted"});
204  params.set<AuxVariableName>("variable") = _penetration_var_name;
205  if (isParamValid("secondary_gap_offset"))
206  params.set<std::vector<VariableName>>("secondary_gap_offset") = {
207  getParam<VariableName>("secondary_gap_offset")};
208  if (isParamValid("mapped_primary_gap_offset"))
209  params.set<std::vector<VariableName>>("mapped_primary_gap_offset") = {
210  getParam<VariableName>("mapped_primary_gap_offset")};
211  params.set<ExecFlagEnum>("execute_on", true) = {EXEC_INITIAL, EXEC_LINEAR};
212  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
213  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
214 
215  _problem->addAuxKernel("PenetrationAux",
216  "penetration_" + name() + "_" + Moose::stringify(aux_kenels_counter++),
217  params);
218  }
219  }
220 }
221 
222 void
224 {
225  // We need to add variables only once per variable name. However, we don't know how many unique
226  // variable names we will have. So, we'll always add them.
227 
228  MooseEnum order = getParam<MooseEnum>("order");
229  std::string family = "LAGRANGE";
230 
231  if (_quadrature)
232  {
233  order = "CONSTANT";
234  family = "MONOMIAL";
235  }
236 
237  auto var_type =
238  AddVariableAction::variableType(FEType(order, Utility::string_to_enum<FEFamily>(family)));
239  auto var_params = _factory.getValidParams(var_type);
240  var_params.set<MooseEnum>("order") = order;
241  var_params.set<MooseEnum>("family") = family;
242 
243  _problem->addAuxVariable(var_type, _penetration_var_name, var_params);
244  _problem->addAuxVariable(var_type, _gap_value_name, var_params);
245 }
246 
247 void
249 {
250  for (const auto & contact_pair : _boundary_pairs)
251  {
252  const std::string object_name = getParam<std::string>("type");
253  InputParameters params = _factory.getValidParams(object_name);
254  params.applyParameters(parameters());
255 
256  if (_quadrature)
257  {
258  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
259  params.set<bool>("use_displaced_mesh") = true;
260  }
261  else
262  {
263  params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
264  params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
265  }
266 
267  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
268 
269  _problem->addBoundaryCondition(
270  object_name, "gap_bc_" + name() + "_" + Moose::stringify(bcs_counter), params);
271 
272  if (_quadrature)
273  {
274  // Swap primary and secondary for this one
275  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
276  params.set<BoundaryName>("paired_boundary") = contact_pair.second;
277 
278  _problem->addBoundaryCondition(
279  object_name, "gap_bc_primary_" + name() + "_" + Moose::stringify(bcs_counter), params);
280  }
281  bcs_counter++;
282  }
283 }
284 
285 void
287 {
288  if (_quadrature)
289  return;
290 
291  for (const auto & contact_pair : _boundary_pairs)
292  {
293  const std::string object_name = "GapHeatPointSourceMaster";
294  InputParameters params = _factory.getValidParams(object_name);
296  {"tangential_tolerance",
297  "normal_smoothing_distance",
298  "normal_smoothing_method",
299  "order",
300  "variable"});
301  params.set<BoundaryName>("boundary") = contact_pair.first;
302  params.set<BoundaryName>("secondary") = contact_pair.second;
303 
304  _problem->addDiracKernel(
305  object_name, object_name + "_" + name() + "_" + Moose::stringify(dirac_counter++), params);
306  }
307 }
308 
309 void
311 {
312  if (getParam<std::string>("type") != "GapHeatTransfer")
313  return;
314 
315  if (parameters().isParamSetByUser("gap_conductance"))
316  {
317  if (parameters().isParamSetByUser("gap_conductivity") ||
318  parameters().isParamSetByUser("gap_conductivity_function"))
319  mooseError(
320  "Cannot specify both gap_conductance and gap_conductivity or gap_conductivity_function");
321 
322  for (const auto & contact_pair : _boundary_pairs)
323  {
324  const std::string object_type = "GapConductanceConstant";
325  InputParameters params = _factory.getValidParams(object_type);
326  params.applyParameters(parameters());
327  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
328  _problem->addMaterial(object_type,
329  name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
330  params);
331 
332  if (_quadrature)
333  {
334  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
335  _problem->addMaterial(object_type,
336  name() + "_" + "gap_value_primary" + "_" +
338  params);
339  }
341  }
342  }
343  else
344  {
345  const std::string object_type = "GapConductance";
346 
347  for (const auto & contact_pair : _boundary_pairs)
348  {
349  InputParameters params = _factory.getValidParams(object_type);
350  params.applyParameters(parameters(), {"variable"});
351 
352  params.set<std::vector<VariableName>>("variable") = {
353  getParam<NonlinearVariableName>("variable")};
354  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.second};
355 
356  if (_quadrature)
357  params.set<BoundaryName>("paired_boundary") = contact_pair.first;
358  else
359  {
360  params.set<std::vector<VariableName>>("gap_temp") = {_gap_value_name};
361  params.set<std::vector<VariableName>>("gap_distance") = {"penetration"};
362  }
363 
364  _problem->addMaterial(object_type,
365  name() + "_" + "gap_value" + "_" + Moose::stringify(materials_counter),
366  params);
367 
368  if (_quadrature)
369  {
370  params.set<BoundaryName>("paired_boundary") = contact_pair.second;
371  params.set<std::vector<BoundaryName>>("boundary") = {contact_pair.first};
372 
373  _problem->addMaterial(object_type,
374  name() + "_" + "gap_value_primary" + "_" +
376  params);
377  }
379  }
380  }
381 }
382 
383 void
385 {
386  _problem->getNonlinearSystemBase(/*nl_sys_num=*/0).addVector("secondary_flux", false, GHOSTED);
387  _problem->getNonlinearSystemBase(/*nl_sys_num=*/0).zeroVectorForResidual("secondary_flux");
388 
389  // It is risky to apply this optimization to contact problems
390  // since the problem configuration may be changed during Jacobian
391  // evaluation. We therefore turn it off for all contact problems so that
392  // PETSc-3.8.4 or higher will have the same behavior as PETSc-3.8.3 or older.
393  if (!_problem->isSNESMFReuseBaseSetbyUser())
394  _problem->setSNESMFReuseBase(false, false);
395 }
static InputParameters actionParameters()
virtual void addAuxVariables()
static std::string variableType(const FEType &fe_type, const bool is_fv=false, const bool is_array=false)
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()
GHOSTED
const std::string & _current_task
ThermalContactAction(const InputParameters &params)
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 &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)
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