Gemmi C++ API
Loading...
Searching...
No Matches
ecalc.hpp
Go to the documentation of this file.
1// Copyright 2023 Global Phasing Ltd.
2//
3// Normalization of amplitudes F->E ("Karle" approach, similar to CCP4 ECALC).
4
5#ifndef GEMMI_ECALC_HPP_
6#define GEMMI_ECALC_HPP_
7
8#include <cassert>
9#include "binner.hpp"
10
11namespace gemmi {
12
13template<typename DataProxy>
14std::vector<double> calculate_amplitude_normalizers(const DataProxy& data, int fcol_idx,
15 const Binner& binner) {
16 struct CountAndSum {
17 int n = 0;
18 double sum = 0.;
19 };
20 int nreflections = data.size() / data.stride();
21 std::vector<double> multipliers(nreflections, NAN);
22 if (data.spacegroup() == nullptr)
23 gemmi::fail("unknown space group in the data file");
24 GroupOps gops = data.spacegroup()->operations();
25 std::vector<double> inv_d2(multipliers.size());
26 for (size_t i = 0, n = 0; n < data.size(); n += data.stride(), ++i)
27 inv_d2[i] = data.unit_cell().calculate_1_d2(data.get_hkl(n));
28 std::vector<int> bin_index = binner.get_bins_from_1_d2(inv_d2);
29 std::vector<CountAndSum> stats(binner.size());
30 for (size_t i = 0, n = 0; n < data.size(); n += data.stride(), i++) {
31 Miller hkl = data.get_hkl(n);
32 double f = data.get_num(n + fcol_idx);
33 if (!std::isnan(f)) {
34 int epsilon = gops.epsilon_factor(hkl);
35 double inv_epsilon = 1.0 / epsilon;
36 double f2 = f * f * inv_epsilon;
37 multipliers[i] = std::sqrt(inv_epsilon);
39 cs.n++;
40 cs.sum += f2;
41 }
42 }
43
44 // simple smoothing with kernel [0.75 1 0.75]
45 std::vector<double> smoothed(stats.size());
46 {
47 const double k = 0.75;
48 smoothed[0] = (stats[0].sum + k * stats[1].sum) / (stats[0].n + k * stats[1].n);
49 size_t n = stats.size() - 1;
50 for (size_t i = 1; i < n; ++i)
51 smoothed[i] = (stats[i].sum + k * (stats[i-1].sum + stats[i+1].sum))
52 / (stats[i].n + k * (stats[i-1].n + stats[i+1].n));
53 smoothed[n] = (stats[n].sum + k * stats[n-1].sum) / (stats[n].n + k * stats[n-1].n);
54 }
55
56#if 0
57 {
58 // print shell statistics
59 std::vector<int> refl_counts(binner.size());
60 printf(" shell\t #F\t d\t <F^2>\tsmoothd\t #refl\t mid d\n");
61 for (int idx : bin_index)
62 ++refl_counts[idx];
63 for (size_t i = 0; i < binner.size(); ++i) {
64 double d = 1 / std::sqrt(binner.limits[i]);
65 double mid_d = 1 / std::sqrt(binner.mids[i]);
66 double avg_f2 = stats[i].sum / stats[i].n;
67 printf("%6zu\t%6d\t%7.3f\t%7.0f\t%7.0f\t%6d\t%7.3f\n",
68 i+1, stats[i].n, d, avg_f2, smoothed[i], refl_counts[i], mid_d);
69 }
70 printf("\n");
71 }
72#endif
73
74 for (double& x : smoothed)
75 x = std::sqrt(x);
76 for (size_t i = 0; i < multipliers.size(); ++i) {
77 double x = inv_d2[i];
78 int bin = bin_index[i];
79 double rms = smoothed[bin];
80 if (x > binner.mids.front() && x < binner.mids.back()) {
81 // linear interpolation in 1/d^2
82 if (x > binner.mids[bin])
83 ++bin;
84 double x0 = binner.mids[bin - 1];
85 double x1 = binner.mids[bin];
86 double y0 = smoothed[bin - 1];
87 double y1 = smoothed[bin];
88 assert(x0 <= x && x <= x1);
89 rms = y0 + (x - x0) * (y1 - y0) / (x1 - x0);
90 }
91 multipliers[i] /= rms;
92 }
93 return multipliers;
94}
95
96} // namespace gemmi
97#endif
std::vector< double > calculate_amplitude_normalizers(const DataProxy &data, int fcol_idx, const Binner &binner)
Definition ecalc.hpp:14
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
Definition unitcell.hpp:128
void fail(const std::string &msg)
Definition fail.hpp:59
int epsilon_factor(const Op::Miller &hkl) const
Definition symmetry.hpp:507