Gemmi C++ API
Loading...
Searching...
No Matches
chemcomp.hpp
Go to the documentation of this file.
1// Copyright 2018 Global Phasing Ltd.
2//
3// ChemComp - chemical component that represents a monomer from Refmac
4// monomer library, or from PDB CCD.
5
6#ifndef GEMMI_CHEMCOMP_HPP_
7#define GEMMI_CHEMCOMP_HPP_
8
9#include <string>
10#include <vector>
11#include "cifdoc.hpp"
12#include "elem.hpp" // for Element
13#include "fail.hpp" // for fail, unreachable
14#include "numb.hpp" // for as_number
15#include "util.hpp" // for istarts_with, join_str
16#include "model.hpp" // for Residue, Atom
17
18namespace gemmi {
19
24
25struct Restraints {
26 struct AtomId {
27 int comp;
28 std::string atom;
29
30 bool operator==(const AtomId& o) const {
31 return comp == o.comp && atom == o.atom;
32 }
33 bool operator!=(const AtomId& o) const { return !operator==(o); }
34
35 bool operator==(const std::string& name) const { return atom == name; }
36 bool operator!=(const std::string& name) const { return atom != name; }
37
38 bool operator<(const AtomId& o) const {
39 return comp == o.comp ? atom < o.atom : comp < o.comp;
40 }
41
42 // altloc2 is needed only in rare case when we have a link between
43 // atoms with different altloc (example: 2e7z).
44 Atom* get_from(Residue& res1, Residue* res2, char alt, char altloc2) const {
45 Residue* residue = &res1;
46 if (comp == 2 && res2 != nullptr) {
47 residue = res2;
48 if (altloc2 != '\0')
49 alt = altloc2;
50 }
51 Atom* a = residue->find_atom(atom, alt);
52 // Special case: microheterogeneity may have shared atoms only in
53 // the first residue. Example: in 1ejg N is shared between PRO and SER.
54 if (a == nullptr && alt != '\0' && residue->group_idx > 0)
55 a = (residue - residue->group_idx)->find_atom(atom, alt);
56 return a;
57 }
58 const Atom* get_from(const Residue& res1, const Residue* res2,
59 char alt, char alt2) const {
60 return get_from(const_cast<Residue&>(res1), const_cast<Residue*>(res2), alt, alt2);
61 }
62 };
63
64 static std::string lexicographic_str(const std::string& name1,
65 const std::string& name2) {
66 return name1 < name2 ? cat(name1, '-', name2) : cat(name2, '-', name1);
67 }
68
70
71 struct Bond {
72 static const char* what() { return "bond"; }
76 double value;
77 double esd;
80 std::string str() const { return cat(id1.atom, '-', id2.atom); }
81 std::string lexicographic_str() const {
83 }
84 double distance(DistanceOf of) const {
86 }
87 template<typename T> const AtomId* other(const T& a) const {
88 if (id1 == a) return &id2;
89 if (id2 == a) return &id1;
90 return nullptr;
91 }
92 };
93
94 struct Angle {
95 static const char* what() { return "angle"; }
97 double value; // degrees
98 double esd;
99 double radians() const { return rad(value); }
100 std::string str() const {
101 return cat(id1.atom, '-', id2.atom, '-', id3.atom);
102 }
103 };
104
105 struct Torsion {
106 static const char* what() { return "torsion"; }
107 std::string label;
109 double value;
110 double esd;
112 std::string str() const {
113 return cat(id1.atom, '-', id2.atom, '-', id3.atom, '-', id4.atom);
114 }
115 };
116
117 struct Chirality {
118 static const char* what() { return "chirality"; }
121
122 bool is_wrong(double volume) const {
123 return (sign == ChiralityType::Positive && volume < 0) ||
124 (sign == ChiralityType::Negative && volume > 0);
125 }
126 std::string str() const {
127 return cat(id_ctr.atom, ',', id1.atom, ',', id2.atom, ',', id3.atom);
128 }
129 };
130
131 struct Plane {
132 static const char* what() { return "plane"; }
133 std::string label;
134 std::vector<AtomId> ids;
135 double esd;
136 std::string str() const {
137 return join_str(ids, ',', [](const AtomId& a) { return a.atom; });
138 }
139 };
140
141 std::vector<Bond> bonds;
142 std::vector<Angle> angles;
143 std::vector<Torsion> torsions;
144 std::vector<Chirality> chirs;
145 std::vector<Plane> planes;
146
147 bool empty() const {
148 return bonds.empty() && angles.empty() && torsions.empty() &&
149 chirs.empty() && planes.empty();
150 }
151
152 template<typename T>
153 std::vector<Bond>::iterator find_bond(const T& a1, const T& a2) {
154 return std::find_if(bonds.begin(), bonds.end(), [&](const Bond& b) {
155 return (b.id1 == a1 && b.id2 == a2) || (b.id1 == a2 && b.id2 == a1);
156 });
157 }
158 template<typename T>
159 std::vector<Bond>::const_iterator find_bond(const T& a1, const T& a2) const {
160 return const_cast<Restraints*>(this)->find_bond(a1, a2);
161 }
162 const Bond& get_bond(const AtomId& a1, const AtomId& a2) const {
163 auto it = find_bond(a1, a2);
164 if (it == bonds.end())
165 fail("Bond restraint not found: ", a1.atom, '-', a2.atom);
166 return *it;
167 }
168
169 template<typename T>
170 bool are_bonded(const T& a1, const T& a2) const {
171 return find_bond(a1, a2) != bonds.end();
172 }
173
174 template<typename T>
175 const AtomId* first_bonded_atom(const T& a) const {
176 for (const Bond& bond : bonds)
177 if (const AtomId* other = bond.other(a))
178 return other;
179 return nullptr;
180 }
181
182 // BFS
183 std::vector<AtomId> find_shortest_path(const AtomId& a, const AtomId& b,
184 std::vector<AtomId> visited) const {
185 int start = (int) visited.size();
186 int end = -1;
187 visited.push_back(b);
188 std::vector<int> parent(visited.size(), -1);
189 for (int n = start; end == -1 && n != (int) visited.size(); ++n) {
190 for (const Bond& bond : bonds)
191 if (const AtomId* id = bond.other(visited[n])) {
192 if (*id == a)
193 end = (int) visited.size();
194 if (!in_vector(*id, visited)) {
195 visited.push_back(*id);
196 parent.push_back(n);
197 }
198 }
199 }
200 std::vector<AtomId> path;
201 for (int n = end; n != -1; n = parent[n])
202 path.push_back(visited[n]);
203 return path;
204 }
205
206 template<typename T>
207 std::vector<Angle>::iterator find_angle(const T& a, const T& b, const T& c) {
208 return std::find_if(angles.begin(), angles.end(), [&](const Angle& ang) {
209 return ang.id2 == b && ((ang.id1 == a && ang.id3 == c) ||
210 (ang.id1 == c && ang.id3 == a));
211 });
212 }
213 template<typename T> std::vector<Angle>::const_iterator
214 find_angle(const T& a, const T& b, const T& c) const {
215 return const_cast<Restraints*>(this)->find_angle(a, b, c);
216 }
217 const Angle& get_angle(const AtomId& a, const AtomId& b, const AtomId& c) const {
218 auto it = const_cast<Restraints*>(this)->find_angle(a, b, c);
219 if (it == angles.end())
220 fail("Angle restraint not found: ", a.atom, '-', b.atom, '-', c.atom);
221 return *it;
222 }
223
224 template<typename T>
225 std::vector<Torsion>::iterator find_torsion(const T& a, const T& b,
226 const T& c, const T& d) {
227 return std::find_if(torsions.begin(), torsions.end(),
228 [&](const Torsion& t) {
229 return (t.id1 == a && t.id2 == b && t.id3 == c && t.id4 == d) ||
230 (t.id1 == d && t.id2 == c && t.id3 == b && t.id4 == a);
231 });
232 }
233 template<typename T> std::vector<Torsion>::const_iterator
234 find_torsion(const T& a, const T& b, const T& c, const T& d) const {
235 return const_cast<Restraints*>(this)->find_torsion(a, b, c, d);
236 }
237
238 template<typename T>
239 std::vector<Chirality>::iterator find_chir(const T& ctr, const T& a,
240 const T& b, const T& c) {
241 return std::find_if(chirs.begin(), chirs.end(), [&](const Chirality& t) {
242 return t.id_ctr == ctr && ((t.id1 == a && t.id2 == b && t.id3 == c) ||
243 (t.id1 == b && t.id2 == c && t.id3 == a) ||
244 (t.id1 == c && t.id2 == a && t.id3 == b));
245 });
246 }
247 template<typename T> std::vector<Chirality>::const_iterator
248 find_chir(const T& ctr, const T& a, const T& b, const T& c) const {
249 return const_cast<Restraints*>(this)->find_chir(ctr, a, b, c);
250 }
251
252 double chiral_abs_volume(const Restraints::Chirality& ch) const;
253
254 std::vector<Plane>::iterator get_plane(const std::string& label) {
255 return std::find_if(planes.begin(), planes.end(),
256 [&label](const Plane& p) { return p.label == label; });
257 }
258
259 Plane& get_or_add_plane(const std::string& label) {
260 std::vector<Plane>::iterator it = get_plane(label);
261 if (it != planes.end())
262 return *it;
263 planes.push_back(Plane{label, {}, 0.0});
264 return planes.back();
265 }
266
267 void rename_atom(const AtomId& atom_id, const std::string& new_name) {
268 auto rename_atom = [&](AtomId& id) {
269 if (id == atom_id)
270 id.atom = new_name;
271 };
272 for (Bond& bond : bonds) {
273 rename_atom(bond.id1);
274 rename_atom(bond.id2);
275 }
276 for (Angle& angle : angles) {
277 rename_atom(angle.id1);
278 rename_atom(angle.id2);
279 rename_atom(angle.id3);
280 }
281 for (Torsion& tor : torsions) {
282 rename_atom(tor.id1);
283 rename_atom(tor.id2);
284 rename_atom(tor.id3);
285 rename_atom(tor.id4);
286 }
287 for (Chirality& chir : chirs) {
288 rename_atom(chir.id_ctr);
289 rename_atom(chir.id1);
290 rename_atom(chir.id2);
291 rename_atom(chir.id3);
292 }
293 for (Plane& plane : planes)
294 for (AtomId& id : plane.ids)
295 rename_atom(id);
296 }
297};
298
299template<typename Restr>
300double angle_z(double value_rad, const Restr& restr, double full=360.) {
301 return angle_abs_diff(deg(value_rad), restr.value, full) / restr.esd;
302}
303
304inline double chiral_abs_volume(double bond1, double bond2, double bond3,
305 double angle1, double angle2, double angle3) {
306 double mult = bond1 * bond2 * bond3;
307 double x = 1;
308 double y = 2;
309 for (double a : {angle1, angle2, angle3}) {
310 double cosine = a == 90. ? 0. : std::cos(rad(a));
311 x -= cosine * cosine;
312 y *= cosine;
313 }
314 return mult * std::sqrt(std::max(0., x + y));
315}
316
318 return gemmi::chiral_abs_volume(get_bond(ch.id_ctr, ch.id1).value,
319 get_bond(ch.id_ctr, ch.id2).value,
320 get_bond(ch.id_ctr, ch.id3).value,
321 get_angle(ch.id1, ch.id_ctr, ch.id2).value,
322 get_angle(ch.id2, ch.id_ctr, ch.id3).value,
323 get_angle(ch.id3, ch.id_ctr, ch.id1).value);
324}
325
326struct ChemComp {
327 // Items used in _chem_comp.group and _chem_link.group_comp_N in CCP4.
328 enum class Group {
329 Peptide, // "peptide"
330 PPeptide, // "P-peptide"
331 MPeptide, // "M-peptide"
332 Dna, // "DNA" - used in _chem_comp.group
333 Rna, // "RNA" - used in _chem_comp.group
334 DnaRna, // "DNA/RNA" - used in _chem_link.group_comp_N
335 Pyranose, // "pyranose"
336 Ketopyranose, // "ketopyranose"
337 Furanose, // "furanose"
338 NonPolymer, // "non-polymer"
339 Null
340 };
341
342 struct Atom {
343 std::string id;
344 std::string old_id; // read from _chem_comp_atom.alt_atom_id
346 // _chem_comp_atom.partial_charge can be non-integer,
347 // _chem_comp_atom.charge is always integer (but sometimes has format
348 // '0.000' which is not correct but we ignore it).
349 float charge;
350 std::string chem_type;
352
353 bool is_hydrogen() const { return gemmi::is_hydrogen(el); }
354 };
355
356 struct Aliasing {
358 // pairs of (name in chem_comp, usual name in this group)
359 std::vector<std::pair<std::string, std::string>> related;
360
361 const std::string* name_from_alias(const std::string& atom_id) const {
362 for (const auto& item : related)
363 if (item.second == atom_id)
364 return &item.first;
365 return nullptr;
366 }
367 };
368
369 std::string name;
370 std::string type_or_group; // _chem_comp.type or _chem_comp.group
372 bool has_coordinates = false;
373 std::vector<Atom> atoms;
374 std::vector<Aliasing> aliases;
376
377 const Aliasing& get_aliasing(Group g) const {
378 for (const Aliasing& aliasing : aliases)
379 if (aliasing.group == g)
380 return aliasing;
381 fail("aliasing not found");
382 }
383
384 static Group read_group(const std::string& str) {
385 if (str.size() >= 3) {
386 const char* cstr = str.c_str();
387 if ((str[0] == '\'' || str[0] == '"') && str.size() >= 5)
388 ++cstr;
389 switch (ialpha4_id(cstr)) {
390 case ialpha4_id("non-"): return Group::NonPolymer;
391 case ialpha4_id("pept"): return Group::Peptide;
392 case ialpha4_id("l-pe"): return Group::Peptide;
393 case ialpha4_id("p-pe"): return Group::PPeptide;
394 case ialpha4_id("m-pe"): return Group::MPeptide;
395 case ialpha4_id("dna"): return Group::Dna;
396 case ialpha4_id("rna"): return Group::Rna;
397 case ialpha4_id("dna/"): return Group::DnaRna;
398 case ialpha4_id("pyra"): return Group::Pyranose;
399 case ialpha4_id("keto"): return Group::Ketopyranose;
400 case ialpha4_id("fura"): return Group::Furanose;
401 }
402 }
403 return Group::Null;
404 }
405
406 static const char* group_str(Group g) {
407 switch (g) {
408 case Group::Peptide: return "peptide";
409 case Group::PPeptide: return "P-peptide";
410 case Group::MPeptide: return "M-peptide";
411 case Group::Dna: return "DNA";
412 case Group::Rna: return "RNA";
413 case Group::DnaRna: return "DNA/RNA";
414 case Group::Pyranose: return "pyranose";
415 case Group::Ketopyranose: return "ketopyranose";
416 case Group::Furanose: return "furanose";
417 case Group::NonPolymer: return "non-polymer";
418 case Group::Null: return ".";
419 }
420 unreachable();
421 }
422
423 void set_group(const std::string& s) {
424 type_or_group = s;
425 group = read_group(s);
426 }
427
428 std::vector<Atom>::iterator find_atom(const std::string& atom_id) {
429 return std::find_if(atoms.begin(), atoms.end(),
430 [&](const Atom& a) { return a.id == atom_id; });
431 }
432 std::vector<Atom>::const_iterator find_atom(const std::string& atom_id) const {
433 return const_cast<ChemComp*>(this)->find_atom(atom_id);
434 }
435 bool has_atom(const std::string& atom_id) const {
436 return find_atom(atom_id) != atoms.end();
437 }
438
439 std::vector<Atom>::iterator find_atom_by_old_name(const std::string& old_id) {
440 return std::find_if(atoms.begin(), atoms.end(),
441 [&](const Atom& a) { return a.old_id == old_id; });
442 }
443 std::vector<Atom>::const_iterator find_atom_by_old_name(const std::string& old_id) const {
444 return const_cast<ChemComp*>(this)->find_atom_by_old_name(old_id);
445 }
446 bool has_old_names() const {
447 return std::any_of(atoms.begin(), atoms.end(),
448 [&](const Atom& a) { return !a.old_id.empty() && a.old_id != a.id; });
449 }
450
451 int get_atom_index(const std::string& atom_id) const {
452 auto it = find_atom(atom_id);
453 if (it == atoms.end())
454 fail("Chemical component ", name, " has no atom ", atom_id);
455 return int(it - atoms.begin());
456 }
457
458 const Atom& get_atom(const std::string& atom_id) const {
460 }
461
463 static bool is_peptide_group(Group g) {
464 return g == Group::Peptide || g == Group::PPeptide || g == Group::MPeptide;
465 }
466
469 return g == Group::Dna || g == Group::Rna || g == Group::DnaRna;
470 }
471
474 return !has_atom(x.id1.atom) ||
475 !has_atom(x.id2.atom);
476 });
478 return !has_atom(x.id1.atom) ||
479 !has_atom(x.id2.atom) ||
480 !has_atom(x.id3.atom);
481 });
483 return !has_atom(x.id1.atom) ||
484 !has_atom(x.id2.atom) ||
485 !has_atom(x.id3.atom) ||
486 !has_atom(x.id4.atom);
487 });
489 return !has_atom(x.id_ctr.atom) ||
490 !has_atom(x.id1.atom) ||
491 !has_atom(x.id2.atom) ||
492 !has_atom(x.id3.atom);
493 });
495 vector_remove_if(plane.ids, [&](const Restraints::AtomId& x) {
496 return !has_atom(x.atom);
497 });
498 }
499
502 return a.is_hydrogen();
503 });
505 return *this;
506 }
507};
508
509inline BondType bond_type_from_string(const std::string& s) {
510 if (s.size() >= 3)
511 switch (ialpha4_id(s.c_str())) {
512 case ialpha4_id("sing"): return BondType::Single;
513 case ialpha4_id("doub"): return BondType::Double;
514 case ialpha4_id("trip"): return BondType::Triple;
515 case ialpha4_id("arom"): return BondType::Aromatic;
516 case ialpha4_id("meta"): return BondType::Metal;
517 case ialpha4_id("delo"): return BondType::Deloc;
518 case ialpha4_id("1.5"): return BondType::Deloc; // rarely used
519 // program PDB2TNT produces a restraint file with bond type 'coval'
520 case ialpha4_id("cova"): return BondType::Unspec;
521 }
522 if (cif::is_null(s))
523 return BondType::Unspec;
524 throw std::out_of_range("Unexpected bond type: " + s);
525}
526
527inline const char* bond_type_to_string(BondType btype) {
528 switch (btype) {
529 case BondType::Unspec: return ".";
530 case BondType::Single: return "single";
531 case BondType::Double: return "double";
532 case BondType::Triple: return "triple";
533 case BondType::Aromatic: return "aromatic";
534 case BondType::Deloc: return "deloc";
535 case BondType::Metal: return "metal";
536 }
537 unreachable();
538}
539
541 switch (btype) {
542 case BondType::Single: return 1.0f;
543 case BondType::Double: return 2.0f;
544 case BondType::Triple: return 3.0f;
545 case BondType::Aromatic: return 1.5f;
546 case BondType::Deloc: return 1.5f;
547 case BondType::Metal: return 1.0f;
548 case BondType::Unspec: return 0.0f;
549 }
550 unreachable();
551}
552
553// it doesn't handle crossN types from the monomer library
554inline ChiralityType chirality_from_string(const std::string& s) {
555 switch (s[0] | 0x20) {
556 case 'p': return ChiralityType::Positive;
557 case 'n': return ChiralityType::Negative;
558 case 'b': return ChiralityType::Both;
559 case '.': return ChiralityType::Both;
560 default: throw std::out_of_range("Unexpected chirality: " + s);
561 }
562}
563
565 double volume) {
566 switch (s[0] | 0x20) {
567 case 's': return volume > 0 ? ChiralityType::Positive
569 case 'n': return ChiralityType::Both;
570 default: throw std::out_of_range("Unexpected volume_flag: " + s);
571 }
572}
573
575 switch (chir_type) {
576 case ChiralityType::Positive: return "positive";
577 case ChiralityType::Negative: return "negative";
578 case ChiralityType::Both: return "both";
579 }
580 unreachable();
581}
582
584 ChemComp cc;
585 cc.name = block_.name.substr(starts_with(block_.name, "comp_") ? 5 : 0);
586 cif::Block& block = const_cast<cif::Block&>(block_);
587 // CCD uses _chem_comp.type, monomer libraries use .group in a separate block
588 // named comp_list, but it'd be a better idea to have _chem_comp.group in the
589 // same block, so we try read it.
590 if (cif::Column group_col = block.find_values("_chem_comp.group"))
591 cc.set_group(group_col.str(0));
592 else if (cif::Column type_col = block.find_values("_chem_comp.type"))
593 cc.type_or_group = type_col.str(0);
594 for (auto row : block.find("_chem_comp_atom.",
595 {"atom_id", "type_symbol", "?type_energy",
596 "?charge", "?partial_charge", "?alt_atom_id"}))
597 cc.atoms.push_back({row.str(0),
598 row.has(5) ? row.str(5) : "",
599 Element(row.str(1)),
600 (float) cif::as_number(row.one_of(3, 4), 0.0),
601 row.has(2) ? row.str(2) : "",
602 Position()});
603 for (auto row : block.find("_chem_comp_bond.",
604 {"atom_id_1", "atom_id_2", // 0, 1
605 "?type", "?value_order", // 2, 3
606 "?aromatic", "?pdbx_aromatic_flag", // 4, 5
607 "?value_dist", "?value_dist_esd", // 6, 7
608 "?value_dist_nucleus", "?value_dist_nucleus_esd"})) { // 8, 9
609 bool aromatic_flag = (row.one_of(4, 5)[0] | 0x20) == 'y';
610 double dist = row.has(6) ? cif::as_number(row[6]) : NAN;
611 double esd = row.has(7) ? cif::as_number(row[7]) : NAN;
612 double dist_nucl = row.has(8) ? cif::as_number(row[8]) : NAN;
613 double esd_nucl = row.has(9) ? cif::as_number(row[9]) : NAN;
614 cc.rt.bonds.push_back({{1, row.str(0)}, {1, row.str(1)},
615 bond_type_from_string(row.one_of(2, 3)),
616 aromatic_flag, dist, esd, dist_nucl, esd_nucl});
617 }
618 for (auto row : block.find("_chem_comp_angle.",
619 {"atom_id_1", "atom_id_2", "atom_id_3",
620 "value_angle", "value_angle_esd"}))
621 cc.rt.angles.push_back({{1, row.str(0)}, {1, row.str(1)}, {1, row.str(2)},
623 for (auto row : block.find("_chem_comp_tor.",
624 {"id",
625 "atom_id_1", "atom_id_2",
626 "atom_id_3", "atom_id_4",
627 "value_angle", "value_angle_esd",
628 "period"}))
629 cc.rt.torsions.push_back({row.str(0),
630 {1, row.str(1)}, {1, row.str(2)},
631 {1, row.str(3)}, {1, row.str(4)},
633 cif::as_int(row[7])});
634 for (auto row : block.find("_chem_comp_chir.",
635 {"atom_id_centre",
636 "atom_id_1", "atom_id_2", "atom_id_3",
637 "volume_sign"}))
638 if (row[4][0] != 'c') // ignore crossN
639 cc.rt.chirs.push_back({{1, row.str(0)},
640 {1, row.str(1)}, {1, row.str(2)}, {1, row.str(3)},
642 // mmCIF compliant
643 cif::Table chir_tab = block.find("_chem_comp_chir_atom.",
644 {"chir_id", "atom_id"});
645 if (chir_tab.ok()) {
646 std::map<std::string, std::vector<std::string>> chir_atoms;
647 for (auto chir : chir_tab)
649 for (auto row : block.find("_chem_comp_chir.",
650 {"id", "atom_id", "volume_flag", "volume_three"})) {
651 auto atoms = chir_atoms.find(row.str(0));
652 if (atoms != chir_atoms.end() && atoms->second.size() == 3)
653 cc.rt.chirs.push_back({{1, row.str(1)},
654 {1, atoms->second[0]}, {1, atoms->second[1]},
655 {1, atoms->second[2]},
657 cif::as_number(row[3]))});
658 }
659 }
660 for (auto row : block.find("_chem_comp_plane_atom.",
661 {"plane_id", "atom_id" , "dist_esd"})) {
662 Restraints::Plane& plane = cc.rt.get_or_add_plane(row.str(0));
663 if (plane.esd == 0.0)
664 plane.esd = cif::as_number(row[2]);
665 plane.ids.push_back({1, row.str(1)});
666 }
667 for (auto row : block.find("_chem_comp_alias.",
668 {"group", "atom_id", "atom_id_standard"})) {
669 ChemComp::Group group = ChemComp::read_group(row.str(0));
670 if (cc.aliases.empty() || cc.aliases.back().group != group) {
671 cc.aliases.emplace_back();
672 cc.aliases.back().group = group;
673 }
674 cc.aliases.back().related.emplace_back(row.str(1), row.str(2));
675 }
676
677 return cc;
678}
679
680} // namespace gemmi
681#endif
double as_number(const std::string &s, double nan=NAN)
Definition numb.hpp:19
bool is_null(const std::string &value)
Definition cifdoc.hpp:77
int as_int(const std::string &str)
Definition cifdoc.hpp:108
void vector_remove_if(std::vector< T > &v, F &&condition)
Definition util.hpp:266
double chiral_abs_volume(double bond1, double bond2, double bond3, double angle1, double angle2, double angle3)
Definition chemcomp.hpp:304
constexpr double deg(double angle)
Definition math.hpp:31
bool is_hydrogen(El el)
Definition elem.hpp:26
ChemComp make_chemcomp_from_block(const cif::Block &block_)
Definition chemcomp.hpp:583
const char * chirality_to_string(ChiralityType chir_type)
Definition chemcomp.hpp:574
ChiralityType chirality_from_flag_and_volume(const std::string &s, double volume)
Definition chemcomp.hpp:564
std::string join_str(T begin, T end, const S &sep, const F &getter)
Definition util.hpp:182
bool in_vector(const T &x, const std::vector< T > &v)
Definition util.hpp:241
double angle_abs_diff(double a, double b, double full=360.0)
Definition math.hpp:39
constexpr double rad(double angle)
Definition math.hpp:32
std::string cat(Args const &... args)
Definition util.hpp:32
const char * bond_type_to_string(BondType btype)
Definition chemcomp.hpp:527
double angle_z(double value_rad, const Restr &restr, double full=360.)
Definition chemcomp.hpp:300
bool starts_with(const std::string &str, const std::string &prefix)
Definition util.hpp:38
void fail(const std::string &msg)
Definition fail.hpp:59
ChiralityType
Definition chemcomp.hpp:23
float order_of_bond_type(BondType btype)
Definition chemcomp.hpp:540
void unreachable()
Definition fail.hpp:80
ChiralityType chirality_from_string(const std::string &s)
Definition chemcomp.hpp:554
constexpr int ialpha4_id(const char *s)
Definition util.hpp:305
BondType bond_type_from_string(const std::string &s)
Definition chemcomp.hpp:509
Represents atom site in macromolecular structure (~100 bytes).
Definition model.hpp:112
const std::string * name_from_alias(const std::string &atom_id) const
Definition chemcomp.hpp:361
std::vector< std::pair< std::string, std::string > > related
Definition chemcomp.hpp:359
bool is_hydrogen() const
Definition chemcomp.hpp:353
std::string chem_type
Definition chemcomp.hpp:350
void set_group(const std::string &s)
Definition chemcomp.hpp:423
ChemComp & remove_hydrogens()
Definition chemcomp.hpp:500
std::string name
Definition chemcomp.hpp:369
int get_atom_index(const std::string &atom_id) const
Definition chemcomp.hpp:451
std::vector< Atom >::const_iterator find_atom(const std::string &atom_id) const
Definition chemcomp.hpp:432
bool has_old_names() const
Definition chemcomp.hpp:446
Restraints rt
Definition chemcomp.hpp:375
static const char * group_str(Group g)
Definition chemcomp.hpp:406
std::vector< Atom >::iterator find_atom_by_old_name(const std::string &old_id)
Definition chemcomp.hpp:439
const Aliasing & get_aliasing(Group g) const
Definition chemcomp.hpp:377
void remove_nonmatching_restraints()
Definition chemcomp.hpp:472
std::vector< Atom >::const_iterator find_atom_by_old_name(const std::string &old_id) const
Definition chemcomp.hpp:443
static Group read_group(const std::string &str)
Definition chemcomp.hpp:384
const Atom & get_atom(const std::string &atom_id) const
Definition chemcomp.hpp:458
std::vector< Atom > atoms
Definition chemcomp.hpp:373
static bool is_nucleotide_group(Group g)
Check if the group is DNA/RNA.
Definition chemcomp.hpp:468
bool has_atom(const std::string &atom_id) const
Definition chemcomp.hpp:435
std::vector< Aliasing > aliases
Definition chemcomp.hpp:374
std::string type_or_group
Definition chemcomp.hpp:370
std::vector< Atom >::iterator find_atom(const std::string &atom_id)
Definition chemcomp.hpp:428
static bool is_peptide_group(Group g)
Check if the group (M-|P-)peptide.
Definition chemcomp.hpp:463
Coordinates in Angstroms - orthogonal (Cartesian) coordinates.
Definition unitcell.hpp:32
Atom * find_atom(const std::string &atom_name, char altloc, El el=El::X)
Definition model.hpp:215
short group_idx
Definition model.hpp:187
double radians() const
Definition chemcomp.hpp:99
std::string str() const
Definition chemcomp.hpp:100
static const char * what()
Definition chemcomp.hpp:95
bool operator<(const AtomId &o) const
Definition chemcomp.hpp:38
const Atom * get_from(const Residue &res1, const Residue *res2, char alt, char alt2) const
Definition chemcomp.hpp:58
bool operator==(const AtomId &o) const
Definition chemcomp.hpp:30
bool operator!=(const std::string &name) const
Definition chemcomp.hpp:36
Atom * get_from(Residue &res1, Residue *res2, char alt, char altloc2) const
Definition chemcomp.hpp:44
bool operator==(const std::string &name) const
Definition chemcomp.hpp:35
bool operator!=(const AtomId &o) const
Definition chemcomp.hpp:33
static const char * what()
Definition chemcomp.hpp:72
std::string str() const
Definition chemcomp.hpp:80
double distance(DistanceOf of) const
Definition chemcomp.hpp:84
const AtomId * other(const T &a) const
Definition chemcomp.hpp:87
std::string lexicographic_str() const
Definition chemcomp.hpp:81
static const char * what()
Definition chemcomp.hpp:118
bool is_wrong(double volume) const
Definition chemcomp.hpp:122
std::string str() const
Definition chemcomp.hpp:126
std::vector< AtomId > ids
Definition chemcomp.hpp:134
std::string str() const
Definition chemcomp.hpp:136
static const char * what()
Definition chemcomp.hpp:132
static const char * what()
Definition chemcomp.hpp:106
std::string str() const
Definition chemcomp.hpp:112
std::vector< Chirality >::const_iterator find_chir(const T &ctr, const T &a, const T &b, const T &c) const
Definition chemcomp.hpp:248
bool are_bonded(const T &a1, const T &a2) const
Definition chemcomp.hpp:170
std::vector< Bond >::iterator find_bond(const T &a1, const T &a2)
Definition chemcomp.hpp:153
std::vector< Bond > bonds
Definition chemcomp.hpp:141
bool empty() const
Definition chemcomp.hpp:147
std::vector< Bond >::const_iterator find_bond(const T &a1, const T &a2) const
Definition chemcomp.hpp:159
void rename_atom(const AtomId &atom_id, const std::string &new_name)
Definition chemcomp.hpp:267
const AtomId * first_bonded_atom(const T &a) const
Definition chemcomp.hpp:175
std::vector< Plane >::iterator get_plane(const std::string &label)
Definition chemcomp.hpp:254
std::vector< Torsion >::const_iterator find_torsion(const T &a, const T &b, const T &c, const T &d) const
Definition chemcomp.hpp:234
std::vector< Chirality > chirs
Definition chemcomp.hpp:144
std::vector< Torsion >::iterator find_torsion(const T &a, const T &b, const T &c, const T &d)
Definition chemcomp.hpp:225
std::vector< Angle >::iterator find_angle(const T &a, const T &b, const T &c)
Definition chemcomp.hpp:207
const Bond & get_bond(const AtomId &a1, const AtomId &a2) const
Definition chemcomp.hpp:162
std::vector< Angle >::const_iterator find_angle(const T &a, const T &b, const T &c) const
Definition chemcomp.hpp:214
std::vector< Angle > angles
Definition chemcomp.hpp:142
Plane & get_or_add_plane(const std::string &label)
Definition chemcomp.hpp:259
std::vector< AtomId > find_shortest_path(const AtomId &a, const AtomId &b, std::vector< AtomId > visited) const
Definition chemcomp.hpp:183
std::vector< Plane > planes
Definition chemcomp.hpp:145
std::vector< Torsion > torsions
Definition chemcomp.hpp:143
const Angle & get_angle(const AtomId &a, const AtomId &b, const AtomId &c) const
Definition chemcomp.hpp:217
static std::string lexicographic_str(const std::string &name1, const std::string &name2)
Definition chemcomp.hpp:64
std::vector< Chirality >::iterator find_chir(const T &ctr, const T &a, const T &b, const T &c)
Definition chemcomp.hpp:239
double chiral_abs_volume(const Restraints::Chirality &ch) const
Definition chemcomp.hpp:317
Column find_values(const std::string &tag)
Definition cifdoc.hpp:848
Table find(const std::string &prefix, const std::vector< std::string > &tags)
Definition cifdoc.hpp:961