Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
AMReX/cutcell/FluxMethod.hpp
Go to the documentation of this file.
1 // Copyright (c) 2019 Maikel Nadolski
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #ifndef FUB_AMREX_CUTCELL_FLUX_METHOD_HPP
22 #define FUB_AMREX_CUTCELL_FLUX_METHOD_HPP
23 
24 #include "fub/Direction.hpp"
25 #include "fub/Duration.hpp"
26 #include "fub/ext/omp.hpp"
27 
28 #include "fub/AMReX/ForEachFab.hpp"
30 
32 
33 #include <AMReX_EBAmrUtil.H>
34 
35 #include <memory>
36 
37 namespace fub::amrex::cutcell {
38 
39 inline ::amrex::Vector<std::string>
40 AddPrefix(const ::amrex::Vector<std::string>& names,
41  const std::string& prefix) {
42  ::amrex::Vector<std::string> new_names{};
43  new_names.reserve(names.size());
44  for (const std::string& name : names) {
45  new_names.push_back(fmt::format("{}_{}", prefix, name));
46  }
47  return new_names;
48 }
49 
50 template <typename Tag, typename Base> class FluxMethod {
51 public:
52  using Equation = typename Base::Equation;
53 
54  explicit FluxMethod(Base&& fm) : FluxMethod(Tag(), std::move(fm)) {}
55  explicit FluxMethod(const Base& fm) : FluxMethod(Tag(), fm) {}
56  FluxMethod(Tag, const Base& fm);
57  FluxMethod(Tag, Base&& fm);
58 
59  static constexpr int GetStencilWidth() noexcept;
60 
61  const Base& GetBase() const noexcept;
62 
64 
65  void ComputeNumericFluxes(IntegratorContext& context, int level, Duration dt,
66  Direction dir);
67 
68  Duration ComputeStableDt(IntegratorContext& context, int level,
69  Direction dir);
70 
71 private:
72  Local<Tag, Base> flux_method_;
73 };
74 
75 template <typename F>
76 FluxMethod(F &&) -> FluxMethod<execution::OpenMpSimdTag, std::decay_t<F>>;
77 
78 template <typename Tag, typename FM>
79 FluxMethod(Tag, FM &&) -> FluxMethod<Tag, std::decay_t<FM>>;
80 
81 template <typename Tag, typename FM>
82 FluxMethod<Tag, FM>::FluxMethod(Tag, FM&& flux_method)
83  : flux_method_(std::move(flux_method)) {}
84 
85 template <typename Tag, typename FM>
86 FluxMethod<Tag, FM>::FluxMethod(Tag, const FM& flux_method)
87  : flux_method_(flux_method) {}
88 
89 template <typename Tag, typename FM>
90 constexpr int FluxMethod<Tag, FM>::GetStencilWidth() noexcept {
91  return FM::GetStencilWidth();
92 }
93 
94 template <typename Tag, typename FM>
95 const FM& FluxMethod<Tag, FM>::GetBase() const noexcept {
96  return *flux_method_;
97 }
98 
99 template <typename Tag, typename FM>
101  if constexpr (is_detected<detail::PreAdvanceHierarchyT, FM&,
103  View<const Complete<Equation>>,
104  CutCellData<AMREX_SPACEDIM>>::value) {
105  const PatchHierarchy& hierarchy = context.GetPatchHierarchy();
106  for (int level = 0; level < hierarchy.GetNumberOfLevels(); ++level) {
107  ::amrex::MultiFab& references = context.GetReferenceStates(level);
108  context.GetGriddingAlgorithm()->FillMultiFabFromLevel(references, level);
109  ForEachFab(Tag(), references, [&](const ::amrex::MFIter& mfi) {
110  if (context.GetFabType(level, mfi) == ::amrex::FabType::singlevalued) {
111  const Equation& eq = flux_method_->GetEquation();
112  const ::amrex::Box box = mfi.growntilebox();
113  View<Complete<Equation>> refs =
114  MakeView<Complete<Equation>>(references[mfi], eq, box);
115  View<const Complete<Equation>> states =
116  MakeView<const Complete<Equation>>(references[mfi], eq, box);
117  CutCellData<AMREX_SPACEDIM> geom =
118  hierarchy.GetCutCellData(level, mfi);
119  flux_method_->PreAdvanceHierarchy(refs, states, geom);
120  }
121  });
122  }
123  }
124 }
125 
126 namespace detail {
127 template <typename T, typename... Args>
128 using ComputeBoundaryFluxesT =
129  decltype(std::declval<T>().ComputeBoundaryFluxes(std::declval<Args>()...));
130 
131 template <typename T, typename... Args>
132 using ComputeCutCellFluxes =
133  decltype(std::declval<T>().ComputeCutCellFluxes(std::declval<Args>()...));
134 
135 template <typename T, typename... Args>
136 using ComputeGradients =
137  decltype(std::declval<T>().ComputeGradients(std::declval<Args>()...));
138 } // namespace detail
139 
140 template <typename Tag, typename FM>
142  int level, Duration dt,
143  Direction dir) {
144  const PatchHierarchy& hierarchy = context.GetPatchHierarchy();
145  ::amrex::MultiFab& references = context.GetReferenceStates(level);
146  const ::amrex::MultiFab& scratch = context.GetScratch(level);
147  ::amrex::MultiCutFab& boundary_fluxes = context.GetBoundaryFluxes(level);
148 
149  ::amrex::MultiFab& fluxes = context.GetFluxes(level, dir);
150  ::amrex::MultiFab& fluxes_s = context.GetStabilizedFluxes(level, dir);
151  ::amrex::MultiFab& fluxes_sL = context.GetShieldedFromLeftFluxes(level, dir);
152  ::amrex::MultiFab& fluxes_sR = context.GetShieldedFromRightFluxes(level, dir);
153  ::amrex::MultiFab& fluxes_ds = context.GetDoublyShieldedFluxes(level, dir);
154 
155  [[maybe_unused]] ::amrex::MultiFab gradient_x;
156  [[maybe_unused]] ::amrex::MultiFab gradient_y;
157  [[maybe_unused]] ::amrex::MultiFab gradient_z;
158 
159  const double dx = context.GetDx(level, dir);
160  const Eigen::Matrix<double, AMREX_SPACEDIM, 1> dx_vec{AMREX_D_DECL(
161  context.GetDx(level, Direction::X), context.GetDx(level, Direction::Y),
162  context.GetDx(level, Direction::Z))};
163 
164  boundary_fluxes.setVal(0.0);
165  if constexpr (is_detected<detail::ComputeBoundaryFluxesT, FM&,
167  View<const Complete<Equation>>,
168  View<const Complete<Equation>>,
170  Direction>::value) {
171  ForEachFab(Tag(), scratch, [&](const ::amrex::MFIter& mfi) {
172  const Equation& equation = flux_method_->GetEquation();
173  const ::amrex::Box box = mfi.growntilebox();
174  const ::amrex::FabType type = context.GetFabType(level, mfi);
175  if (type == ::amrex::FabType::singlevalued) {
176  CutCellData<AMREX_SPACEDIM> geom = hierarchy.GetCutCellData(level, mfi);
177  auto boundary_flux = MakeView<Conservative<Equation>>(
178  boundary_fluxes[mfi], equation, box);
179  auto states =
180  MakeView<const Complete<Equation>>(scratch[mfi], equation, box);
181  auto refs =
182  MakeView<const Complete<Equation>>(references[mfi], equation, box);
183  flux_method_->ComputeBoundaryFluxes(boundary_flux, states, refs, geom,
184  dt, dx, dir);
185  }
186  });
187  }
188 
189  if constexpr (is_detected<
190  detail::ComputeGradients, FM&, View<Conservative<Equation>>,
195  Eigen::Matrix<double, AMREX_SPACEDIM, 1>>::value) {
196  const ::amrex::BoxArray ba = scratch.boxArray();
197  const ::amrex::DistributionMapping dm = scratch.DistributionMap();
198  const int ncons = fluxes.nComp();
199  const ::amrex::IntVect ngrow = scratch.nGrowVect();
200  gradient_x.define(ba, dm, ncons, ngrow);
201  gradient_y.define(ba, dm, ncons, ngrow);
202  gradient_z.define(ba, dm, ncons, ngrow);
203  ::amrex::TagBoxArray limiter_flags(ba, dm, ngrow);
204  ::amrex::TagCutCells(limiter_flags, context.GetData(level));
205  TagBuffer(2).TagCellsForRefinement(limiter_flags);
206 
207  ForEachFab(Tag(), scratch, [&](const ::amrex::MFIter& mfi) {
208  const ::amrex::Box box = mfi.growntilebox();
209  const ::amrex::FabType type = context.GetFabType(level, mfi);
210  if (type == ::amrex::FabType::singlevalued) {
211  CutCellData<AMREX_SPACEDIM> geom = hierarchy.GetCutCellData(level, mfi);
212  auto flags = MakePatchDataView(limiter_flags[mfi], 0, box);
213  const Equation& equation = flux_method_->GetEquation();
214  auto states =
215  MakeView<const Conservative<Equation>>(scratch[mfi], equation, box);
216  auto grad_x =
217  MakeView<Conservative<Equation>>(gradient_x[mfi], equation, box);
218  auto grad_y =
219  MakeView<Conservative<Equation>>(gradient_y[mfi], equation, box);
220  auto grad_z =
221  MakeView<Conservative<Equation>>(gradient_z[mfi], equation, box);
222  flux_method_->ComputeGradients(grad_x, grad_y, grad_z, states, flags,
223  geom, dx_vec);
224  }
225  });
226 
227  DebugStorage& debug = *hierarchy.GetDebugStorage();
228  const ::amrex::Geometry& geom = hierarchy.GetGeometry(level);
229  const Equation& equation = flux_method_->GetEquation();
230  const auto names =
231  VarNames<Conservative<Equation>, ::amrex::Vector<std::string>>(
232  equation);
233  DebugSnapshotProxy snapshot =
234  debug.AddSnapshot(fmt::format("Gradients_{}", int(dir)));
235  snapshot.SaveData(gradient_x, AddPrefix(names, "GradX_"), geom);
236  snapshot.SaveData(gradient_y, AddPrefix(names, "GradY_"), geom);
237  snapshot.SaveData(gradient_z, AddPrefix(names, "GradZ_"), geom);
238  }
239 
240  static constexpr int gcw = GetStencilWidth();
241 
242  ForEachFab(Tag(), fluxes, [&](const ::amrex::MFIter& mfi) {
243  const Equation& equation = flux_method_->GetEquation();
244  const ::amrex::Box face_tilebox = mfi.growntilebox();
245  const ::amrex::Box cell_validbox = scratch[mfi].box();
246  auto [cell_box, face_box] =
247  GetCellsAndFacesInStencilRange(cell_validbox, face_tilebox, gcw, dir);
248  const ::amrex::FabType type = context.GetFabType(level, mfi);
249  if (type == ::amrex::FabType::singlevalued) {
250  CutCellData<AMREX_SPACEDIM> geom = hierarchy.GetCutCellData(level, mfi);
251  {
252  auto flux =
253  MakeView<Conservative<Equation>>(fluxes[mfi], equation, face_box);
254  auto states = MakeView<const Complete<Equation>>(scratch[mfi], equation,
255  cell_box);
256  flux_method_->ComputeRegularFluxes(flux, states, geom, dt, dx, dir);
257  }
258  auto flux_s =
259  MakeView<Conservative<Equation>>(fluxes_s[mfi], equation, face_box);
260  auto flux_sL =
261  MakeView<Conservative<Equation>>(fluxes_sL[mfi], equation, face_box);
262  auto flux_sR =
263  MakeView<Conservative<Equation>>(fluxes_sR[mfi], equation, face_box);
264  auto flux_ds =
265  MakeView<Conservative<Equation>>(fluxes_ds[mfi], equation, face_box);
266  auto flux_B = MakeView<Conservative<Equation>>(boundary_fluxes[mfi],
267  equation, cell_box);
268  auto states =
269  MakeView<const Complete<Equation>>(scratch[mfi], equation, cell_box);
270  if constexpr (is_detected<detail::ComputeCutCellFluxes, FM&,
280  View<const Complete<Equation>>,
282  Eigen::Matrix<double, AMREX_SPACEDIM, 1>,
283  Direction>::value) {
284  auto flux =
285  MakeView<Conservative<Equation>>(fluxes[mfi], equation, face_box);
286  auto grad_x = MakeView<const Conservative<Equation>>(
287  gradient_x[mfi], equation, cell_box);
288  auto grad_y = MakeView<const Conservative<Equation>>(
289  gradient_y[mfi], equation, cell_box);
290  auto grad_z = MakeView<const Conservative<Equation>>(
291  gradient_z[mfi], equation, cell_box);
292  flux_method_->ComputeCutCellFluxes(flux_s, flux_sL, flux_sR, flux_ds,
293  flux, flux_B, grad_x, grad_y, grad_z,
294  states, geom, dt, dx_vec, dir);
295  } else {
296  auto flux = MakeView<const Conservative<Equation>>(fluxes[mfi],
297  equation, face_box);
298  flux_method_->ComputeCutCellFluxes(flux_s, flux_sL, flux_sR, flux_ds,
299  flux_B, flux, states, geom, dt, dx,
300  dir);
301  }
302  } else if (type == ::amrex::FabType::regular) {
303  auto flux =
304  MakeView<Conservative<Equation>>(fluxes[mfi], equation, face_box);
305  auto states =
306  MakeView<const Complete<Equation>>(scratch[mfi], equation, cell_box);
307  flux_method_->ComputeNumericFluxes(Tag(), flux, states, dt, dx, dir);
308  }
309  });
310 
311  DebugStorage& debug = *hierarchy.GetDebugStorage();
312  const ::amrex::Geometry& geom = hierarchy.GetGeometry(level);
313  const Equation& equation = flux_method_->GetEquation();
314  const auto names =
315  VarNames<Conservative<Equation>, ::amrex::Vector<std::string>>(
316  equation);
317  DebugSnapshotProxy snapshot =
318  debug.AddSnapshot(fmt::format("Fluxes_{}", int(dir)));
319  snapshot.SaveData(fluxes, AddPrefix(names, "RegularFlux_"), geom);
320  snapshot.SaveData(fluxes_s, AddPrefix(names, "StableFlux_"), geom);
321  snapshot.SaveData(fluxes_sL, AddPrefix(names, "ShieldedFromLeftFlux_"), geom);
322  snapshot.SaveData(fluxes_sR, AddPrefix(names, "ShieldedFromRightFlux_"),
323  geom);
324  snapshot.SaveData(boundary_fluxes.ToMultiFab(0.0, 0.0),
325  AddPrefix(names, "BoundaryFlux_"), geom);
326 }
327 
328 template <typename Tag, typename FM>
330  int level, Direction dir) {
331  const ::amrex::MultiFab& scratch = context.GetScratch(level);
332  const ::amrex::MultiFab& fluxes = context.GetFluxes(level, dir);
333  const double dx = context.GetDx(level, dir);
334  Local<Tag, Duration> min_dt{
335  Duration(std::numeric_limits<double>::infinity())};
336 
337  static constexpr int gcw = GetStencilWidth();
338 
339  ForEachFab(Tag(), fluxes, [&](const ::amrex::MFIter& mfi) {
340  const Equation& equation = flux_method_->GetEquation();
341  const ::amrex::Box face_tilebox = mfi.growntilebox();
342  const ::amrex::Box cell_validbox = scratch[mfi].box();
343  auto [cell_box, face_box] =
344  GetCellsAndFacesInStencilRange(cell_validbox, face_tilebox, gcw, dir);
345  auto states =
346  MakeView<const Complete<Equation>>(scratch[mfi], equation, cell_box);
347  const ::amrex::FabType type = context.GetFabType(level, mfi);
348  if (type == ::amrex::FabType::singlevalued) {
350  context.GetPatchHierarchy().GetCutCellData(level, mfi);
351  *min_dt = std::min(*min_dt, Duration(flux_method_->ComputeStableDt(
352  states, geom, dx, dir)));
353  } else if (type == ::amrex::FabType::regular) {
354  *min_dt = std::min(*min_dt, Duration(flux_method_->ComputeStableDt(
355  Tag(), states, dx, dir)));
356  }
357  });
358  return Min(min_dt);
359 }
360 
361 } // namespace fub::amrex::cutcell
362 
363 #endif
static constexpr int GetStencilWidth() noexcept
Returns the stencil width of this flux method.
Definition: flux_method/FluxMethod.hpp:183
double ComputeStableDt(const View< const Complete > &states, double dx, Direction dir)
This function computes a time step size such that no signal will leave any cell covered by this view.
Definition: flux_method/FluxMethod.hpp:318
void ComputeNumericFluxes(const View< Conservative > &fluxes, const View< const Complete > &states, Duration dt, double dx, Direction dir)
This function computes numerical fluxes.
Definition: flux_method/FluxMethod.hpp:218
This class is a possibly empty handle to a existing DebugSnapshotProxy.
Definition: output/DebugOutput.hpp:132
void SaveData(const ::amrex::MultiFab &mf, const std::string &name, const ::amrex::Geometry &geom, ::amrex::SrcComp component=::amrex::SrcComp(0))
Saves a current hierarchy state with given component names.
This class stores a list of snapshots and returns proxy objects to those.
Definition: output/DebugOutput.hpp:201
Definition: AMReX/cutcell/FluxMethod.hpp:50
void ComputeNumericFluxes(IntegratorContext &context, int level, Duration dt, Direction dir)
Definition: AMReX/cutcell/FluxMethod.hpp:141
void PreAdvanceHierarchy(IntegratorContext &context)
Definition: AMReX/cutcell/FluxMethod.hpp:100
FluxMethod(Tag, const Base &fm)
FluxMethod(Base &&fm)
Definition: AMReX/cutcell/FluxMethod.hpp:54
FluxMethod(const Base &fm)
Definition: AMReX/cutcell/FluxMethod.hpp:55
Local< Tag, Base > flux_method_
Definition: AMReX/cutcell/FluxMethod.hpp:72
const Base & GetBase() const noexcept
Definition: AMReX/cutcell/FluxMethod.hpp:95
typename Base::Equation Equation
Definition: AMReX/cutcell/FluxMethod.hpp:52
static constexpr int GetStencilWidth() noexcept
Definition: AMReX/cutcell/FluxMethod.hpp:90
Duration ComputeStableDt(IntegratorContext &context, int level, Direction dir)
Definition: AMReX/cutcell/FluxMethod.hpp:329
This class manages data and the numerical method to perform cut cell simulations with the AMReX libra...
Definition: AMReX/cutcell/IntegratorContext.hpp:46
::amrex::MultiFab & GetShieldedFromRightFluxes(int level, Direction dir)
Returns the MultiFab associated with flux data on the specifed level number and direction.
::amrex::MultiFab & GetScratch(int level)
Returns the MultiFab associated with level data with ghost cells on the specifed level number and dir...
::amrex::MultiCutFab & GetBoundaryFluxes(int level)
Returns the MultiFab associated with flux data on the specifed level number and direction.
::amrex::MultiFab & GetFluxes(int level, Direction dir)
Returns the MultiFab associated with flux data on the specifed level number and direction.
::amrex::MultiFab & GetData(int level)
Returns the MultiFab associated with level data on the specifed level number.
const PatchHierarchy & GetPatchHierarchy() const noexcept
Returns a reference to const PatchHierarchy which is a member of the GriddingAlgorithm.
::amrex::MultiFab & GetShieldedFromLeftFluxes(int level, Direction dir)
Returns the MultiFab associated with flux data on the specifed level number and direction.
::amrex::MultiFab & GetDoublyShieldedFluxes(int level, Direction dir)
Returns the MultiFab associated with flux data on the specifed level number and direction.
::amrex::MultiFab & GetReferenceStates(int level)
Returns the MultiFab associated with flux data on the specifed level number and direction.
::amrex::FabType GetFabType(int level, const ::amrex::MFIter &mfi) const noexcept
Returns the refinement ratio in the specified direction.
double GetDx(int level, Direction dir) const noexcept
Returns the refinement ratio in the specified direction.
::amrex::MultiFab & GetStabilizedFluxes(int level, Direction dir)
Returns the MultiFab associated with flux data on the specifed level number and direction.
const std::shared_ptr< GriddingAlgorithm > & GetGriddingAlgorithm() const noexcept
Returns a shared pointer to the underlying GriddingAlgorithm which owns the simulation.
Definition: AMReX/cutcell/PatchHierarchy.hpp:139
const std::shared_ptr< DebugStorage > & GetDebugStorage() const noexcept
Returns a shared pointer to the debug storage.
CutCellData< AMREX_SPACEDIM > GetCutCellData(int level, const ::amrex::MFIter &mfi) const
Returns the number of cycles done for a specific level.
int GetNumberOfLevels() const noexcept
const ::amrex::Geometry & GetGeometry(int level) const
Returns the number of cycles done for a specific level.
Definition: AMReX/cutcell/tagging_method/TagBuffer.hpp:29
void TagCellsForRefinement(::amrex::TagBoxArray &tags, const GriddingAlgorithm &gridding, int level, Duration time_point) const noexcept
void ForEachFab(Tag, const ::amrex::FabArrayBase &fabarray, F function)
Iterate through all local FArrayBox objects in a MultiFab.
Definition: ForEachFab.hpp:34
Definition: FillCutCellData.hpp:30
inline ::amrex::Vector< std::string > AddPrefix(const ::amrex::Vector< std::string > &names, const std::string &prefix)
Definition: AMReX/cutcell/FluxMethod.hpp:40
std::array<::amrex::Box, 2 > GetCellsAndFacesInStencilRange(const ::amrex::Box &cell_tilebox, const ::amrex::Box &face_validbox, int stencil_width, Direction dir)
PatchDataView< T, AMREX_SPACEDIM+1 > MakePatchDataView(::amrex::BaseFab< T > &fab)
Definition: ViewFArrayBox.hpp:86
decltype(std::declval< Context >().PreAdvanceHierarchy(std::declval< Args >()...)) PreAdvanceHierarchy
A template typedef to detect the member function.
Definition: Meta.hpp:36
std::decay_t< decltype(std::declval< T >().GetEquation())> Equation
A template typedef to detect the member function.
Definition: Meta.hpp:59
std::chrono::duration< double > Duration
Definition: Duration.hpp:31
Direction
This is a type safe type to denote a dimensional split direction.
Definition: Direction.hpp:30
IndexBox< Rank > Box(const BasicView< State, Layout, Rank > &view)
Definition: State.hpp:486
typename detail::LocalType< Tag, T >::type Local
Definition: Execution.hpp:56
const T & Min(const std::optional< T > &x)
Definition: Execution.hpp:58
Definition: State.hpp:403
Definition: CutCellData.hpp:34
Definition: PatchDataView.hpp:201
This is std::true_type if Op<Args...> is a valid SFINAE expression.
Definition: type_traits.hpp:92