OpenPFC  0.1.4
Phase Field Crystal simulation framework
Loading...
Searching...
No Matches
/home/runner/work/OpenPFC/OpenPFC/include/openpfc/simulator.hpp

Register a results writer for a specific field.

Register a results writer for a specific fieldAssociates a ResultsWriter with a named field for periodic output during simulation. The writer will be called automatically when save points are reached in the time integration loop.

Parameters
field_nameName of the field to write (must be registered with Model)
writerUnique pointer to ResultsWriter object (ownership transferred)
Returns
true if writer was successfully registered, false if field doesn't exist
Note
Writer is called automatically at intervals specified by Time::set_saveat()
Multiple writers can write the same field to different formats
Domain decomposition info is automatically configured
Warning
Field must be registered with Model before calling this
Writer takes ownership via std::unique_ptr - don't access after transfer
// Set up simulation
MyModel model(fft, world);
model.initialize(0.01);
Time time({0.0, 100.0, 0.01}, 1.0); // save every 1.0 time units
Simulator sim(model, time);
// Register writers for different fields and formats
sim.add_results_writer("density",
std::make_unique<BinaryWriter>("density"));
sim.add_results_writer("temperature",
std::make_unique<VTKWriter>("temp.vtk"));
// Both fields will be written automatically during sim.run()
Definition 10_ui_register_ic.cpp:45
See also
add_results_writer(std::unique_ptr<ResultsWriter>) for "default" field
ResultsWriter for available output formats
Time::set_saveat() to configure output frequency
// SPDX-FileCopyrightText: 2025 VTT Technical Research Centre of Finland Ltd
// SPDX-License-Identifier: AGPL-3.0-or-later
#ifndef PFC_SIMULATOR_HPP
#define PFC_SIMULATOR_HPP
#include "core/world.hpp"
#include "model.hpp"
#include "time.hpp"
#include <iostream>
#include <memory>
#include <unordered_map>
namespace pfc {
void step(class Simulator &s, Model &m);
class Simulator {
private:
Model &m_model;
Time &m_time;
std::unordered_map<std::string, std::unique_ptr<ResultsWriter>> m_result_writers;
std::vector<std::unique_ptr<FieldModifier>> m_initial_conditions;
std::vector<std::unique_ptr<FieldModifier>> m_boundary_conditions;
int m_result_counter = 0;
public:
Simulator(Model &model, Time &time) : m_model(model), m_time(time) {}
Model &get_model() { return m_model; }
/*
const Decomposition &get_decomposition() {
return get_model().get_decomposition();
}
*/
const World &get_world() { return get_model().get_world(); }
FFT &get_fft() { return get_model().get_fft(); }
Time &get_time() { return m_time; }
Field &get_field() { return get_model().get_field(); }
void initialize() { get_model().initialize(get_time().get_dt()); }
bool is_rank0() { return get_model().is_rank0(); }
unsigned int get_increment() { return get_time().get_increment(); }
bool add_results_writer(const std::string &field_name,
std::unique_ptr<ResultsWriter> writer) {
auto inbox = get_inbox(get_fft());
auto world = get_world();
writer->set_domain(get_size(world), inbox.size, inbox.low);
Model &model = get_model();
if (model.has_field(field_name)) {
m_result_writers.insert({field_name, std::move(writer)});
return true;
} else {
std::cout << "Warning: tried to add writer for inexistent field " << field_name
<< ", RESULTS ARE NOT WRITTEN!" << std::endl;
return false;
}
}
bool add_results_writer(std::unique_ptr<ResultsWriter> writer) {
std::cout << "Warning: adding result writer to write field 'default'"
<< std::endl;
return add_results_writer("default", std::move(writer));
}
bool add_initial_conditions(std::unique_ptr<FieldModifier> modifier) {
Model &model = get_model();
std::string field_name = modifier->get_field_name();
if (field_name == "default") {
std::cout << "Warning: adding initial condition to modify field 'default'"
<< std::endl;
}
if (model.has_field(field_name)) {
m_initial_conditions.push_back(std::move(modifier));
return true;
} else {
std::cout << "Warning: tried to add initial condition for inexistent field "
<< field_name << ", INITIAL CONDITIONS ARE NOT APPLIED!"
<< std::endl;
return false;
}
}
const std::vector<std::unique_ptr<FieldModifier>> &get_initial_conditions() const {
return m_initial_conditions;
}
bool add_boundary_conditions(std::unique_ptr<FieldModifier> modifier) {
Model &model = get_model();
std::string field_name = modifier->get_field_name();
if (field_name == "default") {
std::cout << "Warning: adding boundary condition to modify field 'default'"
<< std::endl;
}
if (model.has_field(field_name)) {
m_boundary_conditions.push_back(std::move(modifier));
return true;
} else {
std::cout << "Warning: tried to add boundary condition for inexistent field "
<< field_name << ", BOUNDARY CONDITIONS ARE NOT APPLIED!"
<< std::endl;
return false;
}
}
const std::vector<std::unique_ptr<FieldModifier>> &
return m_boundary_conditions;
}
void set_result_counter(int result_counter) { m_result_counter = result_counter; }
double get_result_counter() const { return m_result_counter; }
void write_results() {
int file_num = get_result_counter();
Model &model = get_model();
for (const auto &[field_name, writer] : m_result_writers) {
if (model.has_real_field(field_name)) {
writer->write(file_num, get_model().get_real_field(field_name));
}
if (model.has_complex_field(field_name)) {
writer->write(file_num, get_model().get_complex_field(field_name));
}
}
set_result_counter(file_num + 1);
}
void apply_initial_conditions() {
Model &model = get_model();
Time &time = get_time();
for (const auto &ic : m_initial_conditions) {
ic->apply(model, time.get_current());
}
}
void apply_boundary_conditions() {
Model &model = get_model();
Time &time = get_time();
for (const auto &bc : m_boundary_conditions) {
bc->apply(model, time.get_current());
}
}
void step() {
Time &time = get_time();
Model &model = get_model();
if (time.get_increment() == 0) {
apply_initial_conditions();
apply_boundary_conditions();
if (time.do_save()) {
write_results();
}
}
time.next();
apply_boundary_conditions();
model.step(time.get_current());
if (time.do_save()) {
write_results();
}
return;
}
bool done() {
Time &time = get_time();
return time.done();
}
};
inline void step(Simulator &s, Model &m) { m.step(s.get_time().get_current()); }
} // namespace pfc
#endif // PFC_SIMULATOR_HPP
bool is_rank0() const noexcept
Check if current MPI rank is 0.
Definition model.hpp:175
const World & get_world() const noexcept
Get the decomposition object associated with the model.
Definition model.hpp:191
virtual Field & get_field()
Get a reference to the default primary unknown field.
Definition model.hpp:662
const std::vector< std::unique_ptr< FieldModifier > > & get_boundary_conditions() const
Gets the boundary conditions of the simulation.
Definition simulator.hpp:353
Field & get_field()
Get the default field object.
Definition simulator.hpp:127
const std::vector< std::unique_ptr< FieldModifier > > & get_initial_conditions() const
Gets the initial conditions of the simulation.
Definition simulator.hpp:273
FFT & get_fft()
Get the FFT object.
Definition simulator.hpp:113
Model & get_model()
Get the model object.
Definition simulator.hpp:88
Time & get_time()
Get the time object.
Definition simulator.hpp:120
const World & get_world()
Get the decomposition object.
Definition simulator.hpp:106
int get_increment() const
Get the current time increment.
Definition time.hpp:397
Base class for initial conditions and boundary conditions.
Physics model abstraction for phase-field simulations.
Base interface for simulation output and I/O operations.
Time state management for simulation time integration.
World class definition and unified interface.