Skip to content

Commit

Permalink
Add ParsedCurveGenerator and FillBetweenCurvesGenerator
Browse files Browse the repository at this point in the history
closes # 22848
  • Loading branch information
miaoyinb authored and MengnanLi91 committed Jan 4, 2023
1 parent 8d52c82 commit ebc0929
Show file tree
Hide file tree
Showing 23 changed files with 1,111 additions and 86 deletions.
@@ -0,0 +1,24 @@
# FillBetweenCurvesGenerator

!syntax description /Mesh/FillBetweenCurvesGenerator

## Overview

The `FillBetweenCurvesGenerator` offers similar functionality to [`FillBetweenPointVectorsGenerator`](/FillBetweenPointVectorsGenerator.md) by leveraging [`FillBetweenPointVectorsTools`](/FillBetweenPointVectorsTools.md). Instead of manually inputting the two boundaries [!param](/Mesh/FillBetweenPointVectorsGenerator/positions_vector_1) and [!param](/Mesh/FillBetweenPointVectorsGenerator/positions_vector_2), The `FillBetweenCurvesGenerator` directly takes boundary information from the two input meshes ([!param](/Mesh/FillBetweenCurvesGenerator/input_mesh_1) and [!param](/Mesh/FillBetweenCurvesGenerator/input_mesh_2)) that contain the curve meshes consisting of `Edge2` elements (e.g., generated by [`ParsedCurveGenerator`](/ParsedCurveGenerator.md)). The input meshes can be translated using [!param](/Mesh/FillBetweenCurvesGenerator/mesh_1_shift) and [!param](/Mesh/FillBetweenCurvesGenerator/mesh_2_shift).

!media reactor/meshgenerators/fill_between_curves.png
style=display: block;margin-left:auto;margin-right:auto;width:80%;
id=example_tlc
caption=A typical example of using `FillBetweenCurvesGenerator` to connect a logarithmic curve and a circular curve.

All the other meshing options are the same as [`FillBetweenPointVectorsGenerator`](/FillBetweenPointVectorsGenerator.md).

## Example Syntax

!listing test/tests/meshgenerators/fill_between_curves_generator/fill_between_curves.i block=Mesh/fbcg

!syntax parameters /Mesh/FillBetweenCurvesGenerator

!syntax inputs /Mesh/FillBetweenCurvesGenerator

!syntax children /Mesh/FillBetweenCurvesGenerator
@@ -0,0 +1,91 @@
# ParsedCurveGenerator

!syntax description /Mesh/ParsedCurveGenerator

## Overview

The `ParsedCurveGenerator` object generates a 3D curve mesh composed of EDGE2 elements which connect the series of points given by $[x(t),~y(t),~z(t)]$, where the range of t is specified by the user.

!equation id=xy_formula
\begin{cases}
x = x(t)\\
y = y(t)\\
z = z(t)
\end{cases},

where, $x(t)$, $y(t)$, and $z(t)$ are all provided in the form of [C++ function parser](http://warp.povusers.org/FunctionParser/) through [!param](/Mesh/ParsedCurveGenerator/x_formulus), [!param](/Mesh/ParsedCurveGenerator/y_formulus), and [!param](/Mesh/ParsedCurveGenerator/z_formulus), respectively. The constants used in these formula can be defined by [!param](/Mesh/ParsedCurveGenerator/constant_names) and [!param](/Mesh/ParsedCurveGenerator/constant_expressions).

!media reactor/meshgenerators/xyz_curve.png
style=display: block;margin-left:auto;margin-right:auto;width:40%;
id=xyz_curve
caption=A 3D open curve generated by `ParsedCurveGenerator` defined as $x(t)\=\cos t$; $y(t)\=\sin t$; $z(t)\= t$ with $t$ ranging from $0$ to $4\pi$.

Key $t$ values including the starting and ending values of $t$ must be specified by [!param](/Mesh/ParsedCurveGenerator/critical_t_series). Optionally, intermediate $t$ values can be added so that the curve can be divided into several sections. Note that the elements in [!param](/Mesh/ParsedCurveGenerator/critical_t_series) must be unique and change monotonically. Each interval defined by [!param](/Mesh/ParsedCurveGenerator/critical_t_series) must have a corresponding number of segments (i.e., EDGE2 elements), $N_{seg}$, defined by [!param](/Mesh/ParsedCurveGenerator/nums_segments).

## Calculating Segment Division Points

Each section of the curve should ideally have segments of similar length. However, it is challenging to predict the corresponding $t$ values that yield segments with similar length. Hence, oversampling is used to determine the $t$ values which result in consistent segement length. The oversampling factor $N_{os}$ can be defined through [!param](/Mesh/ParsedCurveGenerator/oversample_factor). Assuming that a section of curve is defined by $t_n$ and $t_{n+1}$, the distance between the starting and ending points of this section has the following form,

!equation id=section_distance
d_n = \sqrt{\left[x(t_n)-x(t_{n+1})\right]^2+\left[y(t_n)-y(t_{n+1})\right]^2}

Thus, the oversampling target is to achieve that the maximum interval between neighboring sampling points is lower than a threshold value defined as follows,

!equation id=threshold_distance
d_{os,threshold} = \frac{d_n}{N_{seg}N_{os}}

The oversampling is realized by a binary algorithm, which divides oversized intervals in halves until all the intervals are shorter than $d_{os,threshold}$. Then the oversampled section points are used to determine the actual point locations (i.e., $t$ values).

## Example Syntax

`ParsedCurveGenerator` is capable of generating both open and closed curves.

For open curve generation, the approach is straight forward with the example shown as follows.

!listing test/tests/meshgenerators/parsed_curve_generator/parsed_curve_open.i block=Mesh/pcg
id=open_curve_input
caption=the input syntax sample to generate an open logarithmic curve

!media reactor/meshgenerators/open_curve.png
style=display: block;margin-left:auto;margin-right:auto;width:40%;
id=open_curve
caption=An open logarithmic curve generated by `ParsedCurveGenerator`.

On the other hand, for closed curve generation (defined by [!param](/Mesh/ParsedCurveGenerator/is_closed_loop)), ideally the starting and ending values of $t$ should lead to the same $x(t)$ and $y(t)$ values, as shown below.

!listing test/tests/meshgenerators/parsed_curve_generator/parsed_curve_closed.i block=Mesh/pcg
id=closed_curve_input
caption=the input syntax sample to generate a closed half circular and half elliptical curve

!media reactor/meshgenerators/closed_curve.png
style=display: block;margin-left:auto;margin-right:auto;width:40%;
id=closed_curve
caption=A closed half circular and half elliptical curve generated by `ParsedCurveGenerator`.

If the starting and ending values of $t$ lead to different $x(t)$ and $y(t)$ values, the curve will be "forced" to close by directly connection the starting and ending points (see [forced_closed_curve]).

!media reactor/meshgenerators/forced_closed_curve.png
style=display: block;margin-left:auto;margin-right:auto;width:40%;
id=forced_closed_curve
caption=a fraction of the curve shown in [closed_curve] forced to be closed.

## Used with Other Mesh Generators

If [!param](/Mesh/ParsedCurveGenerator/z_formulus) is set as zero (default value), the generated curve resides in the XY-plane, and a pair of such `ParsedCurveGenerator` objects can naturally be connected by [`FillBetweenCurvesGenerator`](/FillBetweenCurvesGenerator.md) using [`FillBetweenPointVectorsTools`](/FillBetweenPointVectorsTools.md).

Additionally, closed XY-plane curve meshes generated by `ParsedCurveGenerator` can be used by [`XYDelaunayGenerator`](/XYDelaunayGenerator.md) as either [!param](/Mesh/XYDelaunayGenerator/boundary) or [!param](/Mesh/XYDelaunayGenerator/holes). See example below.

!listing test/tests/meshgenerators/parsed_curve_generator/xy_curve.i block=Mesh
id=xy_curve_list
caption=the input syntax sample to use `ParsedCurveGenerator` with [`XYDelaunayGenerator`](/XYDelaunayGenerator.md)

!media reactor/meshgenerators/xy_curve.png
style=display: block;margin-left:auto;margin-right:auto;width:40%;
id=xy_curve_fig
caption=An example mesh generated by using `ParsedCurveGenerator` with [`XYDelaunayGenerator`](/XYDelaunayGenerator.md)

!syntax parameters /Mesh/ParsedCurveGenerator

!syntax inputs /Mesh/ParsedCurveGenerator

!syntax children /Mesh/ParsedCurveGenerator
57 changes: 57 additions & 0 deletions framework/include/meshgenerators/FillBetweenCurvesGenerator.h
@@ -0,0 +1,57 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once
#include "MeshGenerator.h"

/**
* This FillBetweenCurvesGenerator object is designed to generate a transition layer to connect
* two curves.
*/
class FillBetweenCurvesGenerator : public MeshGenerator
{
public:
static InputParameters validParams();

FillBetweenCurvesGenerator(const InputParameters & parameters);

std::unique_ptr<MeshBase> generate() override;

protected:
/// Name of the mesh which contains the first input boundary
const MeshGeneratorName _input_name_1;
/// Name of the mesh which contains the second input boundary
const MeshGeneratorName _input_name_2;
/// Translation applied to the first input mesh
const Point _mesh_1_shift;
/// Translation applied to the second input mesh
const Point _mesh_2_shift;
/// Number of sublayers of the mesh to be generated
const unsigned int _num_layers;
/// Subdomain ID to be assigned to the generated transition layer
const subdomain_id_type _block_id;
/// ID to be assigned to the boundary that corresponds to the input boundary on the first input mesh
const boundary_id_type _input_boundary_1_id;
/// ID to be assigned to the boundary that corresponds to the input boundary on the second input mesh
const boundary_id_type _input_boundary_2_id;
/// ID to be assigned to the boundary that connects the starting points of positions_vectors
const boundary_id_type _begin_side_boundary_id;
/// ID to be assigned to the boundary that connects the ending points of positions_vectors
const boundary_id_type _end_side_boundary_id;
/// A boolean parameter to determine whether QUAD4 elements are used instead of TRI3 elements
const bool _use_quad_elements;
/// A parameter used to set up mesh biasing of the layers
const Real _bias_parameter;
/// Parameter used for Gaussian blurring of local node density
const Real _sigma;
/// The mesh which contains the first input boundary
std::unique_ptr<MeshBase> & _input_1;
/// The mesh which contains the second input boundary
std::unique_ptr<MeshBase> & _input_2;
};
90 changes: 90 additions & 0 deletions framework/include/meshgenerators/ParsedCurveGenerator.h
@@ -0,0 +1,90 @@
//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#pragma once
#include "MeshGenerator.h"

#include "FunctionParserUtils.h"

/**
* his ParsedCurveGenerator object is designed to generate a mesh of a curve that consists of EDGE2
* elements.
*/
class ParsedCurveGenerator : public MeshGenerator, public FunctionParserUtils<false>
{
public:
static InputParameters validParams();

ParsedCurveGenerator(const InputParameters & parameters);

std::unique_ptr<MeshBase> generate() override;

/**
* Calculates the oversampled parameter t series and corresponding cumulative distances from the
* starting point of a section of a curve
* @param t_start starting value of parameter t
* @param t_end ending value of parameter t
* @param t_sect_space a vector to store oversampled t value series
* @param dis_sect_space a vector to store oversampled cumulative distance series
* @param num_segments number of EDGE2 elements defined on the section of the curve
* @param is_closed_loop whether the section is a closed loop
* @param oversample_factor oversampling factor used to help make each EDGE2 element has similar
* length
*/
void tSectionSpaceDefiner(const Real t_start,
const Real t_end,
std::vector<Real> & t_sect_space,
std::vector<Real> & dis_sect_space,
unsigned int num_segments,
const bool is_closed_loop,
const Real oversample_factor);

protected:
/// function expression for x(t)
const std::string _function_x;
/// function expression for y(t)
const std::string _function_y;
/// function expression for z(t)
const std::string _function_z;
/// numbers of side segments of each section defined by critical_t_series
const std::vector<unsigned int> _nums_segments;
/// critical t values that define the sections of the curve
const std::vector<Real> _critical_t_series;
/// whether the curve is a closed loop or not
const bool _is_closed_loop;
/// Oversampling factor to help make node distance nearly uniform
const Real _oversample_factor;
/// t values that are sampled for curve points
std::vector<Real> _t_space;
/// cumulative distances of the curve points from the starting ppint
std::vector<Real> _dis_space;
/// function parser object describing the x(t)
SymFunctionPtr _func_Fx;
/// function parser object describing the y(t)
SymFunctionPtr _func_Fy;
/// function parser object describing the z(t)
SymFunctionPtr _func_Fz;

/**
* Calculates the point coordinates {x(t), y(t), 0.0} based on parameter t
* @param t_param parameter t that is used to determine the coordinates of the point
* @return the point coordinates
*/
Point pointCalculator(const Real t_param);

/**
* Calculates the Euclidean distance between two given points
* @param p1 the first point used to calculate the distance
* @param p2 the second point used to calculate the distance
* @return the Euclidean distance between the two given points
*/
Real euclideanDistance(const Point p1, const Point p2);

usingFunctionParserUtilsMembers(false);
};
71 changes: 71 additions & 0 deletions framework/include/utils/FillBetweenPointVectorsTools.h
Expand Up @@ -183,6 +183,7 @@ bool needFlip(const std::vector<Point> vec_pts_1, const std::vector<Point> vec_p
* @param mesh input mesh that contains the boundary to be examined
* @param max_node_radius the maximum radius of the nodes on the
* boundary
* @param boundary_ordered_node_list the ordered node ids on the given boundary
* @param origin_pt origin position of the given mesh (used for azimuthal angle calculation)
* @param bid ID of the boundary to be examined
* @return whether the boundary is a closed loop with consecutive nodes's azimuthal
Expand Down Expand Up @@ -228,6 +229,7 @@ bool isBoundarySimpleClosedLoop(ReplicatedMesh & mesh,
* @param mesh input mesh that contains the boundary to be examined
* @param max_node_radius the maximum radius of the nodes on the
* boundary
* @param boundary_ordered_node_list the ordered node ids on the given boundary
* @param origin_pt origin position of the given mesh (used for azimuthal angle calculation)
* @param bid ID of the boundary to be examined
* @return whether the boundary is an open single-segment boundary
Expand All @@ -238,6 +240,75 @@ bool isBoundaryOpenSingleSegment(ReplicatedMesh & mesh,
const Point origin_pt,
const boundary_id_type bid);

/**
* Decides whether a curve contained in a given mesh is a closed loop with consecutive nodes's
* azimuthal angles change monotonically.
* @param mesh input mesh that contains the curve to be examined
* @param max_node_radius the maximum radius of the nodes on the
* curve
* @param ordered_node_list the ordered node ids on the given curve
* @param origin_pt origin position of the given mesh (used for azimuthal angle calculation)
* @return whether the curve is a closed loop with consecutive nodes's azimuthal
* angles change monotonically
*/
bool isCurveSimpleClosedLoop(ReplicatedMesh & mesh,
Real & max_node_radius,
std::vector<dof_id_type> & ordered_node_list,
const Point origin_pt);

/**
* Decides whether a curve contained in a given mesh is a closed loop with consecutive nodes's
* azimuthal angles change monotonically.
* @param mesh input mesh that contains the curve to be examined
* @param max_node_radius the maximum radius of the nodes on the
* curve
* @param origin_pt origin position of the given mesh (used for azimuthal angle calculation)
* @return whether the curve is a closed loop with consecutive nodes's azimuthal
* angles change monotonically
*/
bool isCurveSimpleClosedLoop(ReplicatedMesh & mesh, Real & max_node_radius, const Point origin_pt);

/**
* Decides whether a curve contained in a given mesh is a closed loop with consecutive nodes's
* azimuthal angles change monotonically.
* @param mesh input mesh that contains the curve to be examined
* @param origin_pt origin position of the given mesh (used for azimuthal angle calculation)
* @return whether the curve is a closed loop with consecutive nodes's azimuthal
* angles change monotonically
*/
bool isCurveSimpleClosedLoop(ReplicatedMesh & mesh, const Point origin_pt);

/**
* Decides whether a curve contained in a given mesh is an open single-segment curve.
* @param mesh input mesh that contains the curve to be examined
* @param max_node_radius the maximum radius of the nodes on the
* curve
* @param ordered_node_list the ordered node ids on the given curve
* @param origin_pt origin position of the given mesh (used for azimuthal angle calculation)
* @return whether the boundary is an open single-segment boundary
*/
bool isCurveOpenSingleSegment(ReplicatedMesh & mesh,
Real & max_node_radius,
std::vector<dof_id_type> & ordered_node_list,
const Point origin_pt);

/**
* Decides whether a series of nodes contained in a given mesh forms a closed loop with consecutive
* nodes's azimuthal angles change monotonically.
* @param mesh input mesh that contains the node series to be examined
* @param max_node_radius the maximum radius of the nodes in the series
* @param ordered_node_list the ordered node ids on the given curve
* @param origin_pt origin position of the given mesh (used for azimuthal angle calculation)
* @return whether the series of nodes form a closed loop with consecutive nodes's azimuthal
* angles change monotonically
*/
bool isClosedLoop(ReplicatedMesh & mesh,
Real & max_node_radius,
std::vector<dof_id_type> & ordered_node_list,
std::vector<std::pair<dof_id_type, dof_id_type>> & node_assm,
const Point origin_pt,
const std::string input_type);

/**
* Decides whether a boundary of a given mesh is an external boundary.
* @param mesh input mesh that contains the boundary to be examined
Expand Down

0 comments on commit ebc0929

Please sign in to comment.