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"
32 return std::max(0., angle);
39 for (
const auto& item :
asu_data.v) {
40 for (
int i = 0;
i != 3; ++
i)
47template<
typename DataProxy>
52 for (
size_t i = 0;
i < data.size();
i += data.stride()) {
54 for (
int j = 0;
j != 3; ++
j) {
55 int v = 2 * std::abs(hkl[
j]) + 1;
64 const UnitCell& cell = data.unit_cell();
66 for (
size_t i = 0;
i < data.size();
i += data.stride())
69 std::array<double, 3>
cellr = {{cell.
ar, cell.
br, cell.
cr}};
70 for (
int i = 0;
i < 3; ++
i)
76template<
typename DataProxy>
78 for (
size_t i = 0;
i < data.size();
i += data.stride()) {
80 for (
int j = 0;
j != 3; ++
j)
81 if (2 * std::abs(hkl[
j]) >= size[
j])
91 for (
int w = 0; w != (grid.half_l ? 1 : grid.nw); ++w) {
92 int w_ = w == 0 ? 0 : grid.nw - w;
93 for (
int v = 0; v != grid.nv; ++v) {
94 int v_ = v == 0 ? 0 : grid.nv - v;
95 for (
int u = 0; u != grid.nu; ++u) {
96 size_t idx = grid.index_q(u, v, w);
98 int u_ = u == 0 ? 0 : grid.nu - u;
106 for (
int w = 0; w != grid.nw; ++w) {
107 int w_ = w == 0 ? 0 : grid.nw - w;
108 for (
int v = 0; v != grid.nv; ++v) {
109 int v_ = v == 0 ? 0 : grid.nv - v;
111 size_t idx = grid.index_q(0, v, w);
117 for (
int u = 0; u != grid.nu; ++u) {
118 size_t idx = grid.index_q(u, v, w);
120 int u_ = u == 0 ? 0 : grid.nu - u;
131template<
typename T,
typename DataProxy>
133 std::array<int, 3> size,
bool half_l,
135 if (data.size() == 0)
137 if (!data.spacegroup())
138 fail(
"No spacegroup.");
140 grid.unit_cell = data.unit_cell();
141 grid.half_l = half_l;
142 grid.axis_order = axis_order;
143 grid.spacegroup = data.spacegroup();
145 size[2] = size[2] / 2 + 1;
147 std::swap(size[0], size[2]);
148 grid.set_size_without_checking(size[0], size[1], size[2]);
151template<
typename DataProxy>
156 fail(
"Map coefficients not found.");
158 using real =
typename DataProxy::num_type;
162 size_t f_col_, phi_col_;
167template<
typename T,
typename FPhi>
169 std::array<int, 3> size,
bool half_l,
175 for (
size_t i = 0;
i <
fphi.size();
i +=
fphi.stride()) {
181 for (
const Op& op :
ops.sym_ops) {
182 auto hklp = op.apply_to_hkl(hkl);
188 int sign = (!half_l ||
lp >= 0 ? 1 : -1);
189 size_t idx = grid.index_n(sign *
hklp[0], sign *
hklp[1], sign *
hklp[2]);
191 T theta = sign *
T(
phi + op.phase_shift(hkl));
192 grid.data[idx] = std::complex<T>(f * std::cos(
theta), f * std::sin(
theta));
196 if (!
ops.is_centrosymmetric())
201template<
typename T,
typename DataProxy>
203 std::array<int, 3> size,
bool half_l,
208 if (column >= data.stride())
209 fail(
"Map coefficients not found.");
211 for (
size_t i = 0;
i < data.size();
i += data.stride()) {
213 T val = (
T) data.get_num(
i + column);
215 for (
const Op& op :
ops.sym_ops) {
216 auto hklp = op.apply_to_hkl(hkl);
222 int sign = (!half_l ||
lp >= 0 ? 1 : -1);
223 size_t idx = grid.index_n(sign *
hklp[0], sign *
hklp[1], sign *
hklp[2]);
224 if (grid.data[idx] == 0.)
225 grid.data[idx] = val;
229 if (!
ops.is_centrosymmetric())
236void transform_f_phi_grid_to_map_(FPhiGrid<T>&& hkl, Grid<T>& map) {
239 for (std::complex<T>& x : hkl.data)
240 if (
std::isnan(x.imag()))
244 map.spacegroup = hkl.spacegroup;
245 map.unit_cell = hkl.unit_cell;
246 map.axis_order = hkl.axis_order;
248 int nw = hkl.half_l ? 2 * (hkl.nw - 1) : hkl.nw;
249 map.set_size(hkl.nu, hkl.nv, nw);
251 int nu = hkl.half_l ? 2 * (hkl.nu - 1) : hkl.nu;
253 map.set_size_without_checking(nu, hkl.nv, hkl.nw);
256 map.axis_order = hkl.axis_order;
257 pocketfft::shape_t shape{(size_t)hkl.nw, (
size_t)hkl.nv, (size_t)hkl.nu};
258 std::ptrdiff_t s =
sizeof(
T);
259 pocketfft::stride_t stride{2*s * hkl.nv * hkl.nu, 2*s * hkl.nu, 2*s};
260 pocketfft::shape_t axes{2, 1, 0};
262 std::swap(axes[0], axes[2]);
263 T norm =
T(1.0 / hkl.unit_cell.volume);
265 size_t last_axis = axes.back();
267 pocketfft::c2c<T>(shape, stride, stride, axes, pocketfft::BACKWARD,
268 &hkl.data[0], &hkl.data[0], norm);
269 pocketfft::stride_t stride_out{s * map.nu * map.nv, s * map.nu, s};
270 shape[0] = (size_t) map.nw;
271 shape[2] = (size_t) map.nu;
272 pocketfft::c2r<T>(shape, stride, stride_out, last_axis, pocketfft::BACKWARD,
273 &hkl.data[0], &map.data[0], 1.0f);
275 pocketfft::c2c<T>(shape, stride, stride, axes, pocketfft::BACKWARD,
276 &hkl.data[0], &hkl.data[0], norm);
277 assert(map.data.size() == hkl.data.size());
278 for (
size_t i = 0; i != map.data.size(); ++i)
279 map.data[i] = hkl.data[i].real();
286 transform_f_phi_grid_to_map_(std::forward<
FPhiGrid<T>>(hkl),
map);
290template<
typename T,
typename FPhi>
292 std::array<int, 3> size,
304template<
typename T,
typename FPhi>
317 if (half_l &&
map.axis_order == AxisOrder::ZYX)
318 fail(
"transform_map_to_f_phi(): half_l + ZYX order are not supported yet");
320 hkl.unit_cell =
map.unit_cell;
321 hkl.spacegroup =
map.spacegroup;
322 hkl.axis_order =
map.axis_order;
327 pocketfft::shape_t
shape{(size_t)
map.nw, (
size_t)
map.nv, (size_t)
map.nu};
328 std::ptrdiff_t s =
sizeof(
T);
329 pocketfft::stride_t
stride_in{s * hkl.nv * hkl.nu, s * hkl.nu, s};
330 pocketfft::stride_t stride{2*s * hkl.nv * hkl.nu, 2*s * hkl.nu, 2*s};
331 pocketfft::r2c<T>(
shape,
stride_in, stride, 0, pocketfft::FORWARD,
332 &
map.data[0], &hkl.data[0],
norm);
334 pocketfft::c2c<T>(
shape, stride, stride, {1, 2}, pocketfft::FORWARD,
335 &hkl.data[0], &hkl.data[0], 1.0f);
337 for (
int w =
half_nw; w != hkl.nw; ++w) {
339 for (
int v = 0; v != hkl.nv; ++v) {
340 int v_ = v == 0 ? 0 : hkl.nv - v;
341 for (
int u = 0; u != hkl.nu; ++u) {
342 int u_ = u == 0 ? 0 : hkl.nu - u;
343 size_t idx = hkl.index_q(u, v, w);
345 hkl.data[idx] = hkl.data[
inv_idx];
349 for (
int i = 0;
i != hkl.nu * hkl.nv *
half_nw; ++
i)
350 hkl.data[
i].imag(-hkl.data[
i].imag());
fail(), unreachable() and __declspec/__attribute__ macros
Math utilities. 3D linear algebra.
AxisOrder
Order of grid axis.
double phase_in_angles(const std::complex< T > &v, double eps=2e-5)
MtzDataProxy data_proxy(const Mtz &mtz)
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(std::array< double, 3 > limit, GridSizeRounding rounding, const SpaceGroup *sg)
T friedel_mate_value(T v)
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)
ReciprocalGrid – grid for reciprocal space data.
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
Crystallographic Symmetry. Space Groups. Coordinate Triplets.