ryujin 2.1.1 revision 0348cbb53a3e4b1da2a4c037e81f88f2d21ce219
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 <boost/signals2.hpp>
16
17#include <string>
18
19namespace ryujin
20{
24 inline const std::string dave =
25 "\nDave, this conversation can serve no purpose anymore. Goodbye.\n\n";
26
33 class EquationDispatch : dealii::ParameterAcceptor
34 {
35 public:
37 : ParameterAcceptor("B - Equation")
38 {
39 dimension_ = 0;
40 add_parameter("dimension", dimension_, "The spatial dimension");
41 add_parameter("equation", equation_, "The PDE system");
42
43 time_loop_executed_ = false;
44 }
45
46
51 {
52 AssertThrow(signals != nullptr,
53 dealii::ExcMessage(
54 dave + "No equation has been registered. Consequently, "
55 "there is nothing for us to do.\n"));
56
58 }
59
60
64 template <typename Callable>
65 static void register_create_parameter_files(const Callable &callable)
66 {
67 if (signals == nullptr)
68 signals = new Signals;
69
70 signals->create_parameter_files.connect(callable);
71 }
72
73
77 void dispatch(const std::string &parameter_file, const MPI_Comm &mpi_comm)
78 {
79 ParameterAcceptor::prm.parse_input(parameter_file,
80 "",
81 /* skip undefined */ true,
82 /* assert entries present */ false);
83
84 AssertThrow(dimension_ >= 1 && dimension_ <= 3,
85 dealii::ExcMessage(dave +
86 "The dimension parameter needs to be "
87 "either 1, 2, or 3, but we encountered »" +
88 std::to_string(dimension_) + "«\n"));
89
90 AssertThrow(signals != nullptr,
91 dealii::ExcMessage(
92 dave + "No equation has been registered. Consequently, "
93 "there is nothing for us to do.\n"));
94
96 dimension_, equation_, parameter_file, mpi_comm, time_loop_executed_);
97
98 AssertThrow(time_loop_executed_ == true,
99 dealii::ExcMessage(dave +
100 "No equation was dispatched "
101 "with the chosen equation parameter »" +
102 equation_ + "«.\n"));
103 }
104
105
109 template <typename Callable>
110 static void register_dispatch(const Callable &callable)
111 {
112 if (signals == nullptr)
113 signals = new Signals;
114
115 signals->dispatch.connect(callable);
116 }
117
118 protected:
123
129 struct Signals {
130 boost::signals2::signal<void()> create_parameter_files;
131
132 boost::signals2::signal<void(int /*dimension*/,
133 const std::string & /*equation*/,
134 const std::string & /*parameter file*/,
135 const MPI_Comm & /*MPI communicator*/,
136 bool & /*time loop executed*/)>
138 };
139
140 /*
141 * Note: as a static field the pointer is zero initialized before any
142 * static/global constructor is run.
143 */
145
146 private:
148
152
153 int dimension_;
154 std::string equation_;
155
157
158 bool time_loop_executed_;
159 };
160
161
167 template <typename Description, int dim, typename Number>
168 void create_prm_files(const std::string &name,
169 bool write_detailed_description)
170 {
171 {
172 /*
173 * Workaround: Add an entry to the "A - TimeLoop" section so that is
174 * shows up first.
175 */
176 auto &prm = dealii::ParameterAcceptor::prm;
177 prm.enter_subsection("A - TimeLoop");
178 prm.declare_entry("basename", "test");
179 prm.leave_subsection();
180
181 /*
182 * Create temporary objects for the sole purpose of populating the
183 * ParameterAcceptor::prm object.
184 */
185
186 ryujin::EquationDispatch equation_dispatch;
187 ryujin::TimeLoop<Description, dim, Number> time_loop(MPI_COMM_SELF);
188
189 /*
190 * Fix up "equation" entry:
191 */
192 prm.enter_subsection("B - Equation");
193 prm.declare_entry("dimension",
194 std::to_string(dim),
195 dealii::Patterns::Integer(),
196 "The spatial dimension");
197 prm.declare_entry(
198 "equation", name, dealii::Patterns::Anything(), "The PDE system");
199 prm.set("dimension", std::to_string(dim));
200 prm.set("equation", name);
201 prm.leave_subsection();
202
203 std::string base_name = name;
204 std::replace(base_name.begin(), base_name.end(), ' ', '_');
205 base_name += "-" + std::to_string(dim) + "d";
206
207 if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_SELF) == 0) {
208 const auto full_name =
209 "default_parameters-" + base_name + "-description.prm";
210 if (write_detailed_description)
211 prm.print_parameters(
212 full_name,
213 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder);
214
215 const auto short_name = "default_parameters-" + base_name + ".prm";
216 prm.print_parameters(
217 short_name,
218 dealii::ParameterHandler::OutputStyle::Short |
219 dealii::ParameterHandler::OutputStyle::KeepDeclarationOrder
220
221 );
222 }
223 // all objects have to go out of scope, see
224 // https://github.com/dealii/dealii/issues/15111
225 }
226
227 dealii::ParameterAcceptor::clear();
228 }
229
230
235 template <typename Description, typename Number>
236 struct Dispatch {
237 Dispatch(const std::string &name)
238 {
239#ifdef DEBUG_OUTPUT
240 std::cout << "Dispatch<Description, Number>::Dispatch() for »" << name
241 << "«" << std::endl;
242#endif
243
245 create_prm_files<Description, 1, Number>(name, false);
246 create_prm_files<Description, 2, Number>(name, true);
247 create_prm_files<Description, 3, Number>(name, false);
248 });
249
251 [name](const int dimension,
252 const std::string &equation,
253 const std::string &parameter_file,
254 const MPI_Comm &mpi_comm,
255 bool &time_loop_executed) {
256 if (equation != name)
257 return;
258
259 if (dealii::Utilities::MPI::this_mpi_process(mpi_comm) == 0) {
260 std::cout << "[INFO] dispatching to driver »" << equation
261 << "« with dim=" << dimension << std::endl;
262 }
263
264 AssertThrow(time_loop_executed == false,
265 dealii::ExcMessage(
266 dave +
267 "Trying to execute more than one TimeLoop object "
268 "with the given equation parameter »" +
269 equation + "«"));
270
271 if (dimension == 1) {
272 TimeLoop<Description, 1, Number> time_loop(mpi_comm);
273 dealii::ParameterAcceptor::initialize(parameter_file);
274 time_loop.run();
275 time_loop_executed = true;
276 } else if (dimension == 2) {
277 TimeLoop<Description, 2, Number> time_loop(mpi_comm);
278 dealii::ParameterAcceptor::initialize(parameter_file);
279 time_loop.run();
280 time_loop_executed = true;
281 } else if (dimension == 3) {
282 TimeLoop<Description, 3, Number> time_loop(mpi_comm);
283 dealii::ParameterAcceptor::initialize(parameter_file);
284 time_loop.run();
285 time_loop_executed = true;
286 }
287 });
288 }
289 };
290
291} // 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