SpECTRE Documentation Coverage Report
Current view: top level - Time - BoundaryHistory.hpp Hit Total Coverage
Commit: 664546099c4dbf27a1b708fac45e39c82dd743d2 Lines: 13 99 13.1 %
Date: 2024-04-19 16:28:01
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <algorithm>
       7             : #include <boost/container/static_vector.hpp>
       8             : #include <cstddef>
       9             : #include <optional>
      10             : #include <ostream>
      11             : #include <pup.h>
      12             : #include <pup_stl.h>
      13             : #include <type_traits>
      14             : #include <utility>
      15             : 
      16             : #include "DataStructures/CircularDeque.hpp"
      17             : #include "DataStructures/MathWrapper.hpp"
      18             : #include "DataStructures/StaticDeque.hpp"
      19             : #include "Time/History.hpp"
      20             : #include "Time/TimeStepId.hpp"
      21             : #include "Utilities/Algorithm.hpp"
      22             : #include "Utilities/ErrorHandling/Assert.hpp"
      23             : #include "Utilities/Gsl.hpp"
      24             : #include "Utilities/Literals.hpp"
      25             : #include "Utilities/Serialization/PupBoost.hpp"
      26             : #include "Utilities/StdHelpers.hpp"
      27             : #include "Utilities/StlBoilerplate.hpp"
      28             : #include "Utilities/TMPL.hpp"
      29             : 
      30           1 : namespace TimeSteppers {
      31             : 
      32             : /// \ingroup TimeSteppersGroup
      33             : /// Access to the list of `TimeStepId`s in a `BoundaryHistory`.
      34             : ///
      35             : /// For simplicity of implementation, iterable-container access is not
      36             : /// provided for substeps within a step, but is instead provided
      37             : /// through additional methods on this class.
      38             : /// @{
      39           1 : class ConstBoundaryHistoryTimes
      40             :     : public stl_boilerplate::RandomAccessSequence<ConstBoundaryHistoryTimes,
      41             :                                                    const TimeStepId, false> {
      42             :  protected:
      43           0 :   ~ConstBoundaryHistoryTimes() = default;
      44             : 
      45             :  public:
      46           0 :   virtual size_t size() const = 0;
      47           0 :   virtual const TimeStepId& operator[](size_t n) const = 0;
      48           0 :   virtual const TimeStepId& operator[](
      49             :       const std::pair<size_t, size_t>& step_and_substep) const = 0;
      50           0 :   virtual size_t integration_order(size_t n) const = 0;
      51           0 :   virtual size_t integration_order(const TimeStepId& id) const = 0;
      52           0 :   virtual size_t number_of_substeps(size_t n) const = 0;
      53             :   /// This returns the same value for any substep of the same step.
      54           1 :   virtual size_t number_of_substeps(const TimeStepId& id) const = 0;
      55             : };
      56             : 
      57           0 : class MutableBoundaryHistoryTimes : public ConstBoundaryHistoryTimes {
      58             :  protected:
      59           0 :   ~MutableBoundaryHistoryTimes() = default;
      60             : 
      61             :  public:
      62             :   /// Remove the earliest step and its substeps.
      63           1 :   virtual void pop_front() const = 0;
      64           0 :   virtual void clear() const = 0;
      65             :   /// Remove all substeps for step \p n except for the step itself.
      66           1 :   virtual void clear_substeps(size_t n) const = 0;
      67             : };
      68             : /// @}
      69             : 
      70             : /// \ingroup TimeSteppersGroup
      71             : /// Type erased base class for evaluating BoundaryHistory couplings.
      72             : ///
      73             : /// The results are cached in the `BoundaryHistory` class.
      74             : template <typename UntypedCouplingResult>
      75           1 : class BoundaryHistoryEvaluator {
      76             :  public:
      77           0 :   virtual MathWrapper<const UntypedCouplingResult> operator()(
      78             :       const TimeStepId& local_id, const TimeStepId& remote_id) const = 0;
      79             : 
      80             :  protected:
      81           0 :   ~BoundaryHistoryEvaluator() = default;
      82             : };
      83             : 
      84             : /// \ingroup TimeSteppersGroup
      85             : /// History data used by a TimeStepper for boundary integration.
      86             : ///
      87             : /// \tparam LocalData local data passed to the boundary coupling
      88             : /// \tparam RemoteData remote data passed to the boundary coupling
      89             : /// \tparam CouplingResult type of cached boundary couplings
      90             : template <typename LocalData, typename RemoteData, typename CouplingResult>
      91           1 : class BoundaryHistory {
      92             :  public:
      93           0 :   BoundaryHistory() = default;
      94           0 :   BoundaryHistory(const BoundaryHistory& other) = default;
      95           0 :   BoundaryHistory(BoundaryHistory&&) = default;
      96           0 :   BoundaryHistory& operator=(const BoundaryHistory& other) = default;
      97           0 :   BoundaryHistory& operator=(BoundaryHistory&&) = default;
      98           0 :   ~BoundaryHistory() = default;
      99             : 
     100             :   /// The wrapped types presented by the type-erased history.  One of
     101             :   /// the types in \ref MATH_WRAPPER_TYPES.
     102           1 :   using UntypedCouplingResult = math_wrapper_type<CouplingResult>;
     103             : 
     104             :   // Factored out of ConstSideAccess so that the base classes of
     105             :   // MutableSideAccess can have protected destructors.
     106             :   template <bool Local, bool Mutable>
     107           0 :   class SideAccessCommon
     108             :       : public tmpl::conditional_t<Mutable, MutableBoundaryHistoryTimes,
     109             :                                    ConstBoundaryHistoryTimes> {
     110             :    public:
     111           0 :     using MutableData = tmpl::conditional_t<Local, LocalData, RemoteData>;
     112           0 :     using Data = tmpl::conditional_t<Mutable, MutableData, const MutableData>;
     113             : 
     114           0 :     size_t size() const override { return parent_data().size(); }
     115           0 :     static constexpr size_t max_size() {
     116             :       return decltype(std::declval<ConstSideAccess>()
     117             :                           .parent_data())::max_size();
     118             :     }
     119             : 
     120           0 :     const TimeStepId& operator[](const size_t n) const override {
     121             :       return (*this)[{n, 0}];
     122             :     }
     123           0 :     const TimeStepId& operator[](
     124             :         const std::pair<size_t, size_t>& step_and_substep) const override {
     125             :       return entry(step_and_substep).id;
     126             :     }
     127             : 
     128           0 :     size_t integration_order(const size_t n) const override {
     129             :       return parent_data()[n].integration_order;
     130             :     }
     131           0 :     size_t integration_order(const TimeStepId& id) const override {
     132             :       return step_data(id).integration_order;
     133             :     }
     134             : 
     135           0 :     size_t number_of_substeps(const size_t n) const override {
     136             :       return parent_data()[n].substeps.size();
     137             :     }
     138           0 :     size_t number_of_substeps(const TimeStepId& id) const override {
     139             :       return step_data(id).substeps.size();
     140             :     }
     141             : 
     142             :     /// Access the data stored on the side.  When performed through a
     143             :     /// `MutableSideAccess`, these allow modification of the data.
     144             :     /// Performing such modifications likely invalidates the coupling
     145             :     /// cache for the associated `BoundaryHistory` object, which
     146             :     /// should be cleared.
     147             :     /// @{
     148           1 :     Data& data(const size_t n) const {
     149             :       return parent_data()[n].substeps.front().data;
     150             :     }
     151           1 :     Data& data(const TimeStepId& id) const {
     152             :       return entry(id).data;
     153             :     }
     154             :     /// @}
     155             : 
     156             :     /// Apply \p func to each entry.
     157             :     ///
     158             :     /// The function \p func must accept two arguments, one of type
     159             :     /// `const TimeStepId&` and a second of either type `const Data&`
     160             :     /// or `gsl::not_null<Data*>`.  (Note that `Data` may be a
     161             :     /// const-qualified type.)  If entries are modified, the coupling
     162             :     /// cache must be cleared by calling `clear_coupling_cache()` on
     163             :     /// the parent `BoundaryHistory` object.
     164             :     template <typename Func>
     165           1 :     void for_each(Func&& func) const;
     166             : 
     167             :    protected:
     168           0 :     ~SideAccessCommon() = default;
     169             : 
     170           0 :     auto& parent_data() const {
     171             :       if constexpr (Local) {
     172             :         return parent_->local_data_;
     173             :       } else {
     174             :         return parent_->remote_data_;
     175             :       }
     176             :     }
     177             : 
     178           0 :     auto& step_data(const TimeStepId& id) const {
     179             :       auto entry =
     180             :           std::upper_bound(parent_data().begin(), parent_data().end(), id);
     181             :       ASSERT(entry != parent_data().begin(), "Id " << id << " not present.");
     182             :       --entry;
     183             :       ASSERT(id.substep() < entry->substeps.size() and
     184             :              entry->substeps[id.substep()].id == id,
     185             :              "Id " << id << " not present.");
     186             :       return *entry;
     187             :     }
     188             : 
     189           0 :     auto& entry(const TimeStepId& id) const {
     190             :       // Bounds and consistency are checked in step_data()
     191             :       return step_data(id).substeps[id.substep()];
     192             :     }
     193             : 
     194           0 :     auto& entry(const std::pair<size_t, size_t>& step_and_substep) const {
     195             :       ASSERT(step_and_substep.first < parent_data().size(),
     196             :              "Step out of range: " << step_and_substep.first);
     197             :       auto& substeps = parent_data()[step_and_substep.first].substeps;
     198             :       ASSERT(step_and_substep.second < substeps.size(),
     199             :              "Substep out of range: " << step_and_substep.second);
     200             :       return substeps[step_and_substep.second];
     201             :     }
     202             : 
     203           0 :     using StoredHistory =
     204             :         tmpl::conditional_t<Mutable, BoundaryHistory, const BoundaryHistory>;
     205           0 :     explicit SideAccessCommon(const gsl::not_null<StoredHistory*> parent)
     206             :         : parent_(parent) {}
     207             : 
     208           0 :     gsl::not_null<StoredHistory*> parent_;
     209             :   };
     210             : 
     211             :   /// \cond
     212             :   template <bool Local>
     213             :   class ConstSideAccess;
     214             :   /// \endcond
     215             : 
     216             :   template <bool Local>
     217           0 :   class MutableSideAccess final : public SideAccessCommon<Local, true> {
     218             :    public:
     219           0 :     using Data = tmpl::conditional_t<Local, LocalData, RemoteData>;
     220             : 
     221           0 :     void pop_front() const override;
     222           0 :     void clear() const override;
     223           0 :     void clear_substeps(size_t n) const override;
     224             : 
     225           0 :     void insert(const TimeStepId& id, size_t integration_order,
     226             :                 Data data) const;
     227             : 
     228           0 :     void insert_initial(const TimeStepId& id, size_t integration_order,
     229             :                         Data data) const;
     230             : 
     231             :    private:
     232           0 :     friend class BoundaryHistory;
     233             :     friend class ConstSideAccess<Local>;
     234           0 :     explicit MutableSideAccess(const gsl::not_null<BoundaryHistory*> parent)
     235             :         : SideAccessCommon<Local, true>(parent) {}
     236             :   };
     237             : 
     238             :   template <bool Local>
     239           0 :   class ConstSideAccess final : public SideAccessCommon<Local, false> {
     240             :    private:
     241           0 :     friend class BoundaryHistory;
     242           0 :     explicit ConstSideAccess(const gsl::not_null<const BoundaryHistory*> parent)
     243             :         : SideAccessCommon<Local, false>(parent) {}
     244             :   };
     245             : 
     246           0 :   MutableSideAccess<true> local() { return MutableSideAccess<true>(this); }
     247           0 :   ConstSideAccess<true> local() const { return ConstSideAccess<true>(this); }
     248             : 
     249           0 :   MutableSideAccess<false> remote() { return MutableSideAccess<false>(this); }
     250           0 :   ConstSideAccess<false> remote() const { return ConstSideAccess<false>(this); }
     251             : 
     252             :  private:
     253             :   template <typename Coupling>
     254           0 :   class EvaluatorImpl final
     255             :       : public BoundaryHistoryEvaluator<UntypedCouplingResult> {
     256             :    public:
     257           0 :     MathWrapper<const UntypedCouplingResult> operator()(
     258             :         const TimeStepId& local_id, const TimeStepId& remote_id) const;
     259             : 
     260             :    private:
     261           0 :     friend class BoundaryHistory;
     262             : 
     263           0 :     EvaluatorImpl(const gsl::not_null<const BoundaryHistory*> parent,
     264             :                   Coupling coupling)
     265             :         : parent_(parent), coupling_(std::move(coupling)) {}
     266             : 
     267           0 :     gsl::not_null<const BoundaryHistory*> parent_;
     268           0 :     Coupling coupling_;
     269             :   };
     270             : 
     271             :  public:
     272             :   /// Obtain an object that can evaluate type-erased boundary
     273             :   /// couplings.
     274             :   ///
     275             :   /// The passed functor must take objects of types `LocalData` and
     276             :   /// `RemoteData` and return an object convertible to
     277             :   /// `CouplingResult`.  Results are cached, so different calls to
     278             :   /// this function should pass equivalent couplings.
     279             :   template <typename Coupling>
     280           1 :   auto evaluator(Coupling&& coupling) const {
     281             :     return EvaluatorImpl<Coupling>(this, std::forward<Coupling>(coupling));
     282             :   }
     283             : 
     284             :   /// Clear the cached values.
     285             :   ///
     286             :   /// This is required after existing history entries that have been
     287             :   /// used in coupling calculations are mutated.
     288           1 :   void clear_coupling_cache();
     289             : 
     290           0 :   void pup(PUP::er& p);
     291             : 
     292             :   template <bool IncludeData>
     293           0 :   std::ostream& print(std::ostream& os, size_t padding_size = 0) const;
     294             : 
     295             :  private:
     296             :   template <typename Data>
     297           0 :   struct StepData {
     298           0 :     struct Entry {
     299           0 :       TimeStepId id;
     300           0 :       Data data;
     301             : 
     302           0 :       void pup(PUP::er& p) {
     303             :         p | id;
     304             :         p | data;
     305             :       }
     306             :     };
     307             : 
     308           0 :     size_t integration_order;
     309             :     // Unlike in History, the full step is the first entry, so we need
     310             :     // one more element.
     311           0 :     boost::container::static_vector<Entry, history_max_substeps + 1> substeps;
     312             : 
     313           0 :     void pup(PUP::er& p) {
     314             :       p | integration_order;
     315             :       p | substeps;
     316             :     }
     317             : 
     318           0 :     friend bool operator<(const StepData& a, const StepData& b) {
     319             :       return a.substeps.front().id < b.substeps.front().id;
     320             :     }
     321           0 :     friend bool operator<(const TimeStepId& a, const StepData& b) {
     322             :       return a < b.substeps.front().id;
     323             :     }
     324           0 :     friend bool operator<(const StepData& a, const TimeStepId& b) {
     325             :       return a.substeps.front().id < b;
     326             :     }
     327             :   };
     328             : 
     329           0 :   void insert_local(const TimeStepId& id, size_t integration_order,
     330             :                     LocalData data);
     331           0 :   void insert_remote(const TimeStepId& id, size_t integration_order,
     332             :                      RemoteData data);
     333             : 
     334           0 :   void insert_initial_local(const TimeStepId& id, size_t integration_order,
     335             :                             LocalData data);
     336           0 :   void insert_initial_remote(const TimeStepId& id, size_t integration_order,
     337             :                              RemoteData data);
     338             : 
     339           0 :   void pop_local();
     340           0 :   void pop_remote();
     341             : 
     342           0 :   void clear_substeps_local(size_t n);
     343           0 :   void clear_substeps_remote(size_t n);
     344             : 
     345           0 :   StaticDeque<StepData<LocalData>, history_max_past_steps + 2> local_data_{};
     346           0 :   CircularDeque<StepData<RemoteData>> remote_data_{};
     347             : 
     348             :   template <typename Data>
     349           0 :   using CouplingSubsteps =
     350             :       boost::container::static_vector<Data, history_max_substeps + 1>;
     351             : 
     352             :   // Putting the CircularDeque outermost means that we are inserting
     353             :   // and removing containers that do not allocate, so we don't have to
     354             :   // worry about that.
     355             :   // NOLINTNEXTLINE(spectre-mutable)
     356             :   mutable CircularDeque<CouplingSubsteps<
     357             :       StaticDeque<CouplingSubsteps<std::optional<CouplingResult>>,
     358             :                   decltype(local_data_)::max_size()>>>
     359           0 :       couplings_;
     360             : };
     361             : 
     362             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     363             : template <bool Local, bool Mutable>
     364             : template <typename Func>
     365             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::SideAccessCommon<
     366             :     Local, Mutable>::for_each(Func&& func) const {
     367             :   for (auto& step : parent_data()) {
     368             :     for (auto& substep : step.substeps) {
     369             :       if constexpr (std::is_invocable_v<Func&, const TimeStepId&,
     370             :                                         const Data&>) {
     371             :         func(std::as_const(substep.id), std::as_const(substep.data));
     372             :       } else {
     373             :         func(std::as_const(substep.id), make_not_null(&substep.data));
     374             :       }
     375             :     }
     376             :   }
     377             : }
     378             : 
     379             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     380             : template <bool Local>
     381             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     382             :     Local>::pop_front() const {
     383             :   if constexpr (Local) {
     384             :     this->parent_->pop_local();
     385             :   } else {
     386             :     this->parent_->pop_remote();
     387             :   }
     388             : }
     389             : 
     390             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     391             : template <bool Local>
     392             : void BoundaryHistory<LocalData, RemoteData,
     393             :                      CouplingResult>::MutableSideAccess<Local>::clear() const {
     394             :   while (not this->empty()) {
     395             :     pop_front();
     396             :   }
     397             : }
     398             : 
     399             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     400             : template <bool Local>
     401             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     402             :     Local>::clear_substeps(const size_t n) const {
     403             :   if constexpr (Local) {
     404             :     this->parent_->clear_substeps_local(n);
     405             :   } else {
     406             :     this->parent_->clear_substeps_remote(n);
     407             :   }
     408             : }
     409             : 
     410             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     411             : template <bool Local>
     412             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     413             :     Local>::insert(const TimeStepId& id, const size_t integration_order,
     414             :                    Data data) const {
     415             :   ASSERT(this->parent_data().empty() or
     416             :              id > this->parent_data().back().substeps.back().id,
     417             :          "New data not newer than current data.");
     418             :   if constexpr (Local) {
     419             :     this->parent_->insert_local(id, integration_order, std::move(data));
     420             :   } else {
     421             :     this->parent_->insert_remote(id, integration_order, std::move(data));
     422             :   }
     423             : }
     424             : 
     425             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     426             : template <bool Local>
     427             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     428             :     Local>::insert_initial(const TimeStepId& id, const size_t integration_order,
     429             :                            Data data) const {
     430             :   ASSERT(id.substep() == 0, "Cannot insert_initial with substeps.");
     431             :   ASSERT(this->parent_data().empty() or
     432             :              id < this->parent_data().front().substeps.front().id,
     433             :          "New data not older than current data.");
     434             :   if constexpr (Local) {
     435             :     this->parent_->insert_initial_local(id, integration_order, std::move(data));
     436             :   } else {
     437             :     this->parent_->insert_initial_remote(id, integration_order,
     438             :                                          std::move(data));
     439             :   }
     440             : }
     441             : 
     442             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     443             : template <typename Coupling>
     444             : auto BoundaryHistory<LocalData, RemoteData, CouplingResult>::EvaluatorImpl<
     445             :     Coupling>::operator()(const TimeStepId& local_id,
     446             :                           const TimeStepId& remote_id) const
     447             :     -> MathWrapper<const UntypedCouplingResult> {
     448             :   auto local_entry = std::upper_bound(
     449             :       parent_->local_data_.begin(), parent_->local_data_.end(), local_id);
     450             :   ASSERT(local_entry != parent_->local_data_.begin(), "local_id not present");
     451             :   --local_entry;
     452             :   ASSERT(local_id.substep() < local_entry->substeps.size() and
     453             :          local_entry->substeps[local_id.substep()].id == local_id,
     454             :          "local_id not present");
     455             :   const auto local_step_offset =
     456             :       static_cast<size_t>(local_entry - parent_->local_data_.begin());
     457             : 
     458             :   auto remote_entry = std::upper_bound(
     459             :       parent_->remote_data_.begin(), parent_->remote_data_.end(), remote_id);
     460             :   ASSERT(remote_entry != parent_->remote_data_.begin(),
     461             :          "remote_id not present");
     462             :   --remote_entry;
     463             :   ASSERT(remote_id.substep() < remote_entry->substeps.size() and
     464             :          remote_entry->substeps[remote_id.substep()].id == remote_id,
     465             :          "remote_id not present");
     466             :   const auto remote_step_offset =
     467             :       static_cast<size_t>(remote_entry - parent_->remote_data_.begin());
     468             : 
     469             :   auto& coupling_entry = parent_->couplings_[remote_step_offset]
     470             :                              [remote_id.substep()][local_step_offset]
     471             :                              [local_id.substep()];
     472             :   if (not coupling_entry.has_value()) {
     473             :     coupling_entry.emplace(coupling_(
     474             :         local_entry->substeps[local_id.substep()].data,
     475             :         remote_entry->substeps[remote_id.substep()].data));
     476             :   }
     477             :   return make_math_wrapper(*coupling_entry);
     478             : }
     479             : 
     480             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     481             : void BoundaryHistory<LocalData, RemoteData,
     482             :                      CouplingResult>::clear_coupling_cache() {
     483             :   for (auto& remote_step : couplings_) {
     484             :     for (auto& remote_substep : remote_step) {
     485             :       for (auto& local_step : remote_substep) {
     486             :         for (auto& local_substep : local_step) {
     487             :           local_substep.reset();
     488             :         }
     489             :       }
     490             :     }
     491             :   }
     492             : }
     493             : 
     494             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     495             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::pup(PUP::er& p) {
     496             :   p | local_data_;
     497             :   p | remote_data_;
     498             :   p | couplings_;
     499             : }
     500             : 
     501             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     502             : template <bool IncludeData>
     503             : std::ostream& BoundaryHistory<LocalData, RemoteData, CouplingResult>::print(
     504             :     std::ostream& os, const size_t padding_size) const {
     505             :   const std::string pad(padding_size, ' ');
     506             :   using ::operator<<;
     507             :   const auto do_print = [&os, &pad](const auto& times) {
     508             :     for (size_t step = 0; step < times.size(); ++step) {
     509             :       const size_t number_of_substeps = times.number_of_substeps(step);
     510             :       for (size_t substep = 0; substep < number_of_substeps; ++substep) {
     511             :         const auto id = times[{step, substep}];
     512             :         os << pad << " Time: " << id;
     513             :         if (substep == 0) {
     514             :           os << " (order " << times.integration_order(step) << ")";
     515             :         }
     516             :         os << "\n";
     517             :         if constexpr (IncludeData) {
     518             :           os << pad << "  Data: ";
     519             :           // os << times.data(id) fails to compile on gcc-11
     520             :           print_stl(os, times.data(id));
     521             :           os << "\n";
     522             :         }
     523             :       }
     524             :     }
     525             :   };
     526             :   os << pad << "Local Data:\n";
     527             :   do_print(local());
     528             :   os << pad << "Remote Data:\n";
     529             :   do_print(remote());
     530             :   return os;
     531             : }
     532             : 
     533             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     534             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::insert_local(
     535             :     const TimeStepId& id, const size_t integration_order, LocalData data) {
     536             :   if (id.substep() == 0) {
     537             :     local_data_.push_back({integration_order, {}});
     538             :   } else {
     539             :     ASSERT(integration_order == local_data_.back().integration_order,
     540             :            "Cannot change integration order during a step.");
     541             :   }
     542             :   local_data_.back().substeps.push_back({id, std::move(data)});
     543             :   for (auto& remote_step : couplings_) {
     544             :     for (auto& remote_substep : remote_step) {
     545             :       if (id.substep() == 0) {
     546             :         remote_substep.emplace_back(1_st);
     547             :       } else {
     548             :         remote_substep.back().emplace_back();
     549             :       }
     550             :     }
     551             :   }
     552             : }
     553             : 
     554             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     555             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::insert_remote(
     556             :     const TimeStepId& id, const size_t integration_order, RemoteData data) {
     557             :   if (id.substep() == 0) {
     558             :     remote_data_.push_back({integration_order, {}});
     559             :   } else {
     560             :     ASSERT(integration_order == remote_data_.back().integration_order,
     561             :            "Cannot change integration order during a step.");
     562             :   }
     563             :   remote_data_.back().substeps.push_back({id, std::move(data)});
     564             :   if (id.substep() == 0) {
     565             :     couplings_.emplace_back(1_st);
     566             :   } else {
     567             :     couplings_.back().emplace_back();
     568             :   }
     569             :   for (const auto& local_step : local_data_) {
     570             :     couplings_.back().back().emplace_back(local_step.substeps.size());
     571             :   }
     572             : }
     573             : 
     574             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     575             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::
     576             :     insert_initial_local(const TimeStepId& id, const size_t integration_order,
     577             :                          LocalData data) {
     578             :   local_data_.push_front({integration_order, {}});
     579             :   local_data_.front().substeps.push_back({id, std::move(data)});
     580             :   for (auto& remote_step : couplings_) {
     581             :     for (auto& remote_substep : remote_step) {
     582             :       remote_substep.emplace_front(1_st);
     583             :     }
     584             :   }
     585             : }
     586             : 
     587             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     588             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::
     589             :     insert_initial_remote(const TimeStepId& id, const size_t integration_order,
     590             :                           RemoteData data) {
     591             :   remote_data_.push_front({integration_order, {}});
     592             :   remote_data_.front().substeps.push_back({id, std::move(data)});
     593             :   couplings_.emplace_front(1_st);
     594             :   for (const auto& local_step : local_data_) {
     595             :     couplings_.front().back().emplace_back(local_step.substeps.size());
     596             :   }
     597             : }
     598             : 
     599             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     600             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::pop_local() {
     601             :   local_data_.pop_front();
     602             :   for (auto& remote_step : couplings_) {
     603             :     for (auto& remote_substep : remote_step) {
     604             :       remote_substep.pop_front();
     605             :     }
     606             :   }
     607             : }
     608             : 
     609             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     610             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::pop_remote() {
     611             :   remote_data_.pop_front();
     612             :   couplings_.pop_front();
     613             : }
     614             : 
     615             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     616             : void BoundaryHistory<LocalData, RemoteData,
     617             :                      CouplingResult>::clear_substeps_local(const size_t n) {
     618             :   local_data_[n].substeps.erase(local_data_[n].substeps.begin() + 1,
     619             :                                 local_data_[n].substeps.end());
     620             :   for (auto& remote_step : couplings_) {
     621             :     for (auto& remote_substep : remote_step) {
     622             :       auto& local_step = remote_substep[n];
     623             :       local_step.erase(local_step.begin() + 1, local_step.end());
     624             :     }
     625             :   }
     626             : }
     627             : 
     628             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     629             : void BoundaryHistory<LocalData, RemoteData,
     630             :                      CouplingResult>::clear_substeps_remote(const size_t n) {
     631             :   remote_data_[n].substeps.erase(remote_data_[n].substeps.begin() + 1,
     632             :                                  remote_data_[n].substeps.end());
     633             :   auto& remote_step = couplings_[n];
     634             :   remote_step.erase(remote_step.begin() + 1, remote_step.end());
     635             : }
     636             : 
     637             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     638           0 : std::ostream& operator<<(
     639             :     std::ostream& os,
     640             :     const BoundaryHistory<LocalData, RemoteData, CouplingResult>& history) {
     641             :   return history.template print<true>(os);
     642             : }
     643             : }  // namespace TimeSteppers

Generated by: LCOV version 1.14