https://mooseframework.inl.gov
ComponentJunction.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 // MOOSE includes
11 #include "ComponentJunction.h"
12 #include "MooseUtils.h"
13 
14 registerMooseAction("MooseApp", ComponentJunction, "add_mesh_generator");
15 // ComponentJunction is an example of ComponentPhysicsInterface
16 registerMooseAction("MooseApp", ComponentJunction, "init_component_physics");
17 // ComponentJunction is an example of ComponentMaterialPropertyInterface
18 registerMooseAction("MooseApp", ComponentJunction, "add_material");
19 // ComponentJunction is an example of ComponentInitialConditionInterface
20 registerMooseAction("MooseApp", ComponentJunction, "check_integrity");
22 
25 {
31 
32  params.addClassDescription("Component to join two other components.");
33 
34  params.addRequiredParam<ComponentName>("first_component", "First component to join");
35  params.addRequiredParam<BoundaryName>("first_boundary", "First boundary to connect to.");
36  params.addRequiredParam<ComponentName>("second_component", "Second component to join");
37  params.addRequiredParam<BoundaryName>("second_boundary", "Second boundary to connect to.");
38 
39  MooseEnum junction_type("stitch_meshes extrude_boundary", "extrude_boundary");
40  params.addParam<MooseEnum>("junction_method", junction_type, "How to join the two components");
41 
42  /* Stitching parameters */
43  params.addParam<bool>("enforce_all_nodes_match_on_boundaries",
44  true,
45  "Only stitch if all nodes match on the boundary. Defaults to true because "
46  "there is a search algorithm that forces nodes to match assuming there are "
47  "equal number of nodes on each target boundary.");
48 
49  /* Meshing the gap parameters */
50  // Parameters for the region between meshes
51  params.addParam<unsigned int>("n_elem_normal",
52  "Number of elements in the normal direction of the junction");
53  params.addParam<SubdomainName>("block", "Block name for the junction, if a block is created.");
54 
55  // Parameters for changing radius -- final radius will be calculated under the hood
56  MooseEnum radial_growth_methods("LINEAR CUBIC", "CUBIC");
57  params.addParam<MooseEnum>("radial_growth_method",
58  radial_growth_methods,
59  "Functional form to change radius while extruding along curve.");
60  params.addParam<Real>("start_radial_growth_rate", 0, "Starting rate of radial expansion.");
61  params.addParam<Real>("end_radial_growth_rate", 0, "Ending rate of radial expansion.");
62 
63  // Parameters for the 1D spline joining the two components (serving as an extrusion guide for
64  // 2,3D)
65  params.addRangeCheckedParam<libMesh::Real>("sharpness",
66  "sharpness>0 & sharpness<=1",
67  "Sharpness of curve bend. See BSplineCurveGenerator "
68  "for explanation of the meaning given to sharpness");
69  params.addParam<unsigned int>(
70  "num_cps",
71  6,
72  "Number of control points used to draw the curve. Miniumum of degree+1 points are required.");
73  MooseEnum edge_elem_type("EDGE2 EDGE3 EDGE4", "EDGE2");
74  params.addParam<MooseEnum>(
75  "edge_element_type", edge_elem_type, "Type of the EDGE elements to be generated.");
76 
77  params.addParamNamesToGroup("sharpness num_cps edge_element_type", "1D mesh junction");
78  params.addParamNamesToGroup(
79  "radial_growth_method start_radial_growth_rate end_radial_growth_rate",
80  "Radial expansion in 2D and 3D junction");
81 
82  return params;
83 }
84 
86  : ActionComponent(params),
91  _junction_method(getParam<MooseEnum>("junction_method")),
92  _enforce_all_nodes_match_on_boundaries(getParam<bool>("enforce_all_nodes_match_on_boundaries"))
93 {
94  addRequiredTask("add_mesh_generator");
95 
96  // Check parameters
97  if (_junction_method != "extrude_boundary")
98  errorDependentParameter("junction_method",
99  "extrude_boundary",
100  {"n_elem_normal",
101  "block",
102  "radial_growth_method",
103  "start_radial_growth_rate",
104  "end_radial_growth_rate",
105  "sharpness",
106  "num_cps",
107  "edge_element_type"});
108  else
109  {
110  if (!isParamValid("n_elem_normal"))
111  paramError("n_elem_normal", "Should be specified if junction_method = 'extrude_boundary'");
112  }
113  // The 1D and 2D meshing parameters will be re-checked later, once we know the dimension
114 }
115 
116 void
118 {
119  auto & first_component =
120  _awh.getAction<ActionComponent>(getParam<ComponentName>("first_component"));
121  auto & second_component =
122  _awh.getAction<ActionComponent>(getParam<ComponentName>("second_component"));
123  const auto first_boundary = getParam<BoundaryName>("first_boundary");
124  const auto second_boundary = getParam<BoundaryName>("second_boundary");
125 
126  // Get the dimension of the components
127  const auto dimension_first = first_component.dimension();
128  const auto dimension_second = second_component.dimension();
129 
130  if (dimension_first == 0 || dimension_second == 0)
131  mooseError("Connecting 0 dimension meshes not implemented!");
132 
133  // Perform junction
134  if (_junction_method == "stitch_meshes")
135  {
136  // Fairly easy to stitch this
137  if (dimension_first == dimension_second)
138  {
139  if (first_component.getCurrentTopLevelMeshGeneratorName() !=
140  second_component.getCurrentTopLevelMeshGeneratorName())
141  { // Stitch the two meshes
142  InputParameters params = _factory.getValidParams("StitchMeshGenerator");
143  params.set<std::vector<MeshGeneratorName>>("inputs") = {
144  first_component.getCurrentTopLevelMeshGeneratorName(),
145  second_component.getCurrentTopLevelMeshGeneratorName()};
146  params.set<std::vector<std::vector<std::string>>>("stitch_boundaries_pairs") = {
147  {first_boundary, second_boundary}};
148  params.set<bool>("verbose_stitching") = _verbose;
149  params.set<bool>("enforce_all_nodes_match_on_boundaries") =
152  "StitchMeshGenerator", name() + "_base", params);
153  _mg_names.push_back(name() + "_base");
154  }
155  else
156  {
157  // Handles case of needing to close a mesh. Using StitchBoundaryMeshGenerator prevents
158  // issues with element overlap.
159  InputParameters params = _factory.getValidParams("StitchBoundaryMeshGenerator");
160  params.set<MeshGeneratorName>("input") =
161  first_component.getCurrentTopLevelMeshGeneratorName();
162  params.set<std::vector<std::vector<std::string>>>("stitch_boundaries_pairs") = {
163  {first_boundary, second_boundary}};
164  params.set<bool>("show_info") = _verbose;
166  "StitchBoundaryMeshGenerator", name() + "_close", params);
167  _mg_names.push_back(name() + "_close");
168  }
169  }
170  else
171  mooseError("Stiching meshes of different dimensions is not implemented");
172  }
173 
174  else if (_junction_method == "extrude_boundary")
175  {
176  //
177  // This junction method is set to use a B-Spline to draw a 1D curve between, then extrude along
178  // that spline
179  //
180 
181  // find start and end directions (may need to take the negative of the end direction).
182  // obey user parameters if set
183  // TODO: modify the spline curve generator to figure out the direction so we can support other
184  // component types
185  // TODO: this really should be the surface direction, not the component direction. Maybe all
186  // this should be deleted and replaced by logic in the Spline curve generator instead.
187  auto get_direction = [this](const auto & component, const auto & param_name) -> RealVectorValue
188  {
189  const auto & cname = component.name();
190  if (dynamic_cast<const ComponentMeshTransformHelper *>(
191  &_awh.getAction<ActionComponent>(cname)))
192  return _awh.getAction<ComponentMeshTransformHelper>(cname).direction();
193  else if (component.isParamValid("direction"))
194  return component.template getParam<RealVectorValue>("direction");
195  else
196  paramError(param_name,
197  "Only components inheriting from 'ComponentMeshTransformerHelper' or with a "
198  "'direction' parameter are supported at this time");
199  };
200 
201  RealVectorValue start_direction = get_direction(first_component, "first_component");
202  RealVectorValue end_direction = get_direction(second_component, "second_component");
203 
204  InputParameters bspline_params = _factory.getValidParams("BSplineCurveGenerator");
205  bspline_params.set<RealVectorValue>("start_direction") = start_direction;
206  bspline_params.set<RealVectorValue>("end_direction") = -end_direction;
207  bspline_params.set<unsigned int>("num_elements") = getParam<unsigned int>("n_elem_normal");
208  if (isParamValid("sharpness"))
209  bspline_params.set<Real>("sharpness") = getParam<Real>("sharpness");
210  bspline_params.set<unsigned int>("num_cps") = getParam<unsigned int>("num_cps");
211  bspline_params.set<MeshGeneratorName>("start_mesh") =
212  first_component.meshGeneratorNames().back();
213  bspline_params.set<MeshGeneratorName>("end_mesh") =
214  second_component.meshGeneratorNames().back();
215  bspline_params.set<BoundaryName>("boundary_providing_start_point") =
216  getParam<BoundaryName>("first_boundary");
217  bspline_params.set<BoundaryName>("boundary_providing_end_point") =
218  getParam<BoundaryName>("second_boundary");
219 
220  if (dimension_first == 1)
221  {
222  if (isParamValid("block"))
223  bspline_params.set<SubdomainName>("new_subdomain_name") = getParam<SubdomainName>("block");
224  bspline_params.set<std::vector<BoundaryName>>("edge_nodesets") = {
225  name() + "_bspline_start_node", name() + "_bspline_end_node"};
226  bspline_params.set<bool>("output") = _verbose;
227  }
228 
230  "BSplineCurveGenerator", name() + "_curve", bspline_params);
231  _mg_names.push_back(name() + "_curve");
232 
233  // Extrude boundary from first component
234  if (dimension_first > 1)
235  {
236  // create lower dimension mesh on the boundary
237  InputParameters ld_source_params = _factory.getValidParams("LowerDBlockFromSidesetGenerator");
238  ld_source_params.set<MeshGeneratorName>("input") =
239  first_component.meshGeneratorNames().back();
240  ld_source_params.set<std::vector<BoundaryName>>("sidesets") =
241  std::vector{getParam<BoundaryName>("first_boundary")};
242  ld_source_params.set<SubdomainName>("new_block_name") =
243  (SubdomainName)(name() + "_LowerDBlockSource");
245  "LowerDBlockFromSidesetGenerator", name() + "_lowerDGenerationSource", ld_source_params);
246  _mg_names.push_back(name() + "_lowerDGenerationSource");
247 
248  InputParameters _bmc_source_params = _factory.getValidParams("BlockToMeshConverterGenerator");
249  _bmc_source_params.set<MeshGeneratorName>("input") = name() + "_lowerDGenerationSource";
250  _bmc_source_params.set<std::vector<SubdomainName>>("target_blocks") = {
251  (SubdomainName)(name() + "_LowerDBlockSource")};
253  "BlockToMeshConverterGenerator", name() + "_blockToMeshSource", _bmc_source_params);
254  _mg_names.push_back(name() + "_blockToMeshSource");
255 
256  // set up AdvancedExtruderGenerator
257  InputParameters aeg_params = _factory.getValidParams("AdvancedExtruderGenerator");
258  aeg_params.set<MeshGeneratorName>("extrusion_curve") = (MeshGeneratorName)(name() + "_curve");
259  aeg_params.set<MeshGeneratorName>("input") =
260  (MeshGeneratorName)(name() + "_blockToMeshSource");
261 
262  aeg_params.set<RealVectorValue>("start_extrusion_direction") = start_direction;
263  aeg_params.set<RealVectorValue>("end_extrusion_direction") = end_direction;
264 
265  aeg_params.set<Real>("start_radial_growth_rate") = getParam<Real>("start_radial_growth_rate");
266  aeg_params.set<Real>("end_radial_growth_rate") = getParam<Real>("end_radial_growth_rate");
267  aeg_params.set<MooseEnum>("radial_growth_method") =
268  getParam<MooseEnum>("radial_growth_method");
269 
270  aeg_params.set<BoundaryName>("bottom_boundary") = name() + "_aeg_bottom_boundary";
271  aeg_params.set<BoundaryName>("top_boundary") = name() + "_aeg_top_boundary";
272  if (isParamValid("block"))
273  paramError("block", "Not yet implemented for 2D or 3D junction");
274  aeg_params.set<bool>("output") = _verbose;
275 
277  "AdvancedExtruderGenerator", name() + "_aeg", aeg_params);
278  _mg_names.push_back(name() + "_aeg");
279  }
280 
281  // Stitch the extrusion / curve (in 1D) to the components
282  if (first_component.getCurrentTopLevelMeshGeneratorName() !=
283  second_component.getCurrentTopLevelMeshGeneratorName())
284  {
285  InputParameters stitcher_params = _factory.getValidParams("StitchMeshGenerator");
286  stitcher_params.set<std::vector<MeshGeneratorName>>("inputs") =
287  std::vector<MeshGeneratorName>{first_component.getCurrentTopLevelMeshGeneratorName(),
288  _mg_names.back(),
289  second_component.getCurrentTopLevelMeshGeneratorName()};
290  if (dimension_first > 1)
291  stitcher_params.set<std::vector<std::vector<std::string>>>("stitch_boundaries_pairs") = {
292  {first_boundary, name() + "_aeg_bottom_boundary"},
293  {name() + "_aeg_top_boundary", second_boundary}};
294  else
295  {
296  stitcher_params.set<bool>("clear_stitched_boundary_ids") = false;
297  stitcher_params.set<std::vector<std::vector<std::string>>>("stitch_boundaries_pairs") = {
298  {first_boundary, name() + "_bspline_start_node"},
299  {name() + "_bspline_end_node", second_boundary}};
300  }
301 
302  stitcher_params.set<bool>("verbose_stitching") = _verbose;
303  stitcher_params.set<bool>("output") = _verbose;
304  stitcher_params.set<bool>("enforce_all_nodes_match_on_boundaries") =
307  "StitchMeshGenerator", name() + "_stitcher", stitcher_params);
308  _mg_names.push_back(name() + "_stitcher");
309  }
310  else
311  {
312  // Handles case of needing to close a mesh. Using StitchBoundaryMeshGenerator prevents
313  // issues with element overlap.
314  InputParameters mesh_stitcher_params = _factory.getValidParams("StitchMeshGenerator");
315  mesh_stitcher_params.set<std::vector<MeshGeneratorName>>("inputs") =
316  std::vector<MeshGeneratorName>{first_component.getCurrentTopLevelMeshGeneratorName(),
317  _mg_names.back()};
318  if (dimension_first > 1)
319  mesh_stitcher_params.set<std::vector<std::vector<std::string>>>(
320  "stitch_boundaries_pairs") = {{first_boundary, name() + "_aeg_bottom_boundary"}};
321  else
322  mesh_stitcher_params.set<std::vector<std::vector<std::string>>>(
323  "stitch_boundaries_pairs") = {{first_boundary, name() + "_bspline_start_node"}};
324  mesh_stitcher_params.set<bool>("verbose_stitching") = _verbose;
325  // TODO: remove this once we understand why it errors without
326  mesh_stitcher_params.set<bool>("clear_stitched_boundary_ids") = false;
327  mesh_stitcher_params.set<bool>("enforce_all_nodes_match_on_boundaries") =
330  "StitchMeshGenerator", name() + "_mesh_stitcher", mesh_stitcher_params);
331  _mg_names.push_back(name() + "_stitcher");
332 
333  InputParameters boundary_stitcher_params =
334  _factory.getValidParams("StitchBoundaryMeshGenerator");
335  boundary_stitcher_params.set<MeshGeneratorName>("input") = name() + "_mesh_stitcher";
336  if (dimension_first > 1)
337  boundary_stitcher_params.set<std::vector<std::vector<std::string>>>(
338  "stitch_boundaries_pairs") = {{name() + "_aeg_top_boundary", second_boundary}};
339  else
340  boundary_stitcher_params.set<std::vector<std::vector<std::string>>>(
341  "stitch_boundaries_pairs") = {{name() + "_bspline_end_node", second_boundary}};
342  boundary_stitcher_params.set<bool>("show_info") = _verbose;
344  "StitchBoundaryMeshGenerator", name() + "_closed", boundary_stitcher_params);
345  _mg_names.push_back(name() + "_closed");
346  }
347  }
348  else
349  mooseError("junction_method specified is invalid!");
350 
351  _top_mg_name = _mg_names.back();
352  first_component.addConnectedComponent(second_component);
353  // Sets it for all connected components
354  // Connected might not be the right abstraction here. It's more like "included in a common mesh"
355  for (auto * component : first_component.getConnectedComponents())
356  component->setCurrentTopLevelMeshGeneratorName(_top_mg_name);
357 
358  // For now this is a safe choice. We might want to decide otherwise once we
359  // do mixed-dimensions. Build the junction with the dimension of the first component?
360  mooseAssert(dimension_first == dimension_second, "Should be the same");
361  _dimension = std::max(dimension_first, dimension_second);
362 }
363 
364 void
366 {
369 }
const T & getAction(const std::string &name) const
Retrieve an action with its name and the desired type.
virtual void addMeshGenerators() override
bool _enforce_all_nodes_match_on_boundaries
Whether to enforce that all nodes match on a boundary when stitching them.
virtual void checkIntegrity() override
Used for various checks notably:
ActionWarehouse & _awh
Reference to ActionWarehouse where we store object build by actions.
Definition: Action.h:169
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition: MooseBase.h:467
static InputParameters validParams()
Factory & _factory
The Factory associated with the MooseApp.
registerActionComponent("MooseApp", ComponentJunction)
T & set(const std::string &name, bool quiet_mode=false)
Returns a writable reference to the named parameters.
InputParameters getValidParams(const std::string &name) const
Get valid parameters for the object.
Definition: Factory.C:68
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
std::vector< MeshGeneratorName > _mg_names
Name(s) of the final mesh generator(s) creating the mesh for the component.
unsigned int _dimension
Maximum dimension of the component.
Base class for components that are defined using an action.
MeshGeneratorName _top_mg_name
Name of the top-most mesh generator in the hierarchy of MGs on top of the ones generating this compon...
Helper class to help Components be located with the orientation and position we want.
static InputParameters validParams()
void addRequiredParam(const std::string &name, const std::string &doc_string)
This method adds a parameter and documentation string to the InputParameters object that will be extr...
auto max(const L &left, const R &right)
ActionComponent to connect two components.
void addMeshGenerator(const std::string &type, const std::string &name, const InputParameters &params)
Add a mesh generator that will act on the meshes in the system.
void errorDependentParameter(const std::string &param1, const std::string &value_not_set, const std::vector< std::string > &dependent_params) const
Error messages for parameters that should depend on another parameter.
virtual void checkIntegrity() override
Used for various checks notably:
static InputParameters validParams()
ComponentJunction(const InputParameters &params)
Helper class to help creating an entire physics Note: Trying out virtual inheritance.
const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:103
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition: MooseEnum.h:54
const bool _verbose
Whether the component setup should be verbose.
Helper class to help Components define the material properties the Physics may need from the paramete...
registerMooseAction("MooseApp", ComponentJunction, "add_mesh_generator")
MooseApp & _app
The MOOSE application this is associated with.
Definition: MooseBase.h:385
void addRequiredTask(const std::string &task)
Add a new required task for all physics deriving from this class NOTE: This does not register the tas...
virtual void checkIntegrity() override
Used for various checks notably:
Helper class to help Components accept boundary condition parameters that the Physics may use to gene...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const MooseEnum _junction_method
How to connect the two components.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition: MooseBase.h:281
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump...
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object...
void addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition: MooseBase.h:209
MeshGeneratorSystem & getMeshGeneratorSystem()
Gets the system that manages the MeshGenerators.
Definition: MooseApp.h:860
Helper class to help Components define the initial conditions the Physics may need from the parameter...
void addParamNamesToGroup(const std::string &space_delim_names, const std::string group_name)
This method takes a space delimited list of parameter names and adds them to the specified group name...