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
|