ThunderEgg  1.0.0
StarPatchOperator.h
Go to the documentation of this file.
1 /***************************************************************************
2  * ThunderEgg, a library for solvers on adaptively refined block-structured
3  * Cartesian grids.
4  *
5  * Copyright (c) 2020-2021 Scott Aiton
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  ***************************************************************************/
20 
21 #ifndef THUNDEREGG_POISSON_STARPATCHOPERATOR_H
22 #define THUNDEREGG_POISSON_STARPATCHOPERATOR_H
23 
29 #include <ThunderEgg/DomainTools.h>
30 #include <ThunderEgg/GMG/Level.h>
31 #include <ThunderEgg/GhostFiller.h>
34 #include <ThunderEgg/Vector.h>
35 
36 namespace ThunderEgg::Poisson {
44 template<int D>
46 {
47 private:
48  constexpr int addValue(int axis) const { return (axis == 0) ? 0 : 1; }
49  bool neumann;
50 
51 public:
60  const GhostFiller<D>& ghost_filler,
61  bool neumann = false)
62  : PatchOperator<D>(domain, ghost_filler)
63  , neumann(neumann)
64  {
65  if (this->getDomain().getNumGhostCells() < 1) {
66  throw RuntimeError("StarPatchOperator needs at least one set of ghost cells");
67  }
68  }
74  StarPatchOperator<D>* clone() const override { return new StarPatchOperator<D>(*this); }
75  void applySinglePatch(const PatchInfo<D>& pinfo,
76  const PatchView<const double, D>& u_view,
77  const PatchView<double, D>& f_view,
78  bool internal) const
79  {
80  if (internal) {
81  enforceInternalBoundaryConditions(pinfo, u_view);
82  }
83 
84  enforceBoundaryConditions(pinfo, u_view);
85 
86  std::array<double, D> h2 = pinfo.spacings;
87  for (size_t i = 0; i < D; i++) {
88  h2[i] *= h2[i];
89  }
90 
91  Loop::Unroll<0, D - 1>([&](int axis) {
92  int stride = u_view.getStrides()[axis];
93  Loop::OverInteriorIndexes<D + 1>(u_view, [&](std::array<int, D + 1> coord) {
94  const double* ptr = &u_view[coord];
95  double lower = *(ptr - stride);
96  double mid = *ptr;
97  double upper = *(ptr + stride);
98  f_view[coord] = addValue(axis) * f_view[coord] + (upper - 2 * mid + lower) / h2[axis];
99  });
100  });
101  }
102  void applySinglePatch(const PatchInfo<D>& pinfo,
103  const PatchView<const double, D>& u_view,
104  const PatchView<double, D>& f_view) const override
105  {
106  applySinglePatch(pinfo, u_view, f_view, false);
107  }
109  const PatchInfo<D>& pinfo,
110  const PatchView<const double, D>& u_view,
111  const PatchView<double, D>& f_view) const override
112  {
113  applySinglePatch(pinfo, u_view, f_view, true);
114  }
115  void enforceBoundaryConditions(const PatchInfo<D>& pinfo,
116  const PatchView<const double, D>& u_view) const
117  {
118  for (int axis = 0; axis < D; axis++) {
119  Side<D> lower_side = LowerSideOnAxis<D>(axis);
120  Side<D> upper_side = HigherSideOnAxis<D>(axis);
121  if (!pinfo.hasNbr(lower_side)) {
122  View<double, D> lower = u_view.getGhostSliceOn(lower_side, { 0 });
123  View<const double, D> lower_mid = u_view.getSliceOn(lower_side, { 0 });
124  if (neumann) {
125  Loop::OverInteriorIndexes<D>(
126  lower_mid, [&](std::array<int, D> coord) { lower[coord] = lower_mid[coord]; });
127  } else {
128  Loop::OverInteriorIndexes<D>(
129  lower_mid, [&](std::array<int, D> coord) { lower[coord] = -lower_mid[coord]; });
130  }
131  }
132  if (!pinfo.hasNbr(upper_side)) {
133  View<double, D> upper = u_view.getGhostSliceOn(upper_side, { 0 });
134  View<const double, D> upper_mid = u_view.getSliceOn(upper_side, { 0 });
135  if (neumann) {
136  Loop::OverInteriorIndexes<D>(
137  upper_mid, [&](std::array<int, D> coord) { upper[coord] = upper_mid[coord]; });
138  } else {
139  Loop::OverInteriorIndexes<D>(
140  upper_mid, [&](std::array<int, D> coord) { upper[coord] = -upper_mid[coord]; });
141  }
142  }
143  }
144  }
145  void enforceInternalBoundaryConditions(const PatchInfo<D>& pinfo,
146  const PatchView<const double, D>& u_view) const
147  {
148  for (int axis = 0; axis < D; axis++) {
149  Side<D> lower_side = LowerSideOnAxis<D>(axis);
150  Side<D> upper_side = HigherSideOnAxis<D>(axis);
151  if (pinfo.hasNbr(lower_side)) {
152  View<double, D> lower = u_view.getGhostSliceOn(lower_side, { 0 });
153  View<const double, D> lower_mid = u_view.getSliceOn(lower_side, { 0 });
154  Loop::OverInteriorIndexes<D>(
155  lower_mid, [&](std::array<int, D> coord) { lower[coord] = -lower_mid[coord]; });
156  }
157  if (pinfo.hasNbr(upper_side)) {
158  View<double, D> upper = u_view.getGhostSliceOn(upper_side, { 0 });
159  View<const double, D> upper_mid = u_view.getSliceOn(upper_side, { 0 });
160  Loop::OverInteriorIndexes<D>(
161  upper_mid, [&](std::array<int, D> coord) { upper[coord] = -upper_mid[coord]; });
162  }
163  }
164  }
166  const PatchView<const double, D>& u_view,
167  const PatchView<double, D>& f_view) const override
168  {
169  for (Side<D> s : Side<D>::getValues()) {
170  if (pinfo.hasNbr(s)) {
171  double h2 = pow(pinfo.spacings[s.getAxisIndex()], 2);
172  View<double, D> f_inner = f_view.getSliceOn(s, { 0 });
173  View<const double, D> u_ghost = u_view.getSliceOn(s, { -1 });
174  View<const double, D> u_inner = u_view.getSliceOn(s, { 0 });
175  Loop::OverInteriorIndexes<D>(f_inner, [&](const std::array<int, D>& coord) {
176  f_inner[coord] -= (u_ghost[coord] + u_inner[coord]) / h2;
177  });
178  }
179  }
180  }
187  void addDrichletBCToRHS(Vector<D>& f, std::function<double(const std::array<double, D>&)> gfunc)
188  {
189  for (int i = 0; i < f.getNumLocalPatches(); i++) {
191  auto pinfo = this->getDomain().getPatchInfoVector()[i];
192  for (Side<D> s : Side<D>::getValues()) {
193  if (!pinfo.hasNbr(s)) {
194  double h2 = pow(pinfo.spacings[s.getAxisIndex()], 2);
195  View<double, D - 1> ld = f_ld.getSliceOn(s, { 0 });
196  Loop::Nested<D - 1>(ld.getStart(), ld.getEnd(), [&](const std::array<int, D - 1>& coord) {
197  std::array<double, D> real_coord;
198  DomainTools::GetRealCoordBound<D>(pinfo, coord, s, real_coord);
199  ld[coord] += -2.0 * gfunc(real_coord) / h2;
200  });
201  }
202  }
203  }
204  }
213  Vector<D>& f,
214  std::function<double(const std::array<double, D>&)> gfunc,
215  std::array<std::function<double(const std::array<double, D>&)>, D> gfunc_grad)
216  {
217  for (int i = 0; i < f.getNumLocalPatches(); i++) {
219  auto pinfo = this->getDomain().getPatchInfoVector()[i];
220  for (Side<D> s : Side<D>::getValues()) {
221  if (!pinfo.hasNbr(s)) {
222  double h = pinfo.spacings[s.getAxisIndex()];
223  View<double, D - 1> ld = f_ld.getSliceOn(s, { 0 });
224  if (s.isLowerOnAxis()) {
225  Loop::Nested<D - 1>(
226  ld.getStart(), ld.getEnd(), [&](const std::array<int, D - 1>& coord) {
227  std::array<double, D> real_coord;
228  DomainTools::GetRealCoordBound<D>(pinfo, coord, s, real_coord);
229  ld[coord] += gfunc_grad[s.getAxisIndex()](real_coord) / h;
230  });
231  } else {
232  Loop::Nested<D - 1>(
233  ld.getStart(), ld.getEnd(), [&](const std::array<int, D - 1>& coord) {
234  std::array<double, D> real_coord;
235  DomainTools::GetRealCoordBound<D>(pinfo, coord, s, real_coord);
236  ld[coord] -= gfunc_grad[s.getAxisIndex()](real_coord) / h;
237  });
238  }
239  }
240  }
241  }
242  }
243 };
244 extern template class StarPatchOperator<2>;
245 extern template class StarPatchOperator<3>;
246 } // namespace ThunderEgg::Poisson
247 #endif
ThunderEgg::Vector::getComponentView
ComponentView< double, D > getComponentView(int component_index, int patch_local_index)
Get the ComponentView for the specified patch and component.
Definition: Vector.h:336
RuntimeError.h
RuntimeError struct.
ThunderEgg::Poisson::StarPatchOperator::clone
StarPatchOperator< D > * clone() const override
Get a clone of this operator.
Definition: StarPatchOperator.h:74
ThunderEgg::Loop::Nested
static void Nested(A start, A end, T lambda)
Loop over a range of integer coordinates.
Definition: Loops.h:125
ThunderEgg::View< double, D >
ThunderEgg::Loop::Unroll
static void Unroll(T lambda)
Unroll a fixed-length loop.
Definition: Loops.h:72
Vector.h
Vector class.
ThunderEgg::View< T, D+1 >::getStrides
const std::array< int, D > & getStrides() const
Get the strides of the patch in each direction.
Definition: View.h:203
ThunderEgg::PatchInfo::hasNbr
bool hasNbr(Face< D, M > s) const
Return whether the patch has a neighbor.
Definition: PatchInfo.h:284
ThunderEgg::Poisson::StarPatchOperator::addNeumannBCToRHS
void addNeumannBCToRHS(Vector< D > &f, std::function< double(const std::array< double, D > &)> gfunc, std::array< std::function< double(const std::array< double, D > &)>, D > gfunc_grad)
Helper function for adding Neumann boundary conditions to right hand side.
Definition: StarPatchOperator.h:212
ThunderEgg::PatchView::getSliceOn
View< T, M+1 > getSliceOn(Face< D, M > f, const std::array< int, D - M > &offset) const
Get the slice on a given face.
Definition: PatchView.h:200
ThunderEgg::PatchView::getGhostSliceOn
View< typename std::remove_const< T >::type, M+1 > getGhostSliceOn(Face< D, M > f, const std::array< size_t, D - M > &offset) const
Get the gosts slice on a given face.
Definition: PatchView.h:219
DomainTools.h
DomainTools class.
ThunderEgg::ComponentView< double, D >
ThunderEgg::Domain
Uses a collection of PatchInfo objects to represent the domain of the problem.
Definition: Domain.h:50
PatchOperator.h
PatchOperator class.
ThunderEgg::Poisson
Classes specific to the Poisson equation.
Definition: DFTPatchSolver.h:40
Level.h
Level class.
ThunderEgg::ComponentView::getSliceOn
View< T, M > getSliceOn(Face< D, M > f, const std::array< int, D - M > &offset) const
Get the slice on a given face.
Definition: ComponentView.h:194
ThunderEgg::PatchView
View for accessing data of a patch. It supports variable striding.
Definition: PatchView.h:37
ThunderEgg::Poisson::StarPatchOperator::StarPatchOperator
StarPatchOperator(const Domain< D > &domain, const GhostFiller< D > &ghost_filler, bool neumann=false)
Construct a new StarPatchOperator object.
Definition: StarPatchOperator.h:59
GhostFiller.h
GhostFiller class.
ThunderEgg::GhostFiller
Fills ghost cells on patches.
Definition: GhostFiller.h:36
ThunderEgg::PatchInfo
Contains metadata for a patch.
Definition: PatchInfo.h:51
ThunderEgg::PatchOperator::getDomain
const Domain< D > & getDomain() const
Get the Domain object associated with this PatchOperator.
Definition: PatchOperator.h:147
ThunderEgg::PatchOperator
This is an Operator where derived classes only have to implement the two virtual functions that opera...
Definition: PatchOperator.h:40
ThunderEgg::PatchInfo::spacings
std::array< double, D > spacings
The cell spacings in each direction.
Definition: PatchInfo.h:125
ThunderEgg::Poisson::StarPatchOperator::applySinglePatch
void applySinglePatch(const PatchInfo< D > &pinfo, const PatchView< const double, D > &u_view, const PatchView< double, D > &f_view) const override
Apply the operator to a single patch.
Definition: StarPatchOperator.h:102
ThunderEgg::Poisson::StarPatchOperator
Implements 2nd order finite-difference Laplacian operator.
Definition: StarPatchOperator.h:45
ThunderEgg::Vector
Vector class for use in thunderegg.
Definition: Vector.h:42
ThunderEgg::Face
Enum-style class for the faces of an n-dimensional cube.
Definition: Face.h:41
ThunderEgg::Poisson::StarPatchOperator::modifyRHSForInternalBoundaryConditions
void modifyRHSForInternalBoundaryConditions(const PatchInfo< D > &pinfo, const PatchView< const double, D > &u_view, const PatchView< double, D > &f_view) const override
Treat the internal patch boundaries as domain boundaires and modify RHS accordingly.
Definition: StarPatchOperator.h:165
ThunderEgg::Poisson::StarPatchOperator::applySinglePatchWithInternalBoundaryConditions
void applySinglePatchWithInternalBoundaryConditions(const PatchInfo< D > &pinfo, const PatchView< const double, D > &u_view, const PatchView< double, D > &f_view) const override
Apply the operator to a single patch.
Definition: StarPatchOperator.h:108
ThunderEgg::Poisson::StarPatchOperator::addDrichletBCToRHS
void addDrichletBCToRHS(Vector< D > &f, std::function< double(const std::array< double, D > &)> gfunc)
Helper function for adding Dirichlet boundary conditions to right hand side.
Definition: StarPatchOperator.h:187
ThunderEgg::Vector::getNumLocalPatches
int getNumLocalPatches() const
Get the number of local patches.
Definition: Vector.h:316
ThunderEgg::RuntimeError
ThunderEgg runtime exception.
Definition: RuntimeError.h:36