The map-coefficient to real-space transform was still gemmi's bundled pocketfft while the map to structure-factor direction had moved to FFTW. MapFromFPhi does that inverse with FFTW - the same half-l XYZ layout, the same 1/V scale, NaN coefficients read as zero, the same conjugation convention - and the output maps are now built with it. Plans are FFTW_ESTIMATE, cached per grid size and direction, and made under the shared planner lock. No pocketfft code is instantiated in rugnux any more (75 symbols -> 0); gemmi's fourier.hpp is still included for its non-FFT helpers (get_size_for_hkl, get_f_phi_on_grid), so the vendored header and its notice stay. Tested element-wise against gemmi on odd and even grids, with arbitrary phases, negative indices and symmetry/Friedel expansion in three space groups, plus a round trip; both new tests fail if the conjugation is dropped. On the eight --model audit sets the merged MTZ is byte-identical, the map coefficients are identical, the CCP4 maps agree to 3e-7 relative (map CC 1.00000000) and every reported key is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT
25 lines
1.5 KiB
C
25 lines
1.5 KiB
C
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include "gemmi/grid.hpp"
|
|
#include "gemmi/recgrid.hpp"
|
|
|
|
// The structure factors of a real-space map on the model path (Fcalc from the model density, Fmask
|
|
// from the bulk-solvent mask): what gemmi::transform_map_to_f_phi(map, true) returns - the
|
|
// conjugated forward transform (F = sum rho exp(+2 pi i h.x)) scaled by V/N, kept for l >= 0 on an (nu, nv, nw/2+1) grid in the map's own XYZ order,
|
|
// ready for prepare_asu_data() - computed with FFTW rather than gemmi's single-threaded pocketfft.
|
|
// The same transform, not the same bits: the two libraries order their arithmetic differently.
|
|
//
|
|
// Plans are FFTW_ESTIMATE only - MEASURE would time candidate algorithms and could pick a different
|
|
// one from run to run - and made once per grid size and kept, so the rigid body's hundred-odd
|
|
// evaluations on one grid plan once. Safe to call from several threads at once.
|
|
gemmi::FPhiGrid<float> MapToFPhi(const gemmi::Grid<float> &map);
|
|
|
|
// The inverse: the real-space map of an (nu, nv, nw/2+1) half-l coefficient grid in XYZ order, as
|
|
// get_f_phi_on_grid() fills it - what gemmi::transform_f_phi_grid_to_map() returns (rho = 1/V sum F
|
|
// exp(-2 pi i h.x) on an (nu, nv, 2*(nw-1)) grid, NaN coefficients read as zero), computed with FFTW
|
|
// under the same planning rules.
|
|
gemmi::Grid<float> MapFromFPhi(const gemmi::FPhiGrid<float> &hkl);
|