Let's embark on the journey of physics modeling. Together, we will construct a captivating diffusion model and unleash its mysteries using OpenPFC. This example implements a simple diffusion model using the OpenPFC library. The code demonstrates a low-level implementation of the model, where the simulation is manually stepped and the initial conditions are defined inside the model. It also shows how to perform local and global reductions using MPI to calculate global properties of the field variable.
The Diffusion class is derived from the base class Model provided by the OpenPFC library. It overrides two class methods:
initialize(double dt): This method is called once to initialize the necessary parameters and data structures for the simulation. It allocates memory for the main variable, psi, and its Fourier transform, psi_F. It also constructs the linear operator L, which is used to solve the diffusion equation.
step(double dt): This method is called to step the model forward in time by one time increment, dt. It applies the linear operator L to the Fourier transform of psi, psi_F, and then performs an inverse Fourier transform to obtain the updated psi values. It also calculates the minimum and maximum values of psi locally for each MPI rank and performs reduction operations to obtain the global minimum and maximum values.
The run() function defines the world dimensions and discretization parameters, constructs the World, Decomposition, FFT, and Diffusion objects, and initializes the simulation. It then enters a loop where the model is stepped forward in time until a specified stopping time is reached. During each iteration, the current time, the iteration number, and the minimum and maximum values of psi are printed.
Expected output is:
( initialization messages ... )
n = 0, t = 0.000000000000, psi[133152] = 1.000000000000
n = 1, t = 0.013985739333, psi[133152] = 0.979721090279
n = 2, t = 0.027971478665, psi[133152] = 0.960110027682
n = 3, t = 0.041957217998, psi[133152] = 0.941136780128
n = 4, t = 0.055942957330, psi[133152] = 0.922773010503
( time stepping continues ...)
n = 40, t = 0.559429573303, psi[133152] = 0.516585236400
n = 41, t = 0.573415312636, psi[133152] = 0.509734461852
n = 42, t = 0.587401051968, psi[133152] = 0.503032957135
#include <algorithm>
#include <iostream>
#include <limits>
using namespace std;
using namespace pfc;
using Model::Model;
private:
public:
double psi_min, psi_max;
auto &fft = get_fft();
psi.resize(fft.size_inbox());
psi_F.resize(fft.size_outbox());
opL.resize(fft.size_outbox());
auto i_low = get_inbox(fft).low;
auto i_high = get_inbox(fft).high;
auto o_low = get_outbox(fft).low;
auto o_high = get_outbox(fft).high;
auto size = get_size(world);
auto origin = get_origin(world);
auto spacing = get_spacing(world);
double D = 1.0;
}
}
}
double pi = std::atan(1.0) * 4.0;
double fx = 2.0 * pi / (spacing[0] * size[0]);
double fy = 2.0 * pi / (spacing[1] * size[1]);
double fz = 2.0 * pi / (spacing[2] * size[2]);
double ki = (
i <= size[0] / 2) ?
i *
fx : (
i - size[0]) *
fx;
double kj = (
j <= size[1] / 2) ?
j *
fy : (
j - size[1]) *
fy;
double kk = (
k <= size[2] / 2) ?
k *
fz : (
k - size[2]) *
fz;
}
}
}
}
void step(
double)
override {
fft.forward(psi, psi_F);
for (
int k = 0,
N = psi_F.size();
k <
N;
k++) {
psi_F[
k] = opL[
k] * psi_F[
k];
}
fft.backward(psi_F, psi);
}
double local_min = std::numeric_limits<double>::max();
double local_max = std::numeric_limits<double>::min();
};
}
};
void run() {
const double pi = 3;
double dx = 2.0 * pi / 8.0;
auto decomp = decomposition::create(world, 1);
auto fft = fft::create(
decomp);
double t_stop = 0.5874010519681994;
if (
model.is_rank0())
cout <<
"n = 0, t = 0, min = 0.0, max = 1.0" <<
endl;
cout <<
"n = " <<
n <<
", t = " <<
t <<
", min = " <<
model.psi_min
}
} else {
}
}
}
run();
}
Definition 04_diffusion_model.cpp:64
void initialize(double dt) override
Initialize the diffusion model.
Definition 04_diffusion_model.cpp:83
void step(double) override
The actual time stepping function.
Definition 04_diffusion_model.cpp:174
void find_minmax()
A simple MPI communication example.
Definition 04_diffusion_model.cpp:190
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
Domain decomposition for parallel MPI simulations.
Factory functions for creating domain decompositions.
Fast Fourier Transform interface for spectral methods.
Physics model abstraction for phase-field simulations.
Strong type aliases for geometric quantities.
Grid dimensions (number of grid points per dimension)
Definition strong_types.hpp:176
Physical spacing between grid points.
Definition strong_types.hpp:370
Physical origin of coordinate system.
Definition strong_types.hpp:424
FFT class for distributed-memory parallel Fourier transforms.
Definition fft.hpp:248
Represents the global simulation domain (the "world").
Definition world.hpp:91
World class definition and unified interface.