https://mooseframework.inl.gov
Loading...
Searching...
No Matches
BSplineCurveGenerator.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
12#include "CastUniquePointer.h"
13#include "MooseMeshUtils.h"
14#include "BSpline.h"
15#include "SplineUtils.h"
16
17#include "libmesh/edge_edge2.h"
18#include "libmesh/edge_edge3.h"
19#include "libmesh/edge_edge4.h"
20
22
25{
27 MooseEnum edge_elem_type("EDGE2 EDGE3 EDGE4", "EDGE2");
28
29 // Convenience parameters
30 params.addParam<SubdomainID>(
31 "new_subdomain_id", 1, "Subdomain ID to assign to the curve elements");
32 params.addParam<SubdomainName>("new_subdomain_name",
33 "Subdomain name to assign to the curve elements");
34
35 // Geometry parameters
36 params.addParam<Point>("start_point", "Starting (x,y,z) point for curve.");
37 params.addParam<Point>("end_point", "Ending (x,y,z) point for curve.");
38 params.addParam<RealVectorValue>("start_direction", "Direction vector of curve at start point.");
39 params.addParam<RealVectorValue>("end_direction", "Direction vector of curve at end point.");
40 params.addParamNamesToGroup("start_point end_point start_direction end_direction",
41 "Curve extremities input");
42
43 // Alternative to start / end point
44 params.addParam<MeshGeneratorName>("start_mesh",
45 "Meshgenerator providing the mesh to start spline from.");
46 params.addParam<BoundaryName>(
47 "boundary_providing_start_point",
48 "Boundary at whose centroid the spline should start. If the start_direction is not set, the "
49 "starting direction is computed from a side-volume average of the side-vertex-average "
50 "normals of the boundary sides");
51 params.addParam<MeshGeneratorName>("end_mesh",
52 "Meshgenerator providing the mesh to end splne on.");
53 params.addParam<BoundaryName>(
54 "boundary_providing_end_point",
55 "Boundary at whose centroid the spline should end. If the end_direction is not set, the "
56 "ending direction is computed from a side-volume average of the side-vertex-average normals "
57 "of the boundary sides");
59 "start_mesh end_mesh boundary_providing_start_point boundary_providing_end_point",
60 "Curve extremities input");
61
62 // Spline shape parameters
63 params.addParam<unsigned int>("degree", 3, "Degree of interpolating polynomial.");
65 "sharpness", 0.6, "sharpness>0 & sharpness<=1", "Sharpness of curve bend.");
66 params.addParam<unsigned int>(
67 "num_cps",
68 6,
69 "Number of control points used to draw the curve. Minimum of degree+1 points are required.");
70 params.addParamNamesToGroup("degree sharpness num_cps", "Spline");
71
72 // Discretization parameters
73 params.addParam<MooseEnum>(
74 "edge_element_type", edge_elem_type, "Type of the EDGE elements to be generated.");
75 params.addRequiredRangeCheckedParam<unsigned int>(
76 "num_elements", "num_elements>=1", "Numer of elements to be drawn. Must be at least 1.");
77 params.addParamNamesToGroup("edge_element_type num_elements", "Discretization");
78
80 "This BSplineMeshGenerator object is designed to generate a mesh of a curve that consists of "
81 "EDGE2, EDGE3, or EDGE4 elements drawn using an open uniform B-Spline.");
82 params.addParam<std::vector<BoundaryName>>("edge_nodesets",
83 std::vector<BoundaryName>(),
84 "Nodeset name to give each edge of the spline curve");
85
86 return params;
87}
88
90 : MeshGenerator(parameters),
91 _new_subdomain_id(getParam<SubdomainID>("new_subdomain_id")),
92 _degree(getParam<unsigned int>("degree")),
93 _sharpness(getParam<libMesh::Real>("sharpness")),
94 _num_cps(getParam<unsigned int>("num_cps")),
95 _order((unsigned int)(getParam<MooseEnum>("edge_element_type")) + 1),
96 _num_elements(getParam<unsigned int>("num_elements")),
97 _node_set_boundaries(getParam<std::vector<BoundaryName>>("edge_nodesets")),
98 _start_mesh_input(getMesh("start_mesh", true)),
99 _end_mesh_input(getMesh("end_mesh", true))
100{
101 if (_num_cps < _degree + 1)
102 paramError("num_cps", "Number of control points must be at least degree+1.");
103
104 // Check input parameters
105 if (!isParamValid("start_point"))
106 {
107 if (!isParamValid("boundary_providing_start_point"))
108 paramError("boundary_providing_start_point",
109 "boundary_providing_start_point must be specified if start_point is not");
110 else if (!isParamValid("start_mesh"))
111 paramError("start_mesh", "start_mesh must be specified if start_point is not.");
112 }
113 else
114 {
115 if (isParamValid("boundary_providing_start_point") || isParamValid("start_mesh"))
116 paramError("start_point",
117 "start_point and boundary_providing_start_point or start_mesh cannot be "
118 "simultaneously specified!");
119 if (!isParamValid("start_direction"))
120 paramError("start_direction",
121 "Starting direction must be specified if the 'start_point' is specified");
122 }
123 if (!isParamValid("end_point"))
124 {
125 if (!isParamValid("boundary_providing_end_point"))
126 paramError("boundary_providing_end_point",
127 "boundary_providing_end_point must be specified if start_point is not");
128 else if (!isParamValid("end_mesh"))
129 paramError("end_mesh", "end_mesh must be specified if start_point is not.");
130 }
131 else
132 {
133 if (isParamValid("boundary_providing_end_point") || isParamValid("end_mesh"))
134 paramError("end_point",
135 "end_point and boundary_providing_end_point or end_mesh cannot be "
136 "simultaneously specified!");
137 if (!isParamValid("end_direction"))
138 paramError("end_direction",
139 "Ending direction must be specified if the 'end_point' is specified");
140 }
141 if (_node_set_boundaries.size() != 0 && _node_set_boundaries.size() != 2)
142 paramError("edge_nodesets", "If specified, edge_nodesets must have exactly 2 entries.");
143}
144
145std::unique_ptr<MeshBase>
147{
148 std::unique_ptr<MeshBase> start_mesh;
149 std::unique_ptr<MeshBase> end_mesh;
151 start_mesh = std::move(_start_mesh_input);
152 if (_end_mesh_input)
153 end_mesh = std::move(_end_mesh_input);
154
155 const auto start_point =
156 isParamValid("start_point") ? getParam<Point>("start_point") : startPoint(*start_mesh);
157 const auto end_point =
158 isParamValid("end_point") ? getParam<Point>("end_point") : endPoint(*end_mesh);
159 const auto start_dir = isParamValid("start_direction")
160 ? getParam<RealVectorValue>("start_direction")
161 : startDirection(*start_mesh);
162 const auto end_dir = isParamValid("end_direction") ? getParam<RealVectorValue>("end_direction")
163 : endDirection(*end_mesh);
164
165 auto mesh = buildReplicatedMesh(2);
166
167 // determine number of control points needed
168 unsigned int half_cps;
169 if (_num_cps % 2 == 0)
170 half_cps = _num_cps / 2;
171 else
172 {
173 half_cps = (_num_cps - 1) / 2;
174 mooseWarning("Need an even number of control points. `num_cps` has been decreased by 1.");
175 }
176
177 // generate points using BSpline functions/class
178 std::vector<Point> control_points = SplineUtils::bSplineControlPoints(
179 start_point, end_point, start_dir, end_dir, half_cps, _sharpness);
180
181 // initialize BSpline class
182 Moose::BSpline b_spline(
183 _degree, start_point, end_point, start_dir, end_dir, half_cps, _sharpness);
184
185 // discretize t and evaluate points, assemble into nodes inside loop
186 const auto n_ts = _num_elements * _order + 1;
187 std::vector<Node *> nodes(n_ts);
188 std::vector<Point> eval_points;
189 for (const auto i : make_range(n_ts))
190 {
191 // n_ts-1 because max(t_current) must be 1.0
192 const auto t_current = ((Real)i / (Real)(n_ts - 1));
193 eval_points.push_back(b_spline.getPoint(t_current));
194 nodes[i] = mesh->add_point(eval_points.back(), i);
195 }
196
197 // create elements from points
198 for (const auto i : make_range(_num_elements))
199 {
200 std::unique_ptr<Elem> new_elem;
201 switch (_order)
202 {
203 case 1:
204 new_elem = std::make_unique<Edge2>();
205 break;
206 case 2:
207 new_elem = std::make_unique<Edge3>();
208 new_elem->set_node(2, nodes[i * _order + 1]);
209 break;
210 default:
211 {
212 new_elem = std::make_unique<Edge4>();
213 new_elem->set_node(2, nodes[i * _order + 1]);
214 new_elem->set_node(3, nodes[i * _order + 2]);
215 }
216 }
217
218 new_elem->set_node(0, nodes[i * _order]);
219 mooseAssert((i + 1) * _order < nodes.size(), "Out of bounds in nodes array");
220 new_elem->set_node(1, nodes[((i + 1) * _order)]);
221
222 new_elem->subdomain_id() = _new_subdomain_id;
223 mesh->add_elem(std::move(new_elem));
224 }
225
226 // Add subdomain name if needed
227 if (isParamValid("new_subdomain_name"))
228 mesh->set_subdomain_name(
229 _new_subdomain_id, getParam<SubdomainName>("new_subdomain_name"), true);
230
231 if (_node_set_boundaries.size())
232 {
233 // Add boundary nodesets to boundary info
234 BoundaryInfo & boundary_info = mesh->get_boundary_info();
235 int i = 0;
236 for (auto & side_name : _node_set_boundaries)
237 boundary_info.nodeset_name(i++) = side_name;
238
239 boundary_info.add_node(*nodes.begin(), boundary_info.get_id_by_name(_node_set_boundaries[0]));
240 boundary_info.add_node(*(nodes.end() - 1),
241 boundary_info.get_id_by_name(_node_set_boundaries[1]));
242 }
243 return dynamic_pointer_cast<MeshBase>(mesh);
244}
245
246Point
247BSplineCurveGenerator::startPoint(MeshBase & start_mesh) const
248{
250 getParam<BoundaryName>("boundary_providing_start_point"), start_mesh);
251}
252
253Point
254BSplineCurveGenerator::endPoint(MeshBase & end_mesh) const
255{
257 getParam<BoundaryName>("boundary_providing_end_point"), end_mesh);
258}
259
260RealVectorValue
261BSplineCurveGenerator::startDirection(MeshBase & start_mesh) const
262{
264 getParam<BoundaryName>("boundary_providing_start_point"), start_mesh);
265}
266
267RealVectorValue
268BSplineCurveGenerator::endDirection(MeshBase & end_mesh) const
269{
271 getParam<BoundaryName>("boundary_providing_end_point"), end_mesh);
272}
subdomain_id_type SubdomainID
registerMooseObject("MooseApp", BSplineCurveGenerator)
void ErrorVector unsigned int
Mesh generator to create a 1D B-spline curve mesh in 3D space.
Point startPoint(MeshBase &start_mesh) const
Return the starting point of the spline.
const unsigned int _degree
degree of interpolating spline
Point endPoint(MeshBase &end_mesh) const
Return the ending point of the spline.
static InputParameters validParams()
BSplineCurveGenerator(const InputParameters &parameters)
const unsigned int _num_elements
number of edge elements on the curve
const unsigned int _num_cps
number of control points to be generated
std::vector< BoundaryName > _node_set_boundaries
vector of the names of the boundaries at the ends of the spline curve
const unsigned int _order
order of the EDGE elements to be generated
const Real _sharpness
sharpness of curve (measure of how close it is to the curve with three orthogonal segments)
RealVectorValue startDirection(MeshBase &start_mesh) const
Return the starting direction of the spline.
RealVectorValue endDirection(MeshBase &end_mesh) const
Return the ending direction of the spline.
std::unique_ptr< MeshBase > & _end_mesh_input
If 'end_mesh' parameter is set, reference to input mesh providing the ending boundary.
std::unique_ptr< MeshBase > & _start_mesh_input
If 'start_mesh' parameter is set, reference to input mesh providing the starting boundary.
const SubdomainID _new_subdomain_id
Subdomain ID for the elements created.
std::unique_ptr< MeshBase > generate() override
Generate / modify the mesh.
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 addRequiredRangeCheckedParam(const std::string &name, const std::string &parsed_function, const std::string &doc_string)
These methods add an range checked parameters.
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 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 addRangeCheckedParam(const std::string &name, const T &value, const std::string &parsed_function, const std::string &doc_string)
MeshGenerators are objects that can modify or add to an existing mesh.
std::unique_ptr< ReplicatedMesh > buildReplicatedMesh(unsigned int dim=libMesh::invalid_uint)
Build a replicated mesh.
static InputParameters validParams()
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
bool isParamValid(const std::string &name) const
Test if the supplied parameter is valid.
Definition MooseBase.h:199
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
Class implementing a uniform clamped B-Spline curve.
Definition BSpline.h:26
libMesh::Point getPoint(const libMesh::Real t) const
Evaluate the BSpline interpolation at given value of t.
Definition BSpline.C:38
void mooseWarning(Args &&... args) const
MeshBase & mesh
Point boundaryCentroidCalculator(const BoundaryName &boundary, MeshBase &mesh)
Calculates the centroid of a boundary on a mesh.
RealVectorValue boundaryWeightedNormal(const BoundaryName &boundary, MeshBase &mesh)
Calculates the side-volume weighted (side-vertex) average normal of a boundary on a mesh.
std::vector< Point > bSplineControlPoints(const libMesh::Point &start_point, const libMesh::Point &end_point, const libMesh::RealVectorValue &start_direction, const libMesh::RealVectorValue &end_direction, const unsigned int cps_per_half, const libMesh::Real sharpness)
Creates control points for an open uniform BSpline.
Definition SplineUtils.C:67
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real