ryujin 2.1.1 revision 955e869188d49b3c97ca7b1cf4fd9ceb0e6f46ef
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 - 2024 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
71 {
72 AssertThrow(signals != nullptr,
73 dealii::ExcMessage(
74 dave + "No equation has been registered. Consequently, "
75 "there is nothing for us to do.\n"));
76
77 if (signals != nullptr)
79 }
80
81
85 template <typename Callable>
86 static void register_create_parameter_files(const Callable &callable)
87 {
88 if (signals == nullptr)
89 signals = new Signals;
90
91 signals->create_parameter_files.connect(callable);
92 }
93
94
98 void dispatch(const std::string &parameter_file, const MPI_Comm &mpi_comm)
99 {
100 ParameterAcceptor::prm.parse_input(parameter_file,
101 "",
102 /* skip undefined */ true,
103 /* assert entries present */ false);
104
105 AssertThrow(dimension_ >= 1 && dimension_ <= 3,
106 dealii::ExcMessage(dave +
107 "The dimension parameter needs to be "
108 "either 1, 2, or 3, but we encountered »" +
109 std::to_string(dimension_) + "«\n"));
110
111 AssertThrow(signals != nullptr,
112 dealii::ExcMessage(
113 dave + "No equation has been registered. Consequently, "
114 "there is nothing for us to do.\n"));
115
116 if (signals != nullptr)
117 signals->dispatch(dimension_,
118 equation_,
119 parameter_file,
120 mpi_comm,
121 time_loop_executed_);
122
123 AssertThrow(time_loop_executed_ == true,
124 dealii::ExcMessage(dave +
125 "No equation was dispatched "
126 "with the chosen equation parameter »" +
127 equation_ + "«.\n"));
128 }
129
130
134 template <typename Callable>
135 static void register_dispatch(const Callable &callable)
136 {
137 if (signals == nullptr)
138 signals = new Signals;
139
140 signals->dispatch.connect(callable);
141 }
142
143 protected:
148
154 struct Signals {
155 boost::signals2::signal<void()> create_parameter_files;
156
157 boost::signals2::signal<void(int /*dimension*/,
158 const std::string & /*equation*/,
159 const std::string & /*parameter file*/,
160 const MPI_Comm & /*MPI communicator*/,
161 bool & /*time loop executed*/)>
163 };
164
165 /*
166 * Note: as a static field the pointer is zero initialized before any
167 * static/global constructor is run.
168 */
170
171 private:
173
177
178 int dimension_;
179 std::string equation_;
180
182
183 bool time_loop_executed_;
184 };
185
186
192 template <typename Description, int dim, typename Number>
193 void create_prm_files(const std::string &name,
194 bool write_detailed_description)
195 {
196 {
197 /*
198 * Workaround: Add an entry to the "A - TimeLoop" section so that is
199 * shows up first.
200 */
201 auto &prm = dealii::ParameterAcceptor::prm;
202 prm.enter_subsection("A - TimeLoop");
203 prm.declare_entry("basename", "test");
204 prm.leave_subsection();
205
206 /*
207 * Create temporary objects for the sole purpose of populating the
208 * ParameterAcceptor::prm object.
209 */
210
211 ryujin::EquationDispatch equation_dispatch;
212 ryujin::TimeLoop<Description, dim, Number> time_loop(MPI_COMM_SELF);
213
214 /*
215 * Fix up "equation" entry:
216 */
217 prm.enter_subsection("B - Equation");
218 prm.declare_entry("dimension",
219 std::to_string(dim),
220 dealii::Patterns::Integer(),
221 "The spatial dimension");
222 prm.declare_entry(
223 "equation", name, dealii::Patterns::Anything(), "The PDE system");
224 prm.set("dimension", std::to_string(dim));
225 prm.set("equation", name);
226 prm.leave_subsection();
227
228 std::string base_name = name;
229 std::ranges::replace(base_name, ' ', '_');
230 base_name += "-" + std::to_string(dim) + "d";
231
232 if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_SELF) == 0) {
233 const auto full_name =
234 "default_parameters-" + base_name + "-description.prm";
235 if (write_detailed_description)
236 prm.print_parameters(
237 full_name,
238 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder);
239
240 const auto short_name = "default_parameters-" + base_name + ".prm";
241 prm.print_parameters(
242 short_name,
243 dealii::ParameterHandler::OutputStyle::Short |
244 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder
245
246 );
247 }
248 // all objects have to go out of scope, see
249 // https://github.com/dealii/dealii/issues/15111
250 }
251
252 dealii::ParameterAcceptor::clear();
253 }
254
255
260 template <typename Description, typename Number>
261 struct Dispatch {
262 Dispatch(const std::string &name)
263 {
264#ifdef DEBUG_OUTPUT
265 std::cout << "Dispatch<Description, Number>::Dispatch() for »" << name
266 << "«" << std::endl;
267#endif
268
270 create_prm_files<Description, 1, Number>(name, false);
271 create_prm_files<Description, 2, Number>(name, true);
272 create_prm_files<Description, 3, Number>(name, false);
273 });
274
276 [name](const int dimension,
277 const std::string &equation,
278 const std::string &parameter_file,
279 const MPI_Comm &mpi_comm,
280 bool &time_loop_executed) {
281 if (equation != name)
282 return;
283
284 if (dealii::Utilities::MPI::this_mpi_process(mpi_comm) == 0) {
285 std::cout << "[INFO] dispatching to driver »" << equation
286 << "« with dim=" << dimension << std::endl;
287 }
288
289 AssertThrow(time_loop_executed == false,
290 dealii::ExcMessage(
291 dave +
292 "Trying to execute more than one TimeLoop object "
293 "with the given equation parameter »" +
294 equation + "«"));
295
296 if (dimension == 1) {
297 TimeLoop<Description, 1, Number> time_loop(mpi_comm);
298 dealii::ParameterAcceptor::initialize(parameter_file);
299 time_loop.run();
300 time_loop_executed = true;
301 } else if (dimension == 2) {
302 TimeLoop<Description, 2, Number> time_loop(mpi_comm);
303 dealii::ParameterAcceptor::initialize(parameter_file);
304 time_loop.run();
305 time_loop_executed = true;
306 } else if (dimension == 3) {
307 TimeLoop<Description, 3, Number> time_loop(mpi_comm);
308 dealii::ParameterAcceptor::initialize(parameter_file);
309 time_loop.run();
310 time_loop_executed = true;
311 }
312 });
313 }
314 };
315
316} // 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