Files
Jungfraujoch/rugnux/ModelFFT.h
T
leonarski_fandClaude Opus 5 1b414909cb rugnux: the model maps come from FFTW too, so the model path uses one FFT library
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
2026-09-20 18:45:17 +02:00

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);