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 <unordered_set>
9 :
10 : #include "DataStructures/DataVector.hpp"
11 : #include "DataStructures/Tensor/Tensor.hpp"
12 : #include "Domain/Structure/Direction.hpp"
13 : #include "Utilities/Gsl.hpp"
14 :
15 : namespace LinearSolver::Schwarz {
16 :
17 : /*!
18 : * \brief Weights for the solution on an element-centered subdomain, decreasing
19 : * from 1 to 0.5 towards the `side` over the logical distance `width`, and
20 : * further to 0 over the same distance outside the element.
21 : *
22 : * The weighting function over a full element-centered subdomain is
23 : *
24 : * \f{equation}
25 : * w(\xi) = \frac{1}{2}\left( \phi\left( \frac{\xi + 1}{\delta} \right) -
26 : * \phi\left( \frac{\xi - 1}{\delta} \right) \right) \f}
27 : *
28 : * where \f$\phi(\xi)\f$ is a second-order `::smoothstep`, i.e. the quintic
29 : * polynomial
30 : *
31 : * \f{align*}
32 : * \phi(\xi) = \begin{cases} \mathrm{sign}(\xi) \quad \text{for}
33 : * \quad |\xi| > 1 \\
34 : * \frac{1}{8}\left(15\xi - 10\xi^3 + 3\xi^5\right) \end{cases}
35 : * \f}
36 : *
37 : * (see Eq. (39) in \cite Vincent2019qpd).
38 : *
39 : * The `LinearSolver::Schwarz::extruding_weight` and
40 : * `LinearSolver::Schwarz::intruding_weight` functions each compute one of the
41 : * two terms in \f$w(\xi)\f$. For example, consider an element-centered
42 : * subdomain `A` that overlaps with a neighboring element-centered subdomain
43 : * `B`. To combine solutions on `A` and `B` to a weighted solution on `A`,
44 : * multiply the solution on `A` with the `extruding_weight` and the solution on
45 : * `B` with the `intruding_weight`, both evaluated at the logical coordinates in
46 : * `A` and at the `side` of `A` that faces `B`.
47 : */
48 1 : DataVector extruding_weight(const DataVector& logical_coords, double width,
49 : const Side& side);
50 :
51 : /// @{
52 : /*!
53 : * \brief Weights for data on the central element of an element-centered
54 : * subdomain
55 : *
56 : * Constructs the weighting field
57 : *
58 : * \f{equation}
59 : * W(\boldsymbol{\xi}) = \prod^d_{i=0} w(\xi^i)
60 : * \f}
61 : *
62 : * where \f$w(\xi^i)\f$ is the one-dimensional weighting function described in
63 : * `LinearSolver::Schwarz::extruding_weight` and \f$\xi^i\f$ are the
64 : * element-logical coordinates (see Eq. (41) in \cite Vincent2019qpd).
65 : */
66 : template <size_t Dim>
67 1 : void element_weight(
68 : gsl::not_null<Scalar<DataVector>*> element_weight,
69 : const tnsr::I<DataVector, Dim, Frame::ElementLogical>& logical_coords,
70 : const std::array<double, Dim>& overlap_widths,
71 : const std::unordered_set<Direction<Dim>>& external_boundaries);
72 :
73 : template <size_t Dim>
74 1 : Scalar<DataVector> element_weight(
75 : const tnsr::I<DataVector, Dim, Frame::ElementLogical>& logical_coords,
76 : const std::array<double, Dim>& overlap_widths,
77 : const std::unordered_set<Direction<Dim>>& external_boundaries);
78 : /// @}
79 :
80 : /*!
81 : * \brief Weights for the intruding solution of a neighboring element-centered
82 : * subdomain, increasing from 0 to 0.5 towards the `side` over the logical
83 : * distance `width`, and further to 1 over the same distance outside the
84 : * element.
85 : *
86 : * \see `LinearSolver::Schwarz::extruding_weight`
87 : */
88 1 : DataVector intruding_weight(const DataVector& logical_coords, double width,
89 : const Side& side);
90 :
91 : /// @{
92 : /*!
93 : * \brief Weights for data on overlap regions intruding into an element-centered
94 : * subdomain
95 : *
96 : * Constructs the weighting field \f$W(\xi)\f$ as described in
97 : * `LinearSolver::Schwarz::element_weight` for the data that overlaps with the
98 : * central element of an element-centered subdomain. The weights are constructed
99 : * in such a way that all weights at a grid point sum to one, i.e. the weight is
100 : * conserved. The `logical_coords` are the element-logical coordinates of the
101 : * central element.
102 : *
103 : * This function assumes that corner- and edge-neighbors of the central element
104 : * are not part of the subdomain, which means that no contributions from those
105 : * neighbors are expected although the weighting field is non-zero in overlap
106 : * regions with those neighbors. Therefore, to retain conservation we must
107 : * account for this missing weight by adding it to the central element, to the
108 : * intruding overlaps from face-neighbors, or split it between the two. We
109 : * choose to add the weight to the intruding overlaps, since that's where
110 : * information from the corner- and edge-regions propagates through in a DG
111 : * context.
112 : */
113 : template <size_t Dim>
114 1 : void intruding_weight(
115 : gsl::not_null<Scalar<DataVector>*> weight,
116 : const tnsr::I<DataVector, Dim, Frame::ElementLogical>& logical_coords,
117 : const Direction<Dim>& direction,
118 : const std::array<double, Dim>& overlap_widths,
119 : size_t num_intruding_overlaps,
120 : const std::unordered_set<Direction<Dim>>& external_boundaries);
121 :
122 : template <size_t Dim>
123 1 : Scalar<DataVector> intruding_weight(
124 : const tnsr::I<DataVector, Dim, Frame::ElementLogical>& logical_coords,
125 : const Direction<Dim>& direction,
126 : const std::array<double, Dim>& overlap_widths,
127 : size_t num_intruding_overlaps,
128 : const std::unordered_set<Direction<Dim>>& external_boundaries);
129 : /// @}
130 :
131 : } // namespace LinearSolver::Schwarz
|