Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <cstddef>
7 :
8 : #include "DataStructures/DataBox/DataBox.hpp"
9 : #include "Time/AdaptiveSteppingDiagnostics.hpp"
10 : #include "Time/Slab.hpp"
11 : #include "Time/Tags/HistoryEvolvedVariables.hpp"
12 : #include "Time/Time.hpp"
13 : #include "Time/TimeStepId.hpp"
14 : #include "Utilities/ErrorHandling/Assert.hpp"
15 : #include "Utilities/Gsl.hpp"
16 : #include "Utilities/TMPL.hpp"
17 :
18 : /// \cond
19 : namespace Tags {
20 : struct AdaptiveSteppingDiagnostics;
21 : struct MinimumTimeStep;
22 : template <typename Tag>
23 : struct Next;
24 : struct TimeStep;
25 : struct TimeStepId;
26 : template <typename StepperInterface>
27 : struct TimeStepper;
28 : } // namespace Tags
29 : class TimeStepper;
30 : namespace evolution::dg::Tags {
31 : template <size_t Dim>
32 : struct MortarNextTemporalId;
33 : } // namespace evolution::dg::Tags
34 : /// \endcond
35 :
36 : /// \ingroup TimeGroup
37 : /// Change the slab size, updating all quantities in the DataBox
38 : /// depending on it.
39 : ///
40 : /// The end of the slab (in the appropriate direction for the
41 : /// evolution's flow of time) will be set to \p new_slab_end. The
42 : /// time step is set to the same fraction of the new slab as it was of
43 : /// the old.
44 : template <typename DbTags>
45 1 : void change_slab_size(const gsl::not_null<db::DataBox<DbTags>*> box,
46 : const double new_slab_end) {
47 : const TimeStepId& old_time_step_id = db::get<Tags::TimeStepId>(*box);
48 :
49 : ASSERT(old_time_step_id.is_at_slab_boundary(),
50 : "Cannot change slab size in middle of slab: " << old_time_step_id);
51 :
52 : const Slab old_slab = old_time_step_id.step_time().slab();
53 : const double old_slab_end = old_time_step_id.time_runs_forward()
54 : ? old_slab.end().value()
55 : : old_slab.start().value();
56 :
57 : if (new_slab_end == old_slab_end) {
58 : return;
59 : }
60 :
61 : const TimeDelta& old_time_step = db::get<Tags::TimeStep>(*box);
62 :
63 : const Slab new_slab = old_time_step_id.time_runs_forward()
64 : ? Slab(old_slab.start().value(), new_slab_end)
65 : : Slab(new_slab_end, old_slab.end().value());
66 : // We are at a slab boundary, so the substep is 0.
67 : const TimeStepId new_time_step_id(
68 : old_time_step_id.time_runs_forward(), old_time_step_id.slab_number(),
69 : old_time_step_id.step_time().with_slab(new_slab));
70 : const auto new_time_step = old_time_step.with_slab(new_slab);
71 :
72 : if (std::abs(new_time_step.value()) <
73 : db::get<::Tags::MinimumTimeStep>(*box)) {
74 : ERROR_NO_TRACE(
75 : "Chosen step size "
76 : << new_time_step.value() << " is smaller than the MinimumTimeStep of "
77 : << db::get<::Tags::MinimumTimeStep>(*box)
78 : << " while changing the slab size to " << new_slab.duration().value()
79 : << ".\n"
80 : "\n"
81 : "This can indicate a flaw in the step chooser, the grid, or a "
82 : "simulation instability that an error-based stepper is naively "
83 : "attempting to resolve. A possible issue is an aliasing-driven "
84 : "instability that could be cured by more aggressive filtering if "
85 : "you are using DG.");
86 : }
87 :
88 : const auto new_next_time_step_id =
89 : db::get<Tags::TimeStepper<TimeStepper>>(*box).next_time_id(
90 : new_time_step_id, new_time_step);
91 :
92 : // For DG evolutions, we need to correct the slab size stored in
93 : // MortarNextTemporalId. This function should work for non-DG
94 : // evolution and should not depend on the DG headers, so we get all
95 : // the types from the DataBox.
96 : tmpl::for_each<tmpl::range<size_t, 1, 4>>(
97 : [&]<size_t Dim>(tmpl::type_<tmpl::size_t<Dim>> /*meta*/) {
98 : using mortar_next_temporal_id_tag =
99 : evolution::dg::Tags::MortarNextTemporalId<Dim>;
100 : if constexpr (db::tag_is_retrievable_v<mortar_next_temporal_id_tag,
101 : db::DataBox<DbTags>>) {
102 : db::mutate_apply<tmpl::list<mortar_next_temporal_id_tag>,
103 : tmpl::list<::Tags::Next<::Tags::TimeStepId>>>(
104 : [&new_next_time_step_id, &new_time_step_id, &old_time_step_id](
105 : const auto mortar_next_temporal_ids,
106 : const TimeStepId& old_next_time_step_id) {
107 : for (auto& [mortar_id, temporal_id] :
108 : *mortar_next_temporal_ids) {
109 : if (temporal_id == old_time_step_id) {
110 : temporal_id = new_time_step_id;
111 : } else {
112 : ASSERT(temporal_id == old_next_time_step_id,
113 : "Don't know how to translate "
114 : << temporal_id << " to new slab. Only know "
115 : << old_time_step_id << " and "
116 : << old_next_time_step_id);
117 : temporal_id = new_next_time_step_id;
118 : }
119 : }
120 : },
121 : box);
122 : }
123 : });
124 :
125 : db::mutate_apply<
126 : tmpl::push_front<Tags::get_all_history_tags<DbTags>,
127 : ::Tags::Next<::Tags::TimeStepId>, ::Tags::TimeStep,
128 : ::Tags::TimeStepId, ::Tags::AdaptiveSteppingDiagnostics>,
129 : tmpl::list<>>(
130 : [&new_next_time_step_id, &new_time_step, &new_time_step_id](
131 : const gsl::not_null<TimeStepId*> next_time_step_id,
132 : const gsl::not_null<TimeDelta*> time_step,
133 : const gsl::not_null<TimeStepId*> local_time_step_id,
134 : const gsl::not_null<AdaptiveSteppingDiagnostics*> diags,
135 : const auto... histories) {
136 : const auto update_history = [&](const auto history) {
137 : if (not history->empty() and
138 : history->back().time_step_id == *local_time_step_id) {
139 : ASSERT(history->at_step_start(),
140 : "Cannot change step size with substep data.");
141 : history->back().time_step_id = new_time_step_id;
142 : }
143 : return 0;
144 : };
145 : expand_pack(update_history(histories)...);
146 :
147 : *next_time_step_id = new_next_time_step_id;
148 : *time_step = new_time_step;
149 : *local_time_step_id = new_time_step_id;
150 : ++diags->number_of_slab_size_changes;
151 : },
152 : box);
153 : }
|