ryujin 2.1.1 revision 5a1111835e8617c1fa5372346ab85a0bd39a2720
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
31 class EquationDispatch : dealii::ParameterAcceptor
32 {
33 public:
35 : ParameterAcceptor("B - Equation")
36 {
37 dimension_ = 0;
38 add_parameter("dimension", dimension_, "The spatial dimension");
39 add_parameter("equation", equation_, "The PDE system");
40
41 time_loop_executed_ = false;
42 }
43
44
49 {
50 AssertThrow(signals != nullptr,
51 dealii::ExcMessage(
52 dave + "No equation has been registered. Consequently, "
53 "there is nothing for us to do.\n"));
54
56 }
57
58
62 template <typename Callable>
63 static void register_create_parameter_files(const Callable &callable)
64 {
65 if (signals == nullptr)
66 signals = new Signals;
67
68 signals->create_parameter_files.connect(callable);
69 }
70
71
75 void dispatch(const std::string &parameter_file, const MPI_Comm &mpi_comm)
76 {
77 ParameterAcceptor::prm.parse_input(parameter_file,
78 "",
79 /* skip undefined */ true,
80 /* assert entries present */ false);
81
82 AssertThrow(dimension_ >= 1 && dimension_ <= 3,
83 dealii::ExcMessage(dave +
84 "The dimension parameter needs to be "
85 "either 1, 2, or 3, but we encountered »" +
86 std::to_string(dimension_) + "«\n"));
87
88 AssertThrow(signals != nullptr,
89 dealii::ExcMessage(
90 dave + "No equation has been registered. Consequently, "
91 "there is nothing for us to do.\n"));
92
94 dimension_, equation_, parameter_file, mpi_comm, time_loop_executed_);
95
96 AssertThrow(time_loop_executed_ == true,
97 dealii::ExcMessage(dave +
98 "No equation was dispatched "
99 "with the chosen equation parameter »" +
100 equation_ + "«.\n"));
101 }
102
103
107 template <typename Callable>
108 static void register_dispatch(const Callable &callable)
109 {
110 if (signals == nullptr)
111 signals = new Signals;
112
113 signals->dispatch.connect(callable);
114 }
115
116 protected:
121
127 struct Signals {
128 boost::signals2::signal<void()> create_parameter_files;
129
130 boost::signals2::signal<void(int /*dimension*/,
131 const std::string & /*equation*/,
132 const std::string & /*parameter file*/,
133 const MPI_Comm & /*MPI communicator*/,
134 bool & /*time loop executed*/)>
136 };
137
138 /*
139 * Note: as a static field the pointer is zero initialized before any
140 * static/global constructor is run.
141 */
143
144 private:
146
150
151 int dimension_;
152 std::string equation_;
153
155
156 bool time_loop_executed_;
157 };
158
159
165 template <typename Description, int dim, typename Number>
166 void create_prm_files(const std::string &name,
167 bool write_detailed_description)
168 {
169 {
170 /*
171 * Create temporary objects for the sole purpose of populating the
172 * ParameterAcceptor::prm object.
173 */
174 ryujin::EquationDispatch equation_dispatch;
175 ryujin::TimeLoop<Description, dim, Number> time_loop(MPI_COMM_SELF);
176
177 /* Fix up "equation" entry: */
178 auto &prm = dealii::ParameterAcceptor::prm;
179 prm.enter_subsection("B - Equation");
180 prm.set("dimension", std::to_string(dim));
181 prm.set("equation", name);
182 prm.leave_subsection();
183
184 std::string base_name = name;
185 std::replace(base_name.begin(), base_name.end(), ' ', '_');
186 base_name += "-" + std::to_string(dim) + "d";
187
188 if (dealii::Utilities::MPI::this_mpi_process(MPI_COMM_SELF) == 0) {
189 const auto full_name =
190 "default_parameters-" + base_name + "-description.prm";
191 if (write_detailed_description)
192 prm.print_parameters(full_name,
193 dealii::ParameterHandler::OutputStyle::PRM);
194
195 const auto short_name = "default_parameters-" + base_name + ".prm";
196 prm.print_parameters(short_name,
197 dealii::ParameterHandler::OutputStyle::Short);
198 }
199 // all objects have to go out of scope, see
200 // https://github.com/dealii/dealii/issues/15111
201 }
202
203 dealii::ParameterAcceptor::clear();
204 }
205
206
211 template <typename Description, typename Number>
212 struct Dispatch {
213 Dispatch(const std::string &name)
214 {
215#ifdef DEBUG_OUTPUT
216 std::cout << "Dispatch<Description, Number>::Dispatch() for »" << name
217 << "«" << std::endl;
218#endif
219
221 create_prm_files<Description, 1, Number>(name, false);
222 create_prm_files<Description, 2, Number>(name, true);
223 create_prm_files<Description, 3, Number>(name, false);
224 });
225
227 [name](const int dimension,
228 const std::string &equation,
229 const std::string &parameter_file,
230 const MPI_Comm &mpi_comm,
231 bool &time_loop_executed) {
232 if (equation != name)
233 return;
234
235 if (dealii::Utilities::MPI::this_mpi_process(mpi_comm) == 0) {
236 std::cout << "[INFO] dispatching to driver »" << equation
237 << "« with dim=" << dimension << std::endl;
238 }
239
240 AssertThrow(time_loop_executed == false,
241 dealii::ExcMessage(
242 dave +
243 "Trying to execute more than one TimeLoop object "
244 "with the given equation parameter »" +
245 equation + "«"));
246
247 if (dimension == 1) {
248 TimeLoop<Description, 1, Number> time_loop(mpi_comm);
249 dealii::ParameterAcceptor::initialize(parameter_file);
250 time_loop.run();
251 time_loop_executed = true;
252 } else if (dimension == 2) {
253 TimeLoop<Description, 2, Number> time_loop(mpi_comm);
254 dealii::ParameterAcceptor::initialize(parameter_file);
255 time_loop.run();
256 time_loop_executed = true;
257 } else if (dimension == 3) {
258 TimeLoop<Description, 3, Number> time_loop(mpi_comm);
259 dealii::ParameterAcceptor::initialize(parameter_file);
260 time_loop.run();
261 time_loop_executed = true;
262 }
263 });
264 }
265 };
266
267} // 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