Gemmi C++ API
Loading...
Searching...
No Matches
calculate.hpp
Go to the documentation of this file.
1// Copyright 2017-2018 Global Phasing Ltd.
2//
3// Calculate various properties of the model.
4
5#ifndef GEMMI_CALCULATE_HPP_
6#define GEMMI_CALCULATE_HPP_
7
8#include <array>
9#include <algorithm> // for std::min, std::minmax
10#include "model.hpp"
11#include "select.hpp"
12
13namespace gemmi {
14
15template<class T> bool has_hydrogen(const T& obj) {
16 for (const auto& child : obj.children())
18 return true;
19 return false;
20}
21template<> inline bool has_hydrogen(const Atom& atom) {
22 return atom.is_hydrogen();
23}
24
25template<class T> size_t count_atom_sites(const T& obj, const Selection* sel=nullptr) {
26 size_t sum = 0;
27 if (!sel || sel->matches(obj))
28 for (const auto& child : obj.children())
29 sum += count_atom_sites(child, sel);
30 return sum;
31}
32template<> inline size_t count_atom_sites(const Atom& atom, const Selection* sel) {
33 return (!sel || sel->matches(atom)) ? 1 : 0;
34}
35
36template<class T> double count_occupancies(const T& obj, const Selection* sel=nullptr) {
37 double sum = 0;
38 if (!sel || sel->matches(obj))
39 for (const auto& child : obj.children())
41 return sum;
42}
43template<> inline double count_occupancies(const Atom& atom, const Selection* sel) {
44 return (!sel || sel->matches(atom)) ? atom.occ : 0;
45}
46
47
48template<class T> double calculate_mass(const T& obj) {
49 double sum = 0;
50 for (const auto& child : obj.children())
51 sum += calculate_mass(child);
52 return sum;
53}
54template<> inline double calculate_mass(const Atom& atom) {
55 return atom.occ * atom.element.weight();
56}
57
63
64template<class T> CenterOfMass calculate_center_of_mass(const T& obj) {
65 CenterOfMass total{{}, 0.};
66 for (const auto& child : obj.children()) {
68 total = {total.weighted_sum + part.weighted_sum, total.mass + part.mass};
69 }
70 return total;
71}
72template<> inline CenterOfMass calculate_center_of_mass(const Atom& atom) {
73 double w_mass = atom.element.weight() * atom.occ;
74 return CenterOfMass{Position(atom.pos * w_mass), w_mass};
75}
76
77template<class T> std::pair<float,float> calculate_b_iso_range(const T& obj) {
78 std::pair<float, float> range{INFINITY, -INFINITY};
79 for (const auto& child : obj.children()) {
81 range.first = std::min(range.first, r.first);
82 range.second = std::max(range.second, r.second);
83 }
84 return range;
85}
86template<> inline std::pair<float,float> calculate_b_iso_range(const Atom& atom) {
87 return {atom.b_iso, atom.b_iso};
88}
89
91inline std::pair<double, double> calculate_b_aniso_range(const Model& model) {
92 std::pair<double, double> range{INFINITY, -INFINITY};
93 for (const Chain& chain : model.chains)
94 for (const Residue& residue : chain.residues)
95 for (const Atom& atom : residue.atoms) {
96 if (atom.occ == 0)
97 continue;
98 if (atom.aniso.nonzero()) {
99 std::array<double,3> eig = atom.aniso.calculate_eigenvalues();
100 auto u = std::minmax({eig[0], eig[1], eig[2]});
101 range.first = std::min(range.first, u.first * u_to_b());
102 range.second = std::max(range.second, u.second * u_to_b());
103 } else {
104 range.first = std::min(range.first, (double) atom.b_iso);
105 range.second = std::max(range.second, (double) atom.b_iso);
106 }
107 }
108 return range;
109}
110
111
112template<class T> void expand_box(const T& obj, Box<Position>& box) {
113 for (const auto& child : obj.children())
115}
116template<> inline void expand_box(const Atom& atom, Box<Position>& box) {
117 box.extend(atom.pos);
118}
119
120// we don't take NCS into account here (cf. NeighborSearch::set_bounding_cell())
121inline Box<Position> calculate_box(const Structure& st, double margin=0.) {
123 expand_box(st, box);
124 if (margin != 0.)
125 box.add_margin(margin);
126 return box;
127}
128
130 if (!st.cell.is_crystal())
131 fail("calculate_fractional_box(): Structure has no unit cell for fractionalization");
133 for (const Model& model : st.models)
134 for (const Chain& chain : model.chains)
135 for (const Residue& res : chain.residues)
136 for (const Atom& atom : res.atoms)
137 box.extend(st.cell.fractionalize(atom.pos));
138 if (margin != 0.)
139 box.add_margins({margin * st.cell.ar, margin * st.cell.br, margin * st.cell.cr});
140 return box;
141}
142
143
144// Calculate B_est from E. Merritt, Some B_eq are more equivalent than others,
145// Acta Cryst. A67, 512 (2011)
146// http://skuld.bmsc.washington.edu/parvati/ActaA_67_512.pdf
147inline double calculate_b_est(const Atom& atom) {
148 auto eig = atom.aniso.calculate_eigenvalues();
149 return u_to_b() * std::sqrt((eig[0] + eig[1] + eig[2]) /
150 (1/eig[0] + 1/eig[1] + 1/eig[2]));
151}
152
153inline double calculate_angle(const Position& p0, const Position& p1,
154 const Position& p2) {
155 return (p0 - p1).angle(p2 - p1);
156}
157
158// discussion: https://stackoverflow.com/questions/20305272/
159inline double calculate_dihedral(const Position& p0, const Position& p1,
160 const Position& p2, const Position& p3) {
161 Vec3 b0 = p1 - p0;
162 Vec3 b1 = p2 - p1;
163 Vec3 b2 = p3 - p2;
164 Vec3 u = b1.cross(b0);
165 Vec3 w = b2.cross(b1);
166 double y = u.cross(w).dot(b1);
167 double x = u.dot(w) * b1.length();
168 return std::atan2(y, x);
169}
170
172inline double calculate_dihedral_from_atoms(const Atom* a, const Atom* b,
173 const Atom* c, const Atom* d) {
174 if (a && b && c && d)
175 return calculate_dihedral(a->pos, b->pos, c->pos, d->pos);
176 return NAN;
177}
178
179inline double calculate_omega(const Residue& res, const Residue& next) {
180 return calculate_dihedral_from_atoms(res.get_ca(), res.get_c(),
181 next.get_n(), next.get_ca());
182}
183
184inline bool is_peptide_bond_cis(const Atom* ca1, const Atom* c,
185 const Atom* n, const Atom* ca2,
186 double tolerance_deg) {
188 return std::fabs(omega) < rad(tolerance_deg);
189}
190
191inline double calculate_chiral_volume(const Position& actr, const Position& a1,
192 const Position& a2, const Position& a3) {
193 return (a1 - actr).dot((a2 - actr).cross(a3 - actr));
194}
195
196inline std::array<double, 2> calculate_phi_psi(const Residue* prev,
197 const Residue& res,
198 const Residue* next) {
199 std::array<double, 2> phi_psi{{NAN, NAN}};
200 if (prev || next) {
201 const Atom* CA = res.get_ca();
202 const Atom* C = res.get_c();
203 const Atom* N = res.get_n();
204 if (prev)
206 if (next)
208 }
209 return phi_psi;
210}
211
212GEMMI_DLL std::array<double, 4> find_best_plane(const std::vector<Atom*>& atoms);
213
214inline double get_distance_from_plane(const Position& pos,
215 const std::array<double, 4>& coeff) {
216 return coeff[0] * pos.x + coeff[1] * pos.y + coeff[2] * pos.z + coeff[3];
217}
218
220
222
223} // namespace gemmi
224#endif
#define GEMMI_DLL
Definition fail.hpp:53
Data structures to store macromolecular structure models.
double calculate_b_est(const Atom &atom)
double calculate_mass(const T &obj)
Definition calculate.hpp:48
double calculate_chiral_volume(const Position &actr, const Position &a1, const Position &a2, const Position &a3)
CenterOfMass calculate_center_of_mass(const T &obj)
Definition calculate.hpp:64
void expand_box(const T &obj, Box< Position > &box)
double calculate_omega(const Residue &res, const Residue &next)
Box< Position > calculate_box(const Structure &st, double margin=0.)
GEMMI_DLL std::array< double, 4 > find_best_plane(const std::vector< Atom * > &atoms)
double get_distance_from_plane(const Position &pos, const std::array< double, 4 > &coeff)
double calculate_dihedral(const Position &p0, const Position &p1, const Position &p2, const Position &p3)
double count_occupancies(const T &obj, const Selection *sel=nullptr)
Definition calculate.hpp:36
bool has_hydrogen(const T &obj)
Definition calculate.hpp:15
double calculate_angle(const Position &p0, const Position &p1, const Position &p2)
Box< Fractional > calculate_fractional_box(const Structure &st, double margin=0.)
constexpr double rad(double angle)
Definition math.hpp:32
bool is_peptide_bond_cis(const Atom *ca1, const Atom *c, const Atom *n, const Atom *ca2, double tolerance_deg)
GEMMI_DLL FTransform parse_triplet_as_ftransform(const std::string &s)
Vec3_< double > Vec3
Definition math.hpp:113
std::array< double, 2 > calculate_phi_psi(const Residue *prev, const Residue &res, const Residue *next)
std::pair< double, double > calculate_b_aniso_range(const Model &model)
uses min/max eigenvalues of Baniso, or Biso if B-factor is isotropic
Definition calculate.hpp:91
GEMMI_DLL SMat33< double > calculate_u_from_tls(const TlsGroup &tls, const Position &pos)
void fail(const std::string &msg)
Definition fail.hpp:59
double calculate_dihedral_from_atoms(const Atom *a, const Atom *b, const Atom *c, const Atom *d)
the return value is in the same range as that of atan2(), i.e. [-pi, pi]
std::pair< float, float > calculate_b_iso_range(const T &obj)
Definition calculate.hpp:77
constexpr double u_to_b()
Definition math.hpp:29
size_t count_atom_sites(const T &obj, const Selection *sel=nullptr)
Definition calculate.hpp:25
Selections.
Represents atom site in macromolecular structure (~100 bytes).
Definition model.hpp:120
SMat33< float > aniso
Definition model.hpp:135
bool is_hydrogen() const
Definition model.hpp:148
float b_iso
Definition model.hpp:134
Element element
Definition model.hpp:125
float occ
Definition model.hpp:132
Position pos
Definition model.hpp:131
Position get() const
Definition calculate.hpp:61
double weight() const
Definition elem.hpp:311
Like Transform, but apply() arg is Fractional (not Vec3 - for type safety).
Definition unitcell.hpp:112
std::vector< Chain > chains
Definition model.hpp:722
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
Definition unitcell.hpp:32
const Atom * get_ca() const
Definition model.hpp:262
const Atom * get_c() const
Definition model.hpp:263
const Atom * get_n() const
Definition model.hpp:264
std::array< double, 3 > calculate_eigenvalues() const
Based on https://en.wikipedia.org/wiki/Eigenvalue_algorithm To calculate both eigenvalues and eigenve...
Definition math.hpp:373