www.mooseframework.org
ParsedGenerateSideset.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 "ParsedGenerateSideset.h"
11 #include "Conversion.h"
12 #include "MooseMeshUtils.h"
13 #include "CastUniquePointer.h"
14 
15 #include "libmesh/fparser_ad.hh"
16 #include "libmesh/distributed_mesh.h"
17 #include "libmesh/elem.h"
18 #include "libmesh/fe_base.h"
19 
20 #include <typeinfo>
21 
23 
26 {
29 
30  params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
31  params.addRequiredParam<std::string>("combinatorial_geometry",
32  "Function expression encoding a combinatorial geometry");
33  params.addRequiredParam<BoundaryName>("new_sideset_name", "The name of the new sideset");
34  params.addParam<std::vector<BoundaryName>>(
35  "included_boundaries",
36  "A set of boundary names or ids whose sides will be included in the new sidesets");
37  params.addParam<std::vector<SubdomainName>>(
38  "included_subdomains",
39  "A set of subdomain names or ids whose sides will be included in the new sidesets");
40  params.addDeprecatedParam<std::vector<subdomain_id_type>>(
41  "included_subdomain_ids",
42  "A set of subdomain ids whose sides will be included in the new sidesets",
43  "included_subdomain_ids is deprecated, use included_subdomains with names or ids");
44  params.addParam<std::vector<SubdomainName>>("included_neighbors",
45  "A set of neighboring subdomain names or ids. A face "
46  "is only added if the subdomain id of the "
47  "neighbor is in this set");
48  params.addDeprecatedParam<std::vector<subdomain_id_type>>(
49  "included_neighbor_ids",
50  "A set of neighboring subdomain ids. A face is only added if the subdomain id of the "
51  "neighbor is in this set",
52  "included_neighbor_ids is deprecated, use included_neighbors with names or ids");
53  params.addParam<bool>(
54  "include_only_external_sides",
55  false,
56  "Whether to only include external sides when considering sides to add to the sideset");
57  params.addParam<Point>(
58  "normal",
59  Point(),
60  "If provided specifies the normal vector on sides that are added to the new ");
61  params.addParam<std::vector<std::string>>(
62  "constant_names", {}, "Vector of constants used in the parsed function");
63  params.addParam<std::vector<std::string>>(
64  "constant_expressions",
65  {},
66  "Vector of values for the constants in constant_names (can be an FParser expression)");
67  params.addClassDescription("A MeshGenerator that adds element sides to a sideset if the "
68  "centroid satisfies the `combinatorial_geometry` expression. "
69  "Optionally, element sides are also added if they are included in "
70  "`included_subdomain_ids` and if they feature the designated normal.");
71 
72  return params;
73 }
74 
76  : SideSetsGeneratorBase(parameters),
77  FunctionParserUtils<false>(parameters),
78  _input(getMesh("input")),
79  _function(parameters.get<std::string>("combinatorial_geometry")),
80  _sideset_name(getParam<BoundaryName>("new_sideset_name")),
81  _check_boundaries(isParamValid("included_boundaries")),
82  _check_subdomains(isParamValid("included_subdomain_ids") ||
83  isParamValid("included_subdomains")),
84  _check_neighbor_subdomains(isParamValid("included_neighbor_ids") ||
85  isParamValid("included_neighbors")),
86  _check_normal(parameters.isParamSetByUser("normal")),
87  _included_ids(isParamValid("included_subdomain_ids")
88  ? parameters.get<std::vector<SubdomainID>>("included_subdomain_ids")
89  : std::vector<SubdomainID>()),
90  _included_neighbor_ids(isParamValid("included_neighbor_ids")
91  ? parameters.get<std::vector<SubdomainID>>("included_neighbor_ids")
92  : std::vector<SubdomainID>()),
93  _include_only_external_sides(getParam<bool>("include_only_external_sides")),
94  _normal(getParam<Point>("normal"))
95 {
96  // Handle deprecated parameters
97  if (isParamValid("included_subdomain_ids") && isParamValid("included_subdomains"))
98  paramError("included_subdomain_ids",
99  "included_subdomain_ids is deprecated, only specify included_subdomains");
100  if (isParamValid("included_neighbor_ids") && isParamValid("included_neighbors"))
101  paramError("included_neighbor_ids",
102  "included_neighbor_ids is deprecated, only specify included_neighbors");
103 
104  // Handle incompatible parameters
106  paramError("include_only_external_sides", "External sides dont have neighbors");
107  if (_check_boundaries)
108  {
109  const auto & included_boundaries = getParam<std::vector<BoundaryName>>("included_boundaries");
110  if (std::find(included_boundaries.begin(), included_boundaries.end(), _sideset_name) !=
111  included_boundaries.end())
112  paramError(
113  "new_boundary",
114  "A boundary cannot be both the new boundary and be included in the list of included "
115  "boundaries. If you are trying to restrict an existing boundary, you must use a "
116  "different name for 'new_boundary', delete the old boundary, and then rename the "
117  "new boundary to the old boundary.");
118  }
119  // base function object
120  _func_F = std::make_shared<SymFunction>();
121 
122  // set FParser internal feature flags
124 
125  // add the constant expressions
127  getParam<std::vector<std::string>>("constant_names"),
128  getParam<std::vector<std::string>>("constant_expressions"));
129 
130  // parse function
131  if (_func_F->Parse(_function, "x,y,z") >= 0)
132  mooseError("Invalid function\n",
133  _function,
134  "\nin ParsedAddSideset ",
135  name(),
136  ".\n",
137  _func_F->ErrorMsg());
138 
139  _func_params.resize(3);
140 }
141 
142 std::unique_ptr<MeshBase>
144 {
145  std::unique_ptr<MeshBase> mesh = std::move(_input);
146  if (!mesh->is_replicated())
147  mooseWarning(
148  "ParsedGenerateSideset is not implemented for distributed meshes. Make sure the "
149  "parsed sideset does NOT cross any mesh distribution boundaries, using the ProcessorAux");
150 
151  setup(*mesh);
152 
153  // Get a reference to our BoundaryInfo object for later use
154  BoundaryInfo & boundary_info = mesh->get_boundary_info();
155 
156  // Get the boundary ids from the names
157  if (parameters().isParamValid("included_subdomains"))
158  {
159  // check that the subdomains exist in the mesh
160  const auto subdomains = getParam<std::vector<SubdomainName>>("included_subdomains");
161  for (const auto & name : subdomains)
163  paramError("included_subdomains", "The block '", name, "' was not found in the mesh");
164 
166  }
167 
168  if (parameters().isParamValid("included_neighbors"))
169  {
170  // check that the subdomains exist in the mesh
171  const auto subdomains = getParam<std::vector<SubdomainName>>("included_neighbors");
172  for (const auto & name : subdomains)
174  paramError("included_neighbors", "The block '", name, "' was not found in the mesh");
175 
177  }
178 
179  std::vector<boundary_id_type> restricted_boundary_ids;
180  if (_check_boundaries)
181  restricted_boundary_ids = MooseMeshUtils::getBoundaryIDs(
182  *mesh, getParam<std::vector<BoundaryName>>("included_boundaries"), true);
183 
184  // Get the BoundaryIDs from the mesh
185  std::vector<boundary_id_type> boundary_ids =
187  mooseAssert(boundary_ids.size() == 1, "Length of boundary_ids should be one");
188 
189  for (const auto & elem : mesh->active_element_ptr_range())
190  {
191  subdomain_id_type curr_subdomain = elem->subdomain_id();
192 
193  // check if the element is included
194  if (_check_subdomains &&
195  std::find(_included_ids.begin(), _included_ids.end(), curr_subdomain) ==
196  _included_ids.end())
197  continue;
198 
199  for (unsigned int side = 0; side < elem->n_sides(); ++side)
200  {
201  const std::vector<Point> & normals = _fe_face->get_normals();
202  _fe_face->reinit(elem, side);
203 
204  // check if the neighboring elems subdomain is included
206  {
207  const Elem * neighbor = elem->neighbor_ptr(side);
208  // if the neighbor does not exist, then skip this face; we only add sidesets
209  // between existing elems if _check_neighbor_subdomains is true
210  if (!neighbor)
211  continue;
212 
213  subdomain_id_type curr_neighbor_subdomain = neighbor->subdomain_id();
214  if (std::find(_included_neighbor_ids.begin(),
216  curr_neighbor_subdomain) == _included_neighbor_ids.end())
217  continue;
218  }
219 
220  // check normal if requested
221  if (_check_normal && std::abs(1.0 - _normal * normals[0]) > _variance)
222  continue;
223 
224  // check that boundary is within the list of included boundaries
225  if (_check_boundaries)
226  {
227  bool in_included_boundaries = false;
228  for (auto bid : restricted_boundary_ids)
229  if (boundary_info.has_boundary_id(elem, side, bid))
230  in_included_boundaries = true;
231  if (!in_included_boundaries)
232  continue;
233  }
234 
235  // avoid internal sides if specified by the suer
236  if (_include_only_external_sides && elem->neighbor_ptr(side))
237  continue;
238 
239  // check expression
240  std::unique_ptr<Elem> curr_side = elem->side_ptr(side);
241  _func_params[0] = curr_side->vertex_average()(0);
242  _func_params[1] = curr_side->vertex_average()(1);
243  _func_params[2] = curr_side->vertex_average()(2);
244  if (evaluate(_func_F))
245  {
246  boundary_info.add_side(elem, side, boundary_ids[0]);
247  }
248  }
249  }
250  finalize();
251  boundary_info.sideset_name(boundary_ids[0]) = _sideset_name;
252  boundary_info.nodeset_name(boundary_ids[0]) = _sideset_name;
253 
254  mesh->set_isnt_prepared();
255  return dynamic_pointer_cast<MeshBase>(mesh);
256 }
GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError.
SymFunctionPtr _func_F
function parser object describing the combinatorial geometry
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
void addDeprecatedParam(const std::string &name, const T &value, const std::string &doc_string, const std::string &deprecation_message)
ParsedGenerateSideset(const InputParameters &parameters)
const bool _check_subdomains
whether to check subdomain ids when adding sides or not
std::unique_ptr< MeshBase > & _input
mesh to add the sidesets to
std::string _function
function expression
static InputParameters validParams()
const bool _check_neighbor_subdomains
whether to check neighbor subdomain ids when adding sides or not
T * get(const std::unique_ptr< T > &u)
The MooseUtils::get() specializations are used to support making forwards-compatible code changes fro...
Definition: MooseUtils.h:1147
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
std::unique_ptr< T_DEST, T_DELETER > dynamic_pointer_cast(std::unique_ptr< T_SRC, T_DELETER > &src)
These are reworked from https://stackoverflow.com/a/11003103.
MeshGenerator for defining a Sideset by a parsed expression and optionally by looking at the subdomai...
std::vector< subdomain_id_type > getSubdomainIDs(const libMesh::MeshBase &mesh, const std::vector< SubdomainName > &subdomain_name)
Get the associated subdomainIDs for the subdomain names that are passed in.
void addFParserConstants(SymFunctionPtr &parser, const std::vector< std::string > &constant_names, const std::vector< std::string > &constant_expressions)
add constants (which can be complex expressions) to the parser object
virtual const std::string & name() const
Get the name of the class.
Definition: MooseBase.h:56
void mooseWarning(Args &&... args) const
Emits a warning prefixed with object name and type.
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...
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
const bool _include_only_external_sides
Whether to consider internal sides or not when building the sideset.
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
std::unique_ptr< FEBase > _fe_face
bool hasSubdomainName(MeshBase &input_mesh, const SubdomainName &name)
Whether a particular subdomain name exists in the mesh.
std::vector< BoundaryID > getBoundaryIDs(const libMesh::MeshBase &mesh, const std::vector< BoundaryName > &boundary_name, bool generate_unknown, const std::set< BoundaryID > &mesh_boundary_ids)
Gets the boundary IDs with their names.
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 ...
void finalize()
This method finalizes the object, setting names back in the boundary_info object and releasing memory...
static InputParameters validParams()
BoundaryName _sideset_name
name of the new sideset
const bool _check_normal
whether to check normals when adding sides or not
std::vector< subdomain_id_type > _included_neighbor_ids
A list of included neighbor subdomain ids.
const bool _check_boundaries
whether to check boundary ids when adding sides or not
std::vector< GenericReal< is_ad > > _func_params
Array to stage the parameters passed to the functions when calling Eval.
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type.
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...
const InputParameters & parameters() const
Get the parameters of the object.
static InputParameters validParams()
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an option parameter and a documentation string to the InputParameters object...
std::vector< subdomain_id_type > _included_ids
A list of included subdomain ids that the side has to be part of.
registerMooseObject("MooseApp", ParsedGenerateSideset)
Point _normal
A normal vector that (if provided) is compared against side&#39;s normals.
void setup(MeshBase &mesh)
This method is used to construct the FE object so we can compute normals of faces.
void setParserFeatureFlags(SymFunctionPtr &)
apply input paramters to internal feature flags of the parser object