OpenPFC  0.1.4
Phase Field Crystal simulation framework
Loading...
Searching...
No Matches
operations.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 VTT Technical Research Centre of Finland Ltd
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
36#pragma once
37
38#include <type_traits>
39
41#include "openpfc/fft.hpp"
42#include "openpfc/model.hpp"
43#include "openpfc/types.hpp"
44// Local iteration implemented inline to work with HeFFTe inbox type
45
46namespace pfc {
47namespace field {
48
58template <typename Fn>
59inline void apply(RealField &field, const World &world, const FFT &fft, Fn &&fn) {
60 const auto inbox = pfc::fft::get_inbox(fft);
61 // Safety: ensure field size matches inbox voxel count
62 const auto nx = inbox.size[0];
63 const auto ny = inbox.size[1];
64 const auto nz = inbox.size[2];
65 const auto expected = static_cast<size_t>(nx) * ny * nz;
66 if (field.size() != expected) {
67 throw std::invalid_argument(
68 "field::apply: field size does not match FFT inbox size");
69 }
70
71 size_t linear_idx = 0;
72 for (int k = inbox.low[2]; k <= inbox.high[2]; ++k) {
73 for (int j = inbox.low[1]; j <= inbox.high[1]; ++j) {
74 for (int i = inbox.low[0]; i <= inbox.high[0]; ++i) {
75 const pfc::Int3 idx{i, j, k};
76 const auto x = pfc::world::to_coords(world, idx);
77 field[linear_idx++] = static_cast<double>(fn(x));
78 }
79 }
80 }
81}
82
93template <typename Fn>
94inline void apply_with_time(RealField &field, const World &world, const FFT &fft,
95 double t, Fn &&fn) {
96 const auto inbox = pfc::fft::get_inbox(fft);
97 const auto nx = inbox.size[0];
98 const auto ny = inbox.size[1];
99 const auto nz = inbox.size[2];
100 const auto expected = static_cast<size_t>(nx) * ny * nz;
101 if (field.size() != expected) {
102 throw std::invalid_argument(
103 "field::apply_with_time: field size does not match FFT inbox size");
104 }
105
106 size_t linear_idx = 0;
107 for (int k = inbox.low[2]; k <= inbox.high[2]; ++k) {
108 for (int j = inbox.low[1]; j <= inbox.high[1]; ++j) {
109 for (int i = inbox.low[0]; i <= inbox.high[0]; ++i) {
110 const pfc::Int3 idx{i, j, k};
111 const auto x = pfc::world::to_coords(world, idx);
112 field[linear_idx++] = static_cast<double>(fn(x, t));
113 }
114 }
115 }
116}
117
131template <typename Fn>
132inline void apply_inplace(RealField &field, const World &world, const FFT &fft,
133 Fn &&fn) {
134 const auto inbox = pfc::fft::get_inbox(fft);
135 const auto nx = inbox.size[0];
136 const auto ny = inbox.size[1];
137 const auto nz = inbox.size[2];
138 const auto expected = static_cast<size_t>(nx) * ny * nz;
139 if (field.size() != expected) {
140 throw std::invalid_argument(
141 "field::apply_inplace: field size does not match FFT inbox size");
142 }
143
144 size_t linear_idx = 0;
145 for (int k = inbox.low[2]; k <= inbox.high[2]; ++k) {
146 for (int j = inbox.low[1]; j <= inbox.high[1]; ++j) {
147 for (int i = inbox.low[0]; i <= inbox.high[0]; ++i) {
148 const pfc::Int3 idx{i, j, k};
149 const auto x = pfc::world::to_coords(world, idx);
150 field[linear_idx] = static_cast<double>(fn(x, field[linear_idx]));
151 ++linear_idx;
152 }
153 }
154 }
155}
156
162template <typename Fn>
163inline void apply_inplace_with_time(RealField &field, const World &world,
164 const FFT &fft, double t, Fn &&fn) {
165 const auto inbox = pfc::fft::get_inbox(fft);
166 const auto nx = inbox.size[0];
167 const auto ny = inbox.size[1];
168 const auto nz = inbox.size[2];
169 const auto expected = static_cast<size_t>(nx) * ny * nz;
170 if (field.size() != expected) {
171 throw std::invalid_argument(
172 "field::apply_inplace_with_time: field size does not match FFT inbox size");
173 }
174
175 size_t linear_idx = 0;
176 for (int k = inbox.low[2]; k <= inbox.high[2]; ++k) {
177 for (int j = inbox.low[1]; j <= inbox.high[1]; ++j) {
178 for (int i = inbox.low[0]; i <= inbox.high[0]; ++i) {
179 const pfc::Int3 idx{i, j, k};
180 const auto x = pfc::world::to_coords(world, idx);
181 field[linear_idx] = static_cast<double>(fn(x, field[linear_idx], t));
182 ++linear_idx;
183 }
184 }
185 }
186}
187
191template <typename Fn>
192inline void apply_inplace(Model &model, std::string_view field_name, Fn &&fn) {
193 auto &f = model.get_real_field(field_name);
194 apply_inplace(f, model.get_world(), model.get_fft(), std::forward<Fn>(fn));
195}
196
200template <typename Fn>
201inline void apply_inplace_with_time(Model &model, std::string_view field_name,
202 double t, Fn &&fn) {
203 auto &f = model.get_real_field(field_name);
204 apply_inplace_with_time(f, model.get_world(), model.get_fft(), t,
205 std::forward<Fn>(fn));
206}
207
213template <typename Fn>
214inline void apply(Model &model, std::string_view field_name, Fn &&fn) {
215 auto &f = model.get_real_field(field_name);
216 apply(f, model.get_world(), model.get_fft(), std::forward<Fn>(fn));
217}
218
222template <typename Fn>
223inline void apply_with_time(Model &model, std::string_view field_name, double t,
224 Fn &&fn) {
225 auto &f = model.get_real_field(field_name);
226 apply_with_time(f, model.get_world(), model.get_fft(), t, std::forward<Fn>(fn));
227}
228
229} // namespace field
230} // namespace pfc
The Model class represents the physics model for simulations in OpenPFC.
Definition model.hpp:95
Fast Fourier Transform interface for spectral methods.
Physics model abstraction for phase-field simulations.
void apply_with_time(RealField &field, const World &world, const FFT &fft, double t, Fn &&fn)
Apply a space-time function over a real field (local inbox)
Definition operations.hpp:94
void apply_inplace(RealField &field, const World &world, const FFT &fft, Fn &&fn)
Apply a coordinate-space function in-place over a real field (local inbox)
Definition operations.hpp:132
void apply_inplace_with_time(RealField &field, const World &world, const FFT &fft, double t, Fn &&fn)
Apply a space-time function in-place over a real field (local inbox)
Definition operations.hpp:163
FFT class for distributed-memory parallel Fourier transforms.
Definition fft.hpp:248
Represents the global simulation domain (the "world").
Definition world.hpp:91
Common type aliases used throughout OpenPFC.
World class definition and unified interface.