5#ifndef GEMMI_FOURIER_HPP_
6#define GEMMI_FOURIER_HPP_
16# define POCKETFFT_CACHE_SIZE 0
18#define POCKETFFT_NO_MULTITHREADING
19#include "third_party/pocketfft_hdronly.h"
28 if (
static_cast<T>(angle) == 360.f)
37 for (
const auto& item :
asu_data.v) {
38 for (
int i = 0;
i != 3; ++
i)
45template<
typename DataProxy>
50 for (
size_t i = 0;
i < data.size();
i += data.stride()) {
52 for (
int j = 0;
j != 3; ++
j) {
53 int v = 2 * std::abs(hkl[
j]) + 1;
62 const UnitCell& cell = data.unit_cell();
64 for (
size_t i = 0;
i < data.size();
i += data.stride())
67 std::array<double, 3>
cellr = {{cell.
ar, cell.
br, cell.
cr}};
68 for (
int i = 0;
i < 3; ++
i)
74template<
typename DataProxy>
76 for (
size_t i = 0;
i < data.size();
i += data.stride()) {
78 for (
int j = 0;
j != 3; ++
j)
79 if (2 * std::abs(hkl[
j]) >= size[
j])
89 for (
int w = 0; w != (grid.half_l ? 1 : grid.nw); ++w) {
90 int w_ = w == 0 ? 0 : grid.nw - w;
91 for (
int v = 0; v != grid.nv; ++v) {
92 int v_ = v == 0 ? 0 : grid.nv - v;
93 for (
int u = 0; u != grid.nu; ++u) {
94 size_t idx = grid.index_q(u, v, w);
96 int u_ = u == 0 ? 0 : grid.nu - u;
104 for (
int w = 0; w != grid.nw; ++w) {
105 int w_ = w == 0 ? 0 : grid.nw - w;
106 for (
int v = 0; v != grid.nv; ++v) {
107 int v_ = v == 0 ? 0 : grid.nv - v;
109 size_t idx = grid.index_q(0, v, w);
115 for (
int u = 0; u != grid.nu; ++u) {
116 size_t idx = grid.index_q(u, v, w);
118 int u_ = u == 0 ? 0 : grid.nu - u;
129template<
typename T,
typename DataProxy>
131 std::array<int, 3> size,
bool half_l,
133 if (data.size() == 0)
135 if (!data.spacegroup())
136 fail(
"No spacegroup.");
138 grid.unit_cell = data.unit_cell();
139 grid.half_l = half_l;
140 grid.axis_order = axis_order;
141 grid.spacegroup = data.spacegroup();
143 size[2] = size[2] / 2 + 1;
145 std::swap(size[0], size[2]);
146 grid.set_size_without_checking(size[0], size[1], size[2]);
149template<
typename DataProxy>
154 fail(
"Map coefficients not found.");
156 using real =
typename DataProxy::num_type;
160 size_t f_col_, phi_col_;
165template<
typename T,
typename FPhi>
167 std::array<int, 3> size,
bool half_l,
173 for (
size_t i = 0;
i <
fphi.size();
i +=
fphi.stride()) {
179 for (
const Op& op :
ops.sym_ops) {
180 auto hklp = op.apply_to_hkl(hkl);
186 int sign = (!half_l ||
lp >= 0 ? 1 : -1);
187 size_t idx = grid.index_n(sign *
hklp[0], sign *
hklp[1], sign *
hklp[2]);
189 T theta = sign *
T(
phi + op.phase_shift(hkl));
190 grid.data[idx] = std::complex<T>(f * std::cos(
theta), f * std::sin(
theta));
194 if (!
ops.is_centrosymmetric())
199template<
typename T,
typename DataProxy>
201 std::array<int, 3> size,
bool half_l,
206 if (column >= data.stride())
207 fail(
"Map coefficients not found.");
209 for (
size_t i = 0;
i < data.size();
i += data.stride()) {
211 T val = (
T) data.get_num(
i + column);
213 for (
const Op& op :
ops.sym_ops) {
214 auto hklp = op.apply_to_hkl(hkl);
220 int sign = (!half_l ||
lp >= 0 ? 1 : -1);
221 size_t idx = grid.index_n(sign *
hklp[0], sign *
hklp[1], sign *
hklp[2]);
222 if (grid.data[idx] == 0.)
223 grid.data[idx] = val;
227 if (!
ops.is_centrosymmetric())
234void transform_f_phi_grid_to_map_(FPhiGrid<T>&& hkl, Grid<T>& map) {
237 for (std::complex<T>& x : hkl.data)
238 if (
std::isnan(x.imag()))
242 map.spacegroup = hkl.spacegroup;
243 map.unit_cell = hkl.unit_cell;
244 map.axis_order = hkl.axis_order;
246 int nw = hkl.half_l ? 2 * (hkl.nw - 1) : hkl.nw;
247 map.set_size(hkl.nu, hkl.nv, nw);
249 int nu = hkl.half_l ? 2 * (hkl.nu - 1) : hkl.nu;
251 map.set_size_without_checking(nu, hkl.nv, hkl.nw);
254 map.axis_order = hkl.axis_order;
255 pocketfft::shape_t shape{(size_t)hkl.nw, (
size_t)hkl.nv, (size_t)hkl.nu};
256 std::ptrdiff_t s =
sizeof(
T);
257 pocketfft::stride_t stride{2*s * hkl.nv * hkl.nu, 2*s * hkl.nu, 2*s};
258 pocketfft::shape_t axes{2, 1, 0};
260 std::swap(axes[0], axes[2]);
261 T norm =
T(1.0 / hkl.unit_cell.volume);
263 size_t last_axis = axes.back();
265 pocketfft::c2c<T>(shape, stride, stride, axes, pocketfft::BACKWARD,
266 &hkl.data[0], &hkl.data[0], norm);
267 pocketfft::stride_t stride_out{s * map.nu * map.nv, s * map.nu, s};
268 shape[0] = (size_t) map.nw;
269 shape[2] = (size_t) map.nu;
270 pocketfft::c2r<T>(shape, stride, stride_out, last_axis, pocketfft::BACKWARD,
271 &hkl.data[0], &map.data[0], 1.0f);
273 pocketfft::c2c<T>(shape, stride, stride, axes, pocketfft::BACKWARD,
274 &hkl.data[0], &hkl.data[0], norm);
275 assert(map.data.size() == hkl.data.size());
276 for (
size_t i = 0; i != map.data.size(); ++i)
277 map.data[i] = hkl.data[i].real();
284 transform_f_phi_grid_to_map_(std::forward<
FPhiGrid<T>>(hkl),
map);
288template<
typename T,
typename FPhi>
290 std::array<int, 3> size,
302template<
typename T,
typename FPhi>
315 if (half_l &&
map.axis_order == AxisOrder::ZYX)
316 fail(
"transform_map_to_f_phi(): half_l + ZYX order are not supported yet");
318 hkl.unit_cell =
map.unit_cell;
319 hkl.spacegroup =
map.spacegroup;
320 hkl.axis_order =
map.axis_order;
325 pocketfft::shape_t
shape{(size_t)
map.nw, (
size_t)
map.nv, (size_t)
map.nu};
326 std::ptrdiff_t s =
sizeof(
T);
327 pocketfft::stride_t
stride_in{s * hkl.nv * hkl.nu, s * hkl.nu, s};
328 pocketfft::stride_t stride{2*s * hkl.nv * hkl.nu, 2*s * hkl.nu, 2*s};
329 pocketfft::r2c<T>(
shape,
stride_in, stride, 0, pocketfft::FORWARD,
330 &
map.data[0], &hkl.data[0],
norm);
332 pocketfft::c2c<T>(
shape, stride, stride, {1, 2}, pocketfft::FORWARD,
333 &hkl.data[0], &hkl.data[0], 1.0f);
335 for (
int w =
half_nw; w != hkl.nw; ++w) {
337 for (
int v = 0; v != hkl.nv; ++v) {
338 int v_ = v == 0 ? 0 : hkl.nv - v;
339 for (
int u = 0; u != hkl.nu; ++u) {
340 int u_ = u == 0 ? 0 : hkl.nu - u;
341 size_t idx = hkl.index_q(u, v, w);
343 hkl.data[idx] = hkl.data[
inv_idx];
347 for (
int i = 0;
i != hkl.nu * hkl.nv *
half_nw; ++
i)
348 hkl.data[
i].imag(-hkl.data[
i].imag());
AxisOrder
Order of grid axis.
double phase_in_angles(const std::complex< T > &v)
MtzDataProxy data_proxy(const Mtz &mtz)
signed char friedel_mate_value(signed char v)
constexpr double deg(double angle)
FPhiGrid< T > get_f_phi_on_grid(const FPhi &fphi, std::array< int, 3 > size, bool half_l, AxisOrder axis_order=AxisOrder::XYZ)
void add_friedel_mates(ReciprocalGrid< T > &grid)
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
void add_asu_f_phi_to_float_vector(std::vector< float > &float_data, const AsuData< std::complex< float > > &asu_data)
constexpr double rad(double angle)
Grid< T > transform_f_phi_to_map2(const FPhi &fphi, std::array< int, 3 > min_size, double sample_rate, std::array< int, 3 > exact_size, AxisOrder order=AxisOrder::XYZ)
FPhiGrid< T > transform_map_to_f_phi(const Grid< T > &map, bool half_l, bool use_scale=true)
std::array< int, 3 > good_grid_size(const std::array< double, 3 > &limit, GridSizeRounding rounding, const SpaceGroup *sg)
void check_grid_factors(const SpaceGroup *sg, std::array< int, 3 > size)
Grid< T > transform_f_phi_grid_to_map(FPhiGrid< T > &&hkl)
void initialize_hkl_grid(ReciprocalGrid< T > &grid, const DataProxy &data, std::array< int, 3 > size, bool half_l, AxisOrder axis_order)
void fail(const std::string &msg)
std::array< int, 3 > get_size_for_hkl(const DataProxy &data, std::array< int, 3 > min_size, double sample_rate)
Grid< T > transform_f_phi_to_map(const FPhi &fphi, std::array< int, 3 > size, double sample_rate, bool exact_size=false, AxisOrder order=AxisOrder::XYZ)
bool data_fits_into(const DataProxy &data, std::array< int, 3 > size)
ReciprocalGrid< T > get_value_on_grid(const DataProxy &data, size_t column, std::array< int, 3 > size, bool half_l, AxisOrder axis_order=AxisOrder::XYZ)
FPhiProxy(const DataProxy &data_proxy, size_t f_col, size_t phi_col)
double get_phi(size_t offset) const
typename DataProxy::num_type real
real get_f(size_t offset) const
double ar
reciprocal parameters a*, b*, c*, alpha*, beta*, gamma*
double calculate_1_d2(const Miller &hkl) const