PutModelDensityOnGrid walked each atom's box as gemmi does, with every point's place relative to the atom and its test against the atom's radius in double. The Apple GPU has no double, so a Metal gather could only come to the same grid to rounding. The density now has its own walk, UseDensityBoxesByPlane: the same planes, atoms, box and order as before, with the point's place in single precision in one fixed order of operations (f = centre - (u, v, w); x = m00 fx + (m01 fy + m02 fz), y = m11 fy + m12 fz, z = m22 fz with gemmi's upper-triangular orth_n; r2 = (y y + z z) + x x, taken where not above the radius squared). A gather that spells the same arithmetic out then finds the same points with the same bits, and gemmi's float expapprox and the Gaussian sums are already single precision. The solvent mask keeps the double walk: its points are 0 or 1, and a point at the edge would flip. The density differs from gemmi's in the last bits, so everything computed from it moves at that level. 9s02 on an Apple M6 against the previous commit: p.hkl unchanged; the MR decision (AGREES, P 21 21 2) and every R-work/R-free within 0.001; validation R(all) 0.3719 -> 0.3718; the validation rigid body took 29 evaluations instead of 22 to the same place (rotation 0.003 deg); Z of rejected candidates in other groups by up to 0.7; the model and maps differ in their last digits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018My7tqt8a4LyKKjP3FhScT
44 lines
2.5 KiB
C++
44 lines
2.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 <cstddef>
|
|
#include <vector>
|
|
|
|
#include "gemmi/dencalc.hpp" // DensityCalculator
|
|
#include "gemmi/grid.hpp"
|
|
#include "gemmi/it92.hpp" // IT92 x-ray form factors
|
|
#include "gemmi/model.hpp"
|
|
|
|
// gemmi's gridding of a model - the density of DensityCalculator::put_model_density_on_grid() and the
|
|
// bulk-solvent mask of SolventMasker(AtomicRadiiSet::Refmac).put_mask_on_grid() - spread over
|
|
// `nthreads` threads of ParallelFor's pool. Every grid point receives the same operations in the same
|
|
// order as in gemmi's serial loops, so the grids are the same on any number of threads: the mask is gemmi's
|
|
// bit for bit, the density gemmi's but for the last bits (its points are placed in single precision, as the
|
|
// Apple GPU places them).
|
|
|
|
// The points gemmi's Grid::symmetrize() reduces the orbits of this grid's size and space group into
|
|
// (empty in P1). Both functions below take them, for a grid of the same size.
|
|
std::vector<size_t> OrbitLeaders(const gemmi::Grid<float> &grid, size_t nthreads);
|
|
|
|
// `dc` set up as for put_model_density_on_grid(): d_min, rate, blur, the grid's cell and group.
|
|
void PutModelDensityOnGrid(gemmi::DensityCalculator<gemmi::IT92<float>, float> &dc, const gemmi::Model &model,
|
|
const std::vector<size_t> &orbit_leaders, size_t nthreads);
|
|
|
|
// `grid` sized, with its cell and group set.
|
|
void PutMaskOnGrid(gemmi::Grid<float> &grid, const gemmi::Model &model, const std::vector<size_t> &orbit_leaders,
|
|
size_t nthreads);
|
|
|
|
// The number of points of the grid a model's structure factors to d_min are computed on at DensityCalculator's
|
|
// `rate` (a spacing of d_min / (2 rate)) in this cell and space group: the grid's size, without making it.
|
|
size_t ModelGridPoints(const gemmi::UnitCell &cell, const gemmi::SpaceGroup *sg, double d_min, double rate = 1.5);
|
|
|
|
// What computing a model's structure factors on the CPU holds at its peak, per point of that grid: the density
|
|
// and the bulk-solvent mask grids, and for each of them its transform's input copy, spectrum and coefficients,
|
|
// with the two made at once (ModelValidation's compute_model_factors).
|
|
constexpr size_t MODEL_FACTORS_BYTES_PER_GRID_POINT = 32;
|
|
// What a molecular-replacement placement's structure factors and rigid body hold on the CPU at their peak, per
|
|
// point of that grid: measured at under half of the above.
|
|
constexpr size_t MODEL_PLACEMENT_BYTES_PER_GRID_POINT = 16;
|