12 #include "Informer/Tags.hpp"
13 #include "Informer/Verbosity.hpp"
15 #include "Parallel/Invoke.hpp"
17 #include "ParallelAlgorithms/NonlinearSolver/NewtonRaphson/LineSearch.hpp"
18 #include "ParallelAlgorithms/NonlinearSolver/NewtonRaphson/Tags/InboxTags.hpp"
19 #include "ParallelAlgorithms/NonlinearSolver/Observe.hpp"
21 #include "Utilities/EqualWithinRoundoff.hpp"
22 #include "Utilities/Functional.hpp"
23 #include "Utilities/GetOutput.hpp"
27 template <
typename...>
32 namespace NonlinearSolver::newton_raphson::detail {
34 template <
typename FieldsTag,
typename OptionsGroup,
typename BroadcastTarget>
35 struct CheckResidualMagnitude {
36 using fields_tag = FieldsTag;
39 using residual_magnitude_square_tag =
41 using initial_residual_magnitude_tag =
43 using prev_residual_magnitude_square_tag =
46 template <
typename ParallelComponent,
typename DataBox,
47 typename Metavariables,
typename ArrayIndex,
typename... Args>
50 Args&&... args) noexcept {
51 if constexpr (db::tag_is_retrievable_v<residual_magnitude_square_tag,
53 apply_impl(box, cache, std::forward<Args>(args)...);
56 "The residual monitor is not yet initialized. This is a bug, so "
57 "please file an issue.");
62 template <
typename DbTagsList,
typename Metavariables>
63 static void apply_impl(db::DataBox<DbTagsList>& box,
65 const size_t iteration_id,
66 const size_t globalization_iteration_id,
67 const double next_residual_magnitude_square,
68 const double step_length) noexcept {
69 const double residual_magnitude =
sqrt(next_residual_magnitude_square);
71 NonlinearSolver::observe_detail::contribute_to_reduction_observer<
72 OptionsGroup>(iteration_id, globalization_iteration_id,
73 residual_magnitude, step_length, cache);
76 db::mutate<initial_residual_magnitude_tag>(
79 initial_residual_magnitude) noexcept {
80 *initial_residual_magnitude =
sqrt(residual_magnitude);
88 const double sufficient_decrease =
89 get<NonlinearSolver::Tags::SufficientDecrease<OptionsGroup>>(box);
90 const double residual_magnitude_square =
91 get<residual_magnitude_square_tag>(box);
92 const double initial_residual_magnitude =
93 get<initial_residual_magnitude_tag>(box);
94 const double abs_tolerance =
95 get<Convergence::Tags::Criteria<OptionsGroup>>(box).absolute_residual;
96 const double rel_tolerance =
97 get<Convergence::Tags::Criteria<OptionsGroup>>(box).relative_residual;
100 const double residual_magnitude_square_slope =
101 -2. * residual_magnitude_square;
104 if (residual_magnitude > abs_tolerance and
105 residual_magnitude / initial_residual_magnitude > rel_tolerance and
106 next_residual_magnitude_square >
107 residual_magnitude_square + sufficient_decrease * step_length *
108 residual_magnitude_square_slope) {
111 if (globalization_iteration_id <
116 globalization_iteration_id, step_length,
118 residual_magnitude_square, residual_magnitude_square_slope,
119 next_residual_magnitude_square,
120 get<prev_residual_magnitude_square_tag>(box)),
121 0.1 * step_length, 0.5 * step_length);
122 db::mutate<NonlinearSolver::Tags::StepLength<OptionsGroup>,
123 prev_residual_magnitude_square_tag>(
125 [step_length, next_residual_magnitude_square](
128 prev_residual_magnitude_square) noexcept {
129 *prev_step_length = step_length;
130 *prev_residual_magnitude_square =
131 next_residual_magnitude_square;
135 ::Verbosity::Verbose)) {
137 "Step with length %s didn't sufficiently decrease the '" +
138 Options::name<OptionsGroup>() +
139 "' iteration %zu residual (possible overshoot). Residual: "
140 "%s. Next step length: %s.\n",
144 ::Verbosity::Debug)) {
151 Parallel::receive_data<Tags::GlobalizationResult<OptionsGroup>>(
152 Parallel::get_parallel_component<BroadcastTarget>(cache),
158 ::Verbosity::Quiet)) {
160 "WARNING: Failed to sufficiently decrease the '" +
161 Options::name<OptionsGroup>() +
162 "' iteration %zu residual in %zu globalization steps. This "
163 "is usually indicative of an ill-posed problem, for "
164 "example when the linearization of the nonlinear operator "
165 "is not computed correctly.",
166 iteration_id, globalization_iteration_id);
171 db::mutate<residual_magnitude_square_tag>(
174 local_residual_magnitude_square) noexcept {
175 *local_residual_magnitude_square = next_residual_magnitude_square;
183 get<Convergence::Tags::Criteria<OptionsGroup>>(box), iteration_id,
184 residual_magnitude, get<initial_residual_magnitude_tag>(box)};
188 ::Verbosity::Quiet)) {
191 "' initialized with residual %e.\n",
195 "' iteration %zu done. Remaining residual: %e\n",
196 iteration_id, residual_magnitude);
200 box) >= ::Verbosity::Quiet)) {
203 Options::name<OptionsGroup>() +
204 "' has converged without any iterations: %s\n",
208 Options::name<OptionsGroup>() +
209 "' has converged in %zu iterations: %s\n",
210 iteration_id, has_converged);
214 Parallel::receive_data<Tags::GlobalizationResult<OptionsGroup>>(
215 Parallel::get_parallel_component<BroadcastTarget>(cache), iteration_id,
218 std::move(has_converged)));