https://mooseframework.inl.gov
Loading...
Searching...
No Matches
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
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>();
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
87std::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->set_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
142Point
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
190Real
192{
193 _func_params[0] = point(0);
194 _func_params[1] = point(1);
195 _func_params[2] = point(2);
197}
registerMooseObject("MooseApp", ProjectSideSetOntoLevelSetGenerator)
std::vector< GenericReal< is_ad > > _func_params
Array to stage the parameters passed to the functions when calling Eval.
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.
GenericReal< is_ad > evaluate(SymFunctionPtr &, const std::string &object_name="")
Evaluate FParser object and check EvalError.
static InputParameters validParams()
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
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...
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 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...
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.
MeshGenerators are objects that can modify or add to an existing mesh.
static InputParameters validParams()
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.
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:457
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:271
const T & getParam(const std::string &name) const
Retrieve a parameter for the object.
Definition MooseBase.h:406
Projects a sideset onto a level set function using a fixed vector.
const Real _max_search_distance
Maximum distance to search for from starting nodeset to projection point.
const std::string _level_set
The analytic level set function in the form of a string that can be parsed by FParser.
SymFunctionPtr _func_level_set
function parser object describing the level set
Real levelSetEvaluator(const Point &point)
Evaluate the level set function at a given point.
std::unique_ptr< MeshBase > & _input
Reference to input mesh pointer.
ProjectSideSetOntoLevelSetGenerator(const InputParameters &parameters)
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
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...
const Parallel::Communicator & comm() const
MeshBase & mesh
SubdomainID getNextFreeSubdomainID(MeshBase &input_mesh)
Checks input mesh and returns max(block ID) + 1, which represents a block ID that is not currently in...
std::string stringify(const T &t)
conversion to string
Definition Conversion.h:64
const boundary_id_type side_id
const dof_id_type n_nodes