Gemmi C++ API
Loading...
Searching...
No Matches
binner.hpp
Go to the documentation of this file.
1// Copyright 2022 Global Phasing Ltd.
2//
3// Binning - resolution shells for reflections.
4
5#ifndef GEMMI_BINNER_HPP_
6#define GEMMI_BINNER_HPP_
7
8#include <vector>
9#include <limits> // for numeric_limits
10#include "unitcell.hpp" // for UnitCell
11
12namespace gemmi {
13
14struct Binner {
15 enum class Method {
17 Dstar,
18 Dstar2,
19 Dstar3,
20 };
21
22 void setup_from_1_d2(int nbins, Method method, std::vector<double>&& inv_d2,
23 const UnitCell* cell_) {
24 if (nbins < 1)
25 fail("Binner: nbins argument must be positive");
26 if (inv_d2.empty())
27 fail("Binner: no data");
28 if (cell_)
29 cell = *cell_;
30 if (!cell.is_crystal())
31 fail("Binner: unknown unit cell");
32 // first setup 2N bins to get both bin limits and middle points
33 limits.resize(2 * nbins);
34 if (method == Method::EqualCount) {
35 std::sort(inv_d2.begin(), inv_d2.end());
36 min_1_d2 = inv_d2.front();
37 max_1_d2 = inv_d2.back();
38 } else {
39 min_1_d2 = max_1_d2 = inv_d2.front();
40 for (double x : inv_d2) {
41 if (x < min_1_d2)
42 min_1_d2 = x;
43 if (x > max_1_d2)
44 max_1_d2 = x;
45 }
46 }
47 switch (method) {
48 case Method::EqualCount: {
49 double avg_count = double(inv_d2.size()) / limits.size();
50 for (size_t i = 1; i < limits.size(); ++i)
51 limits[i-1] = inv_d2[int(avg_count * i)];
52 break;
53 }
54 case Method::Dstar2: {
55 double step = (max_1_d2 - min_1_d2) / limits.size();
56 for (size_t i = 1; i < limits.size(); ++i)
57 limits[i-1] = min_1_d2 + i * step;
58 break;
59 }
60 case Method::Dstar: {
61 double min_1_d = std::sqrt(min_1_d2);
62 double max_1_d = std::sqrt(max_1_d2);
63 double step = (max_1_d - min_1_d) / limits.size();
64 for (size_t i = 1; i < limits.size(); ++i)
65 limits[i-1] = sq(min_1_d + i * step);
66 break;
67 }
68 case Method::Dstar3: {
69 double min_1_d3 = min_1_d2 * std::sqrt(min_1_d2);
70 double max_1_d3 = max_1_d2 * std::sqrt(max_1_d2);
71 double step = (max_1_d3 - min_1_d3) / limits.size();
72 for (size_t i = 1; i < limits.size(); ++i)
73 limits[i-1] = sq(std::cbrt(min_1_d3 + i * step));
74 break;
75 }
76 }
77 limits.back() = std::numeric_limits<double>::infinity();
78
79 mids.resize(nbins);
80 for (int i = 0; i < nbins; ++i) {
81 mids[i] = limits[2*i];
82 limits[i] = limits[2*i+1];
83 }
84 limits.resize(nbins);
85 }
86
87 template<typename DataProxy>
88 void setup(int nbins, Method method, const DataProxy& proxy,
89 const UnitCell* cell_=nullptr, size_t col_idx=0) {
90 if (col_idx >= proxy.stride())
91 fail("wrong col_idx in Binner::setup()");
92 cell = cell_ ? *cell_ : proxy.unit_cell();
93 std::vector<double> inv_d2;
94 inv_d2.reserve(proxy.size() / proxy.stride());
95 for (size_t offset = 0; offset < proxy.size(); offset += proxy.stride())
96 if (col_idx == 0 || !std::isnan(proxy.get_num(offset + col_idx)))
97 inv_d2.push_back(cell.calculate_1_d2(proxy.get_hkl(offset)));
98 setup_from_1_d2(nbins, method, std::move(inv_d2), nullptr);
99 }
100
102 if (limits.empty())
103 fail("Binner not set up");
104 }
105
106 // Generic. Method-specific versions could be faster.
109 auto it = std::lower_bound(limits.begin(), limits.end(), inv_d2);
110 // it can't be limits.end() b/c limits.back() is +inf
111 return int(it - limits.begin());
112 }
113
114 int get_bin(const Miller& hkl) {
115 double inv_d2 = cell.calculate_1_d2(hkl);
117 }
118
119 // We assume that bins are seeked mostly for sorted reflections,
120 // so it's usually either the same bin as previously, or the next one.
121 int get_bin_from_1_d2_hinted(double inv_d2, int& hint) const {
122 if (inv_d2 <= limits[hint]) {
123 while (hint != 0 && limits[hint-1] > inv_d2)
124 --hint;
125 } else {
126 // limits.back() is +inf, so we won't overrun
127 while (limits[hint] < inv_d2)
128 ++hint;
129 }
130 return hint;
131 }
132
133 int get_bin_hinted(const Miller& hkl, int& hint) const {
134 double inv_d2 = cell.calculate_1_d2(hkl);
136 }
137
138 template<typename DataProxy>
139 std::vector<int> get_bins(const DataProxy& proxy) const {
141 int hint = 0;
142 std::vector<int> nums(proxy.size() / proxy.stride());
143 for (size_t i = 0, offset = 0; i < nums.size(); ++i, offset += proxy.stride())
144 nums[i] = get_bin_hinted(proxy.get_hkl(offset), hint);
145 return nums;
146 }
147
148 std::vector<int> get_bins_from_1_d2(const double* inv_d2, size_t size) const {
150 int hint = 0;
151 std::vector<int> nums(size);
152 for (size_t i = 0; i < size; ++i)
154 return nums;
155 }
156
157 std::vector<int> get_bins_from_1_d2(const std::vector<double>& inv_d2) const {
158 return get_bins_from_1_d2(inv_d2.data(), inv_d2.size());
159 }
160
161 double dmin_of_bin(int n) const {
162 return 1. / std::sqrt(n == (int) size() - 1 ? max_1_d2 : limits.at(n));
163 }
164 double dmax_of_bin(int n) const {
165 return 1. / std::sqrt(n == 0 ? min_1_d2 : limits.at(n-1));
166 }
167
168 size_t size() const { return limits.size(); }
169
171 double min_1_d2;
172 double max_1_d2;
173 std::vector<double> limits; // upper limit of each bin
174 std::vector<double> mids; // the middle of each bin
175};
176
177} // namespace gemmi
178#endif
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
Definition unitcell.hpp:129
constexpr float sq(float x)
Definition math.hpp:34
void fail(const std::string &msg)
Definition fail.hpp:59
int get_bin(const Miller &hkl)
Definition binner.hpp:114
std::vector< double > mids
Definition binner.hpp:174
UnitCell cell
Definition binner.hpp:170
std::vector< double > limits
Definition binner.hpp:173
double dmin_of_bin(int n) const
Definition binner.hpp:161
void ensure_limits_are_set() const
Definition binner.hpp:101
double max_1_d2
Definition binner.hpp:172
size_t size() const
Definition binner.hpp:168
std::vector< int > get_bins_from_1_d2(const double *inv_d2, size_t size) const
Definition binner.hpp:148
void setup_from_1_d2(int nbins, Method method, std::vector< double > &&inv_d2, const UnitCell *cell_)
Definition binner.hpp:22
int get_bin_hinted(const Miller &hkl, int &hint) const
Definition binner.hpp:133
std::vector< int > get_bins(const DataProxy &proxy) const
Definition binner.hpp:139
int get_bin_from_1_d2_hinted(double inv_d2, int &hint) const
Definition binner.hpp:121
void setup(int nbins, Method method, const DataProxy &proxy, const UnitCell *cell_=nullptr, size_t col_idx=0)
Definition binner.hpp:88
std::vector< int > get_bins_from_1_d2(const std::vector< double > &inv_d2) const
Definition binner.hpp:157
int get_bin_from_1_d2(double inv_d2)
Definition binner.hpp:107
double dmax_of_bin(int n) const
Definition binner.hpp:164
double min_1_d2
Definition binner.hpp:171
Unit cell.
Definition unitcell.hpp:165
bool is_crystal() const
Definition unitcell.hpp:187
double calculate_1_d2(const Miller &hkl) const
Definition unitcell.hpp:573
Unit cell.