SpECTRE Documentation Coverage Report
Current view: top level - Time - BoundaryHistory.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 13 99 13.1 %
Date: 2025-12-05 05:03:31
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 "Time/History.hpp"
      19             : #include "Time/TimeStepId.hpp"
      20             : #include "Utilities/Algorithm.hpp"
      21             : #include "Utilities/ErrorHandling/Assert.hpp"
      22             : #include "Utilities/Gsl.hpp"
      23             : #include "Utilities/Literals.hpp"
      24             : #include "Utilities/Serialization/PupBoost.hpp"
      25             : #include "Utilities/StdHelpers.hpp"
      26             : #include "Utilities/StlBoilerplate.hpp"
      27             : #include "Utilities/TMPL.hpp"
      28             : 
      29           1 : namespace TimeSteppers {
      30             : 
      31             : /// \ingroup TimeSteppersGroup
      32             : /// Access to the list of `TimeStepId`s in a `BoundaryHistory`.
      33             : ///
      34             : /// For simplicity of implementation, iterable-container access is not
      35             : /// provided for substeps within a step, but is instead provided
      36             : /// through additional methods on this class.
      37             : /// @{
      38           1 : class ConstBoundaryHistoryTimes
      39             :     : public stl_boilerplate::RandomAccessSequence<ConstBoundaryHistoryTimes,
      40             :                                                    const TimeStepId, false> {
      41             :  protected:
      42           0 :   ~ConstBoundaryHistoryTimes() = default;
      43             : 
      44             :  public:
      45           0 :   virtual size_t size() const = 0;
      46           0 :   virtual const TimeStepId& operator[](size_t n) const = 0;
      47           0 :   virtual const TimeStepId& operator[](
      48             :       const std::pair<size_t, size_t>& step_and_substep) const = 0;
      49           0 :   virtual size_t integration_order(size_t n) const = 0;
      50           0 :   virtual size_t integration_order(const TimeStepId& id) const = 0;
      51           0 :   virtual size_t number_of_substeps(size_t n) const = 0;
      52             :   /// This returns the same value for any substep of the same step.
      53           1 :   virtual size_t number_of_substeps(const TimeStepId& id) const = 0;
      54             : };
      55             : 
      56           0 : class MutableBoundaryHistoryTimes : public ConstBoundaryHistoryTimes {
      57             :  protected:
      58           0 :   ~MutableBoundaryHistoryTimes() = default;
      59             : 
      60             :  public:
      61             :   /// Remove the earliest step and its substeps.
      62           1 :   virtual void pop_front() const = 0;
      63           0 :   virtual void clear() const = 0;
      64             :   /// Remove all substeps for step \p n except for the step itself.
      65           1 :   virtual void clear_substeps(size_t n) const = 0;
      66             : };
      67             : /// @}
      68             : 
      69             : /// \ingroup TimeSteppersGroup
      70             : /// Type erased base class for evaluating BoundaryHistory couplings.
      71             : ///
      72             : /// The results are cached in the `BoundaryHistory` class.
      73             : template <typename UntypedCouplingResult>
      74           1 : class BoundaryHistoryEvaluator {
      75             :  public:
      76           0 :   virtual MathWrapper<const UntypedCouplingResult> operator()(
      77             :       const TimeStepId& local_id, const TimeStepId& remote_id) const = 0;
      78             : 
      79             :  protected:
      80           0 :   ~BoundaryHistoryEvaluator() = default;
      81             : };
      82             : 
      83             : /// \ingroup TimeSteppersGroup
      84             : /// History data used by a TimeStepper for boundary integration.
      85             : ///
      86             : /// \tparam LocalData local data passed to the boundary coupling
      87             : /// \tparam RemoteData remote data passed to the boundary coupling
      88             : /// \tparam CouplingResult type of cached boundary couplings
      89             : template <typename LocalData, typename RemoteData, typename CouplingResult>
      90           1 : class BoundaryHistory {
      91             :  public:
      92           0 :   BoundaryHistory() = default;
      93           0 :   BoundaryHistory(const BoundaryHistory& other) = default;
      94           0 :   BoundaryHistory(BoundaryHistory&&) = default;
      95           0 :   BoundaryHistory& operator=(const BoundaryHistory& other) = default;
      96           0 :   BoundaryHistory& operator=(BoundaryHistory&&) = default;
      97           0 :   ~BoundaryHistory() = default;
      98             : 
      99             :   /// The wrapped types presented by the type-erased history.  One of
     100             :   /// the types in \ref MATH_WRAPPER_TYPES.
     101           1 :   using UntypedCouplingResult = math_wrapper_type<CouplingResult>;
     102             : 
     103             :   // Factored out of ConstSideAccess so that the base classes of
     104             :   // MutableSideAccess can have protected destructors.
     105             :   template <bool Local, bool Mutable>
     106           0 :   class SideAccessCommon
     107             :       : public tmpl::conditional_t<Mutable, MutableBoundaryHistoryTimes,
     108             :                                    ConstBoundaryHistoryTimes> {
     109             :    public:
     110           0 :     using MutableData = tmpl::conditional_t<Local, LocalData, RemoteData>;
     111           0 :     using Data = tmpl::conditional_t<Mutable, MutableData, const MutableData>;
     112             : 
     113           0 :     size_t size() const override { return parent_data().size(); }
     114           0 :     static constexpr size_t max_size() {
     115             :       return decltype(std::declval<ConstSideAccess>()
     116             :                           .parent_data())::max_size();
     117             :     }
     118             : 
     119           0 :     const TimeStepId& operator[](const size_t n) const override {
     120             :       return (*this)[{n, 0}];
     121             :     }
     122           0 :     const TimeStepId& operator[](
     123             :         const std::pair<size_t, size_t>& step_and_substep) const override {
     124             :       return entry(step_and_substep).id;
     125             :     }
     126             : 
     127           0 :     size_t integration_order(const size_t n) const override {
     128             :       return parent_data()[n].integration_order;
     129             :     }
     130           0 :     size_t integration_order(const TimeStepId& id) const override {
     131             :       return step_data(id).integration_order;
     132             :     }
     133             : 
     134           0 :     size_t number_of_substeps(const size_t n) const override {
     135             :       return parent_data()[n].substeps.size();
     136             :     }
     137           0 :     size_t number_of_substeps(const TimeStepId& id) const override {
     138             :       return step_data(id).substeps.size();
     139             :     }
     140             : 
     141             :     /// Access the data stored on the side.  When performed through a
     142             :     /// `MutableSideAccess`, these allow modification of the data.
     143             :     /// Performing such modifications likely invalidates the coupling
     144             :     /// cache for the associated `BoundaryHistory` object, which
     145             :     /// should be cleared.
     146             :     /// @{
     147           1 :     Data& data(const size_t n) const {
     148             :       return parent_data()[n].substeps.front().data;
     149             :     }
     150           1 :     Data& data(const TimeStepId& id) const {
     151             :       return entry(id).data;
     152             :     }
     153             :     /// @}
     154             : 
     155             :     /// Apply \p func to each entry.
     156             :     ///
     157             :     /// The function \p func must accept two arguments, one of type
     158             :     /// `const TimeStepId&` and a second of either type `const Data&`
     159             :     /// or `gsl::not_null<Data*>`, with the `not_null` version only
     160             :     /// available if this is a `MutableSideAccess`.  If \p func takes
     161             :     /// a `not_null`, it must return a `bool` indicating if it
     162             :     /// modified the entry.  If any entries are modified, the coupling
     163             :     /// cache of parent `BoundaryHistory` will be cleared.
     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 :   CircularDeque<StepData<LocalData>> 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             :   // NOLINTNEXTLINE(spectre-mutable)
     353             :   mutable CircularDeque<CouplingSubsteps<
     354             :       CircularDeque<CouplingSubsteps<std::optional<CouplingResult>>>>>
     355           0 :       couplings_;
     356             : };
     357             : 
     358             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     359             : template <bool Local, bool Mutable>
     360             : template <typename Func>
     361             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::SideAccessCommon<
     362             :     Local, Mutable>::for_each(Func&& func) const {
     363             :   bool entries_changed = false;
     364             :   for (auto& step : parent_data()) {
     365             :     for (auto& substep : step.substeps) {
     366             :       if constexpr (std::is_invocable_v<Func&, const TimeStepId&,
     367             :                                         const Data&>) {
     368             :         func(std::as_const(substep.id), std::as_const(substep.data));
     369             :       } else {
     370             :         static_assert(Mutable,
     371             :                       "Cannot perform mutating for_each on a ConstSideAccess");
     372             :         if (func(std::as_const(substep.id), make_not_null(&substep.data))) {
     373             :           entries_changed = true;
     374             :         }
     375             :       }
     376             :     }
     377             :   }
     378             :   if constexpr (Mutable) {
     379             :     if (entries_changed) {
     380             :       // A minor optimization would be to only clear the cache entries
     381             :       // that have actually been invalidated, but most things that
     382             :       // modify the history modify all the entries.
     383             :       parent_->clear_coupling_cache();
     384             :     }
     385             :   }
     386             : }
     387             : 
     388             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     389             : template <bool Local>
     390             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     391             :     Local>::pop_front() const {
     392             :   if constexpr (Local) {
     393             :     this->parent_->pop_local();
     394             :   } else {
     395             :     this->parent_->pop_remote();
     396             :   }
     397             : }
     398             : 
     399             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     400             : template <bool Local>
     401             : void BoundaryHistory<LocalData, RemoteData,
     402             :                      CouplingResult>::MutableSideAccess<Local>::clear() const {
     403             :   while (not this->empty()) {
     404             :     pop_front();
     405             :   }
     406             : }
     407             : 
     408             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     409             : template <bool Local>
     410             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     411             :     Local>::clear_substeps(const size_t n) const {
     412             :   if constexpr (Local) {
     413             :     this->parent_->clear_substeps_local(n);
     414             :   } else {
     415             :     this->parent_->clear_substeps_remote(n);
     416             :   }
     417             : }
     418             : 
     419             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     420             : template <bool Local>
     421             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     422             :     Local>::insert(const TimeStepId& id, const size_t integration_order,
     423             :                    Data data) const {
     424             :   ASSERT(this->parent_data().empty() or
     425             :              id > this->parent_data().back().substeps.back().id,
     426             :          "New data not newer than current data.");
     427             :   if constexpr (Local) {
     428             :     this->parent_->insert_local(id, integration_order, std::move(data));
     429             :   } else {
     430             :     this->parent_->insert_remote(id, integration_order, std::move(data));
     431             :   }
     432             : }
     433             : 
     434             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     435             : template <bool Local>
     436             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::MutableSideAccess<
     437             :     Local>::insert_initial(const TimeStepId& id, const size_t integration_order,
     438             :                            Data data) const {
     439             :   ASSERT(id.substep() == 0, "Cannot insert_initial with substeps.");
     440             :   ASSERT(this->parent_data().empty() or
     441             :              id < this->parent_data().front().substeps.front().id,
     442             :          "New data not older than current data.");
     443             :   if constexpr (Local) {
     444             :     this->parent_->insert_initial_local(id, integration_order, std::move(data));
     445             :   } else {
     446             :     this->parent_->insert_initial_remote(id, integration_order,
     447             :                                          std::move(data));
     448             :   }
     449             : }
     450             : 
     451             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     452             : template <typename Coupling>
     453             : auto BoundaryHistory<LocalData, RemoteData, CouplingResult>::EvaluatorImpl<
     454             :     Coupling>::operator()(const TimeStepId& local_id,
     455             :                           const TimeStepId& remote_id) const
     456             :     -> MathWrapper<const UntypedCouplingResult> {
     457             :   auto local_entry = std::upper_bound(
     458             :       parent_->local_data_.begin(), parent_->local_data_.end(), local_id);
     459             :   ASSERT(local_entry != parent_->local_data_.begin(), "local_id not present");
     460             :   --local_entry;
     461             :   ASSERT(local_id.substep() < local_entry->substeps.size() and
     462             :          local_entry->substeps[local_id.substep()].id == local_id,
     463             :          "local_id not present");
     464             :   const auto local_step_offset =
     465             :       static_cast<size_t>(local_entry - parent_->local_data_.begin());
     466             : 
     467             :   auto remote_entry = std::upper_bound(
     468             :       parent_->remote_data_.begin(), parent_->remote_data_.end(), remote_id);
     469             :   ASSERT(remote_entry != parent_->remote_data_.begin(),
     470             :          "remote_id not present");
     471             :   --remote_entry;
     472             :   ASSERT(remote_id.substep() < remote_entry->substeps.size() and
     473             :          remote_entry->substeps[remote_id.substep()].id == remote_id,
     474             :          "remote_id not present");
     475             :   const auto remote_step_offset =
     476             :       static_cast<size_t>(remote_entry - parent_->remote_data_.begin());
     477             : 
     478             :   auto& coupling_entry = parent_->couplings_[remote_step_offset]
     479             :                              [remote_id.substep()][local_step_offset]
     480             :                              [local_id.substep()];
     481             :   if (not coupling_entry.has_value()) {
     482             :     coupling_entry.emplace(coupling_(
     483             :         local_entry->substeps[local_id.substep()].data,
     484             :         remote_entry->substeps[remote_id.substep()].data));
     485             :   }
     486             :   return make_math_wrapper(*coupling_entry);
     487             : }
     488             : 
     489             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     490             : void BoundaryHistory<LocalData, RemoteData,
     491             :                      CouplingResult>::clear_coupling_cache() {
     492             :   for (auto& remote_step : couplings_) {
     493             :     for (auto& remote_substep : remote_step) {
     494             :       for (auto& local_step : remote_substep) {
     495             :         for (auto& local_substep : local_step) {
     496             :           local_substep.reset();
     497             :         }
     498             :       }
     499             :     }
     500             :   }
     501             : }
     502             : 
     503             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     504             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::pup(PUP::er& p) {
     505             :   p | local_data_;
     506             :   p | remote_data_;
     507             :   p | couplings_;
     508             : }
     509             : 
     510             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     511             : template <bool IncludeData>
     512             : std::ostream& BoundaryHistory<LocalData, RemoteData, CouplingResult>::print(
     513             :     std::ostream& os, const size_t padding_size) const {
     514             :   const std::string pad(padding_size, ' ');
     515             :   using ::operator<<;
     516             :   const auto do_print = [&os, &pad](const auto& times) {
     517             :     for (size_t step = 0; step < times.size(); ++step) {
     518             :       const size_t number_of_substeps = times.number_of_substeps(step);
     519             :       for (size_t substep = 0; substep < number_of_substeps; ++substep) {
     520             :         const auto id = times[{step, substep}];
     521             :         os << pad << " Time: " << id;
     522             :         if (substep == 0) {
     523             :           os << " (order " << times.integration_order(step) << ")";
     524             :         }
     525             :         os << "\n";
     526             :         if constexpr (IncludeData) {
     527             :           os << pad << "  Data: ";
     528             :           // os << times.data(id) fails to compile on gcc-11
     529             :           print_stl(os, times.data(id));
     530             :           os << "\n";
     531             :         }
     532             :       }
     533             :     }
     534             :   };
     535             :   os << pad << "Local Data:\n";
     536             :   do_print(local());
     537             :   os << pad << "Remote Data:\n";
     538             :   do_print(remote());
     539             :   return os;
     540             : }
     541             : 
     542             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     543             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::insert_local(
     544             :     const TimeStepId& id, const size_t integration_order, LocalData data) {
     545             :   if (id.substep() == 0) {
     546             :     local_data_.push_back({integration_order, {}});
     547             :   } else {
     548             :     ASSERT(integration_order == local_data_.back().integration_order,
     549             :            "Cannot change integration order during a step.");
     550             :   }
     551             :   local_data_.back().substeps.push_back({id, std::move(data)});
     552             :   for (auto& remote_step : couplings_) {
     553             :     for (auto& remote_substep : remote_step) {
     554             :       if (id.substep() == 0) {
     555             :         remote_substep.emplace_back(1_st);
     556             :       } else {
     557             :         remote_substep.back().emplace_back();
     558             :       }
     559             :     }
     560             :   }
     561             : }
     562             : 
     563             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     564             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::insert_remote(
     565             :     const TimeStepId& id, const size_t integration_order, RemoteData data) {
     566             :   if (id.substep() == 0) {
     567             :     remote_data_.push_back({integration_order, {}});
     568             :   } else {
     569             :     ASSERT(integration_order == remote_data_.back().integration_order,
     570             :            "Cannot change integration order during a step.");
     571             :   }
     572             :   remote_data_.back().substeps.push_back({id, std::move(data)});
     573             :   if (id.substep() == 0) {
     574             :     couplings_.emplace_back(1_st);
     575             :   } else {
     576             :     couplings_.back().emplace_back();
     577             :   }
     578             :   for (const auto& local_step : local_data_) {
     579             :     couplings_.back().back().emplace_back(local_step.substeps.size());
     580             :   }
     581             : }
     582             : 
     583             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     584             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::
     585             :     insert_initial_local(const TimeStepId& id, const size_t integration_order,
     586             :                          LocalData data) {
     587             :   local_data_.push_front({integration_order, {}});
     588             :   local_data_.front().substeps.push_back({id, std::move(data)});
     589             :   for (auto& remote_step : couplings_) {
     590             :     for (auto& remote_substep : remote_step) {
     591             :       remote_substep.emplace_front(1_st);
     592             :     }
     593             :   }
     594             : }
     595             : 
     596             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     597             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::
     598             :     insert_initial_remote(const TimeStepId& id, const size_t integration_order,
     599             :                           RemoteData data) {
     600             :   remote_data_.push_front({integration_order, {}});
     601             :   remote_data_.front().substeps.push_back({id, std::move(data)});
     602             :   couplings_.emplace_front(1_st);
     603             :   for (const auto& local_step : local_data_) {
     604             :     couplings_.front().back().emplace_back(local_step.substeps.size());
     605             :   }
     606             : }
     607             : 
     608             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     609             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::pop_local() {
     610             :   local_data_.pop_front();
     611             :   for (auto& remote_step : couplings_) {
     612             :     for (auto& remote_substep : remote_step) {
     613             :       remote_substep.pop_front();
     614             :     }
     615             :   }
     616             : }
     617             : 
     618             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     619             : void BoundaryHistory<LocalData, RemoteData, CouplingResult>::pop_remote() {
     620             :   remote_data_.pop_front();
     621             :   couplings_.pop_front();
     622             : }
     623             : 
     624             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     625             : void BoundaryHistory<LocalData, RemoteData,
     626             :                      CouplingResult>::clear_substeps_local(const size_t n) {
     627             :   local_data_[n].substeps.erase(local_data_[n].substeps.begin() + 1,
     628             :                                 local_data_[n].substeps.end());
     629             :   for (auto& remote_step : couplings_) {
     630             :     for (auto& remote_substep : remote_step) {
     631             :       auto& local_step = remote_substep[n];
     632             :       local_step.erase(local_step.begin() + 1, local_step.end());
     633             :     }
     634             :   }
     635             : }
     636             : 
     637             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     638             : void BoundaryHistory<LocalData, RemoteData,
     639             :                      CouplingResult>::clear_substeps_remote(const size_t n) {
     640             :   remote_data_[n].substeps.erase(remote_data_[n].substeps.begin() + 1,
     641             :                                  remote_data_[n].substeps.end());
     642             :   auto& remote_step = couplings_[n];
     643             :   remote_step.erase(remote_step.begin() + 1, remote_step.end());
     644             : }
     645             : 
     646             : template <typename LocalData, typename RemoteData, typename CouplingResult>
     647           0 : std::ostream& operator<<(
     648             :     std::ostream& os,
     649             :     const BoundaryHistory<LocalData, RemoteData, CouplingResult>& history) {
     650             :   return history.template print<true>(os);
     651             : }
     652             : }  // namespace TimeSteppers

Generated by: LCOV version 1.14