Demonstrates Simulator API for running complete simulations.
#include <cmath>
#include <iomanip>
#include <iostream>
using namespace pfc;
private:
double m_diffusion_coeff = 0.1;
std::vector<double> m_propagator;
public:
void initialize(
double dt)
override {
std::cout << "Initializing diffusion model with D = " << m_diffusion_coeff
<< "\n";
}
auto &fft = get_fft();
m_real_field.resize(fft.size_inbox(), 0.0);
m_complex_field.resize(fft.size_outbox());
add_real_field("concentration", m_real_field);
add_complex_field("concentration_k", m_complex_field);
auto outbox = fft::get_outbox(fft);
auto size = world::get_size(world);
auto spacing = world::get_spacing(world);
m_propagator.resize(fft.size_outbox());
double kx = (
i < size[0] / 2) ?
i :
i - size[0];
double ky = (
j < size[1] / 2) ?
j :
j - size[1];
kx *= 2.0 * M_PI / (size[0] * spacing[0]);
ky *= 2.0 * M_PI / (size[1] * spacing[1]);
kz *= 2.0 * M_PI / (size[2] * spacing[2]);
m_propagator[
idx] = 1.0 / (1.0 + m_diffusion_coeff *
dt *
k2);
}
}
}
}
void step(
double t)
override {
auto &
u = get_real_field(
"concentration");
auto &
u_k = get_complex_field(
"concentration_k");
auto &fft = get_fft();
for (
size_t i = 0;
i <
u_k.size(); ++
i) {
u_k[
i] *= m_propagator[
i];
}
}
private:
std::vector<double> m_real_field;
std::vector<std::complex<double>> m_complex_field;
};
private:
std::string m_field_name;
types::Real3 m_center;
double m_amplitude;
double m_sigma;
public:
std::string get_field_name() const override { return m_field_name; }
auto &field =
model.get_real_field(m_field_name);
auto &fft =
model.get_fft();
auto inbox = fft::get_inbox(fft);
auto world =
model.get_world();
auto spacing = world::get_spacing(world);
double x =
i * spacing[0] - m_center[0];
double y =
j * spacing[1] - m_center[1];
double z =
k * spacing[2] - m_center[2];
field[
idx] = m_amplitude * std::exp(-
r2 / (2.0 * m_sigma * m_sigma));
}
}
}
}
};
public:
void write(
int iteration,
const RealField &field)
override {
double min_val = std::numeric_limits<double>::max();
double max_val = std::numeric_limits<double>::lowest();
for (
double val : field) {
}
if (mpi::get_rank() == 0) {
std::cout <<
"Iteration " << std::setw(4) <<
iteration <<
": "
<<
"mean=" << std::fixed << std::setprecision(6) <<
mean
}
}
void write(
int iteration,
const ComplexField &field)
override {
}
};
void example_complete_simulation() {
std::cout << "\n" << std::string(60, '=') << "\n";
std::cout << " Complete Simulation Workflow\n";
std::cout << std::string(60, '=') << "\n\n";
auto world = world::create({64, 64, 64}, {0, 0, 0}, {0.1, 0.1, 0.1});
if (mpi::get_rank() == 0) {
std::cout << "Step 1: Created 64³ computational domain\n";
std::cout << " Physical size: 6.4 × 6.4 × 6.4\n\n";
}
auto fft = fft::create(
decomp);
if (mpi::get_rank() == 0) {
std::cout << "Step 2: Initialized FFT\n";
std::cout << " MPI ranks: " << mpi::get_size() << "\n\n";
}
if (mpi::get_rank() == 0) {
std::cout << "Step 3: Created diffusion model\n\n";
}
if (mpi::get_rank() == 0) {
std::cout << "Step 4: Configured time integration\n";
std::cout <<
" Duration: " <<
time.get_tspan()[1] <<
" time units\n";
std::cout <<
" Time step: " <<
time.get_dt() <<
"\n";
std::cout <<
" Save interval: " <<
time.get_saveat() <<
"\n\n";
}
if (mpi::get_rank() == 0) {
std::cout << "Step 5: Created simulator\n\n";
}
types::Real3
center = {3.2, 3.2, 3.2};
sim.add_initial_conditions(
std::make_unique<GaussianIC>(
"concentration",
center, 1.0, 0.5));
if (mpi::get_rank() == 0) {
std::cout << "Step 6: Added Gaussian initial condition\n";
<< ")\n";
std::cout << " σ = 0.5\n\n";
}
sim.add_results_writer(
"concentration", std::make_unique<StatsWriter>());
if (mpi::get_rank() == 0) {
std::cout << "Step 7: Added statistics writer\n\n";
std::cout << "Step 8: Running simulation...\n\n";
}
}
if (mpi::get_rank() == 0) {
std::cout << "\n✓ Simulation completed successfully!\n";
std::cout <<
" Final time: " <<
sim.get_time().get_current() <<
"\n";
std::cout <<
" Total steps: " <<
sim.get_increment() <<
"\n";
}
}
if (mpi::get_rank() == 0) {
std::cout << "OpenPFC Simulator API Example\n";
std::cout << "==============================\n";
std::cout << "\nThis example demonstrates a complete simulation workflow:\n";
std::cout << " - Model setup and initialization\n";
std::cout << " - Initial conditions\n";
std::cout << " - Time integration loop\n";
std::cout << " - Results output\n";
}
try {
example_complete_simulation();
if (mpi::get_rank() == 0) {
std::cout << "\n" << std::string(60, '=') << "\n";
std::cout << " Summary\n";
std::cout << std::string(60, '=') << "\n\n";
std::cout << "Key takeaways:\n";
std::cout << " ✓ Simulator orchestrates the entire workflow\n";
std::cout << " ✓ Initial conditions applied automatically at t=0\n";
std::cout << " ✓ Results writers called at specified intervals\n";
std::cout << " ✓ Main loop: while (!sim.done()) { sim.step(); }\n";
std::cout << "\nSee include/openpfc/simulator.hpp for complete API.\n";
}
} catch (const std::exception &e) {
std::cerr <<
"Error on rank " << mpi::get_rank() <<
": " <<
e.what() <<
"\n";
}
return 0;
}
Simple diffusion model for demonstration.
Definition 03_simulator_workflow.cpp:42
Custom field modifier: Gaussian initial condition.
Definition 05_simulator.cpp:44
void apply(Model &m, double t) override
Apply the field modification to the model (pure virtual)
Definition 05_simulator.cpp:49
Simple writer that prints statistics.
Definition 03_simulator_workflow.cpp:170
Definition field_modifier.hpp:240
The Model class represents the physics model for simulations in OpenPFC.
Definition model.hpp:95
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
Definition results_writer.hpp:182
The Simulator class is responsible for running the simulation of the model.
Definition simulator.hpp:63
constexpr double e
Euler's number (e)
Definition constants.hpp:187
Domain decomposition for parallel MPI simulations.
Fast Fourier Transform interface for spectral methods.
Physics model abstraction for phase-field simulations.
MPI utilities and wrappers.
Simulation orchestration and time integration loop.
FFT class for distributed-memory parallel Fourier transforms.
Definition fft.hpp:248
Represents the global simulation domain (the "world").
Definition world.hpp:91
Time state management for simulation time integration.
World class definition and unified interface.