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

Construct a new Model object.

Construct a new Model objectConstructs a Model with the given FFT backend and simulation domain. The FFT object must outlive the Model instance.

Parameters
fftReference to the FFT object used by the model
worldReference to the World object
Note
FFT is required at construction and cannot be changed later (immutable)
FFT object must outlive Model (reference semantics)
auto world = world::create({256, 256, 256});
auto decomp = decomposition::create(world, MPI_COMM_WORLD);
auto fft = fft::create(decomp);
MyModel model(fft, world); // FFT required at construction
model.initialize(0.01);
Definition 10_ui_register_ic.cpp:45
Since
v2.0 (breaking change - FFT now required)
// SPDX-FileCopyrightText: 2025 VTT Technical Research Centre of Finland Ltd
// SPDX-License-Identifier: AGPL-3.0-or-later
#ifndef PFC_MODEL_HPP
#define PFC_MODEL_HPP
#include "core/world.hpp"
#include "fft.hpp"
#include "mpi.hpp"
#include "types.hpp"
#include <algorithm>
#include <iostream>
#include <memory>
#include <numeric>
#include <string_view>
#include <vector>
namespace pfc {
class Model {
private:
FFT &m_fft;
RealFieldSet m_real_fields;
ComplexFieldSet m_complex_fields;
const World &m_world;
bool m_rank0 = false;
public:
~Model() {}
Model(FFT &fft, const World &world)
: m_fft(fft), m_world(world),
domain(to_heffte_box(world)), // Use to_heffte_box
m_rank0(mpi::get_rank() == 0) {}
Model(const Model &) = delete;
Model &operator=(const Model &) = delete;
inline bool is_rank0() const noexcept { return m_rank0; }
/*
const Decomposition &get_decomposition() { return get_fft().get_decomposition(); }
*/
const World &get_world() const noexcept { return m_world; }
[[nodiscard]] FFT &get_fft() noexcept { return m_fft; }
virtual void step(double t) = 0;
virtual void initialize(double dt) = 0;
virtual size_t get_allocated_memory_bytes() const { return 0; }
[[nodiscard]] bool has_real_field(std::string_view field_name) const noexcept {
return m_real_fields.count(std::string(field_name)) > 0;
}
void add_real_field(std::string_view name, RealField &field) {
m_real_fields.emplace(std::string(name), field);
}
[[nodiscard]] bool has_complex_field(std::string_view field_name) const noexcept {
return m_complex_fields.count(std::string(field_name)) > 0;
}
void add_complex_field(std::string_view name, ComplexField &field) {
m_complex_fields.emplace(std::string(name), field);
}
[[nodiscard]] RealField &get_real_field(std::string_view name) {
auto it = m_real_fields.find(std::string(name));
if (it == m_real_fields.end()) {
throw std::out_of_range("Real field '" + std::string(name) +
"' not found. "
"Available fields: " +
list_field_names());
}
return it->second;
}
[[nodiscard]] const RealField &get_real_field(std::string_view name) const {
auto it = m_real_fields.find(std::string(name));
if (it == m_real_fields.end()) {
throw std::out_of_range("Real field '" + std::string(name) +
"' not found. "
"Available fields: " +
list_field_names());
}
return it->second;
}
[[nodiscard]] ComplexField &get_complex_field(std::string_view name) {
auto it = m_complex_fields.find(std::string(name));
if (it == m_complex_fields.end()) {
throw std::out_of_range("Complex field '" + std::string(name) +
"' not found. "
"Available fields: " +
list_field_names());
}
return it->second;
}
[[nodiscard]] const ComplexField &get_complex_field(std::string_view name) const {
auto it = m_complex_fields.find(std::string(name));
if (it == m_complex_fields.end()) {
throw std::out_of_range("Complex field '" + std::string(name) +
"' not found. "
"Available fields: " +
list_field_names());
}
return it->second;
}
void add_field(const std::string &name, RealField &field) {
add_real_field(name, field);
}
void add_field(const std::string &name, ComplexField &field) {
add_complex_field(name, field);
}
[[nodiscard]] bool has_field(std::string_view field_name) const noexcept {
return has_real_field(field_name) || has_complex_field(field_name);
}
virtual Field &get_field() {
if (!has_real_field("default")) {
throw std::runtime_error("'default' field is not defined.");
}
return get_real_field("default");
};
private:
std::string list_field_names() const {
std::vector<std::string> names;
for (const auto &[name, _] : m_real_fields) {
names.push_back(name);
}
for (const auto &[name, _] : m_complex_fields) {
names.push_back(name);
}
if (names.empty()) {
return "(none)";
}
return std::accumulate(
std::next(names.begin()), names.end(), names[0],
[](const std::string &a, const std::string &b) { return a + ", " + b; });
}
};
} // namespace pfc
#endif
~Model()
Destroy the Model object.
Definition model.hpp:119
bool is_rank0() const noexcept
Check if current MPI rank is 0.
Definition model.hpp:175
void add_field(const std::string &name, RealField &field)
Add a field to the model.
Definition model.hpp:604
Model & operator=(const Model &)=delete
Disable copy assignment operator.
bool has_real_field(std::string_view field_name) const noexcept
Check if the model has a real-valued field with the given name.
Definition model.hpp:370
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
Domain decomposition for parallel MPI simulations.
Fast Fourier Transform interface for spectral methods.
Adapter functions for HeFFTe library integration.
MPI utilities and wrappers.
World(const Int3 &lower, const Int3 &upper, const CoordinateSystem< T > &cs)
Constructs a World object.
World class definition and unified interface.