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
21using namespace libMesh;
22
24
27{
29 MooseEnum edge_elem_type("EDGE2 EDGE3 EDGE4", "EDGE2");
30
31 // Convenience parameters
32 params.addParam<SubdomainID>(
33 "new_subdomain_id", 1, "Subdomain ID to assign to the curve elements");
34 params.addParam<SubdomainName>("new_subdomain_name",
35 "Subdomain name to assign to the curve elements");
36
37 // Geometry parameters
38 params.addParam<Point>("start_point", "Starting (x,y,z) point for curve.");
39 params.addParam<Point>("end_point", "Ending (x,y,z) point for curve.");
40 params.addParam<RealVectorValue>("start_direction", "Direction vector of curve at start point.");
41 params.addParam<RealVectorValue>("end_direction", "Direction vector of curve at end point.");
42 params.addParamNamesToGroup("start_point end_point start_direction end_direction",
43 "Curve extremities input");
44
45 // Alternative to start / end point
46 params.addParam<MeshGeneratorName>("start_mesh",
47 "Meshgenerator providing the mesh to start spline from.");
48 params.addParam<BoundaryName>(
49 "boundary_providing_start_point",
50 "Boundary at whose centroid the spline should start. If the start_direction is not set, the "
51 "starting direction is computed from a side-volume average of the side-vertex-average "
52 "normals of the boundary sides");
53 params.addParam<MeshGeneratorName>("end_mesh",
54 "Meshgenerator providing the mesh to end splne on.");
55 params.addParam<BoundaryName>(
56 "boundary_providing_end_point",
57 "Boundary at whose centroid the spline should end. If the end_direction is not set, the "
58 "ending direction is computed from a side-volume average of the side-vertex-average normals "
59 "of the boundary sides");
61 "start_mesh end_mesh boundary_providing_start_point boundary_providing_end_point",
62 "Curve extremities input");
63
64 // Spline shape parameters
65 params.addParam<unsigned int>("degree", 3, "Degree of interpolating polynomial.");
67 "sharpness", 0.6, "sharpness>0 & sharpness<=1", "Sharpness of curve bend.");
68 params.addParam<unsigned int>(
69 "num_cps",
70 6,
71 "Number of control points used to draw the curve. Minimum of degree+1 points are required.");
72 params.addParamNamesToGroup("degree sharpness num_cps", "Spline");
73
74 // Discretization parameters
75 params.addParam<MooseEnum>(
76 "edge_element_type", edge_elem_type, "Type of the EDGE elements to be generated.");
77 params.addRequiredRangeCheckedParam<unsigned int>(
78 "num_elements", "num_elements>=1", "Numer of elements to be drawn. Must be at least 1.");
79 params.addParamNamesToGroup("edge_element_type num_elements", "Discretization");
80
82 "This BSplineMeshGenerator object is designed to generate a mesh of a curve that consists of "
83 "EDGE2, EDGE3, or EDGE4 elements drawn using an open uniform B-Spline.");
84 params.addParam<std::vector<BoundaryName>>("edge_nodesets",
85 std::vector<BoundaryName>(),
86 "Nodeset name to give each edge of the spline curve");
87
88 return params;
89}
90
92 : MeshGenerator(parameters),
93 _new_subdomain_id(getParam<SubdomainID>("new_subdomain_id")),
94 _degree(getParam<unsigned int>("degree")),
95 _sharpness(getParam<libMesh::Real>("sharpness")),
96 _num_cps(getParam<unsigned int>("num_cps")),
97 _order((unsigned int)(getParam<MooseEnum>("edge_element_type")) + 1),
98 _num_elements(getParam<unsigned int>("num_elements")),
99 _node_set_boundaries(getParam<std::vector<BoundaryName>>("edge_nodesets")),
100 _start_mesh_input(getMesh("start_mesh", true)),
101 _end_mesh_input(getMesh("end_mesh", true))
102{
103 if (_num_cps < _degree + 1)
104 paramError("num_cps", "Number of control points must be at least degree+1.");
105
106 // Check input parameters
107 if (!isParamValid("start_point"))
108 {
109 if (!isParamValid("boundary_providing_start_point"))
110 paramError("boundary_providing_start_point",
111 "boundary_providing_start_point must be specified if start_point is not");
112 else if (!isParamValid("start_mesh"))
113 paramError("start_mesh", "start_mesh must be specified if start_point is not.");
114 }
115 else
116 {
117 if (isParamValid("boundary_providing_start_point") || isParamValid("start_mesh"))
118 paramError("start_point",
119 "start_point and boundary_providing_start_point or start_mesh cannot be "
120 "simultaneously specified!");
121 if (!isParamValid("start_direction"))
122 paramError("start_direction",
123 "Starting direction must be specified if the 'start_point' is specified");
124 }
125 if (!isParamValid("end_point"))
126 {
127 if (!isParamValid("boundary_providing_end_point"))
128 paramError("boundary_providing_end_point",
129 "boundary_providing_end_point must be specified if start_point is not");
130 else if (!isParamValid("end_mesh"))
131 paramError("end_mesh", "end_mesh must be specified if start_point is not.");
132 }
133 else
134 {
135 if (isParamValid("boundary_providing_end_point") || isParamValid("end_mesh"))
136 paramError("end_point",
137 "end_point and boundary_providing_end_point or end_mesh cannot be "
138 "simultaneously specified!");
139 if (!isParamValid("end_direction"))
140 paramError("end_direction",
141 "Ending direction must be specified if the 'end_point' is specified");
142 }
143 if (_node_set_boundaries.size() != 0 && _node_set_boundaries.size() != 2)
144 paramError("edge_nodesets", "If specified, edge_nodesets must have exactly 2 entries.");
145}
146
147std::unique_ptr<MeshBase>
149{
150 std::unique_ptr<MeshBase> start_mesh;
151 std::unique_ptr<MeshBase> end_mesh;
153 start_mesh = std::move(_start_mesh_input);
154 if (_end_mesh_input)
155 end_mesh = std::move(_end_mesh_input);
156
157 const auto start_point =
158 isParamValid("start_point") ? getParam<Point>("start_point") : startPoint(*start_mesh);
159 const auto end_point =
160 isParamValid("end_point") ? getParam<Point>("end_point") : endPoint(*end_mesh);
161 const auto start_dir = isParamValid("start_direction")
162 ? getParam<RealVectorValue>("start_direction")
163 : startDirection(*start_mesh);
164 const auto end_dir = isParamValid("end_direction") ? getParam<RealVectorValue>("end_direction")
165 : endDirection(*end_mesh);
166
167 auto mesh = buildReplicatedMesh(2);
168
169 // determine number of control points needed
170 unsigned int half_cps;
171 if (_num_cps % 2 == 0)
172 half_cps = _num_cps / 2;
173 else
174 {
175 half_cps = (_num_cps - 1) / 2;
176 mooseWarning("Need an even number of control points. `num_cps` has been decreased by 1.");
177 }
178
179 // generate points using BSpline functions/class
180 std::vector<Point> control_points = SplineUtils::bSplineControlPoints(
181 start_point, end_point, start_dir, end_dir, half_cps, _sharpness);
182
183 // initialize BSpline class
184 Moose::BSpline b_spline(
185 _degree, start_point, end_point, start_dir, end_dir, half_cps, _sharpness);
186
187 // discretize t and evaluate points, assemble into nodes inside loop
188 const auto n_ts = _num_elements * _order + 1;
189 std::vector<Node *> nodes(n_ts);
190 std::vector<Point> eval_points;
191 for (const auto i : make_range(n_ts))
192 {
193 // n_ts-1 because max(t_current) must be 1.0
194 const auto t_current = ((Real)i / (Real)(n_ts - 1));
195 eval_points.push_back(b_spline.getPoint(t_current));
196 nodes[i] = mesh->add_point(eval_points.back(), i);
197 }
198
199 // create elements from points
200 for (const auto i : make_range(_num_elements))
201 {
202 std::unique_ptr<Elem> new_elem;
203 switch (_order)
204 {
205 case 1:
206 new_elem = std::make_unique<Edge2>();
207 break;
208 case 2:
209 new_elem = std::make_unique<Edge3>();
210 new_elem->set_node(2, nodes[i * _order + 1]);
211 break;
212 default:
213 {
214 new_elem = std::make_unique<Edge4>();
215 new_elem->set_node(2, nodes[i * _order + 1]);
216 new_elem->set_node(3, nodes[i * _order + 2]);
217 }
218 }
219
220 new_elem->set_node(0, nodes[i * _order]);
221 mooseAssert((i + 1) * _order < nodes.size(), "Out of bounds in nodes array");
222 new_elem->set_node(1, nodes[((i + 1) * _order)]);
223
224 new_elem->subdomain_id() = _new_subdomain_id;
225 mesh->add_elem(std::move(new_elem));
226 }
227
228 // Add subdomain name if needed
229 if (isParamValid("new_subdomain_name"))
231 _new_subdomain_id, getParam<SubdomainName>("new_subdomain_name"), true);
232
233 if (_node_set_boundaries.size())
234 {
235 // Add boundary nodesets to boundary info
236 BoundaryInfo & boundary_info = mesh->get_boundary_info();
237 int i = 0;
238 for (auto & side_name : _node_set_boundaries)
239 boundary_info.nodeset_name(i++) = side_name;
240
241 boundary_info.add_node(*nodes.begin(), boundary_info.get_id_by_name(_node_set_boundaries[0]));
242 boundary_info.add_node(*(nodes.end() - 1),
243 boundary_info.get_id_by_name(_node_set_boundaries[1]));
244 }
245 return dynamic_pointer_cast<MeshBase>(mesh);
246}
247
248Point
250{
252 getParam<BoundaryName>("boundary_providing_start_point"), start_mesh);
253}
254
255Point
257{
259 getParam<BoundaryName>("boundary_providing_end_point"), end_mesh);
260}
261
264{
266 getParam<BoundaryName>("boundary_providing_start_point"), start_mesh);
267}
268
271{
273 getParam<BoundaryName>("boundary_providing_end_point"), end_mesh);
274}
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:40
void mooseWarning(Args &&... args) const
boundary_id_type get_id_by_name(std::string_view name) const
std::string & nodeset_name(boundary_id_type id)
void add_node(const Node *node, const boundary_id_type id)
void set_subdomain_name(subdomain_id_type id, const std::string &name, bool synchronous=false)
const BoundaryInfo & get_boundary_info() const
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
virtual Elem * add_elem(Elem *e)=0
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
IntRange< T > make_range(T beg, T end)