Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <array> 7 : #include <cstddef> 8 : #include <functional> 9 : #include <ostream> 10 : 11 : /// \cond 12 : class Matrix; 13 : template <size_t Dim> 14 : class Mesh; 15 : /// \endcond 16 : 17 : namespace Spectral { 18 : 19 : /// The portion of a mesh covered by a child mesh. 20 0 : enum class ChildSize { Full, UpperHalf, LowerHalf }; 21 : 22 : /// The portion of an element covered by a mortar. 23 1 : using MortarSize = ChildSize; 24 : 25 0 : std::ostream& operator<<(std::ostream& os, ChildSize mortar_size); 26 : 27 : /// Determine whether data needs to be projected between a child mesh and its 28 : /// parent mesh. If no projection is necessary the data may be used as-is. 29 : /// Projection is necessary if the child is either p-refined or h-refined 30 : /// relative to its parent, or both. This operation is symmetric, i.e. it is 31 : /// irrelevant in which order the child and the parent mesh are passed in. 32 : template <size_t Dim> 33 1 : bool needs_projection(const Mesh<Dim>& mesh1, const Mesh<Dim>& mesh2, 34 : const std::array<ChildSize, Dim>& child_sizes); 35 : 36 : /*! 37 : * \brief The projection matrix from a child mesh to its parent. 38 : * 39 : * The projection matrices returned by this function (and by 40 : * projection_matrix_parent_to_child()) define orthogonal projection operators 41 : * between the spaces of functions on a parent mesh and its children. These 42 : * projections are usually the correct way to transfer data between meshes in 43 : * a mesh-refinement hierarchy, as well as between an element face and its 44 : * adjacent mortars. 45 : * 46 : * These functions assume that the `child_mesh` is at least as fine as the 47 : * `parent_mesh`, i.e. functions on the `parent_mesh` can be represented exactly 48 : * on the `child_mesh`. In practice this means that functions can be projected 49 : * to a mortar (the `child_mesh`) from both adjacent element faces (the 50 : * `parent_mesh`) without losing accuracy. Similarly, functions in a 51 : * mesh-refinement hierarchy don't lose accuracy when an element is split 52 : * (h-refined). For this reason, the `projection_matrix_child_to_parent` is 53 : * sometimes referred to as a "restriction operator" and the 54 : * `projection_matrix_parent_to_child` as a "prolongation operator". 55 : * 56 : * \par Massive quantities 57 : * If the quantity that should be projected is not a function over the 58 : * computational grid but a "massive" residual, i.e. a quantity 59 : * \f$\int_{\Omega_k} f(x) \psi_p(x) \mathrm{d}V\f$ where \f$\psi_p\f$ are the 60 : * basis functions on the mesh, then pass `true` for the parameter 61 : * `operand_is_massive` (default is `false`). The restriction operator for this 62 : * case is just the transpose of the prolongation operator, i.e. just an 63 : * interpolation matrix transpose. Note that the "massive" residual already 64 : * takes the difference in element size between parent and children into account 65 : * by including a Jacobian in the volume element of the integral. 66 : * 67 : * \par Implementation details 68 : * The half-interval projections are based on an equation derived by 69 : * Saul. This shows that the projection from the spectral basis for 70 : * the entire interval to the spectral basis for the upper half 71 : * interval is 72 : * \f{equation*} 73 : * T_{jk} = \frac{2 j + 1}{2} 2^j \sum_{n=0}^{j-k} \binom{j}{k+n} 74 : * \binom{(j + k + n - 1)/2}{j} \frac{(k + n)!^2}{(2 k + n + 1)! n!} 75 : * \f} 76 : */ 77 1 : const Matrix& projection_matrix_child_to_parent( 78 : const Mesh<1>& child_mesh, const Mesh<1>& parent_mesh, ChildSize size, 79 : bool operand_is_massive = false); 80 : 81 : /// The projection matrix from a child mesh to its parent, in `Dim` dimensions. 82 : template <size_t Dim> 83 : std::array<std::reference_wrapper<const Matrix>, Dim> 84 1 : projection_matrix_child_to_parent(const Mesh<Dim>& child_mesh, 85 : const Mesh<Dim>& parent_mesh, 86 : const std::array<ChildSize, Dim>& child_sizes, 87 : bool operand_is_massive = false); 88 : 89 : /// The projection matrix from a parent mesh to one of its children. 90 : /// 91 : /// \see projection_matrix_child_to_parent() 92 1 : const Matrix& projection_matrix_parent_to_child(const Mesh<1>& parent_mesh, 93 : const Mesh<1>& child_mesh, 94 : ChildSize size); 95 : 96 : /// The projection matrix from a parent mesh to one of its children, in `Dim` 97 : /// dimensions 98 : template <size_t Dim> 99 : std::array<std::reference_wrapper<const Matrix>, Dim> 100 1 : projection_matrix_parent_to_child( 101 : const Mesh<Dim>& parent_mesh, const Mesh<Dim>& child_mesh, 102 : const std::array<ChildSize, Dim>& child_sizes); 103 : 104 : /// The projection matrices from a source mesh to a target mesh where the 105 : /// meshes cover the same physical volume 106 : template <size_t Dim> 107 1 : std::array<std::reference_wrapper<const Matrix>, Dim> p_projection_matrices( 108 : const Mesh<Dim>& source_mesh, const Mesh<Dim>& target_mesh); 109 : } // namespace Spectral