Gemmi C++ API
Loading...
Searching...
No Matches
sfcalc.hpp
Go to the documentation of this file.
1// Copyright 2019 Global Phasing Ltd.
2//
3// Direct calculation of structure factors.
4//
5// It does not use optimizations described in the literature,
6// cf. Bourhis et al (2014) https://doi.org/10.1107/S2053273314022207,
7// because direct calculations are not used in MX if performance is important.
8// For FFT-based calculations see dencalc.hpp + fourier.hpp.
9
10#ifndef GEMMI_SFCALC_HPP_
11#define GEMMI_SFCALC_HPP_
12
13#include <complex>
14#include "addends.hpp" // for Addends
15#include "model.hpp" // for Structure, ...
16#include "small.hpp" // for SmallStructure
17
18namespace gemmi {
19
20// calculate part of the structure factor: exp(2 pi i r * s)
21inline std::complex<double> calculate_sf_part(const Fractional& fpos,
22 const Miller& hkl) {
23 double arg = 2 * pi() * (hkl[0]*fpos.x + hkl[1]*fpos.y + hkl[2]*fpos.z);
24 return std::complex<double>{std::cos(arg), std::sin(arg)};
25}
26
27template <typename Table>
29public:
30 using coef_type = typename Table::Coef::coef_type;
31
32 StructureFactorCalculator(const UnitCell& cell) : cell_(cell) {}
33
35 stol2_ = (coef_type) cell_.calculate_stol_sq(hkl);
36 scattering_factors_.clear();
37 scattering_factors_.resize(addends.size(), 0.);
38 }
39
40 double get_scattering_factor(Element element, signed char charge) {
41 double& sfactor = scattering_factors_[element.ordinal()];
42 if (sfactor == 0.) {
43 if (!Table::has(element.elem))
44 fail("Missing scattering factor for ", element.name());
45 sfactor = Table::get(element.elem, charge).calculate_sf(stol2_) + addends.get(element);
46 }
47 return sfactor;
48 }
49
50 // Calculation of Debye-Waller factor with isotropic ADPs
51 double dwf_iso(const SmallStructure::Site& site) const {
52 return std::exp(-u_to_b() * stol2_ * site.u_iso);
53 }
54 double dwf_iso(const Atom& atom) const {
55 return std::exp(-stol2_ * atom.b_iso);
56 }
57
58 // Calculation of Debye-Waller factor exp(-2 pi^2 s.U.s)
59 // cf. B. Rupp's book, p. 641 or RWGK & Adams 2002, J. Appl. Cryst. 35, 477
60 // Small molecule and macromolecular anisotropic U's are defined differently,
61 // so we have two functions.
62 double dwf_aniso(const SmallStructure::Site& site, const Vec3& hkl) const {
63 Vec3 arh(cell_.ar * hkl.x, cell_.br * hkl.y, cell_.cr * hkl.z);
64 return std::exp(-2 * pi() * pi() * site.aniso.r_u_r(arh));
65 }
66 double dwf_aniso(const Atom& atom, const Vec3& hkl) const {
67 return std::exp(-2 * pi() * pi() *
68 atom.aniso.transformed_by<>(cell_.frac.mat).r_u_r(hkl));
69 }
70
71 template<typename Site>
72 std::complex<double> calculate_sf_from_atom_sf(const Fractional& fract,
73 const Site& site,
74 const Miller& hkl,
75 double sf) {
76 double oc_sf = site.occ * sf;
77 std::complex<double> sum = calculate_sf_part(fract, hkl);
78 if (!site.aniso.nonzero()) {
79 for (const FTransform& image : cell_.images)
80 sum += calculate_sf_part(image.apply(fract), hkl);
81 return oc_sf * dwf_iso(site) * sum;
82 }
83 Vec3 vhkl(hkl[0], hkl[1], hkl[2]);
84 sum *= dwf_aniso(site, vhkl);
85 for (const FTransform& image : cell_.images)
86 sum += calculate_sf_part(image.apply(fract), hkl) *
87 dwf_aniso(site, image.mat.left_multiply(vhkl));
88 return oc_sf * sum;
89 }
90
91 template<typename Site>
92 std::complex<double> calculate_sf_from_atom(const Fractional& fract,
93 const Site& site,
94 const Miller& hkl) {
95 double atom_sf = get_scattering_factor(site.element, site.charge);
96 return calculate_sf_from_atom_sf(fract, site, hkl, atom_sf);
97 }
98
99 std::complex<double> calculate_sf_from_model(const Model& model, const Miller& hkl) {
100 std::complex<double> sf = 0.;
102 for (const Chain& chain : model.chains)
103 for (const Residue& res : chain.residues)
104 for (const Atom& site : res.atoms)
105 sf += calculate_sf_from_atom(cell_.fractionalize(site.pos), site, hkl);
106 return sf;
107 }
108
109 // Z part of Mott-Bethe formula (when need to use different model)
110 std::complex<double> calculate_mb_z(const Model& model, const Miller& hkl, bool only_h) {
111 std::complex<double> sf = 0.;
112 stol2_ = (coef_type) cell_.calculate_stol_sq(hkl);
113 for (const Chain& chain : model.chains)
114 for (const Residue& res : chain.residues)
115 for (const Atom& site : res.atoms)
116 if (!only_h || site.element.is_hydrogen())
117 sf += calculate_sf_from_atom_sf(cell_.fractionalize(site.pos), site, hkl,
118 -site.element.atomic_number());
119 return sf;
120 }
121
122 double mott_bethe_factor() const {
123 return -mott_bethe_const() / 4 / stol2_;
124 }
125
126 // The occupancy is assumed to take into account symmetry,
127 // i.e. to be fractional if the atom is on special position.
129 const Miller& hkl) {
130 std::complex<double> sf = 0.;
132 for (const SmallStructure::Site& site : small_st.sites)
133 sf += calculate_sf_from_atom(site.fract, site, hkl);
134 return sf;
135 }
136
137private:
138 const UnitCell& cell_;
139 coef_type stol2_;
140 std::vector<double> scattering_factors_;
141public:
142 Addends addends; // usually f' for X-rays
143};
144
145} // namespace gemmi
146#endif
std::complex< double > calculate_sf_from_model(const Model &model, const Miller &hkl)
Definition sfcalc.hpp:99
double dwf_aniso(const SmallStructure::Site &site, const Vec3 &hkl) const
Definition sfcalc.hpp:62
double dwf_iso(const SmallStructure::Site &site) const
Definition sfcalc.hpp:51
double dwf_aniso(const Atom &atom, const Vec3 &hkl) const
Definition sfcalc.hpp:66
std::complex< double > calculate_sf_from_atom(const Fractional &fract, const Site &site, const Miller &hkl)
Definition sfcalc.hpp:92
std::complex< double > calculate_mb_z(const Model &model, const Miller &hkl, bool only_h)
Definition sfcalc.hpp:110
typename Table::Coef::coef_type coef_type
Definition sfcalc.hpp:30
void set_stol2_and_scattering_factors(const Miller &hkl)
Definition sfcalc.hpp:34
double dwf_iso(const Atom &atom) const
Definition sfcalc.hpp:54
std::complex< double > calculate_sf_from_atom_sf(const Fractional &fract, const Site &site, const Miller &hkl, double sf)
Definition sfcalc.hpp:72
StructureFactorCalculator(const UnitCell &cell)
Definition sfcalc.hpp:32
double get_scattering_factor(Element element, signed char charge)
Definition sfcalc.hpp:40
std::complex< double > calculate_sf_from_small_structure(const SmallStructure &small_st, const Miller &hkl)
Definition sfcalc.hpp:128
std::complex< double > calculate_sf_part(const Fractional &fpos, const Miller &hkl)
Definition sfcalc.hpp:21
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
Vec3_< double > Vec3
Definition math.hpp:101
constexpr double pi()
Definition math.hpp:16
void fail(const std::string &msg)
Definition fail.hpp:59
constexpr double u_to_b()
Definition math.hpp:29
size_t size() const
Definition addends.hpp:19
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
float b_iso
Definition model.hpp:126
const char * name() const
Definition elem.hpp:309
int ordinal() const
Definition elem.hpp:301
Like Transform, but apply() arg is Fractional (not Vec3 - for type safety).
Definition unitcell.hpp:112
Fractional coordinates.
Definition unitcell.hpp:50
std::vector< Chain > chains
Definition model.hpp:700
SMat33< Real > transformed_by(const Mat33 &m) const
Definition math.hpp:319
auto r_u_r(const Vec3_< VT > &r) const -> decltype(r.x+u11)
Definition math.hpp:295
Unit cell.
Definition unitcell.hpp:139