Gemmi C++ API
Loading...
Searching...
No Matches
dencalc.hpp
Go to the documentation of this file.
1// Copyright 2019 Global Phasing Ltd.
2//
3// Tools to prepare a grid with values of electron density of a model.
4
5#ifndef GEMMI_DENCALC_HPP_
6#define GEMMI_DENCALC_HPP_
7
8#include <cassert>
9#include "addends.hpp" // for Addends
10#include "formfact.hpp" // for ExpSum
11#include "grid.hpp" // for Grid
12#include "model.hpp" // for Structure, ...
13
14namespace gemmi {
15
16template<int N, typename Real>
18 Real y1, dy;
19 std::tie(y1, dy) = precal.calculate_with_derivative(x1);
20 // Generally, density is supposed to decrease with radius.
21 // But if we have addends (in particular -Z for Mott-Bothe),
22 // it can first rise, then decrease. We want to be after the maximum.
23 while (dy > 0) { // unlikely
24 x1 += 1.0f;
25 std::tie(y1, dy) = precal.calculate_with_derivative(x1);
26 }
27 Real x2 = x1;
28 Real y2 = y1;
29 if (y1 < cutoff_level) {
30 while (y1 < cutoff_level) {
31 x2 = x1;
32 y2 = y1;
33 x1 -= 0.5f;
34 std::tie(y1, dy) = precal.calculate_with_derivative(x1);
35 // with addends it's possible to land on the left side of the maximum
36 if (dy > 0) { // unlikely
37 while (dy > 0 && x1 + 0.1f < x2) {
38 x1 += 0.1f;
39 std::tie(y1, dy) = precal.calculate_with_derivative(x1);
40 }
41 if (y1 < cutoff_level)
42 return x1;
43 break;
44 }
45 if (x1 < 0) { // unlikely
46 x1 = 0;
47 y1 = precal.calculate(x1 * x1);
48 break;
49 }
50 }
51 } else {
52 while (y2 > cutoff_level) {
53 x1 = x2;
54 y1 = y2;
55 x2 += 0.5f;
56 y2 = precal.calculate(x2 * x2);
57 }
58 }
59
60 return x1 + (x1 - x2) / (y1 - y2) * (cutoff_level - y1);
61}
62
63// approximated radius of electron density (IT92) above cutoff=1e-5 for C
64template <typename Real>
66 return (8.5f + 0.075f * b) / (2.4f + 0.0045f * b);
67}
68
69inline double get_minimum_b(const Model& model) {
70 double b_min = 1000.;
71 for (const Chain& chain : model.chains)
72 for (const Residue& residue : chain.residues)
73 for (const Atom& atom : residue.atoms) {
74 if (atom.occ == 0) continue;
75 double b = atom.b_iso;
76 if (atom.aniso.nonzero()) {
77 std::array<double,3> eig = atom.aniso.calculate_eigenvalues();
78 b = std::min(std::min(eig[0], eig[1]), eig[2]) * u_to_b();
79 }
80 if (b < b_min)
81 b_min = b;
82 }
83 return b_min;
84}
85
86// Usual usage:
87// - set d_min and optionally also other parameters,
88// - set addends to f' values for your wavelength (see fprime.hpp)
89// - use set_grid_cell_and_spacegroup() to set grid's unit cell and space group
90// - check that Table has SF coefficients for all elements that are to be used
91// - call put_model_density_on_grid()
92// - do FFT using transform_map_to_f_phi()
93// - if blur is used, multiply the SF by reciprocal_space_multiplier()
94template <typename Table, typename GReal>
96 // GReal = type of grid; CReal = type of coefficients in Table
97 using CReal = typename Table::Coef::coef_type;
99 double d_min = 0.;
100 double rate = 1.5;
101 double blur = 0.;
102 float cutoff = 1e-5f;
103#if GEMMI_COUNT_DC
104 size_t atoms_added = 0;
105 size_t density_computations = 0;
106#endif
108
109 double requested_grid_spacing() const { return d_min / (2 * rate); }
110
112 double spacing = requested_grid_spacing();
113 if (spacing <= 0)
114 spacing = grid.min_spacing();
115 double b_min = get_minimum_b(model);
116 blur = std::max(u_to_b() / 1.1 * sq(spacing) - b_min, 0.);
117 }
118
119 // pre: check if Table::has(atom.element)
120 void add_atom_density_to_grid(const Atom& atom) {
121 Element el = atom.element;
122 do_add_atom_density_to_grid(atom, Table::get(el, atom.charge), addends.get(el));
123 }
124
125 // Parameter c is a constant factor and has the same meaning as either addend
126 // or c in scattering factor coefficients (a1, b1, ..., c).
127 void add_c_contribution_to_grid(const Atom& atom, float c) {
129 }
130
131 template<int N>
133 if (N == 1)
134 return std::sqrt(std::log(cutoff / std::abs(precal.a[0])) / precal.b[0]);
137 }
138
139 template<typename Coef>
140 void do_add_atom_density_to_grid(const Atom& atom, const Coef& coef, float addend) {
141#if GEMMI_COUNT_DC
142 ++atoms_added;
143#endif
145 if (!atom.aniso.nonzero()) {
146 // isotropic
147 CReal b = static_cast<CReal>(atom.b_iso + blur);
148 auto precal = coef.precalculate_density_iso(b, addend);
150 grid.template use_points_around<true>(fpos, radius, [&](GReal& point, double r2) {
151 point += GReal(atom.occ * precal.calculate((CReal)r2));
152#if GEMMI_COUNT_DC
154#endif
155 }, /*fail_on_too_large_radius=*/false);
156 } else {
157 // anisotropic
158 auto aniso_b = atom.aniso.scaled(CReal(u_to_b())).added_kI(CReal(blur));
159 // rough estimate, so we don't calculate eigenvalues
160 CReal b_max = std::max(std::max(aniso_b.u11, aniso_b.u22), aniso_b.u33);
161 auto precal_iso = coef.precalculate_density_iso(b_max, addend);
163 auto precal = coef.precalculate_density_aniso_b(aniso_b, addend);
164 int du = (int) std::ceil(radius / grid.spacing[0]);
165 int dv = (int) std::ceil(radius / grid.spacing[1]);
166 int dw = (int) std::ceil(radius / grid.spacing[2]);
168 fpos, du, dv, dw,
169 [&](GReal& point, double, const Position& delta, int, int, int) {
170 point += GReal(atom.occ * precal.calculate(delta));
171#if GEMMI_COUNT_DC
173#endif
174 },
175 false, radius);
176 }
177 }
178
180 grid.data.clear();
181 double spacing = requested_grid_spacing();
182 if (spacing > 0)
184 else if (grid.point_count() > 0)
185 // d_min not set, but a custom grid has been setup by the user
186 grid.fill(0.);
187 else
188 fail("initialize_grid(): d_min is not set");
189 }
190
191 void add_model_density_to_grid(const Model& model) {
193 for (const Chain& chain : model.chains)
194 for (const Residue& res : chain.residues)
195 for (const Atom& atom : res.atoms)
197 }
198
204
206 grid.unit_cell = st.cell;
207 grid.spacegroup = st.find_spacegroup();
208 }
209
210 // The argument is 1/d^2 - as outputted by unit_cell.calculate_1_d2(hkl).
211 double reciprocal_space_multiplier(double inv_d2) const {
212 return std::exp(blur * 0.25 * inv_d2);
213 }
214
215 double mott_bethe_factor(const Miller& hkl) const {
216 double inv_d2 = grid.unit_cell.calculate_1_d2(hkl);
217 double factor = -mott_bethe_const() / inv_d2;
219 }
220};
221
222} // namespace gemmi
223#endif
std::array< int, 3 > Miller
A synonym for convenient passing of hkl.
Definition unitcell.hpp:128
constexpr double mott_bethe_const()
Definition math.hpp:26
double get_minimum_b(const Model &model)
Definition dencalc.hpp:69
Real determine_cutoff_radius(Real x1, const ExpSum< N, Real > &precal, Real cutoff_level)
Definition dencalc.hpp:17
constexpr float sq(float x)
Definition math.hpp:34
void fail(const std::string &msg)
Definition fail.hpp:59
constexpr double u_to_b()
Definition math.hpp:29
Real it92_radius_approx(Real b)
Definition dencalc.hpp:65
float get(Element el) const
Definition addends.hpp:18
Represents atom site in macromolecular structure (~100 bytes).
Definition model.hpp:112
SMat33< float > aniso
Definition model.hpp:127
signed char charge
Definition model.hpp:116
float b_iso
Definition model.hpp:126
Element element
Definition model.hpp:117
float occ
Definition model.hpp:124
Position pos
Definition model.hpp:123
void set_grid_cell_and_spacegroup(const Structure &st)
Definition dencalc.hpp:205
double mott_bethe_factor(const Miller &hkl) const
Definition dencalc.hpp:215
void add_model_density_to_grid(const Model &model)
Definition dencalc.hpp:191
void set_refmac_compatible_blur(const Model &model)
Definition dencalc.hpp:111
void add_c_contribution_to_grid(const Atom &atom, float c)
Definition dencalc.hpp:127
typename Table::Coef::coef_type CReal
Definition dencalc.hpp:97
CReal estimate_radius(const ExpSum< N, CReal > &precal, CReal b) const
Definition dencalc.hpp:132
void put_model_density_on_grid(const Model &model)
Definition dencalc.hpp:199
double reciprocal_space_multiplier(double inv_d2) const
Definition dencalc.hpp:211
void add_atom_density_to_grid(const Atom &atom)
Definition dencalc.hpp:120
double requested_grid_spacing() const
Definition dencalc.hpp:109
void do_add_atom_density_to_grid(const Atom &atom, const Coef &coef, float addend)
Definition dencalc.hpp:140
Fractional coordinates.
Definition unitcell.hpp:50
std::vector< T > data
Definition grid.hpp:235
void fill(T value)
Definition grid.hpp:261
void check_not_empty() const
Definition grid.hpp:237
const SpaceGroup * spacegroup
Definition grid.hpp:163
size_t point_count() const
Definition grid.hpp:167
UnitCell unit_cell
Definition grid.hpp:162
double min_spacing() const
Definition grid.hpp:338
void set_size_from_spacing(double approx_spacing, GridSizeRounding rounding)
Definition grid.hpp:353
void symmetrize_sum()
multiplies grid points on special position
Definition grid.hpp:757
double spacing[3]
spacing between virtual planes, not between points
Definition grid.hpp:312
std::vector< Chain > chains
Definition model.hpp:700
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
Definition unitcell.hpp:32
SMat33< Real > scaled(Real s) const
Definition math.hpp:284
bool nonzero() const
Definition math.hpp:273
Fractional fractionalize(const Position &o) const
Definition unitcell.hpp:374
double calculate_1_d2(const Miller &hkl) const
Definition unitcell.hpp:529