https://mooseframework.inl.gov
ProjectSideSetOntoLevelSetGenerator.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 
11 #include "MooseMeshUtils.h"
12 #include "CastUniquePointer.h"
13 
14 #include "libmesh/elem.h"
15 #include "libmesh/boundary_info.h"
16 #include "libmesh/mesh_base.h"
17 
18 // C++ includes
19 #include <cmath>
20 
22 
25 {
28 
29  params.addRequiredParam<Point>("direction", "Projection direction");
30  params.addParam<SubdomainName>(
31  "subdomain_name", "projected", "Name of the subdomain of the projected surface");
32  params.addParam<Real>("max_search_distance",
33  1e6,
34  "Maximum distance from the sideset to search for the projected point in "
35  "the projection direction.");
36 
37  // Source domain parameters
38  params.addRequiredParam<MeshGeneratorName>(
39  "input", "The input mesh generator in which the sideset exists.");
40  params.addRequiredParam<BoundaryName>("sideset", "The name of the sideset to project");
41 
42  // Surface definition
43  params.addRequiredParam<std::string>(
44  "level_set",
45  "Level set to define the surface to project onto as a function of x, y, and z. The surface "
46  "should be 'in front of' the sideset when following the projection direction.");
47  params.addParam<std::vector<std::string>>(
48  "constant_names", {}, "Vector of constants used in the parsed function");
49  params.addParam<std::vector<std::string>>(
50  "constant_expressions",
51  {},
52  "Vector of values for the constants in constant_names (can be an FParser expression)");
53  params.addParamNamesToGroup("level_set constant_names constant_expressions", "Level set surface");
54 
55  params.addClassDescription(
56  "Projects a sideset onto a surface defined by a level set and creates a surface mesh.");
57 
58  return params;
59 }
60 
62  const InputParameters & parameters)
63  : MeshGenerator(parameters),
64  FunctionParserUtils<false>(parameters),
65  _input_name(getParam<MeshGeneratorName>("input")),
66  _input(getMeshByName(_input_name)),
67  _level_set(getParam<std::string>("level_set")),
68  _max_search_distance(getParam<Real>("max_search_distance"))
69 {
70  // Create parsed function
71  _func_level_set = std::make_shared<SymFunction>();
73  _level_set,
74  "x,y,z",
75  getParam<std::vector<std::string>>("constant_names"),
76  getParam<std::vector<std::string>>("constant_expressions"),
77  comm());
78  _func_params.resize(3);
79 
80  // Get the projection direction and normalize it
81  auto proj_d = getParam<Point>("direction");
82  if (MooseUtils::absoluteFuzzyEqual(proj_d.norm_sq(), 0))
83  paramError("direction", "Should not be 0");
84  _proj_dir = proj_d.unit();
85 }
86 
87 std::unique_ptr<MeshBase>
89 {
90  auto mesh_uptr = std::move(_input);
91  auto mesh = mesh_uptr.get();
92  auto new_mesh = buildMeshBaseObject(3);
93 
94  if (!mesh_uptr->is_serial())
95  paramError("input", "Input mesh must not be distributed");
96 
97  // Use a new subdomain ID to avoid an overlap if merging the two later
98  const auto projection_block_id = MooseMeshUtils::getNextFreeSubdomainID(*mesh);
99 
100  BoundaryInfo & boundary_info = mesh->get_boundary_info();
101  const auto bdry_side_list = boundary_info.build_side_list();
102  const auto side_id = boundary_info.get_id_by_name(getParam<BoundaryName>("sideset"));
103 
104  // Loop over the sides on a given set
105  for (const auto & [elem_id, side_i, bc_id] : bdry_side_list)
106  {
107  if (bc_id != side_id)
108  continue;
109 
110  // Find the intersection with the surface (projection) for each node of the side
111  std::unique_ptr<Elem> side_elem = mesh->elem_ptr(elem_id)->build_side_ptr(side_i);
112  const auto n_nodes = side_elem->n_nodes();
113  const auto side_type = side_elem->type();
114  std::vector<Node *> new_nodes(n_nodes);
115 
116  for (const auto i : make_range(n_nodes))
117  {
118  const auto start = side_elem->point(i);
119  const auto end = start + _max_search_distance * _proj_dir;
120 
121  new_nodes[i] = new_mesh->add_point(pointPairLevelSetInterception(start, end));
122  }
123 
124  // Build the same element as the side, on the surface, using the projected nodes
125  if (side_type == libMesh::C0POLYGON)
126  mooseError("Projection of polygonal sides is not supported at this time");
127  std::unique_ptr<Elem> new_elem = Elem::build(side_type);
128  for (const auto i : make_range(n_nodes))
129  new_elem->set_node(i, new_nodes[i]);
130 
131  // User-selected block name: same for all element types for now
132  new_elem->subdomain_id() = projection_block_id;
133 
134  new_mesh->add_elem(std::move(new_elem));
135  }
136 
137  new_mesh->subdomain_name(projection_block_id) = getParam<SubdomainName>("subdomain_name");
138  new_mesh->unset_is_prepared();
139  return dynamic_pointer_cast<MeshBase>(new_mesh);
140 }
141 
142 Point
144  const Point & point2)
145 {
146  Real dist1 = levelSetEvaluator(point1);
147  Real dist2 = levelSetEvaluator(point2);
148 
149  if (MooseUtils::absoluteFuzzyEqual(dist1, 0.0) || MooseUtils::absoluteFuzzyEqual(dist2, 0.0))
150  mooseError("At least one of the two points are on the plane.");
151  if (MooseUtils::absoluteFuzzyGreaterThan(dist1 * dist2, 0.0))
152  mooseError("The two points are on the same side of the plane.");
153 
154  Point p1(point1);
155  Point p2(point2);
156  Real dist = abs(dist1) + abs(dist2);
157  Point mid_point;
158 
159  // Bisection method to find midpoint
160  unsigned int num_its = 0;
161  while (MooseUtils::absoluteFuzzyGreaterThan(dist, 0.0) && num_its < 1e3)
162  {
163  num_its++;
164  mid_point = 0.5 * (p1 + p2);
165  const Real dist_mid = levelSetEvaluator(mid_point);
166  // We do not need Fuzzy here as it will be covered by the while loop
167  if (dist_mid == 0.0)
168  dist = 0.0;
169  else if (dist_mid * dist1 < 0.0)
170  {
171  p2 = mid_point;
172  dist2 = levelSetEvaluator(p2);
173  dist = abs(dist1) + abs(dist2);
174  }
175  else
176  {
177  p1 = mid_point;
178  dist1 = levelSetEvaluator(p1);
179  dist = abs(dist1) + abs(dist2);
180  }
181  }
182 
183  if (num_its == 1e3)
184  mooseError("Projection failed for point " + Moose::stringify(point1) +
185  ". Is the level set 'in front of' the sideset when following the projection "
186  "direction?");
187  return mid_point;
188 }
189 
190 Real
192 {
193  _func_params[0] = point(0);
194  _func_params[1] = point(1);
195  _func_params[2] = point(2);
196  return evaluate(_func_level_set);
197 }
GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError.
MetaPhysicL::DualNumber< V, D, asd > abs(const MetaPhysicL::DualNumber< V, D, asd > &a)
Definition: EigenADReal.h:50
ProjectSideSetOntoLevelSetGenerator(const InputParameters &parameters)
registerMooseObject("MooseApp", ProjectSideSetOntoLevelSetGenerator)
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
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
Definition: MooseBase.h:416
const boundary_id_type side_id
std::unique_ptr< MeshBase > & _input
Reference to input mesh pointer.
MeshBase & mesh
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system...
const Parallel::Communicator & comm() const
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.
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...
SymFunctionPtr _func_level_set
function parser object describing the level set
const std::string _level_set
The analytic level set function in the form of a string that can be parsed by FParser.
const Real _max_search_distance
Maximum distance to search for from starting nodeset to projection point.
const dof_id_type n_nodes
Point pointPairLevelSetInterception(const Point &point1, const Point &point2)
Calculate the intersection point of a level set and a line segment defined by two points separated by...
void parsedFunctionSetup(SymFunctionPtr &function, const std::string &expression, const std::string &variables, const std::vector< std::string > &constant_names, const std::vector< std::string > &constant_expressions, const libMesh::Parallel::Communicator &comm) const
Performs setup steps on a SymFunction.
static InputParameters validParams()
Definition: MeshGenerator.C:23
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Projects a sideset onto a level set function using a fixed vector.
std::vector< GenericReal< is_ad > > _func_params
Array to stage the parameters passed to the functions when calling Eval.
IntRange< T > make_range(T beg, T end)
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
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
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...
static InputParameters validParams()
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...
std::unique_ptr< MeshBase > buildMeshBaseObject(unsigned int dim=libMesh::invalid_uint)
Build a MeshBase object whose underlying type will be determined by the Mesh input file block...
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
Real levelSetEvaluator(const Point &point)
Evaluate the level set function at a given point.
MeshGenerators are objects that can modify or add to an existing mesh.
Definition: MeshGenerator.h:33
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...