ryujin 2.1.1 revision ee5cbcbf2346c1299c942d0e1f13b46449973c18
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 - 2025 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 Description, int dim, typename Number>
208 void create_prm_files(const std::string &name,
209 bool write_detailed_description)
210 {
211 {
212 /*
213 * Workaround: Add an entry to the "A - TimeLoop" section so that is
214 * shows up first.
215 */
216 auto &prm = dealii::ParameterAcceptor::prm;
217 prm.enter_subsection("A - TimeLoop");
218 prm.declare_entry("basename", "test");
219 prm.leave_subsection();
220
221 /*
222 * Create temporary objects for the sole purpose of populating the
223 * ParameterAcceptor::prm object.
224 */
225
226 ryujin::EquationDispatch equation_dispatch;
227 ryujin::TimeLoop<Description, dim, Number> time_loop(MPI_COMM_SELF);
228
229 /*
230 * Fix up "equation" entry:
231 */
232 prm.enter_subsection("B - Equation");
233 prm.declare_entry("dimension",
234 std::to_string(dim),
235 dealii::Patterns::Integer(),
236 "The spatial dimension");
237 prm.declare_entry(
238 "equation", name, dealii::Patterns::Anything(), "The PDE system");
239 prm.set("dimension", std::to_string(dim));
240 prm.set("equation", name);
241 prm.leave_subsection();
242
243 std::string base_name = name;
244 std::ranges::replace(base_name, ' ', '_');
245 base_name += "-" + std::to_string(dim) + "d";
246
247 if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_SELF) == 0) {
248 const auto full_name =
249 "default_parameters-" + base_name + "-description.prm";
250 if (write_detailed_description)
251 prm.print_parameters(
252 full_name,
253 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder);
254
255 const auto short_name = "default_parameters-" + base_name + ".prm";
256 prm.print_parameters(
257 short_name,
258 dealii::ParameterHandler::OutputStyle::Short |
259 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder
260
261 );
262 }
263 // all objects have to go out of scope, see
264 // https://github.com/dealii/dealii/issues/15111
265 }
266
267 dealii::ParameterAcceptor::clear();
268 }
269
270
277 template <typename Description, typename Number>
278 struct Dispatch {
279 Dispatch(const std::string &name)
280 {
281#ifdef DEBUG_OUTPUT
282 std::cout << "Dispatch<Description, Number>::Dispatch() for »" << name
283 << "«" << std::endl;
284#endif
285
287 create_prm_files<Description, 1, Number>(name, false);
288 create_prm_files<Description, 2, Number>(name, true);
289 create_prm_files<Description, 3, Number>(name, false);
290 });
291
293 [name](const int dimension,
294 const std::string &equation,
295 const std::string &parameter_file,
296 const MPI_Comm &mpi_comm,
297 bool &time_loop_executed) {
298 if (equation != name)
299 return;
300
301 if (dealii::Utilities::MPI::this_mpi_process(mpi_comm) == 0) {
302 std::cout << "[INFO] dispatching to driver »" << equation
303 << "« with dim=" << dimension << std::endl;
304 }
305
306 AssertThrow(time_loop_executed == false,
307 dealii::ExcMessage(
308 dave +
309 "Trying to execute more than one TimeLoop object "
310 "with the given equation parameter »" +
311 equation + "«"));
312
313 if (dimension == 1) {
314 TimeLoop<Description, 1, Number> time_loop(mpi_comm);
315 dealii::ParameterAcceptor::initialize(parameter_file);
316 time_loop.run();
317 time_loop_executed = true;
318 } else if (dimension == 2) {
319 TimeLoop<Description, 2, Number> time_loop(mpi_comm);
320 dealii::ParameterAcceptor::initialize(parameter_file);
321 time_loop.run();
322 time_loop_executed = true;
323 } else if (dimension == 3) {
324 TimeLoop<Description, 3, Number> time_loop(mpi_comm);
325 dealii::ParameterAcceptor::initialize(parameter_file);
326 time_loop.run();
327 time_loop_executed = true;
328 }
329 });
330 }
331 };
332
333} // 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)
void create_prm_files(const std::string &name, bool write_detailed_description)
const std::string dave
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