ThunderEgg  1.0.0
PatchSolverWrapper.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) 2018-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_SCHUR_PATCHSOLVERWRAPPER_H
22 #define THUNDEREGG_SCHUR_PATCHSOLVERWRAPPER_H
23 
29 #include <ThunderEgg/PatchSolver.h>
31 
32 namespace ThunderEgg {
33 namespace Schur {
39 template<int D>
40 class PatchSolverWrapper : public Operator<D - 1>
41 {
42 private:
46  std::shared_ptr<const InterfaceDomain<D>> iface_domain;
50  std::shared_ptr<const PatchSolver<D>> solver;
54  PatchIfaceScatter<D> scatter;
58  std::deque<std::shared_ptr<const PatchIfaceInfo<D>>> patches_with_only_local_ifaces;
62  std::deque<std::shared_ptr<const PatchIfaceInfo<D>>> patches_with_ifaces_on_neighbor_rank;
63 
64 public:
71  PatchSolverWrapper(const InterfaceDomain<D>& iface_domain, const PatchSolver<D>& solver)
72  : iface_domain(std::make_shared<InterfaceDomain<D>>(iface_domain))
73  , solver(solver.clone())
74  , scatter(iface_domain)
75  {
76  int rank;
77  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
78  for (auto piinfo : iface_domain.getPatchIfaceInfos()) {
79  for (Side<D> s : Side<D>::getValues()) {
80  if (piinfo->pinfo.hasNbr(s) && piinfo->getIfaceInfo(s)->rank != rank) {
81  patches_with_ifaces_on_neighbor_rank.push_back(piinfo);
82  break;
83  }
84  }
85  if (patches_with_ifaces_on_neighbor_rank.empty() ||
86  patches_with_ifaces_on_neighbor_rank.back() != piinfo) {
87  patches_with_only_local_ifaces.push_back(piinfo);
88  }
89  }
90  }
96  PatchSolverWrapper<D>* clone() const override { return new PatchSolverWrapper<D>(*this); }
103  void apply(const Vector<D - 1>& x, Vector<D - 1>& b) const override
104  {
105  int rank;
106  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
107 
108  Vector<D> u(solver->getDomain(), 1);
109  Vector<D> f(solver->getDomain(), 1);
110 
111  // scatter local iface vector
112  auto local_x = scatter.getNewLocalPatchIfaceVector();
113  auto state = scatter.scatterStart(x, *local_x);
114 
115  // each patch has a local interface, go ahead and set the ghost values using those
116  // interfaces
117  for (auto piinfo : iface_domain->getPatchIfaceInfos()) {
118  for (Side<D> s : Side<D>::getValues()) {
119  auto local_data = u.getComponentView(0, piinfo->pinfo.local_index);
120  if (piinfo->pinfo.hasNbr(s) && piinfo->getIfaceInfo(s)->rank == rank) {
121  auto ghosts = local_data.getSliceOn(s, { -1 });
122  auto interface = local_x->getComponentView(0, piinfo->getIfaceInfo(s)->patch_local_index);
123  Loop::OverInteriorIndexes<D - 1>(interface, [&](const std::array<int, D - 1>& coord) {
124  ghosts[coord] = 2 * interface[coord];
125  });
126  }
127  }
128  }
129  // go ahead and solve for patches with only local interfaces
130  for (auto piinfo : patches_with_only_local_ifaces) {
131  PatchView<double, D> u_view = u.getPatchView(piinfo->pinfo.local_index);
132  PatchView<double, D> f_view = f.getPatchView(piinfo->pinfo.local_index);
133  solver->solveSinglePatch(piinfo->pinfo, f_view, u_view);
134  }
135 
136  scatter.scatterFinish(state, x, *local_x);
137 
138  // set ghosts using interfaces that were on a neighboring rank
139  for (auto piinfo : patches_with_ifaces_on_neighbor_rank) {
140  for (Side<D> s : Side<D>::getValues()) {
141  auto local_data = u.getComponentView(0, piinfo->pinfo.local_index);
142  if (piinfo->pinfo.hasNbr(s) && piinfo->getIfaceInfo(s)->rank != rank) {
143  auto ghosts = local_data.getSliceOn(s, { -1 });
144  auto interface = local_x->getComponentView(0, piinfo->getIfaceInfo(s)->patch_local_index);
145  Loop::OverInteriorIndexes<D - 1>(interface, [&](const std::array<int, D - 1>& coord) {
146  ghosts[coord] = 2 * interface[coord];
147  });
148  }
149  }
150  }
151  // solve the remaining patches
152  for (auto piinfo : patches_with_ifaces_on_neighbor_rank) {
153  PatchView<double, D> u_view = u.getPatchView(piinfo->pinfo.local_index);
154  PatchView<double, D> f_view = f.getPatchView(piinfo->pinfo.local_index);
155  solver->solveSinglePatch(piinfo->pinfo, f_view, u_view);
156  }
157 
158  solver->getGhostFiller().fillGhost(u);
159 
160  for (auto iface : iface_domain->getInterfaces()) {
161  for (auto patch : iface->patches) {
162  if (patch.piinfo->pinfo.rank == rank &&
163  (patch.type.isNormal() || patch.type.isCoarseToCoarse() || patch.type.isFineToFine())) {
164  auto local_data = u.getComponentView(0, patch.piinfo->pinfo.local_index);
165  auto ghosts = local_data.getSliceOn(patch.side, { -1 });
166  auto inner = local_data.getSliceOn(patch.side, { 0 });
167  auto interface =
168  b.getComponentView(0, patch.piinfo->getIfaceInfo(patch.side)->patch_local_index);
169  Loop::Nested<D - 1>(
170  interface.getStart(), interface.getEnd(), [&](const std::array<int, D - 1>& coord) {
171  interface[coord] = (ghosts[coord] + inner[coord]) / 2;
172  });
173  break;
174  }
175  }
176  }
177  b.scaleThenAdd(-1, x);
178  }
185  void getSchurRHSFromDomainRHS(const Vector<D>& domain_b, Vector<D - 1>& schur_b) const
186  {
187  int rank;
188  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
189 
190  Vector<D> u(solver->getDomain(), 1);
191 
192  for (auto piinfo : iface_domain->getPatchIfaceInfos()) {
193  for (Side<D> s : Side<D>::getValues()) {
194  auto local_data = u.getComponentView(0, piinfo->pinfo.local_index);
195  if (piinfo->pinfo.hasNbr(s)) {
196  auto ghosts = local_data.getSliceOn(s, { -1 });
197  auto inner = local_data.getSliceOn(s, { 0 });
198  Loop::Nested<D - 1>(
199  ghosts.getStart(), ghosts.getEnd(), [&](const std::array<int, D - 1>& coord) {
200  ghosts[coord] = -inner[coord];
201  });
202  }
203  }
204  }
205  for (auto piinfo : iface_domain->getPatchIfaceInfos()) {
206  PatchView<double, D> u_view = u.getPatchView(piinfo->pinfo.local_index);
207  PatchView<const double, D> f_view = domain_b.getPatchView(piinfo->pinfo.local_index);
208  solver->solveSinglePatch(piinfo->pinfo, f_view, u_view);
209  }
210 
211  solver->getGhostFiller().fillGhost(u);
212 
213  for (auto iface : iface_domain->getInterfaces()) {
214  for (auto patch : iface->patches) {
215  if (patch.piinfo->pinfo.rank == rank &&
216  (patch.type.isNormal() || patch.type.isCoarseToCoarse() || patch.type.isFineToFine())) {
217  auto local_data = u.getComponentView(0, patch.piinfo->pinfo.local_index);
218  auto ghosts = local_data.getSliceOn(patch.side, { -1 });
219  auto inner = local_data.getSliceOn(patch.side, { 0 });
220  auto interface =
221  schur_b.getComponentView(0, patch.piinfo->getIfaceInfo(patch.side)->patch_local_index);
222  Loop::Nested<D - 1>(
223  interface.getStart(), interface.getEnd(), [&](const std::array<int, D - 1>& coord) {
224  interface[coord] = (ghosts[coord] + inner[coord]) / 2;
225  });
226  break;
227  }
228  }
229  }
230  }
231 };
232 extern template class PatchSolverWrapper<2>;
233 extern template class PatchSolverWrapper<3>;
234 } // namespace Schur
235 } // namespace ThunderEgg
236 #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
ThunderEgg::Loop::Nested
static void Nested(A start, A end, T lambda)
Loop over a range of integer coordinates.
Definition: Loops.h:125
ThunderEgg::PatchSolver
Solves the problem on the patches using a specified interface value.
Definition: PatchSolver.h:42
ThunderEgg::Schur::PatchIfaceScatter::scatterStart
State scatterStart(const Vector< D - 1 > &global_vector, Vector< D - 1 > &local_patch_iface_vector) const
Start the scatter from the global Schur compliment vector to the local patch iface vector.
Definition: PatchIfaceScatter.h:273
ThunderEgg::Schur::PatchIfaceScatter::getNewLocalPatchIfaceVector
std::shared_ptr< Vector< D - 1 > > getNewLocalPatchIfaceVector() const
Get a nw local patch iface vector.
Definition: PatchIfaceScatter.h:256
ThunderEgg::Schur::PatchIfaceScatter::scatterFinish
void scatterFinish(const State &state, const Vector< D - 1 > &global_vector, Vector< D - 1 > &local_patch_iface_vector) const
Finish the scatter from the global Schur compliment vector to the local patch iface vector.
Definition: PatchIfaceScatter.h:340
ThunderEgg::Schur::PatchSolverWrapper::clone
PatchSolverWrapper< D > * clone() const override
Get a clone of this PatchSolverWrapper.
Definition: PatchSolverWrapper.h:96
PatchIfaceScatter.h
PatchIfaceScatter class.
ThunderEgg::Schur::PatchIfaceScatter
Scatters between a global Schur compliment vector and a local patch iface vector.
Definition: PatchIfaceScatter.h:42
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< double, D >
ThunderEgg
The ThunderEgg namespace.
Definition: BiLinearGhostFiller.h:31
ThunderEgg::Schur::InterfaceDomain::getPatchIfaceInfos
const std::vector< std::shared_ptr< const PatchIfaceInfo< D > > > & getPatchIfaceInfos() const
Get the vector PatchIfaceInfo objects for this rank.
Definition: InterfaceDomain.h:649
ThunderEgg::Loop::OverInteriorIndexes
static void OverInteriorIndexes(const V &view, T lambda)
Loop over all the interior coordinates of a view.
Definition: Loops.h:140
ThunderEgg::Schur::PatchSolverWrapper
Creates a Schur compliment matrix operator for an InterfaceDomain by using a PatchSolver.
Definition: PatchSolverWrapper.h:40
ThunderEgg::Operator
Base class for operators.
Definition: Operator.h:37
ThunderEgg::Vector::getPatchView
PatchView< double, D > getPatchView(int patch_local_index)
Get the View objects for the specified patch index of View object will correspond to component index.
Definition: Vector.h:358
ThunderEgg::Schur::PatchSolverWrapper::getSchurRHSFromDomainRHS
void getSchurRHSFromDomainRHS(const Vector< D > &domain_b, Vector< D - 1 > &schur_b) const
Get the RHS for the Schur system from a given RHS for the domain system.
Definition: PatchSolverWrapper.h:185
ThunderEgg::Schur::PatchSolverWrapper::apply
void apply(const Vector< D - 1 > &x, Vector< D - 1 > &b) const override
Apply Schur matrix.
Definition: PatchSolverWrapper.h:103
ThunderEgg::Vector< D - 1 >
ThunderEgg::Face
Enum-style class for the faces of an n-dimensional cube.
Definition: Face.h:41
PatchSolver.h
PatchSolver class.
ThunderEgg::Schur::PatchSolverWrapper::PatchSolverWrapper
PatchSolverWrapper(const InterfaceDomain< D > &iface_domain, const PatchSolver< D > &solver)
Construct a new PatchSolverWrapper object.
Definition: PatchSolverWrapper.h:71
ThunderEgg::Schur::InterfaceDomain
Represents the Schur compliment domain of the problem.
Definition: InterfaceDomain.h:55