Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <array> 7 : #include <unordered_map> 8 : #include <utility> 9 : 10 : #include "Evolution/DiscontinuousGalerkin/Limiters/MinmodHelpers.hpp" 11 : #include "Utilities/Gsl.hpp" 12 : #include "Utilities/TMPL.hpp" 13 : 14 : /// \cond 15 : class DataVector; 16 : template <size_t VolumeDim> 17 : class Direction; 18 : template <size_t Dim, typename T> 19 : class DirectionMap; 20 : template <size_t VolumeDim> 21 : class Element; 22 : template <size_t VolumeDim> 23 : class ElementId; 24 : template <size_t VolumeDim> 25 : class Mesh; 26 : 27 : namespace boost { 28 : template <class T> 29 : struct hash; 30 : } // namespace boost 31 : /// \endcond 32 : 33 1 : namespace Limiters::Tci { 34 : 35 : // Implements the TVB troubled-cell indicator from Cockburn1999. 36 : template <size_t VolumeDim> 37 0 : bool tvb_minmod_indicator( 38 : gsl::not_null<Minmod_detail::BufferWrapper<VolumeDim>*> buffer, 39 : double tvb_constant, const DataVector& u, const Mesh<VolumeDim>& mesh, 40 : const Element<VolumeDim>& element, 41 : const std::array<double, VolumeDim>& element_size, 42 : const DirectionMap<VolumeDim, double>& effective_neighbor_means, 43 : const DirectionMap<VolumeDim, double>& effective_neighbor_sizes); 44 : 45 : // Implements the TVB troubled-cell indicator from Cockburn1999 for several 46 : // tensors. Returns true if any component of any tensor needs limiting. 47 : // 48 : // Expects type `PackagedData` to contain, as in Limiters::Minmod: 49 : // - a variable `means` that is a `TaggedTuple<Tags::Mean<Tags>...>` 50 : // - a variable `element_size` that is a `std::array<double, VolumeDim>` 51 : template <size_t VolumeDim, typename PackagedData, typename... Tags> 52 0 : bool tvb_minmod_indicator( 53 : const double tvb_constant, const typename Tags::type&... tensors, 54 : const Mesh<VolumeDim>& mesh, const Element<VolumeDim>& element, 55 : const std::array<double, VolumeDim>& element_size, 56 : const std::unordered_map<DirectionalId<VolumeDim>, PackagedData, 57 : boost::hash<DirectionalId<VolumeDim>>>& 58 : neighbor_data) { 59 : Minmod_detail::BufferWrapper<VolumeDim> buffer(mesh); 60 : const auto effective_neighbor_sizes = 61 : Minmod_detail::compute_effective_neighbor_sizes(element, neighbor_data); 62 : 63 : // Ideally, as soon as one component is found that needs limiting, then we 64 : // would exit the TCI early with return value `true`. But there is no natural 65 : // way to return early from the pack expansion. So we use this bool to keep 66 : // track of whether a previous component needed limiting... and if so, then 67 : // we simply skip any work. 68 : bool some_component_needs_limiting = false; 69 : const auto wrap_tci_one_tensor = [&](auto tag, const auto tensor) { 70 : if (some_component_needs_limiting) { 71 : // Skip this tensor completely 72 : return '0'; 73 : } 74 : 75 : for (size_t tensor_storage_index = 0; tensor_storage_index < tensor.size(); 76 : ++tensor_storage_index) { 77 : const auto effective_neighbor_means = 78 : Minmod_detail::compute_effective_neighbor_means<decltype(tag)>( 79 : tensor_storage_index, element, neighbor_data); 80 : 81 : const DataVector& u = tensor[tensor_storage_index]; 82 : const bool component_needs_limiting = tvb_minmod_indicator( 83 : make_not_null(&buffer), tvb_constant, u, mesh, element, element_size, 84 : effective_neighbor_means, effective_neighbor_sizes); 85 : 86 : if (component_needs_limiting) { 87 : some_component_needs_limiting = true; 88 : // Skip remaining components of this tensor 89 : return '0'; 90 : } 91 : } 92 : return '0'; 93 : }; 94 : expand_pack(wrap_tci_one_tensor(Tags{}, tensors)...); 95 : return some_component_needs_limiting; 96 : } 97 : 98 : } // namespace Limiters::Tci