Reference documentation for deal.II version 9.1.0-pre
Public Member Functions | Private Member Functions | Private Attributes | List of all members
TransfiniteInterpolationManifold< dim, spacedim > Class Template Reference

#include <deal.II/grid/manifold_lib.h>

Inheritance diagram for TransfiniteInterpolationManifold< dim, spacedim >:
[legend]

Public Member Functions

 TransfiniteInterpolationManifold ()
 
virtual ~TransfiniteInterpolationManifold () override
 
virtual std::unique_ptr< Manifold< dim, spacedim > > clone () const override
 
void initialize (const Triangulation< dim, spacedim > &triangulation)
 
virtual Point< spacedim > get_new_point (const ArrayView< const Point< spacedim >> &surrounding_points, const ArrayView< const double > &weights) const override
 
virtual void get_new_points (const ArrayView< const Point< spacedim >> &surrounding_points, const Table< 2, double > &weights, ArrayView< Point< spacedim >> new_points) const override
 
- Public Member Functions inherited from Manifold< dim, spacedim >
virtual ~Manifold () override=default
 
virtual Point< spacedim > get_intermediate_point (const Point< spacedim > &p1, const Point< spacedim > &p2, const double w) const
 
virtual Point< spacedim > project_to_manifold (const ArrayView< const Point< spacedim >> &surrounding_points, const Point< spacedim > &candidate) const
 
virtual Point< spacedim > get_new_point_on_line (const typename Triangulation< dim, spacedim >::line_iterator &line) const
 
virtual Point< spacedim > get_new_point_on_quad (const typename Triangulation< dim, spacedim >::quad_iterator &quad) const
 
virtual Point< spacedim > get_new_point_on_hex (const typename Triangulation< dim, spacedim >::hex_iterator &hex) const
 
Point< spacedim > get_new_point_on_face (const typename Triangulation< dim, spacedim >::face_iterator &face) const
 
Point< spacedim > get_new_point_on_cell (const typename Triangulation< dim, spacedim >::cell_iterator &cell) const
 
virtual Tensor< 1, spacedim > get_tangent_vector (const Point< spacedim > &x1, const Point< spacedim > &x2) const
 
virtual Tensor< 1, spacedim > normal_vector (const typename Triangulation< dim, spacedim >::face_iterator &face, const Point< spacedim > &p) const
 
virtual void get_normals_at_vertices (const typename Triangulation< dim, spacedim >::face_iterator &face, FaceVertexNormals &face_vertex_normals) const
 
- Public Member Functions inherited from Subscriptor
 Subscriptor ()
 
 Subscriptor (const Subscriptor &)
 
 Subscriptor (Subscriptor &&) noexcept
 
virtual ~Subscriptor ()
 
Subscriptoroperator= (const Subscriptor &)
 
Subscriptoroperator= (Subscriptor &&) noexcept
 
void subscribe (const char *identifier=nullptr) const
 
void unsubscribe (const char *identifier=nullptr) const
 
unsigned int n_subscriptions () const
 
template<typename StreamType >
void list_subscribers (StreamType &stream) const
 
void list_subscribers () const
 
template<class Archive >
void serialize (Archive &ar, const unsigned int version)
 

Private Member Functions

std::array< unsigned int, 20 > get_possible_cells_around_points (const ArrayView< const Point< spacedim >> &surrounding_points) const
 
Triangulation< dim, spacedim >::cell_iterator compute_chart_points (const ArrayView< const Point< spacedim >> &surrounding_points, ArrayView< Point< dim >> chart_points) const
 
Point< dim > pull_back (const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< spacedim > &p, const Point< dim > &initial_guess) const
 
Point< spacedim > push_forward (const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &chart_point) const
 
DerivativeForm< 1, dim, spacedim > push_forward_gradient (const typename Triangulation< dim, spacedim >::cell_iterator &cell, const Point< dim > &chart_point, const Point< spacedim > &pushed_forward_chart_point) const
 

Private Attributes

const Triangulation< dim, spacedim > * triangulation
 
int level_coarse
 
std::vector< bool > coarse_cell_is_flat
 
FlatManifold< dim > chart_manifold
 
boost::signals2::connection clear_signal
 

Additional Inherited Members

- Public Types inherited from Manifold< dim, spacedim >
using FaceVertexNormals = std::array< Tensor< 1, spacedim >, GeometryInfo< dim >::vertices_per_face >
 
- Static Public Member Functions inherited from Subscriptor
static::ExceptionBase & ExcInUse (int arg1, std::string arg2, std::string arg3)
 
static::ExceptionBase & ExcNoSubscriber (std::string arg1, std::string arg2)
 

Detailed Description

template<int dim, int spacedim = dim>
class TransfiniteInterpolationManifold< dim, spacedim >

A mapping class that extends curved boundary descriptions into the interior of the computational domain. The outer curved boundary description is assumed to be given by another manifold (e.g. a polar manifold on a circle). The mechanism to extend the boundary information is a so-called transfinite interpolation.

The formula for extending such a description in 2D is, for example, described on Wikipedia. Given a point \((u,v)\) on the chart, the image of this point in real space is given by

\begin{align*} \mathbf S(u,v) &= (1-v)\mathbf c_0(u)+v \mathbf c_1(u) + (1-u)\mathbf c_2(v) + u \mathbf c_3(v) \\ &\quad - \left[(1-u)(1-v) \mathbf x_0 + u(1-v) \mathbf x_1 + (1-u)v \mathbf x_2 + uv \mathbf x_3 \right] \end{align*}

where \(\bf x_0, \bf x_1, \bf x_2, \bf x_3\) denote the four bounding vertices bounding the image space and \(\bf c_0, \bf c_1, \bf c_2, \bf c_3\) are the four curves describing the lines of the cell. If a curved manifold is attached to any of these lines, the evaluation is done according to Manifold::get_new_point() with the two end points of the line and appropriate weight. In 3D, the generalization of this formula is implemented, creating a weighted sum of the vertices (positive contribution), the lines (negative), and the faces (positive contribution).

This manifold is usually attached to a coarse mesh and then places new points as a combination of the descriptions on the boundaries, weighted appropriately according to the position of the point in the original chart coordinates \((u,v)\). This manifold should be preferred over setting only a curved manifold on the boundary of a mesh in most situations as it yields more uniform mesh distributions as the mesh is refined because it switches from a curved description to a straight description over all children of the initial coarse cell this manifold was attached to. This way, the curved nature of the manifold that is originally contained in one coarse mesh layer will be applied to more than one fine mesh layer once the mesh gets refined. Note that the mechanisms of TransfiniteInterpolationManifold are also built into the MappingQGeneric class when only a surface of a cell is subject to a curved description, ensuring that even the default case without this manifold gets optimal convergence rates when applying curved boundary descriptions.

If no curved boundaries surround a coarse cell, this class reduces to a flat manifold description.

To give an example of using this class, the following code attaches a transfinite manifold to a circle:

PolarManifold<dim> polar_manifold;
GridGenerator::hyper_ball (triangulation);
triangulation.set_all_manifold_ids(1);
triangulation.set_manifold (0, polar_manifold);
inner_manifold.initialize(triangulation);
triangulation.set_manifold (1, inner_manifold);
triangulation.refine_global(4);

In this code, we first set all manifold ids to the id of the transfinite interpolation, and then re-set the manifold ids on the boundary to identify the curved boundary described by the polar manifold. With this code, one gets a really nice mesh:

circular_mesh_transfinite_interpolation.png

which is obviously much nicer than the polar manifold applied to just the boundary:

circular_mesh_only_boundary_manifold.png

Implementation details

In the implementation of this class, the manifolds surrounding a coarse cell are queried repeatedly to compute points on their interior. For optimal mesh quality, those manifolds should be compatible with a chart notion. For example, computing a point that is 0.25 along the line between two vertices using the weights 0.25 and 0.75 for the two vertices should give the same result as first computing the mid point at 0.5 and then again compute the midpoint between the first vertex and coarse mid point. This is the case for most of the manifold classes provided by deal.II, such as SphericalManifold or PolarManifold, but it might be violated by naive implementations. In case the quality of the manifold is not good enough, upon mesh refinement it may happen that the transformation to a chart inside the get_new_point() or get_new_points() methods produces points that are outside the unit cell. Then this class throws an exception of type Mapping::ExcTransformationFailed. In that case, the mesh should be refined before attaching this class, as done in the following example:

SphericalManifold<dim> spherical_manifold;
GridGenerator::hyper_ball (triangulation);
triangulation.set_all_manifold_ids(1);
triangulation.set_manifold (0, spherical_manifold);
inner_manifold.initialize(triangulation);
triangulation.set_manifold (1, inner_manifold);
triangulation.refine_global(1);
// initialize the transfinite manifold again
inner_manifold.initialize(triangulation);
triangulation.refine_global(4);
Note
For performance and accuracy reasons, it is recommended to apply the transfinite manifold to as coarse a mesh as possible. Regarding accuracy, the curved description can only be applied to new points created from a given neighborhood, and the grid quality is typically higher when extending the curved description over as large a domain as possible. Regarding performance, the identification of the correct coarse cell in the get_new_point() method needs to pass all coarse cells, so expect a linear complexity in the number of coarse cells for each single mapping operation, i.e., at least quadratic in the number of coarse mesh cells for any global operation on the whole mesh. Thus, the current implementation is only economical when there are not more than a few hundreds of coarse cells. To make performance better for larger numbers of cells, one could extend the current implementation by a pre-identification of relevant cells with axis-aligned bounding boxes.
Author
Martin Kronbichler, Luca Heltai, 2017

Definition at line 836 of file manifold_lib.h.

Constructor & Destructor Documentation

template<int dim, int spacedim>
TransfiniteInterpolationManifold< dim, spacedim >::TransfiniteInterpolationManifold ( )

Constructor.

Definition at line 1406 of file manifold_lib.cc.

template<int dim, int spacedim>
TransfiniteInterpolationManifold< dim, spacedim >::~TransfiniteInterpolationManifold ( )
overridevirtual

Destructor.

Definition at line 1417 of file manifold_lib.cc.

Member Function Documentation

template<int dim, int spacedim>
std::unique_ptr< Manifold< dim, spacedim > > TransfiniteInterpolationManifold< dim, spacedim >::clone ( ) const
overridevirtual

Make a clone of this Manifold object.

Implements Manifold< dim, spacedim >.

Definition at line 1427 of file manifold_lib.cc.

template<int dim, int spacedim>
void TransfiniteInterpolationManifold< dim, spacedim >::initialize ( const Triangulation< dim, spacedim > &  triangulation)

Initializes the manifold with a coarse mesh. The prerequisite for using this class is that the input triangulation is uniformly refined and the manifold is later attached to the same triangulation.

Whenever the assignment of manifold ids changes on the level of the triangulation which this class was initialized with, initialize() must be called again to update the manifold ids connected to the coarse cells.

Note
The triangulation used to construct the manifold must not be destroyed during the usage of this object.

Definition at line 1439 of file manifold_lib.cc.

template<int dim, int spacedim>
Point< spacedim > TransfiniteInterpolationManifold< dim, spacedim >::get_new_point ( const ArrayView< const Point< spacedim >> &  surrounding_points,
const ArrayView< const double > &  weights 
) const
overridevirtual

Return the point which shall become the new vertex surrounded by the given points surrounding_points. weights contains appropriate weights for the surrounding points according to which the manifold determines the new point's position.

The implementation in this class overrides the method in the base class and computes the new point by a transfinite interpolation. The first step in the implementation is to identify the coarse cell on which the surrounding points are located. Then, the coordinates are transformed to the unit coordinates on the coarse cell by a Newton iteration, where the new point is then computed according to the weights. Finally, it is pushed forward to the real space according to the transfinite interpolation.

Reimplemented from Manifold< dim, spacedim >.

Definition at line 2286 of file manifold_lib.cc.

template<int dim, int spacedim>
void TransfiniteInterpolationManifold< dim, spacedim >::get_new_points ( const ArrayView< const Point< spacedim >> &  surrounding_points,
const Table< 2, double > &  weights,
ArrayView< Point< spacedim >>  new_points 
) const
overridevirtual

Compute a new set of points that interpolate between the given points surrounding_points. weights is a table with as many columns as surrounding_points.size(). The number of columns in weights must match the length of new_points.

The implementation in this class overrides the method in the base class and computes the new point by a transfinite interpolation. The first step in the implementation is to identify the coarse cell on which the surrounding points are located. Then, the coordinates are transformed to the unit coordinates on the coarse cell by a Newton iteration, where the new points are then computed according to the weights. Finally, the is pushed forward to the real space according to the transfinite interpolation.

The implementation does not allow for surrounding_points and new_points to point to the same vector, so make sure to pass different objects into the function.

Reimplemented from Manifold< dim, spacedim >.

Definition at line 2306 of file manifold_lib.cc.

template<int dim, int spacedim>
std::array< unsigned int, 20 > TransfiniteInterpolationManifold< dim, spacedim >::get_possible_cells_around_points ( const ArrayView< const Point< spacedim >> &  surrounding_points) const
private

Internal function to identify the most suitable cells (=charts) where the given surrounding points are located. We use a cheap algorithm to identify the cells and rank the cells by probability before we actually do the search inside the relevant cells. The cells are sorted by the distance of a Q1 approximation of the inverse mapping to the unit cell of the surrounding points. We expect at most 20 cells (it should be up to 8 candidates on a 3D structured mesh and a bit more on unstructured ones, typically we only get two or three), so get an array with 20 entries of a the indices cell->index().

Definition at line 1973 of file manifold_lib.cc.

template<int dim, int spacedim>
Triangulation< dim, spacedim >::cell_iterator TransfiniteInterpolationManifold< dim, spacedim >::compute_chart_points ( const ArrayView< const Point< spacedim >> &  surrounding_points,
ArrayView< Point< dim >>  chart_points 
) const
private

Finalizes the identification of the correct chart and populates chart_points with the pullbacks of the surrounding points. This method internally calls get_possible_cells_around_points().

Return an iterator to the cell on which the chart is defined.

Definition at line 2059 of file manifold_lib.cc.

template<int dim, int spacedim>
Point< dim > TransfiniteInterpolationManifold< dim, spacedim >::pull_back ( const typename Triangulation< dim, spacedim >::cell_iterator &  cell,
const Point< spacedim > &  p,
const Point< dim > &  initial_guess 
) const
private

Pull back operation into the unit coordinates on the given coarse cell.

This method is currently based on a Newton-like iteration to find the point in the origin. One may speed up the iteration by providing a good initial guess as the third argument. If no better point is known, use cell->real_to_unit_cell_affine_approximation(p)

Note
This internal function is currently not compatible with the ChartManifold::pull_back() function because the given class represents an atlas of charts, not a single chart. Thus, the pull_back() operation is only valid with the additional information of the chart, given by a cell on the coarse grid. An alternative implementation could shift the index depending on the coarse cell for a 1-to-1 relation between the chart space and the image space.

Definition at line 1840 of file manifold_lib.cc.

template<int dim, int spacedim>
Point< spacedim > TransfiniteInterpolationManifold< dim, spacedim >::push_forward ( const typename Triangulation< dim, spacedim >::cell_iterator &  cell,
const Point< dim > &  chart_point 
) const
private

Push forward operation.

Note
This internal function is currently not compatible with the ChartManifold::push_forward() function because the given class represents an atlas of charts, not a single chart. Thus, the push_forward() operation is only valid with the additional information of the chart, given by a cell on the coarse grid. An alternative implementation could shift the index depending on the coarse cell for a 1-to-1 relation between the chart space and the image space.

Definition at line 1790 of file manifold_lib.cc.

template<int dim, int spacedim>
DerivativeForm< 1, dim, spacedim > TransfiniteInterpolationManifold< dim, spacedim >::push_forward_gradient ( const typename Triangulation< dim, spacedim >::cell_iterator &  cell,
const Point< dim > &  chart_point,
const Point< spacedim > &  pushed_forward_chart_point 
) const
private

Gradient of the push_forward method.

Note
This internal function is not compatible with the ChartManifold::push_forward_gradient() function because the given class represents an atlas of charts, not a single chart. Furthermore, this private function also requires the user to provide the result of the push_forward() call on the chart point for the single use case of this function, namely inside a Newton iteration where the gradient is computed by finite differences.

Definition at line 1811 of file manifold_lib.cc.

Member Data Documentation

template<int dim, int spacedim = dim>
const Triangulation<dim, spacedim>* TransfiniteInterpolationManifold< dim, spacedim >::triangulation
private

The underlying triangulation.

Definition at line 997 of file manifold_lib.h.

template<int dim, int spacedim = dim>
int TransfiniteInterpolationManifold< dim, spacedim >::level_coarse
private

The level of the mesh cells where the transfinite approximation is applied, usually level 0.

Definition at line 1003 of file manifold_lib.h.

template<int dim, int spacedim = dim>
std::vector<bool> TransfiniteInterpolationManifold< dim, spacedim >::coarse_cell_is_flat
private

In case there all surrounding manifolds are the transfinite manifold or have default (invalid) manifold id, the manifold degenerates to a flat manifold and we can choose cheaper algorithms for the push_forward method.

Definition at line 1010 of file manifold_lib.h.

template<int dim, int spacedim = dim>
FlatManifold<dim> TransfiniteInterpolationManifold< dim, spacedim >::chart_manifold
private

A flat manifold used to compute new points in the chart space where we use a FlatManifold description.

Definition at line 1016 of file manifold_lib.h.

template<int dim, int spacedim = dim>
boost::signals2::connection TransfiniteInterpolationManifold< dim, spacedim >::clear_signal
private

The connection to Triangulation::signals::clear that must be reset once this class goes out of scope.

Definition at line 1022 of file manifold_lib.h.


The documentation for this class was generated from the following files: