ryujin 2.1.1 revision e1e0c9cf84519540dcc04ed5bb49dc8a8c052779
Loading...
Searching...
No Matches
equation_dispatch.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2023 - 2026 by the ryujin authors
4//
5
6#pragma once
7
8#include <compile_time_options.h>
9
10#include "time_loop.h"
11
12#include <deal.II/base/mpi.h>
13#include <deal.II/base/parameter_acceptor.h>
14
15#include <algorithm>
16#include <boost/signals2.hpp>
17
18#include <string>
19
20namespace ryujin
21{
25 inline const std::string dave =
26 "\nDave, this conversation can serve no purpose anymore. Goodbye.\n\n";
27
53 class EquationDispatch : dealii::ParameterAcceptor
54 {
55 public:
57 : ParameterAcceptor("B - Equation")
58 {
59 dimension_ = 0;
60 add_parameter("dimension", dimension_, "The spatial dimension");
61 add_parameter("equation", equation_, "The PDE system");
62
63 time_loop_executed_ = false;
64 }
65
66
68 {
69 if (signals) {
70 delete signals;
71 signals = nullptr;
72 }
73 }
74
75
80 {
81 AssertThrow(signals != nullptr,
82 dealii::ExcMessage(
83 dave + "No equation has been registered. Consequently, "
84 "there is nothing for us to do.\n"));
85
86 if (signals != nullptr)
88 }
89
90
94 template <typename Callable>
95 static void register_create_parameter_files(const Callable &callable)
96 {
97 if (signals == nullptr)
98 signals = new Signals;
99
100 signals->create_parameter_files.connect(callable);
101 }
102
103
107 void dispatch(const std::string &parameter_file, const MPI_Comm &mpi_comm)
108 {
109 ParameterAcceptor::prm.parse_input(parameter_file,
110 "",
111 /* skip undefined */ true,
112 /* assert entries present */ false);
113
114 AssertThrow(dimension_ >= 1 && dimension_ <= 3,
115 dealii::ExcMessage(dave +
116 "The dimension parameter needs to be "
117 "either 1, 2, or 3, but we encountered »" +
118 std::to_string(dimension_) + "«\n"));
119
120 AssertThrow(signals != nullptr,
121 dealii::ExcMessage(
122 dave + "No equation has been registered. Consequently, "
123 "there is nothing for us to do.\n"));
124
125 if (signals != nullptr)
126 signals->dispatch(dimension_,
127 equation_,
128 parameter_file,
129 mpi_comm,
130 time_loop_executed_);
131
132 AssertThrow(time_loop_executed_ == true,
133 dealii::ExcMessage(dave +
134 "No equation was dispatched "
135 "with the chosen equation parameter »" +
136 equation_ + "«.\n"));
137 }
138
139
143 template <typename Callable>
144 static void register_dispatch(const Callable &callable)
145 {
146 if (signals == nullptr)
147 signals = new Signals;
148
149 signals->dispatch.connect(callable);
150 }
151
152 protected:
157
163 struct Signals {
164 boost::signals2::signal<void()> create_parameter_files;
165
166 boost::signals2::signal<void(int /*dimension*/,
167 const std::string & /*equation*/,
168 const std::string & /*parameter file*/,
169 const MPI_Comm & /*MPI communicator*/,
170 bool & /*time loop executed*/)>
172 };
173
174 /*
175 * Note: as a static field the pointer is zero initialized before any
176 * static/global constructor is run.
177 */
179
180 private:
182
186
187 int dimension_;
188 std::string equation_;
189
191
195
196 bool time_loop_executed_;
197
199 };
200
201
207 template <typename HyperbolicDescription,
208 typename ParabolicDescription,
209 int dim,
210 typename Number>
211 void create_prm_files(const std::string &name,
212 bool write_detailed_description)
213 {
214 {
215 /*
216 * Workaround: Add an entry to the "A - TimeLoop" section so that is
217 * shows up first.
218 */
219 auto &prm = dealii::ParameterAcceptor::prm;
220 prm.enter_subsection("A - TimeLoop");
221 prm.declare_entry("basename", "test");
222 prm.leave_subsection();
223
224 /*
225 * Create temporary objects for the sole purpose of populating the
226 * ParameterAcceptor::prm object.
227 */
228
229 ryujin::EquationDispatch equation_dispatch;
231 time_loop(MPI_COMM_SELF);
232
233 /*
234 * Fix up "equation" entry:
235 */
236 prm.enter_subsection("B - Equation");
237 prm.declare_entry("dimension",
238 std::to_string(dim),
239 dealii::Patterns::Integer(),
240 "The spatial dimension");
241 prm.declare_entry(
242 "equation", name, dealii::Patterns::Anything(), "The PDE system");
243 prm.set("dimension", std::to_string(dim));
244 prm.set("equation", name);
245 prm.leave_subsection();
246
247 std::string base_name = name;
248 std::ranges::replace(base_name, ' ', '_');
249 base_name += "-" + std::to_string(dim) + "d";
250
251 if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_SELF) == 0) {
252 const auto full_name =
253 "default_parameters-" + base_name + "-description.prm";
254 if (write_detailed_description)
255 prm.print_parameters(
256 full_name,
257 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder);
258
259 const auto short_name = "default_parameters-" + base_name + ".prm";
260 prm.print_parameters(
261 short_name,
262 dealii::ParameterHandler::OutputStyle::Short |
263 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder
264
265 );
266 }
267 // all objects have to go out of scope, see
268 // https://github.com/dealii/dealii/issues/15111
269 }
270
271 dealii::ParameterAcceptor::clear();
272 }
273
274
281 template <typename HyperbolicDescription,
282 typename ParabolicDescription,
283 typename Number>
284 struct Dispatch {
285 Dispatch(const std::string &name)
286 {
287 using HD = HyperbolicDescription;
288 using PD = ParabolicDescription;
289
290#ifdef DEBUG_OUTPUT
291 std::cout << "Dispatch<HD, PD, Number>::Dispatch() for »" << name << "«"
292 << std::endl;
293#endif
294
296 create_prm_files<HD, PD, 1, Number>(name, false);
297 create_prm_files<HD, PD, 2, Number>(name, true);
298 create_prm_files<HD, PD, 3, Number>(name, false);
299 });
300
302 [name](const int dimension,
303 const std::string &equation,
304 const std::string &parameter_file,
305 const MPI_Comm &mpi_comm,
306 bool &time_loop_executed) {
307 if (equation != name)
308 return;
309
310 if (dealii::Utilities::MPI::this_mpi_process(mpi_comm) == 0) {
311 std::cout << "[INFO] dispatching to driver »" << equation
312 << "« with dim=" << dimension << std::endl;
313 }
314
315 AssertThrow(time_loop_executed == false,
316 dealii::ExcMessage(
317 dave +
318 "Trying to execute more than one TimeLoop object "
319 "with the given equation parameter »" +
320 equation + "«"));
321
322 if (dimension == 1) {
323 TimeLoop<HD, PD, 1, Number> time_loop(mpi_comm);
324 dealii::ParameterAcceptor::initialize(parameter_file);
325 time_loop.run();
326 time_loop_executed = true;
327 } else if (dimension == 2) {
328 TimeLoop<HD, PD, 2, Number> time_loop(mpi_comm);
329 dealii::ParameterAcceptor::initialize(parameter_file);
330 time_loop.run();
331 time_loop_executed = true;
332 } else if (dimension == 3) {
333 TimeLoop<HD, PD, 3, Number> time_loop(mpi_comm);
334 dealii::ParameterAcceptor::initialize(parameter_file);
335 time_loop.run();
336 time_loop_executed = true;
337 }
338 });
339 }
340 };
341
342} // namespace ryujin
void dispatch(const std::string &parameter_file, const MPI_Comm &mpi_comm)
static void register_create_parameter_files(const Callable &callable)
static void create_parameter_files()
static void register_dispatch(const Callable &callable)
const std::string dave
StubParabolicDescription ParabolicDescription
Definition instantiate.h:19
void create_prm_files(const std::string &name, bool write_detailed_description)
Dispatch(const std::string &name)
boost::signals2::signal< void(int, const std::string &, const std::string &, const MPI_Comm &, bool &)> dispatch
boost::signals2::signal< void()> create_parameter_files