45template <
class ConcreteModel>
class App {
52 double m_total_steptime = 0.0;
53 double m_total_fft_time = 0.0;
54 double m_steptime = 0.0;
55 double m_fft_time = 0.0;
56 double m_avg_steptime = 0.0;
60 bool m_detailed_timing =
false;
61 bool m_detailed_timing_print =
false;
62 bool m_detailed_timing_write =
false;
63 std::string m_detailed_timing_filename =
"timing.bin";
66 json read_settings(
int argc,
char *
argv[]) {
69 std::cerr <<
"Error: Configuration file required.\n";
70 std::cerr <<
"Usage: " <<
argv[0] <<
" <config.json|config.toml>\n";
76 if (!std::filesystem::exists(
file)) {
77 if (rank0) std::cerr <<
"Error: File " <<
file <<
" does not exist!\n";
81 auto ext =
file.extension().string();
85 if (rank0) std::cout <<
"Reading TOML configuration from " <<
file <<
"\n\n";
91 std::cerr <<
"Error parsing TOML file: " <<
err.description() <<
"\n";
92 std::cerr <<
" at line " <<
err.source().begin.line <<
", column "
93 <<
err.source().begin.column <<
"\n";
97 }
else if (
ext ==
".json") {
98 if (rank0) std::cout <<
"Reading JSON configuration from " <<
file <<
"\n\n";
104 std::cerr <<
"Error parsing JSON file: " <<
err.what() <<
"\n";
105 std::cerr <<
" at byte position " <<
err.byte <<
"\n";
111 std::cerr <<
"Error: Unsupported file format: " <<
ext <<
"\n";
112 std::cerr <<
"Supported formats: .json, .toml\n";
126 : m_comm(comm), m_worker(
MPI_Worker(0,
nullptr, comm)),
129 bool create_results_dir(
const std::string &
output) {
133 std::cout <<
"Results dir " <<
results_dir <<
" does not exist, creating\n";
137 std::cout <<
"Warning: results dir " <<
results_dir <<
" already exists\n";
142 void read_detailed_timing_configuration() {
143 if (m_settings.contains(
"detailed_timing")) {
144 auto timing = m_settings[
"detailed_timing"];
145 if (
timing.contains(
"enabled")) m_detailed_timing =
timing[
"enabled"];
146 if (
timing.contains(
"print")) m_detailed_timing_print =
timing[
"print"];
147 if (
timing.contains(
"write")) m_detailed_timing_write =
timing[
"write"];
148 if (
timing.contains(
"filename"))
149 m_detailed_timing_filename =
timing[
"filename"];
154 std::cout <<
"Adding results writers" << std::endl;
155 if (m_settings.contains(
"saveat") && m_settings.contains(
"fields") &&
156 m_settings[
"saveat"] > 0) {
157 for (
const auto &field : m_settings[
"fields"]) {
158 std::string name = field[
"name"];
159 std::string data = field[
"data"];
160 if (rank0) create_results_dir(data);
161 std::cout <<
"Writing field " << name <<
" to " << data << std::endl;
162 sim.add_results_writer(name, std::make_unique<BinaryWriter>(data));
165 std::cout <<
"Warning: not writing results to anywhere." << std::endl;
166 std::cout <<
"To write results, add ResultsWriter to model." << std::endl;
171 if (!m_settings.contains(
"initial_conditions")) {
172 std::cout <<
"WARNING: no initial conditions are set!" << std::endl;
175 std::cout <<
"Adding initial conditions" << std::endl;
176 for (
const json &
params : m_settings[
"initial_conditions"]) {
177 std::cout <<
"Creating initial condition from data " <<
params << std::endl;
178 if (!
params.contains(
"type")) {
179 std::cout <<
"Warning: no type is set for initial condition!" << std::endl;
184 if (!
params.contains(
"target")) {
185 std::cout <<
"Warning: no target is set for initial condition! Using "
190 std::cout <<
"Setting initial condition target to " <<
target << std::endl;
198 if (!m_settings.contains(
"boundary_conditions")) {
199 std::cout <<
"Warning: no boundary conditions are set!" << std::endl;
202 std::cout <<
"Adding boundary conditions" << std::endl;
203 for (
const json &
params : m_settings[
"boundary_conditions"]) {
204 std::cout <<
"Creating boundary condition from data " <<
params << std::endl;
205 if (!
params.contains(
"type")) {
206 std::cout <<
"Warning: no type is set for initial condition!" << std::endl;
211 if (!
params.contains(
"target")) {
212 std::cout <<
"Warning: no target is set for boundary condition! Using "
217 std::cout <<
"Setting boundary condition target to " <<
target << std::endl;
225 std::cout <<
"Reading configuration from json file:" << std::endl;
226 std::cout << m_settings.dump(4) <<
"\n\n";
228 World world(ui::from_json<World>(m_settings));
229 std::cout <<
"World: " << world << std::endl;
239 m_settings.contains(
"plan_options")
240 ? ui::from_json<heffte::plan_options>(m_settings[
"plan_options"])
245 Time time(ui::from_json<Time>(m_settings));
249 if (m_settings.contains(
"model") && m_settings[
"model"].contains(
"params")) {
250 from_json(m_settings[
"model"][
"params"],
model);
252 read_detailed_timing_configuration();
254 std::cout <<
"Initializing model... " << std::endl;
260 size_t fft_mem = fft.get_allocated_memory_bytes();
263 pfc::utils::report_memory_usage(
usage, world,
logger, m_comm);
270 if (m_settings.contains(
"simulator")) {
271 const json &
j = m_settings[
"simulator"];
272 if (
j.contains(
"result_counter")) {
274 throw std::invalid_argument(
275 "Invalid JSON input: missing or invalid 'result_counter' field.");
280 if (
j.contains(
"increment")) {
282 throw std::invalid_argument(
283 "Invalid JSON input: missing or invalid 'increment' field.");
290 std::cout <<
"Applying initial conditions" << std::endl;
292 if (
time.get_increment() == 0) {
293 std::cout <<
"First increment: apply boundary conditions" << std::endl;
298 while (!
time.done()) {
311 if (m_detailed_timing) {
317 for (
int rank = 0; rank <
num_ranks; rank++) {
321 auto inc =
time.get_increment();
322 if (m_detailed_timing_print) {
324 std::cout <<
"Timing information for all processes:" << std::endl;
325 std::cout <<
"step;rank;step_time;fft_time" << std::endl;
326 for (
int rank = 0; rank <
num_ranks; rank++) {
327 std::cout <<
inc <<
";" << rank <<
";" <<
all_timing[rank][0] <<
";"
332 if (m_detailed_timing_write) {
335 std::ofstream
outfile(m_detailed_timing_filename, std::ios::app);
346 if (
time.do_save()) {
353 m_avg_steptime = m_steptime;
354 if (m_steps_done > 3) {
355 m_avg_steptime = 0.01 * m_steptime + 0.99 * m_avg_steptime;
362 std::cout <<
"Step " <<
increment <<
" done in " << m_steptime <<
" s ";
363 std::cout <<
"(" << m_fft_time <<
" s FFT, " <<
other_time <<
" s other). ";
364 std::cout <<
"Simulation time: " <<
t <<
" / " <<
t1;
365 std::cout <<
" (" << (
t /
t1 * 100) <<
" % done). ";
368 m_total_steptime += m_steptime;
369 m_total_fft_time += m_fft_time;
378 std::cout <<
"\nSimulated " << m_steps_done
379 <<
" steps. Average times:" << std::endl;
380 std::cout <<
"Step time: " <<
avg_steptime <<
" s" << std::endl;
std::unique_ptr< FieldModifier > create_field_modifier(const std::string &type, const json ¶ms)
Create an instance of a field modifier based on its type.
Definition field_modifier_registry.hpp:128