Finite Volume Solver  prototype
A framework to build finite volume solvers for the AG Klein at the Freie Universität Berlin.
MyStabilisation.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_CUTCELL_METHOD_MY_STABILISATION_HPP
22 #define FUB_CUTCELL_METHOD_MY_STABILISATION_HPP
23 
24 #include "fub/CutCellData.hpp"
25 #include "fub/Duration.hpp"
26 #include "fub/Equation.hpp"
28 #include "fub/ForEach.hpp"
29 #include "fub/State.hpp"
30 #include "fub/StateRow.hpp"
31 #include "fub/core/span.hpp"
32 #include "fub/core/tuple.hpp"
33 
34 #include <algorithm>
35 
36 namespace fub {
37 
39  const PatchDataView<double, 2, layout_stride>& stabilised_fluxes,
40  const PatchDataView<double, 2, layout_stride>& shielded_left_fluxes,
41  const PatchDataView<double, 2, layout_stride>& shielded_right_fluxes,
43  const PatchDataView<const double, 2, layout_stride>& boundary_fluxes,
44  const CutCellData<2>& geom, Duration dt, double dx, Direction dir);
45 
47  const PatchDataView<double, 3, layout_stride>& stabilised_fluxes,
48  const PatchDataView<double, 3, layout_stride>& shielded_left_fluxes,
49  const PatchDataView<double, 3, layout_stride>& shielded_right_fluxes,
51  const PatchDataView<const double, 3, layout_stride>& boundary_fluxes,
52  const CutCellData<3>& geom, Duration dt, double dx, Direction dir);
53 
54 template <int Rank> using Coordinates = Eigen::Matrix<double, Rank, 1>;
55 
56 inline Coordinates<2>
58  const Coordinates<2>& boundary_normal) {
59  Coordinates<2> reflected =
60  offset - 2.0 * offset.dot(boundary_normal) * boundary_normal;
61  return reflected;
62 }
63 
64 template <int Rank>
66  const Coordinates<Rank>& dx) {
67  Index<Rank> i{};
68  Coordinates<Rank> rel_x = x / dx;
69  for (int d = 0; d < Rank; ++d) {
70  i[d] = std::floor(rel_x[d]);
71  }
72  return i;
73 }
74 
75 template <int Rank>
77  return std::apply(
78  [dir](auto... is) {
79  return Index<Rank + 1>{is..., static_cast<int>(dir)};
80  },
81  index);
82 }
83 
84 template <typename State, std::ptrdiff_t Rank>
86  State& u, span<const State, Rank> grad,
87  nodeduce_t<const Eigen::Matrix<double, Rank, 1>&> x) noexcept {
88  if constexpr (Rank == 2) {
90  [&x](double& u, auto&&... grad_x) {
91  Coordinates<Rank> grad{grad_x...};
92  u = grad.dot(x);
93  },
94  u, grad[0], grad[1]);
95  } else if constexpr (Rank == 3) {
97  [&x](double& u, auto&&... grad_x) {
98  Coordinates<Rank> grad{grad_x...};
99  u = grad.dot(x);
100  },
101  u, grad[0], grad[1], grad[2]);
102  }
103 }
104 
105 template <int Rank> struct BasicHGridReconstruction {
107  span<const Coordinates<Rank>, 4> x);
108 
110  span<const Coordinates<Rank>, 5> x);
111 
112  void
113  LimitGradients(const std::array<StridedDataView<double, Rank>, Rank>& grad_u,
115  StridedDataView<const char, Rank> needs_limiter,
116  const CutCellData<Rank>& geom,
117  const Coordinates<Rank>& dx) const;
118 
119 private:
121  const std::array<StridedDataView<double, Rank>, Rank>& grad_u,
123  const Index<Rank>& index, const Coordinates<Rank>& dx) const;
124 };
125 
126 extern template struct BasicHGridReconstruction<2>;
127 
128 template <typename Equation>
130  : BasicHGridReconstruction<Equation::Rank()> {
131  using Base = BasicHGridReconstruction<Equation::Rank()>;
132 
137 
138  static constexpr int Rank = Equation::Rank();
139 
141  static constexpr int kMaxSources = 6;
142 
143  std::array<Index<Rank>, kMaxSources> sources{};
144  std::array<double, kMaxSources> start{};
145  std::array<double, kMaxSources> end{};
146 
148 
151  };
152 
154  : equation_(equation) {}
155 
158  span<const Coordinates<Rank>, 4> x) {
160  [&](double& grad_x, double& grad_y, double uM, double u1, double u2,
161  double u3) {
162  std::array<double, 2> grad{0.0, 0.0};
163  const std::array<double, 4> quantities{uM, u1, u2, u3};
164  Base::ComputeGradients(grad, quantities, x);
165  grad_x = grad[0];
166  grad_y = grad[1];
167  },
168  gradient[0], gradient[1], states[0], states[1], states[2], states[3]);
169  }
170 
173  span<const Coordinates<Rank>, 5> x) {
175  [&](double& grad_x, double& grad_y, double uM, double u1, double u2,
176  double u3, double u4) {
177  std::array<double, 2> grad{0.0, 0.0};
178  const std::array<double, 5> quantities{uM, u1, u2, u3, u4};
179  Base::ComputeGradients(grad, quantities, x);
180  grad_x = grad[0];
181  grad_y = grad[1];
182  },
183  gradient[0], gradient[1], states[0], states[1], states[2], states[3],
184  states[4]);
185  }
186 
187  void ComputeGradients(const View<Conservative>& gradient_x,
188  const View<Conservative>& gradient_y,
189  const View<Conservative>& gradient_z,
190  const View<const Conservative>& states,
192  const CutCellData<Rank>& geom,
193  const Coordinates<Rank>& dx) {
194  Conservative zero{equation_};
195  if constexpr (Rank == 2) {
196  std::array<Conservative, 2> gradient{equation_};
197  std::array<Conservative, 5> u;
198  u.fill(Conservative{equation_});
199  const IndexBox<Rank> box =
200  Shrink(Shrink(Box<0>(gradient_x), Direction::X, {1, 1}), Direction::Y,
201  {1, 1});
202  ForEachIndex(box, [&](int i, int j) {
203  ////////////////////////////////////////////////
204  // All regular case
205  if (geom.volume_fractions(i, j) == 1.0 &&
206  geom.volume_fractions(i + 1, j) == 1.0 &&
207  geom.volume_fractions(i - 1, j) == 1.0 &&
208  geom.volume_fractions(i, j + 1) == 1.0 &&
209  geom.volume_fractions(i, j - 1) == 1.0) {
210  Load(u[0], AsCons(states), {i - 1, j});
211  Load(u[1], AsCons(states), {i + 1, j});
213  [&](double& gradient, double qL, double qR) {
214  return gradient = 0.5 * (qR - qL) / dx[0];
215  },
216  gradient[0], u[0], u[1]);
217  Load(u[2], AsCons(states), {i, j - 1});
218  Load(u[3], AsCons(states), {i, j + 1});
220  [&](double& gradient, double qL, double qR) {
221  return gradient = 0.5 * (qR - qL) / dx[1];
222  },
223  gradient[1], u[2], u[3]);
224  //////////////////////////////////////////////////
225  // Cut-Cell case
226  } else if (geom.volume_fractions(i, j) == 0.0) {
227  SetZero(gradient[0]);
228  SetZero(gradient[1]);
229  } else {
230  std::array<Index<Rank + 1>, 4> edges{
231  Index<Rank + 1>{i, j, 0}, Index<Rank + 1>{i + 1, j, 0},
232  Index<Rank + 1>{i, j, 1}, Index<Rank + 1>{i, j + 1, 1}};
233  std::array<double, 4> betas{};
234  std::transform(edges.begin(), edges.end(), betas.begin(),
235  [&geom](const Index<Rank + 1>& ijd) {
236  return geom.face_fractions[ijd[2]](ijd[0], ijd[1]);
237  });
238  std::array<Index<Rank>, 4> neighbors{
239  Index<Rank>{i - 1, j}, Index<Rank>{i + 1, j},
240  Index<Rank>{i, j - 1}, Index<Rank>{i, j + 1}};
241  std::array<double, 4> alphas{};
242  std::transform(neighbors.begin(), neighbors.end(), alphas.begin(),
243  [&geom](const Index<Rank>& ij) {
244  return geom.volume_fractions(ij);
245  });
246  std::array<int, 4> is{0, 1, 2, 3};
247  std::sort(is.begin(), is.end(), [&](int i, int j) {
248  return betas[i] >= betas[j] && alphas[i] >= alphas[j];
249  });
250  if (betas[is[2]] <= 0.0) {
251  // Set neighbors[is[2]] to corner between neighbors[is[0]] and
252  // neighbors[is[1]]
253  FUB_ASSERT(betas[is[0]] > 0.0 && betas[is[1]] > 0.0);
254  FUB_ASSERT(edges[is[0]][2] != edges[is[1]][2]);
255  Index<Rank> corner{};
256  corner[edges[is[0]][2]] = neighbors[is[0]][edges[is[0]][2]];
257  corner[edges[is[1]][2]] = neighbors[is[1]][edges[is[1]][2]];
258  neighbors[is[2]] = corner;
259  Load(u[0], AsCons(states), {i, j});
260  Load(u[1], AsCons(states), neighbors[is[0]]);
261  Load(u[2], AsCons(states), neighbors[is[1]]);
262  Load(u[3], AsCons(states), neighbors[is[2]]);
263  std::array<Coordinates<Rank>, 4> xM;
264  xM[0] = GetAbsoluteVolumeCentroid(geom, {i, j}, dx);
265  xM[1] = GetAbsoluteVolumeCentroid(geom, neighbors[is[0]], dx);
266  xM[2] = GetAbsoluteVolumeCentroid(geom, neighbors[is[1]], dx);
267  xM[3] = GetAbsoluteVolumeCentroid(geom, neighbors[is[2]], dx);
268  ComputeGradients(gradient, fub::span<const Conservative>(u).template subspan<0, 4>(), xM);
269  // Load(u[0], AsCons(states), {i, j});
270  // Load(u[1], AsCons(states), neighbors[is[0]]);
271  // Load(u[2], AsCons(states), neighbors[is[1]]);
272  // u[3] = u[1];
273  // u[4] = u[2];
274  // const Coordinates<Rank> xB =
275  // GetAbsoluteBoundaryCentroid(geom, {i, j}, dx);
276  // const Coordinates<Rank> n = GetBoundaryNormal(geom, {i, j});
277  // std::array<Coordinates<Rank>, 5> xM;
278  // xM[0] = GetAbsoluteVolumeCentroid(geom, {i, j}, dx);
279  // xM[1] = GetAbsoluteVolumeCentroid(geom, neighbors[is[0]], dx);
280  // xM[2] = GetAbsoluteVolumeCentroid(geom, neighbors[is[1]], dx);
281  // xM[3] = xB + ComputeReflectedCoordinates(xM[1] - xB, n);
282  // xM[4] = xB + ComputeReflectedCoordinates(xM[2] - xB, n);
283  // ComputeGradients(gradient, span(u), xM);
284  } else if (betas[is[3]] > 0.0) {
285  FUB_ASSERT(betas[is[0]] > 0.0 && betas[is[2]] > 0.0 &&
286  betas[is[1]] > 0.0);
287  Load(u[0], AsCons(states), {i, j});
288  Load(u[1], AsCons(states), neighbors[is[0]]);
289  Load(u[2], AsCons(states), neighbors[is[1]]);
290  Load(u[3], AsCons(states), neighbors[is[2]]);
291  Load(u[4], AsCons(states), neighbors[is[3]]);
292  std::array<Coordinates<Rank>, 5> xM;
293  xM[0] = GetAbsoluteVolumeCentroid(geom, {i, j}, dx);
294  xM[1] = GetAbsoluteVolumeCentroid(geom, neighbors[is[0]], dx);
295  xM[2] = GetAbsoluteVolumeCentroid(geom, neighbors[is[1]], dx);
296  xM[3] = GetAbsoluteVolumeCentroid(geom, neighbors[is[2]], dx);
297  xM[4] = GetAbsoluteVolumeCentroid(geom, neighbors[is[3]], dx);
298  ComputeGradients(gradient, u, xM);
299  } else if (betas[is[2]] > 0.0) {
300  FUB_ASSERT(betas[is[0]] > 0.0 && betas[is[1]] > 0.0);
301  Load(u[0], AsCons(states), {i, j});
302  Load(u[1], AsCons(states), neighbors[is[0]]);
303  Load(u[2], AsCons(states), neighbors[is[1]]);
304  Load(u[3], AsCons(states), neighbors[is[2]]);
305  std::array<Coordinates<Rank>, 4> xM;
306  xM[0] = GetAbsoluteVolumeCentroid(geom, {i, j}, dx);
307  xM[1] = GetAbsoluteVolumeCentroid(geom, neighbors[is[0]], dx);
308  xM[2] = GetAbsoluteVolumeCentroid(geom, neighbors[is[1]], dx);
309  xM[3] = GetAbsoluteVolumeCentroid(geom, neighbors[is[2]], dx);
310  ComputeGradients(gradient, fub::span<const Conservative>(u).template subspan<0, 4>(), xM);
311  }
312  }
313  Store(gradient_x, gradient[0], {i, j});
314  Store(gradient_y, gradient[1], {i, j});
315  Store(gradient_z, zero, {i, j});
316  });
318  [&](const StridedDataView<double, 2>& u_x,
319  const StridedDataView<double, 2>& u_y,
321  std::array<StridedDataView<double, 2>, 2> grad_u{u_x.Subview(box),
322  u_y.Subview(box)};
323  Base::LimitGradients(grad_u, u.Subview(box), flags, geom, dx);
324  },
325  gradient_x, gradient_y, states);
326  }
327  }
328 
329  std::array<double, 2> FindAdmissibleInterval(const Coordinates<Rank>& xM,
330  const Coordinates<Rank>& xB,
331  const Coordinates<Rank>& slope,
332  const Coordinates<Rank>& dx) {
333  double lower = std::numeric_limits<double>::lowest();
334  double upper = std::numeric_limits<double>::max();
335  for (int d = 0; d < Rank; ++d) {
336  if (slope[d] != 0) {
337  // xM - (xB + slope * lambda) <= 0.5 * dx
338  const double lambda_lower = (xM[d] - xB[d] - 0.5 * dx[d]) / slope[d];
339  // (xB + slope * lambda) - xM <= 0.5 * dx
340  const double lambda_upper = (0.5 * dx[d] + xM[d] - xB[d]) / slope[d];
341  if (slope[d] > 0) {
342  upper = std::min(upper, lambda_upper);
343  lower = std::max(lower, lambda_lower);
344  } else {
345  upper = std::min(upper, lambda_lower);
346  lower = std::max(lower, lambda_upper);
347  }
348  } else if (std::abs(xM[d] - xB[d]) > 0.5 * dx[d]) {
349  lower = std::numeric_limits<double>::max();
350  upper = std::numeric_limits<double>::lowest();
351  }
352  }
353  return {lower, upper};
354  }
355 
356  double Length(const std::array<double, 2>& interval) {
357  return interval[1] - interval[0];
358  }
359 
360  IndexBox<Rank> MakeIndexBox(const Index<Rank>& signs) noexcept {
361  IndexBox<Rank> box{};
362  for (int d = 0; d < Rank; ++d) {
363  if (signs[d] >= 0) {
364  box.upper[d] = 2 * signs[d] + 1;
365  } else {
366  box.upper[d] = 1;
367  box.lower[d] = 2 * signs[d];
368  }
369  }
370  return box;
371  }
372 
374  std::array<int, AuxiliaryReconstructionData::kMaxSources> indices;
375  const int count = aux_data.n_sources;
376  std::iota(indices.begin(), indices.begin() + count, 0);
377  std::sort(indices.begin(), indices.begin() + count, [&](int i, int j) {
378  return aux_data.start[i] < aux_data.start[j];
379  });
380  AuxiliaryReconstructionData sorted_aux{};
381  sorted_aux.slope = aux_data.slope;
382  sorted_aux.xB = aux_data.xB;
383  for (int i = 0; i < count; ++i) {
384  sorted_aux.sources[i] = aux_data.sources[indices[i]];
385  sorted_aux.start[i] = aux_data.start[indices[i]];
386  sorted_aux.end[i] = aux_data.end[indices[i]];
387  }
388  for (int i = count; i < AuxiliaryReconstructionData::kMaxSources; ++i) {
389  sorted_aux.sources[i] = sorted_aux.sources[count - 1];
390  sorted_aux.start[i] = sorted_aux.end[count - 1];
391  sorted_aux.end[i] = sorted_aux.end[count - 1];
392  }
393  sorted_aux.n_sources = count;
394  return sorted_aux;
395  }
396 
397  std::array<AuxiliaryReconstructionData, 2>
398  SplitAt(const AuxiliaryReconstructionData& aux, double dx) {
399  std::array<AuxiliaryReconstructionData, 2> datas{};
400  datas[0].slope = aux.slope;
401  datas[0].xB = aux.xB;
402  datas[1].slope = aux.slope;
403  datas[1].xB = aux.xB;
404  int i = 0;
405  while (i < AuxiliaryReconstructionData::kMaxSources) {
406  datas[0].sources[i] = aux.sources[i];
407  datas[0].start[i] = aux.start[i];
408  datas[0].n_sources = i + 1;
409  if (dx < aux.end[i]) {
410  datas[0].end[i] = dx;
411  break;
412  } else {
413  datas[0].end[i] = aux.end[i];
414  }
415  ++i;
416  }
417  datas[1].sources[0] = aux.sources[i];
418  datas[1].start[0] = dx;
419  datas[1].end[0] = aux.end[i];
420  for (int j = i + 1; j < AuxiliaryReconstructionData::kMaxSources; ++j) {
421  datas[1].sources[j - i] = aux.sources[j];
422  datas[1].start[j - i] = aux.start[j];
423  datas[1].end[j - i] = aux.end[j];
424  datas[1].n_sources = aux.n_sources - datas[0].n_sources;
425  }
426  return datas;
427  }
428 
429  void SetZero(Conservative& cons) {
430  ForEachComponent([](auto&& u) { u = 0.0; }, cons);
431  }
432 
434  const CutCellData<Rank>& geom,
435  const Coordinates<Rank>& dx,
436  const Coordinates<Rank>& slope,
437  double required_length) {
438  Index<Rank> signs{};
439  for (int d = 0; d < Rank; ++d) {
440  signs[d] = (slope[d] > 0.0) - (slope[d] < 0.0);
441  }
442  // Fill aux data for the cut-cell itself
443  const Coordinates<Rank> xB =
444  GetBoundaryCentroid(geom, index).array() * dx.array();
445  AuxiliaryReconstructionData aux_data{};
446  aux_data.slope = slope;
447  aux_data.xB = GetAbsoluteBoundaryCentroid(geom, index, dx);
448  int count = 0;
449  ForEachIndex(MakeIndexBox(signs), [&](auto... is) {
450  Coordinates<Rank> x_i{double(is)...};
451  const Coordinates<Rank> xM = x_i.array() * dx.array();
452  const auto interval = FindAdmissibleInterval(xM, xB, slope, dx);
453  const auto [a, b] = Intersect(interval, {0.0, required_length});
454  if (b - a > 0.0) {
455  FUB_ASSERT(count < AuxiliaryReconstructionData::kMaxSources);
456  Index<Rank> i{is...};
457  Index<Rank> global{};
458  std::transform(i.begin(), i.end(), index.begin(), global.begin(),
459  std::plus<>());
460  aux_data.sources[count] = global;
461  aux_data.start[count] = a;
462  aux_data.end[count] = b;
463  ++count;
464  }
465  });
466  FUB_ASSERT(count > 0 && count <= AuxiliaryReconstructionData::kMaxSources);
467  aux_data.n_sources = count;
468  AuxiliaryReconstructionData sorted_aux = Sort(aux_data);
469  return sorted_aux;
470  }
471 
473  const CutCellData<Rank>& geom,
474  const Coordinates<Rank>& dx,
475  Direction dir) {
476  const Coordinates<Rank> normal = GetBoundaryNormal(geom, index);
477  const int dir_v = static_cast<int>(dir);
478  const Coordinates<Rank> unit_vector =
479  ((normal[dir_v] < 0) - (normal[dir_v] >= 0)) *
480  Eigen::Matrix<double, Rank, 1>::Unit(dir_v);
481  const Coordinates<Rank> slope =
482  unit_vector - 2.0 * unit_vector.dot(normal) * normal;
483  return GetAuxiliaryData(index, geom, dx, slope, dx[int(dir)]);
484  }
485 
486  double TotalLength(const AuxiliaryReconstructionData& aux) noexcept {
487  double total = 0.0;
488  for (int i = 0; i < AuxiliaryReconstructionData::kMaxSources; ++i) {
489  total += aux.end[i] - aux.start[i];
490  }
491  return total;
492  }
493 
495  Conservative& integral_gradient,
496  const View<const Conservative>& states,
497  const View<const Conservative>& gradient_x,
498  const View<const Conservative>& gradient_y,
499  const View<const Conservative>& gradient_z,
500  const CutCellData<Rank>& geom,
501  const AuxiliaryReconstructionData& aux_data,
502  const Coordinates<Rank>& dx, double total_length) {
503  for (int i = 0; i < aux_data.n_sources; ++i) {
504  const Index<Rank> index = aux_data.sources[i];
505  if (Contains(Box<0>(states), index) &&
506  geom.volume_fractions(index) > 0.0) {
507  Load(gradient_[0], gradient_x, index);
508  Load(gradient_[1], gradient_y, index);
509  Load(gradient_[2], gradient_z, index);
510  span<const Conservative, Rank> grads{gradient_.data(), Rank};
511  const Coordinates<Rank> xM = GetAbsoluteVolumeCentroid(geom, index, dx);
512  const Coordinates<Rank> x0 =
513  aux_data.xB +
514  0.5 * (aux_data.start[i] + aux_data.end[i]) * aux_data.slope;
515  const Coordinates<Rank> dx = x0 - xM;
516  ApplyGradient(gradient_dir_, grads, dx);
517  Load(state_, states, index);
518  state_ += gradient_dir_;
519  ApplyGradient(gradient_dir_, grads, aux_data.slope);
520  const double length = aux_data.end[i] - aux_data.start[i];
522  [length, total_length](auto&& u, auto&& grad_u, auto&& u_0,
523  auto&& grad_u_0) {
524  u += length / total_length * u_0;
525  grad_u += length / total_length * grad_u_0;
526  },
527  integral, integral_gradient, state_, gradient_dir_);
528  } else {
529  return false;
530  }
531  }
532  return true;
533  }
534 
535  // int_0^l (u0 + gradient * x) = l ( u_0 + l/2 * gradient )
537  Conservative& integral_gradient,
538  const View<const Conservative>& states,
539  const View<const Conservative>& gradient_x,
540  const View<const Conservative>& gradient_y,
541  const View<const Conservative>& gradient_z,
542  const CutCellData<Rank>& geom,
543  const AuxiliaryReconstructionData& aux_data,
544  const Coordinates<Rank>& dx) {
545  const double total_length = TotalLength(aux_data);
546  return IntegrateCellState(integral, integral_gradient, states, gradient_x,
547  gradient_y, gradient_z, geom, aux_data, dx,
548  total_length);
549  }
550 
552  span<Complete, 2> h_grid_singly_shielded,
553  span<Conservative, 2> h_grid_singly_shielded_gradients,
554  const View<const Complete>& states,
555  const View<const Conservative>& gradient_x,
556  const View<const Conservative>& gradient_y,
557  const View<const Conservative>& gradient_z,
558  const CutCellData<Rank>& cutcell_data, const Index<Rank>& cell,
559  Duration /*dt*/, const Coordinates<Rank>& dx, Direction dir) {
560  AuxiliaryReconstructionData boundary_aux_data =
561  GetAuxiliaryData(cell, cutcell_data, dx, dir);
562  const Coordinates<Rank> normal = GetBoundaryNormal(cutcell_data, cell);
563  const int dir_v = static_cast<int>(dir);
564  const Coordinates<Rank> unit_vector =
565  ((normal[dir_v] >= 0) - (normal[dir_v] < 0)) *
566  Eigen::Matrix<double, Rank, 1>::Unit(dir_v);
567  AuxiliaryReconstructionData interior_aux_data =
568  GetAuxiliaryData(cell, cutcell_data, dx, unit_vector, 2.0 * dx[dir_v]);
569  SetZero(boundary_state_);
570  SetZero(boundary_gradient_);
571  SetZero(interior_state_);
572  SetZero(interior_gradient_);
573  const int d = static_cast<std::size_t>(dir);
574  const Index<Rank> face_L = cell;
575  const Index<Rank> face_R = Shift(face_L, dir, 1);
576  const double betaL = cutcell_data.face_fractions[d](face_L);
577  const double betaR = cutcell_data.face_fractions[d](face_R);
578 
579  const Index<Rank + 1> cell_d = EmbedIndex<Rank>(cell, dir);
580 
581  if (betaL < betaR) {
582  const double d = 0.5 - cutcell_data.boundary_centeroids(cell_d);
583 
584  auto [laux1, raux1] = SplitAt(boundary_aux_data, (1.0 - d) * dx[d]);
585  auto [laux2, raux2] = SplitAt(interior_aux_data, d * dx[d]);
586  auto [interior_aux, raux3] = SplitAt(raux2, (1.0 + d) * dx[d]);
587 
588  if (!IntegrateCellState(boundary_state_, boundary_gradient_, states,
589  gradient_x, gradient_y, gradient_z, cutcell_data,
590  laux1, dx, dx[d])) {
591  Load(boundary_state_, AsCons(states), cell);
592  SetZero(boundary_gradient_);
593  } else {
594  ForEachComponent([](auto&& u) { u *= -1.0; }, boundary_gradient_);
595  if (!IntegrateCellState(boundary_state_, boundary_gradient_, states,
596  gradient_x, gradient_y, gradient_z,
597  cutcell_data, laux2, dx, dx[d])) {
598  Load(boundary_state_, AsCons(states), cell);
599  SetZero(boundary_gradient_);
600  }
601  }
602  Reflect(boundary_state_, boundary_state_, normal, equation_);
603  Reflect(boundary_gradient_, boundary_gradient_, normal, equation_);
604 
605  CompleteFromCons(equation_, h_grid_singly_shielded[0], boundary_state_);
606  h_grid_singly_shielded_gradients[0] = boundary_gradient_;
607 
608  if (!IntegrateCellState(interior_state_, interior_gradient_, states,
609  gradient_x, gradient_y, gradient_z, cutcell_data,
610  interior_aux, dx)) {
611  Load(interior_state_, AsCons(states), cell);
612  SetZero(interior_gradient_);
613  }
614 
615  CompleteFromCons(equation_, h_grid_singly_shielded[1], interior_state_);
616  h_grid_singly_shielded_gradients[1] = interior_gradient_;
617 
618  } else if (betaR < betaL) {
619  const double d = 0.5 + cutcell_data.boundary_centeroids(cell_d);
620 
621  auto [laux1, raux1] = SplitAt(boundary_aux_data, (1.0 - d) * dx[d]);
622  auto [laux2, raux2] = SplitAt(interior_aux_data, d * dx[d]);
623  auto [interior_aux, raux3] = SplitAt(raux2, (1.0 + d) * dx[d]);
624 
625  if (!IntegrateCellState(interior_state_, interior_gradient_, states,
626  gradient_x, gradient_y, gradient_z, cutcell_data,
627  interior_aux, dx)) {
628  Load(interior_state_, AsCons(states), cell);
629  SetZero(interior_gradient_);
630  } else {
631  ForEachComponent([](auto&& u) { u *= -1.0; }, interior_gradient_);
632  }
633 
634  CompleteFromCons(equation_, h_grid_singly_shielded[0], interior_state_);
635  h_grid_singly_shielded_gradients[0] = interior_gradient_;
636 
637  if (!IntegrateCellState(boundary_state_, boundary_gradient_, states,
638  gradient_x, gradient_y, gradient_z, cutcell_data,
639  laux2, dx, dx[d])) {
640  Load(boundary_state_, AsCons(states), cell);
641  SetZero(boundary_gradient_);
642  } else {
643  ForEachComponent([](auto&& u) { u *= -1.0; }, boundary_gradient_);
644  if (!IntegrateCellState(boundary_state_, boundary_gradient_, states,
645  gradient_x, gradient_y, gradient_z,
646  cutcell_data, laux1, dx, dx[d])) {
647  Load(boundary_state_, AsCons(states), cell);
648  SetZero(boundary_gradient_);
649  }
650  }
651  Reflect(boundary_state_, boundary_state_, normal, equation_);
652  Reflect(boundary_gradient_, boundary_gradient_, normal, equation_);
653 
654  CompleteFromCons(equation_, h_grid_singly_shielded[1], boundary_state_);
655  h_grid_singly_shielded_gradients[1] = boundary_gradient_;
656  }
657  }
658 
660  span<Complete, 2> h_grid_embedded_boundary,
661  span<Conservative, 2> h_grid_embedded_boundary_slopes,
662  const View<const Complete>& states,
663  const View<const Conservative>& gradient_x,
664  const View<const Conservative>& gradient_y,
665  const View<const Conservative>& gradient_z,
666  const CutCellData<Rank>& cutcell_data, const Index<Rank>& cell,
667  Duration /*dt*/, Eigen::Matrix<double, Rank, 1> dx, Direction dir) {
668  AuxiliaryReconstructionData boundary_aux_data =
669  GetAuxiliaryData(cell, cutcell_data, dx, dir);
670  const Coordinates<Rank> normal = GetBoundaryNormal(cutcell_data, cell);
671  const int dir_v = static_cast<int>(dir);
672  const Coordinates<Rank> unit_vector =
673  ((normal[dir_v] >= 0) - (normal[dir_v] < 0)) *
674  Eigen::Matrix<double, Rank, 1>::Unit(dir_v);
675  AuxiliaryReconstructionData interior_aux_data =
676  GetAuxiliaryData(cell, cutcell_data, dx, unit_vector, dx[dir_v]);
677  SetZero(boundary_state_);
678  SetZero(boundary_gradient_);
679  if (!IntegrateCellState(boundary_state_, boundary_gradient_, states,
680  gradient_x, gradient_y, gradient_z, cutcell_data,
681  boundary_aux_data, dx)) {
682  Load(boundary_state_, AsCons(states), cell);
683  SetZero(boundary_gradient_);
684  }
685  SetZero(interior_state_);
686  SetZero(interior_gradient_);
687  if (!IntegrateCellState(interior_state_, interior_gradient_, states,
688  gradient_x, gradient_y, gradient_z, cutcell_data,
689  interior_aux_data, dx)) {
690  interior_state_ = boundary_state_;
691  interior_gradient_ = boundary_gradient_;
692  }
693  const int d = static_cast<std::size_t>(dir);
694  const Index<Rank> face_L = cell;
695  const Index<Rank> face_R = Shift(face_L, dir, 1);
696  const double betaL = cutcell_data.face_fractions[d](face_L);
697  const double betaR = cutcell_data.face_fractions[d](face_R);
698 
699  Reflect(boundary_state_, boundary_state_, normal, equation_);
700  Reflect(boundary_gradient_, boundary_gradient_, normal, equation_);
701 
702  if (betaL < betaR) {
703  ForEachComponent([](auto&& u) { u *= -1.0; }, boundary_gradient_);
704 
705  CompleteFromCons(equation_, h_grid_embedded_boundary[0], boundary_state_);
706  h_grid_embedded_boundary_slopes[0] = boundary_gradient_;
707  CompleteFromCons(equation_, h_grid_embedded_boundary[1], interior_state_);
708  h_grid_embedded_boundary_slopes[1] = interior_gradient_;
709 
710  } else if (betaR < betaL) {
711  ForEachComponent([](auto&& u) { u *= -1.0; }, interior_gradient_);
712 
713  CompleteFromCons(equation_, h_grid_embedded_boundary[1], boundary_state_);
714  h_grid_embedded_boundary_slopes[1] = boundary_gradient_;
715  CompleteFromCons(equation_, h_grid_embedded_boundary[0], interior_state_);
716  h_grid_embedded_boundary_slopes[0] = interior_gradient_;
717  }
718  }
719 
721  span<Conservative, 2> h_grid_regular_gradients,
722  const View<const Complete>& states,
723  const View<const Conservative>& gradient_x,
724  const View<const Conservative>& gradient_y,
725  const View<const Conservative>& gradient_z,
726  const CutCellData<Rank>& geom,
727  const Index<Rank>& face, Duration /*dt*/,
728  Eigen::Matrix<double, Rank, 1> dx,
729  Direction dir) {
730  Index<Rank> iL = LeftTo(face, dir);
731  Index<Rank> iR = RightTo(face, dir);
732 
733  const Coordinates<Rank> face_xM =
734  GetUnshieldedCentroid(geom, face, dx, dir);
735  const Coordinates<Rank> xL_us = Shift(face_xM, dir, -0.5 * dx[int(dir)]);
736  const Coordinates<Rank> xR_us = Shift(face_xM, dir, +0.5 * dx[int(dir)]);
737  const Coordinates<Rank> xL = GetAbsoluteVolumeCentroid(geom, iL, dx);
738  const Coordinates<Rank> xR = GetAbsoluteVolumeCentroid(geom, iR, dx);
739  Load(state_, AsCons(states), iL);
740  Load(gradient_[0], gradient_x, iL);
741  Load(gradient_[1], gradient_y, iL);
742  Load(gradient_[2], gradient_z, iL);
743 
744  span<const Conservative, Rank> grads{gradient_.data(), Rank};
745 
746  const Coordinates<Rank> delta_xL = xL_us - xL;
747  ApplyGradient(gradient_dir_, grads, delta_xL);
748  state_ += gradient_dir_;
749  CompleteFromCons(equation_, h_grid_regular[0], state_);
750  h_grid_regular_gradients[0] = gradient_[int(dir)];
751 
752  Load(state_, AsCons(states), iR);
753  Load(gradient_[0], gradient_x, iR);
754  Load(gradient_[1], gradient_y, iR);
755  Load(gradient_[2], gradient_z, iR);
756 
757  const Coordinates<Rank> delta_xR = xR_us - xR;
758  ApplyGradient(gradient_dir_, grads, delta_xR);
759  state_ += gradient_dir_;
760  CompleteFromCons(equation_, h_grid_regular[1], state_);
761  h_grid_regular_gradients[1] = gradient_[int(dir)];
762  }
763 
765  std::array<Conservative, 3> gradient_{Conservative(equation_),
766  Conservative(equation_),
767  Conservative(equation_)};
768  std::array<Conservative, 4> stencil{
769  Conservative(equation_), Conservative(equation_), Conservative(equation_),
770  Conservative(equation_)};
771  Conservative limited_slope_{equation_};
772  Conservative state_{equation_};
773  Conservative gradient_dir_{equation_};
774  Conservative boundary_state_{equation_};
775  Conservative boundary_gradient_{equation_};
776  Conservative interior_state_{equation_};
777  Conservative interior_gradient_{equation_};
778 };
779 
780 template <typename EquationT, typename FluxMethod,
781  typename HGridReconstruction =
782  ConservativeHGridReconstruction<EquationT>>
783 class MyCutCellMethod : public FluxMethod {
784 public:
785  using Equation = EquationT;
786 
787  // Typedefs
792 
793  // Static Variables
794 
795  static constexpr int Rank = Equation::Rank();
796  static constexpr std::size_t sRank = static_cast<std::size_t>(Rank);
797  static constexpr int StencilWidth = FluxMethod::GetStencilWidth();
798  static_assert(StencilWidth > 0);
799  static constexpr std::size_t StencilSize =
800  static_cast<std::size_t>(2 * StencilWidth);
801 
802  template <typename T> using DataView = PatchDataView<T, Rank, layout_stride>;
803 
804  // Constructors
805 
806  /// Constructs a CutCell method from a given base flux method.
807  ///
808  /// This constructor uses a default constructed riemann problem solver.
809  explicit MyCutCellMethod(const Equation& equation);
810  MyCutCellMethod(const Equation& equation, const FluxMethod& flux_method);
811 
812  using FluxMethod::ComputeStableDt;
813 
814  /// \todo compute stable dt inside of cutcells, i.e. in the reflection with
815  /// their boundary state.
816  double ComputeStableDt(const View<const Complete>& states,
817  const CutCellData<Rank>& cutcell_data, double dx,
818  Direction dir);
819 
820  void ComputeRegularFluxes(const View<Conservative>& regular_fluxes,
821  const View<const Complete>& states,
822  const CutCellData<Rank>& cutcell_data, Duration dt,
823  double dx, Direction dir);
824 
825  void ComputeCutCellFluxes(const View<Conservative>& stabilised_fluxes,
826  const View<Conservative>& shielded_left_fluxes,
827  const View<Conservative>& shielded_right_fluxes,
828  const View<Conservative>& doubly_shielded_fluxes,
829  const View<Conservative>& regular_fluxes,
830  const View<Conservative>& boundary_fluxes,
831  const View<const Conservative>& gradient_x,
832  const View<const Conservative>& gradient_y,
833  const View<const Conservative>& gradient_z,
834  const View<const Complete>& states,
835  const CutCellData<Rank>& geom, Duration dt,
836  const Eigen::Matrix<double, Rank, 1>& dx,
837  Direction dir);
838 
839  void ComputeGradients(const View<Conservative>& gradient_x,
840  const View<Conservative>& gradient_y,
841  const View<Conservative>& gradient_z,
842  const View<const Conservative>& states,
844  const CutCellData<Rank>& geom,
845  const Coordinates<Rank>& dx) {
846  h_grid_reconstruction_.ComputeGradients(gradient_x, gradient_y, gradient_z,
847  states, flags, geom, dx);
848  }
849 
850 private:
852  HGridReconstruction h_grid_reconstruction_;
853 
854  std::array<Complete, 2> h_grid_eb_{};
855  std::array<Conservative, 2> h_grid_eb_gradients_{};
856  std::array<Complete, 2> h_grid_singly_shielded_{};
857  std::array<Conservative, 2> h_grid_singly_shielded_gradients_{};
858  std::array<Complete, 2> h_grid_regular_{};
859  std::array<Conservative, 2> h_grid_regular_gradients_{};
860 
861  Conservative boundary_flux_{equation_};
862  Conservative singly_shielded_flux_{equation_};
863  Conservative regular_flux_{equation_};
864 
865  std::array<CompleteArray, StencilSize> stencil_array_{};
866  ConservativeArray numeric_flux_array_{equation_};
867 };
868 
869 template <typename Equation, typename FluxMethod>
871 
872 // IMPLEMENTATION
873 
874 template <typename Equation, typename FluxMethod, typename HGridReconstruction>
876  const Equation& eq)
877  : MyCutCellMethod(eq, FluxMethod(eq)) {}
878 
879 template <typename Equation, typename FluxMethod, typename HGridReconstruction>
881  const Equation& eq, const FluxMethod& flux_method)
882  : FluxMethod(flux_method), equation_(eq), h_grid_reconstruction_(eq) {
890 }
891 
892 /// \todo compute stable dt inside of cutcells, i.e. in the reflection with
893 /// their boundary state.
894 template <typename Equation, typename FluxMethod, typename HGridReconstruction>
895 double
897  const View<const Complete>& states, const CutCellData<Rank>& geom,
898  double dx, Direction dir) {
899  double min_dt = std::numeric_limits<double>::infinity();
900  static constexpr int kWidth = StencilWidth;
901  IndexBox<Rank> cellbox = Box<0>(states);
902  IndexBox<Rank> fluxbox = Shrink(cellbox, dir, {kWidth, kWidth - 1});
903  View<const Complete> base = Subview(states, cellbox);
905  ArrayView volumes = geom.volume_fractions.Subview(cellbox);
906  const int d = static_cast<int>(dir);
907  ArrayView faces = geom.face_fractions[d].Subview(fluxbox);
908  std::array<View<const Complete>, StencilSize> stencil_views;
909  std::array<ArrayView, StencilSize> stencil_volumes;
910  for (std::size_t i = 0; i < StencilSize; ++i) {
911  stencil_views[i] =
912  Shrink(base, dir,
913  {static_cast<std::ptrdiff_t>(i),
914  static_cast<std::ptrdiff_t>(StencilSize - i) - 1});
915  stencil_volumes[i] = volumes.Subview(
916  Shrink(cellbox, dir,
917  {static_cast<std::ptrdiff_t>(i),
918  static_cast<std::ptrdiff_t>(StencilSize - i) - 1}));
919  }
920  std::tuple views = std::tuple_cat(std::tuple(faces), AsTuple(stencil_volumes),
921  AsTuple(stencil_views));
922  ForEachRow(views, [this, &min_dt, dx, dir](span<const double> faces,
923  auto... rest) {
924  std::tuple args{rest...};
925  std::array<span<const double>, StencilSize> volumes =
926  AsArray(Take<StencilSize>(args));
927  std::array states = std::apply(
928  [](const auto&... xs)
929  -> std::array<ViewPointer<const Complete>, StencilSize> {
930  return {Begin(xs)...};
931  },
932  Drop<StencilSize>(args));
933  std::array<Array1d, StencilSize> alphas;
934  alphas.fill(Array1d::Zero());
935  Array1d betas = Array1d::Zero();
936  int n = static_cast<int>(faces.size());
937  while (n >= kDefaultChunkSize) {
938  betas = Array1d::Map(faces.data());
939  for (std::size_t i = 0; i < StencilSize; ++i) {
940  Load(stencil_array_[i], states[i]);
941  alphas[i] = Array1d::Map(volumes[i].data());
942  }
943  Array1d dts =
944  FluxMethod::ComputeStableDt(stencil_array_, betas, alphas, dx, dir);
945  min_dt = std::min(min_dt, dts.minCoeff());
946  for (std::size_t i = 0; i < StencilSize; ++i) {
947  Advance(states[i], kDefaultChunkSize);
948  volumes[i] = volumes[i].subspan(kDefaultChunkSize);
949  }
950  faces = faces.subspan(kDefaultChunkSize);
951  n = static_cast<int>(faces.size());
952  }
953  std::copy_n(faces.data(), n, betas.data());
954  std::fill_n(betas.data() + n, kDefaultChunkSize - n, 0.0);
955  for (std::size_t i = 0; i < StencilSize; ++i) {
956  LoadN(stencil_array_[i], states[i], n);
957  std::copy_n(volumes[i].data(), n, alphas[i].data());
958  std::fill_n(alphas[i].data() + n, kDefaultChunkSize - n, 0.0);
959  }
960  Array1d dts =
961  FluxMethod::ComputeStableDt(stencil_array_, betas, alphas, dx, dir);
962  min_dt = std::min(min_dt, dts.minCoeff());
963  });
964  return min_dt;
965 }
966 
967 template <typename Equation, typename FluxMethod, typename HGridReconstruction>
970  const View<const Complete>& states,
971  const CutCellData<Rank>& cutcell_data, Duration dt,
972  double dx, Direction dir) {
973  IndexBox<Rank> fluxbox = Box<0>(fluxes);
974  static constexpr int kWidth = FluxMethod::GetStencilWidth();
975  IndexBox<Rank> cellbox = Grow(fluxbox, dir, {kWidth, kWidth - 1});
976  View<const Complete> base = Subview(states, cellbox);
978  ArrayView volumes = cutcell_data.volume_fractions.Subview(cellbox);
979  const int d = static_cast<int>(dir);
980  ArrayView faces = cutcell_data.face_fractions[d].Subview(fluxbox);
981  std::array<View<const Complete>, StencilSize> stencil_views;
982  std::array<ArrayView, StencilSize> stencil_volumes;
983  for (std::size_t i = 0; i < StencilSize; ++i) {
984  stencil_views[i] =
985  Shrink(base, dir,
986  {static_cast<std::ptrdiff_t>(i),
987  static_cast<std::ptrdiff_t>(StencilSize - i) - 1});
988  stencil_volumes[i] = volumes.Subview(
989  Shrink(cellbox, dir,
990  {static_cast<std::ptrdiff_t>(i),
991  static_cast<std::ptrdiff_t>(StencilSize - i) - 1}));
992  }
993  std::tuple views =
994  std::tuple_cat(std::tuple(fluxes, faces), AsTuple(stencil_volumes),
995  AsTuple(stencil_views));
996  ForEachRow(views, [this, dt, dx, dir](const Row<Conservative>& fluxes,
997  span<const double> faces,
998  auto... rest) {
999  ViewPointer fit = Begin(fluxes);
1000  ViewPointer fend = End(fluxes);
1001  std::tuple args{rest...};
1002  std::array<span<const double>, StencilSize> volumes =
1003  AsArray(Take<StencilSize>(args));
1004  std::array states = std::apply(
1005  [](const auto&... xs)
1006  -> std::array<ViewPointer<const Complete>, StencilSize> {
1007  return {Begin(xs)...};
1008  },
1009  Drop<StencilSize>(args));
1010  std::array<Array1d, StencilSize> alphas;
1011  alphas.fill(Array1d::Zero());
1012  Array1d betas = Array1d::Zero();
1013  int n = static_cast<int>(get<0>(fend) - get<0>(fit));
1014  while (n >= kDefaultChunkSize) {
1015  betas = Array1d::Map(faces.data());
1016  for (std::size_t i = 0; i < StencilSize; ++i) {
1017  Load(stencil_array_[i], states[i]);
1018  alphas[i] = Array1d::Map(volumes[i].data());
1019  }
1020  FluxMethod::ComputeNumericFlux(numeric_flux_array_, betas, stencil_array_,
1021  alphas, dt, dx, dir);
1022  for (int i = 0; i < betas.size(); ++i) {
1024  [&](auto&& flux [[maybe_unused]]) {
1025  FUB_ASSERT(betas[i] == 0.0 ||
1026  (betas[i] > 0.0 && !std::isnan(flux[i])));
1027  },
1028  numeric_flux_array_);
1029  }
1030  Store(fit, numeric_flux_array_);
1031  Advance(fit, kDefaultChunkSize);
1032  for (std::size_t i = 0; i < StencilSize; ++i) {
1033  Advance(states[i], kDefaultChunkSize);
1034  volumes[i] = volumes[i].subspan(kDefaultChunkSize);
1035  }
1036  faces = faces.subspan(kDefaultChunkSize);
1037  n = static_cast<int>(get<0>(fend) - get<0>(fit));
1038  }
1039  std::copy_n(faces.data(), n, betas.data());
1040  std::fill_n(betas.data() + n, kDefaultChunkSize - n, 0.0);
1041  for (std::size_t i = 0; i < StencilSize; ++i) {
1042  LoadN(stencil_array_[i], states[i], n);
1043  std::copy_n(volumes[i].data(), n, alphas[i].data());
1044  std::fill_n(alphas[i].data() + n, kDefaultChunkSize - n, 0.0);
1045  }
1046  FluxMethod::ComputeNumericFlux(numeric_flux_array_, betas, stencil_array_,
1047  alphas, dt, dx, dir);
1048  StoreN(fit, numeric_flux_array_, n);
1049  });
1050 }
1051 
1052 template <typename Equation, typename FluxMethod, typename HGridReconstruction>
1054  ComputeCutCellFluxes(const View<Conservative>& stabilised_fluxes,
1055  const View<Conservative>& shielded_left_fluxes,
1056  const View<Conservative>& shielded_right_fluxes,
1057  const View<Conservative>& /* doubly_shielded_fluxes */,
1058  const View<Conservative>& regular_fluxes,
1059  const View<Conservative>& boundary_fluxes,
1060  const View<const Conservative>& gradient_x,
1061  const View<const Conservative>& gradient_y,
1062  const View<const Conservative>& gradient_z,
1063  const View<const Complete>& states,
1064  const CutCellData<Rank>& geom, Duration dt,
1065  const Eigen::Matrix<double, Rank, 1>& dx,
1066  Direction dir) {
1067 
1068  // Iterate through each EB cell and then
1069  //
1070  // (i) Compute h grid centered at EB and keep the slopes for the reflected
1071  // states
1072  // (ii) Compute boundary flux using the underlying flux method and its h grid
1073  // (iii) Compute h grid centered at singly shielded fluxes where boundary
1074  // states and slopes are interpolated from step (i)
1075  // (iv) Compute singly shielded fluxes using the underlying flux method and
1076  // its h grid
1077  const auto d = static_cast<std::size_t>(dir);
1078  const PatchDataView<const double, Rank>& betas = geom.face_fractions[d];
1079  const PatchDataView<const double, Rank>& betaUs =
1080  geom.unshielded_fractions[d];
1081  ForEachIndex(Shrink(Box<0>(states), dir, {1, 1}), [&](auto... is) {
1082  Index<Rank> cell{is...};
1083  Index<Rank> faceL = cell;
1084  Index<Rank> faceR = Shift(faceL, dir, 1);
1085  const double betaL = betas(faceL);
1086  const double betaR = betas(faceR);
1087  const double betaUsL = betaUs(faceL);
1088  const double betaUsR = betaUs(faceR);
1089  if (betaL < betaR) {
1090  h_grid_reconstruction_.ReconstructEmbeddedBoundaryStencil(
1091  h_grid_eb_, h_grid_eb_gradients_, states, gradient_x, gradient_y,
1092  gradient_z, geom, cell, dt, dx, dir);
1093  FluxMethod::ComputeNumericFlux(boundary_flux_, h_grid_eb_,
1094  h_grid_eb_gradients_, dt, dx[d], dir);
1095  Store(boundary_fluxes, boundary_flux_, cell);
1096 
1097  h_grid_reconstruction_.ReconstructSinglyShieldedStencil(
1098  h_grid_singly_shielded_, h_grid_singly_shielded_gradients_, states,
1099  gradient_x, gradient_y, gradient_z, geom, cell, dt, dx, dir);
1100  FluxMethod::ComputeNumericFlux(
1101  singly_shielded_flux_, h_grid_singly_shielded_,
1102  h_grid_singly_shielded_gradients_, dt, dx[d], dir);
1103  if (Contains(Box<0>(shielded_left_fluxes), faceR)) {
1104  Store(shielded_left_fluxes, singly_shielded_flux_, faceR);
1105  if (betaUsR > 0.0) {
1106  h_grid_reconstruction_.ReconstructRegularStencil(
1107  h_grid_regular_, h_grid_regular_gradients_, states, gradient_x,
1108  gradient_y, gradient_z, geom, faceR, dt, dx, dir);
1109  FluxMethod::ComputeNumericFlux(regular_flux_, h_grid_regular_,
1110  h_grid_regular_gradients_, dt, dx[d],
1111  dir);
1112  Store(regular_fluxes, regular_flux_, faceR);
1113  }
1114  }
1115  } else if (betaR < betaL) {
1116  h_grid_reconstruction_.ReconstructEmbeddedBoundaryStencil(
1117  h_grid_eb_, h_grid_eb_gradients_, states, gradient_x, gradient_y,
1118  gradient_z, geom, cell, dt, dx, dir);
1119  FluxMethod::ComputeNumericFlux(boundary_flux_, h_grid_eb_,
1120  h_grid_eb_gradients_, dt, dx[d], dir);
1121  Store(boundary_fluxes, boundary_flux_, cell);
1122 
1123  h_grid_reconstruction_.ReconstructSinglyShieldedStencil(
1124  h_grid_singly_shielded_, h_grid_singly_shielded_gradients_, states,
1125  gradient_x, gradient_y, gradient_z, geom, cell, dt, dx, dir);
1126  FluxMethod::ComputeNumericFlux(
1127  singly_shielded_flux_, h_grid_singly_shielded_,
1128  h_grid_singly_shielded_gradients_, dt, dx[d], dir);
1129  if (Contains(Box<0>(shielded_right_fluxes), faceL)) {
1130  Store(shielded_right_fluxes, singly_shielded_flux_, faceL);
1131  if (betaUsL > 0.0) {
1132  h_grid_reconstruction_.ReconstructRegularStencil(
1133  h_grid_regular_, h_grid_regular_gradients_, states, gradient_x,
1134  gradient_y, gradient_z, geom, faceL, dt, dx, dir);
1135  FluxMethod::ComputeNumericFlux(regular_flux_, h_grid_regular_,
1136  h_grid_regular_gradients_, dt, dx[d],
1137  dir);
1138  Store(regular_fluxes, regular_flux_, faceL);
1139  }
1140  }
1141  }
1142  });
1143 
1144  // Do the convex combiination of regular and singly shielded fluxes
1146  [&](DataView<double> stabilised, DataView<double> shielded_left,
1147  DataView<double> shielded_right, DataView<const double> regular,
1148  DataView<const double> boundary) {
1149  MyStab_ComputeStableFluxComponents(stabilised, shielded_left,
1150  shielded_right, regular, boundary,
1151  geom, dt, dx[d], dir);
1152  },
1153  stabilised_fluxes, shielded_left_fluxes, shielded_right_fluxes,
1154  regular_fluxes, boundary_fluxes);
1155 }
1156 
1157 } // namespace fub
1158 
1159 #endif
#define FUB_ASSERT(x)
Definition: assert.hpp:39
This class applies a base flux nethod on a view of states.
Definition: flux_method/FluxMethod.hpp:57
static constexpr int GetStencilWidth() noexcept
Returns the stencil width of this flux method.
Definition: flux_method/FluxMethod.hpp:183
meta::Equation< const BaseMethod & > Equation
Definition: flux_method/FluxMethod.hpp:59
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
Definition: MyStabilisation.hpp:783
std::array< Conservative, 2 > h_grid_singly_shielded_gradients_
Definition: MyStabilisation.hpp:857
std::array< Complete, 2 > h_grid_eb_
Definition: MyStabilisation.hpp:854
std::array< Complete, 2 > h_grid_singly_shielded_
Definition: MyStabilisation.hpp:856
MyCutCellMethod(const Equation &equation)
Constructs a CutCell method from a given base flux method.
Definition: MyStabilisation.hpp:875
::fub::Conservative< Equation > Conservative
Definition: MyStabilisation.hpp:788
::fub::Complete< Equation > Complete
Definition: MyStabilisation.hpp:790
::fub::CompleteArray< Equation > CompleteArray
Definition: MyStabilisation.hpp:791
HGridReconstruction h_grid_reconstruction_
Definition: MyStabilisation.hpp:852
void ComputeCutCellFluxes(const View< Conservative > &stabilised_fluxes, const View< Conservative > &shielded_left_fluxes, const View< Conservative > &shielded_right_fluxes, const View< Conservative > &doubly_shielded_fluxes, const View< Conservative > &regular_fluxes, const View< Conservative > &boundary_fluxes, const View< const Conservative > &gradient_x, const View< const Conservative > &gradient_y, const View< const Conservative > &gradient_z, const View< const Complete > &states, const CutCellData< Rank > &geom, Duration dt, const Eigen::Matrix< double, Rank, 1 > &dx, Direction dir)
Definition: MyStabilisation.hpp:1054
std::array< CompleteArray, StencilSize > stencil_array_
Definition: MyStabilisation.hpp:865
Equation equation_
Definition: MyStabilisation.hpp:851
void ComputeGradients(const View< Conservative > &gradient_x, const View< Conservative > &gradient_y, const View< Conservative > &gradient_z, const View< const Conservative > &states, const StridedDataView< const char, Rank > &flags, const CutCellData< Rank > &geom, const Coordinates< Rank > &dx)
Definition: MyStabilisation.hpp:839
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
std::array< Conservative, 2 > h_grid_regular_gradients_
Definition: MyStabilisation.hpp:859
std::array< Conservative, 2 > h_grid_eb_gradients_
Definition: MyStabilisation.hpp:855
std::array< Complete, 2 > h_grid_regular_
Definition: MyStabilisation.hpp:858
void ComputeRegularFluxes(const View< Conservative > &regular_fluxes, const View< const Complete > &states, const CutCellData< Rank > &cutcell_data, Duration dt, double dx, Direction dir)
Definition: MyStabilisation.hpp:969
A span is a view over a contiguous sequence of objects, the storage of which is owned by some other o...
Definition: span.hpp:81
constexpr pointer data() const noexcept
Returns the underlying pointer.
Definition: span.hpp:411
void CompleteFromCons(Equation &&equation, Complete< std::decay_t< Equation >> &complete, const Conservative< std::decay_t< Equation >> &cons)
Definition: CompleteFromCons.hpp:42
Function ForEachIndex(const layout_left::mapping< Extents > &mapping, Function function)
Iterate through the multi-dimensional index space descibed by mapping and invoke function for each su...
Definition: ForEach.hpp:74
FluxMethod(F &&) -> FluxMethod< execution::OpenMpSimdTag, std::decay_t< F >>
std::decay_t< decltype(std::declval< T >().GetEquation())> Equation
A template typedef to detect the member function.
Definition: Meta.hpp:59
The fub namespace.
Definition: AnyBoundaryCondition.hpp:31
auto Shrink(const layout_left::mapping< Extent > &layout, Direction dir, std::ptrdiff_t n=1)
Definition: Equation.hpp:78
Eigen::Vector2d GetBoundaryNormal(const CutCellData< 2 > &ccdata, const std::array< std::ptrdiff_t, 2 > &index)
Eigen::Vector2d GetUnshieldedCentroid(const CutCellData< 2 > &geom, const Index< 2 > &face, const Eigen::Vector2d &dx, Direction dir)
std::chrono::duration< double > Duration
Definition: Duration.hpp:31
View< State > Subview(const BasicView< State, Layout, Rank > &state, const IndexBox< Rank > &box)
Definition: Equation.hpp:86
Array< double, 1 > Array1d
Definition: Eigen.hpp:53
constexpr const int kDefaultChunkSize
Definition: Eigen.hpp:39
void ForEachVariable(F function, Ts &&... states)
Definition: State.hpp:89
void StoreN(nodeduce_t< ViewPointer< Conservative< Eq >>> pointer, const ConservativeArray< Eq > &state, int n)
Definition: StateArray.hpp:416
IndexBox< Rank > Grow(const IndexBox< Rank > &box, Direction dir, const std::array< std::ptrdiff_t, 2 > &shifts)
Definition: PatchDataView.hpp:106
std::array< std::ptrdiff_t, N > RightTo(const std::array< std::ptrdiff_t, N > &idx, Direction dir, std::ptrdiff_t shift=1)
Definition: PatchDataView.hpp:51
constexpr std::array< std::ptrdiff_t, Extents::rank()> AsArray(Extents e) noexcept
Definition: PatchDataView.hpp:154
void ForEachRow(const Tuple &views, Function f)
Definition: StateRow.hpp:172
typename nodeduce< T >::type nodeduce_t
Definition: type_traits.hpp:47
void Load(State &state, const BasicView< const State, Layout, Rank > &view, const std::array< std::ptrdiff_t, State::Equation::Rank()> &index)
Definition: State.hpp:640
ViewPointer< State > Begin(const BasicView< State, Layout, Rank > &view)
Definition: State.hpp:769
void LoadN(CompleteArray< Eq, N > &state, const BasicView< const Complete< Eq >, Layout, Rank > &view, int size, nodeduce_t< const std::array< std::ptrdiff_t, std::size_t(Rank)> & > pos)
Definition: StateArray.hpp:310
Coordinates< 2 > ComputeReflectedCoordinates(const Coordinates< 2 > &offset, const Coordinates< 2 > &boundary_normal)
Definition: MyStabilisation.hpp:57
Eigen::Vector2d GetBoundaryCentroid(const CutCellData< 2 > &ccdata, const std::array< std::ptrdiff_t, 2 > &index)
Index< Rank > RelativeCellIndex(const Coordinates< Rank > &x, const Coordinates< Rank > &dx)
Definition: MyStabilisation.hpp:65
Eigen::Matrix< double, Rank, 1 > GetAbsoluteBoundaryCentroid(const CutCellData< Rank > &geom, const Index< Rank > &index, const Eigen::Matrix< double, Rank, 1 > &dx)
Definition: CutCellData.hpp:120
Eigen::Matrix< double, Rank, 1 > GetAbsoluteVolumeCentroid(const CutCellData< Rank > &geom, const Index< Rank > &index, const Eigen::Matrix< double, Rank, 1 > &dx)
Definition: CutCellData.hpp:107
void MyStab_ComputeStableFluxComponents(const PatchDataView< double, 2, layout_stride > &stabilised_fluxes, const PatchDataView< double, 2, layout_stride > &shielded_left_fluxes, const PatchDataView< double, 2, layout_stride > &shielded_right_fluxes, const PatchDataView< const double, 2, layout_stride > &regular_fluxes, const PatchDataView< const double, 2, layout_stride > &boundary_fluxes, const CutCellData< 2 > &geom, Duration dt, double dx, Direction dir)
void ApplyGradient(State &u, span< const State, Rank > grad, nodeduce_t< const Eigen::Matrix< double, Rank, 1 > & > x) noexcept
Definition: MyStabilisation.hpp:85
Direction
This is a type safe type to denote a dimensional split direction.
Definition: Direction.hpp:30
void Advance(ViewPointer< State > &pointer, std::ptrdiff_t n) noexcept
Definition: State.hpp:825
std::array< std::ptrdiff_t, static_cast< std::size_t >(Rank)> Index
Definition: PatchDataView.hpp:34
Index< Rank+1 > EmbedIndex(const Index< Rank > &index, Direction dir)
Definition: MyStabilisation.hpp:76
constexpr auto AsTuple(const TupleLike &t)
Definition: tuple.hpp:69
const Conservative< Eq > & AsCons(const Conservative< Eq > &x)
Definition: State.hpp:438
bool Contains(const IndexBox< Rank > &b1, const IndexBox< Rank > &b2)
Definition: PatchDataView.hpp:73
void Reflect(Complete< IdealGasMix< 1 >> &reflected, const Complete< IdealGasMix< 1 >> &state, const Eigen::Matrix< double, 1, 1 > &normal, const IdealGasMix< 1 > &gas)
Eigen::Matrix< double, Rank, 1 > Coordinates
Definition: MyStabilisation.hpp:54
void Store(const BasicView< Conservative< Eq >, Layout, Eq::Rank()> &view, const Conservative< Eq > &state, const std::array< std::ptrdiff_t, Eq::Rank()> &index)
Definition: State.hpp:663
ViewPointer< State > End(const BasicView< State, Layout, Rank > &view)
Definition: State.hpp:782
std::array< double, 2 > Intersect(const std::array< double, 2 > &i1, const std::array< double, 2 > &i2)
Definition: CutCellData.hpp:29
void ForEachComponent(F function, Ts &&... states)
Definition: State.hpp:624
std::array< std::ptrdiff_t, N > Shift(const std::array< std::ptrdiff_t, N > &idx, Direction dir, std::ptrdiff_t shift)
Definition: PatchDataView.hpp:37
MyCutCellMethod(const Equation &, const FluxMethod &) -> MyCutCellMethod< Equation, FluxMethod >
std::ptrdiff_t index
Definition: type_traits.hpp:179
std::array< std::ptrdiff_t, N > LeftTo(const std::array< std::ptrdiff_t, N > &idx, Direction dir, std::ptrdiff_t shift=1)
Definition: PatchDataView.hpp:45
Definition: MyStabilisation.hpp:105
void LimitGradientsAtIndex(const std::array< StridedDataView< double, Rank >, Rank > &grad_u, StridedDataView< const double, Rank > u, const CutCellData< Rank > &geom, const Index< Rank > &index, const Coordinates< Rank > &dx) const
void ComputeGradients(span< double, 2 > gradient, span< const double, 5 > states, span< const Coordinates< Rank >, 5 > x)
void LimitGradients(const std::array< StridedDataView< double, Rank >, Rank > &grad_u, StridedDataView< const double, Rank > u, StridedDataView< const char, Rank > needs_limiter, const CutCellData< Rank > &geom, const Coordinates< Rank > &dx) const
void ComputeGradients(span< double, 2 > gradient, span< const double, 4 > states, span< const Coordinates< Rank >, 4 > x)
Definition: State.hpp:403
Coordinates< Rank > slope
Definition: MyStabilisation.hpp:149
std::array< Index< Rank >, kMaxSources > sources
Definition: MyStabilisation.hpp:143
std::array< double, kMaxSources > end
Definition: MyStabilisation.hpp:145
Coordinates< Rank > xB
Definition: MyStabilisation.hpp:150
std::array< double, kMaxSources > start
Definition: MyStabilisation.hpp:144
Definition: MyStabilisation.hpp:130
void ComputeGradients(span< Conservative, 2 > gradient, span< const Conservative, 5 > states, span< const Coordinates< Rank >, 5 > x)
Definition: MyStabilisation.hpp:171
void ComputeGradients(span< Conservative, 2 > gradient, span< const Conservative, 4 > states, span< const Coordinates< Rank >, 4 > x)
Definition: MyStabilisation.hpp:156
std::array< AuxiliaryReconstructionData, 2 > SplitAt(const AuxiliaryReconstructionData &aux, double dx)
Definition: MyStabilisation.hpp:398
void ReconstructEmbeddedBoundaryStencil(span< Complete, 2 > h_grid_embedded_boundary, span< Conservative, 2 > h_grid_embedded_boundary_slopes, const View< const Complete > &states, const View< const Conservative > &gradient_x, const View< const Conservative > &gradient_y, const View< const Conservative > &gradient_z, const CutCellData< Rank > &cutcell_data, const Index< Rank > &cell, Duration, Eigen::Matrix< double, Rank, 1 > dx, Direction dir)
Definition: MyStabilisation.hpp:659
double Length(const std::array< double, 2 > &interval)
Definition: MyStabilisation.hpp:356
ConservativeHGridReconstruction(const Equation &equation)
Definition: MyStabilisation.hpp:153
void SetZero(Conservative &cons)
Definition: MyStabilisation.hpp:429
AuxiliaryReconstructionData Sort(const AuxiliaryReconstructionData &aux_data)
Definition: MyStabilisation.hpp:373
AuxiliaryReconstructionData GetAuxiliaryData(const Index< Rank > &index, const CutCellData< Rank > &geom, const Coordinates< Rank > &dx, const Coordinates< Rank > &slope, double required_length)
Definition: MyStabilisation.hpp:433
double TotalLength(const AuxiliaryReconstructionData &aux) noexcept
Definition: MyStabilisation.hpp:486
void ReconstructRegularStencil(span< Complete, 2 > h_grid_regular, span< Conservative, 2 > h_grid_regular_gradients, const View< const Complete > &states, const View< const Conservative > &gradient_x, const View< const Conservative > &gradient_y, const View< const Conservative > &gradient_z, const CutCellData< Rank > &geom, const Index< Rank > &face, Duration, Eigen::Matrix< double, Rank, 1 > dx, Direction dir)
Definition: MyStabilisation.hpp:720
Equation equation_
Definition: MyStabilisation.hpp:764
bool IntegrateCellState(Conservative &integral, Conservative &integral_gradient, const View< const Conservative > &states, const View< const Conservative > &gradient_x, const View< const Conservative > &gradient_y, const View< const Conservative > &gradient_z, const CutCellData< Rank > &geom, const AuxiliaryReconstructionData &aux_data, const Coordinates< Rank > &dx, double total_length)
Definition: MyStabilisation.hpp:494
bool IntegrateCellState(Conservative &integral, Conservative &integral_gradient, const View< const Conservative > &states, const View< const Conservative > &gradient_x, const View< const Conservative > &gradient_y, const View< const Conservative > &gradient_z, const CutCellData< Rank > &geom, const AuxiliaryReconstructionData &aux_data, const Coordinates< Rank > &dx)
Definition: MyStabilisation.hpp:536
std::array< double, 2 > FindAdmissibleInterval(const Coordinates< Rank > &xM, const Coordinates< Rank > &xB, const Coordinates< Rank > &slope, const Coordinates< Rank > &dx)
Definition: MyStabilisation.hpp:329
void ComputeGradients(const View< Conservative > &gradient_x, const View< Conservative > &gradient_y, const View< Conservative > &gradient_z, const View< const Conservative > &states, const StridedDataView< const char, Rank > &flags, const CutCellData< Rank > &geom, const Coordinates< Rank > &dx)
Definition: MyStabilisation.hpp:187
void ReconstructSinglyShieldedStencil(span< Complete, 2 > h_grid_singly_shielded, span< Conservative, 2 > h_grid_singly_shielded_gradients, const View< const Complete > &states, const View< const Conservative > &gradient_x, const View< const Conservative > &gradient_y, const View< const Conservative > &gradient_z, const CutCellData< Rank > &cutcell_data, const Index< Rank > &cell, Duration, const Coordinates< Rank > &dx, Direction dir)
Definition: MyStabilisation.hpp:551
IndexBox< Rank > MakeIndexBox(const Index< Rank > &signs) noexcept
Definition: MyStabilisation.hpp:360
AuxiliaryReconstructionData GetAuxiliaryData(const Index< Rank > &index, const CutCellData< Rank > &geom, const Coordinates< Rank > &dx, Direction dir)
Definition: MyStabilisation.hpp:472
Definition: CutCellData.hpp:34
std::array< PatchDataView< const double, Rank >, sRank > unshielded_fractions
Definition: CutCellData.hpp:46
PatchDataView< const double, Rank > volume_fractions
Definition: CutCellData.hpp:38
PatchDataView< const double, Rank+1 > boundary_centeroids
Definition: CutCellData.hpp:42
std::array< PatchDataView< const double, Rank >, sRank > face_fractions
Definition: CutCellData.hpp:40
Definition: PatchDataView.hpp:56
Index< Rank > upper
Definition: PatchDataView.hpp:59
Definition: PatchDataView.hpp:201
PatchDataView< T, R, layout_stride > Subview(const IndexBox< R > &box) const
Definition: PatchDataView.hpp:245
Definition: StateRow.hpp:51
Definition: State.hpp:750