Xmipp  v3.23.11-Nereus
compound.cpp
Go to the documentation of this file.
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020-2022 NKI/AVL, Netherlands Cancer Institute
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "cif++.hpp"
28 
29 #include <filesystem>
30 #include <fstream>
31 #include <map>
32 #include <mutex>
33 #include <numeric>
34 #include <shared_mutex>
35 
36 namespace fs = std::filesystem;
37 
38 namespace cif
39 {
40 
41 // --------------------------------------------------------------------
42 
43 std::string to_string(bond_type bondType)
44 {
45  switch (bondType)
46  {
47  case bond_type::sing: return "sing";
48  case bond_type::doub: return "doub";
49  case bond_type::trip: return "trip";
50  case bond_type::quad: return "quad";
51  case bond_type::arom: return "arom";
52  case bond_type::poly: return "poly";
53  case bond_type::delo: return "delo";
54  case bond_type::pi: return "pi";
55  }
56  throw std::invalid_argument("Invalid bondType");
57 }
58 
59 bond_type from_string(const std::string &bondType)
60 {
61  if (cif::iequals(bondType, "sing"))
62  return bond_type::sing;
63  if (cif::iequals(bondType, "doub"))
64  return bond_type::doub;
65  if (cif::iequals(bondType, "trip"))
66  return bond_type::trip;
67  if (cif::iequals(bondType, "quad"))
68  return bond_type::quad;
69  if (cif::iequals(bondType, "arom"))
70  return bond_type::arom;
71  if (cif::iequals(bondType, "poly"))
72  return bond_type::poly;
73  if (cif::iequals(bondType, "delo"))
74  return bond_type::delo;
75  if (cif::iequals(bondType, "pi"))
76  return bond_type::pi;
77  throw std::invalid_argument("Invalid bondType: " + bondType);
78 }
79 
80 // --------------------------------------------------------------------
81 // compound helper classes
82 
84 {
85  bool operator()(const compound_atom &a, const compound_atom &b) const
86  {
87  int d = a.id.compare(b.id);
88  if (d == 0)
89  d = a.type_symbol - b.type_symbol;
90  return d < 0;
91  }
92 };
93 
95 {
96  bool operator()(const compound_bond &a, const compound_bond &b) const
97  {
98  int d = a.atom_id[0].compare(b.atom_id[0]);
99  if (d == 0)
100  d = a.atom_id[1].compare(b.atom_id[1]);
101  if (d == 0)
102  d = static_cast<int>(a.type) - static_cast<int>(b.type);
103  return d < 0;
104  }
105 };
106 
107 // --------------------------------------------------------------------
108 // compound
109 
110 compound::compound(cif::datablock &db)
111 {
112  auto &chemComp = db["chem_comp"];
113 
114  if (chemComp.size() != 1)
115  throw std::runtime_error("Invalid compound file, chem_comp should contain a single row");
116 
117  cif::tie(m_id, m_name, m_type, m_formula, m_formula_weight, m_formal_charge) =
118  chemComp.front().get("id", "name", "type", "formula", "formula_weight", "pdbx_formal_charge");
119 
120  // The name should not contain newline characters since that triggers validation errors later on
121  cif::replace_all(m_name, "\n", "");
122 
123  m_group = "non-polymer";
124 
125  auto &chemCompAtom = db["chem_comp_atom"];
126  for (auto row : chemCompAtom)
127  {
128  compound_atom atom;
129  std::string type_symbol;
130  cif::tie(atom.id, type_symbol, atom.charge, atom.aromatic, atom.leaving_atom, atom.stereo_config, atom.x, atom.y, atom.z) =
131  row.get("atom_id", "type_symbol", "charge", "pdbx_aromatic_flag", "pdbx_leaving_atom_flag", "pdbx_stereo_config",
132  "model_Cartn_x", "model_Cartn_y", "model_Cartn_z");
133  atom.type_symbol = atom_type_traits(type_symbol).type();
134  m_atoms.push_back(std::move(atom));
135  }
136 
137  auto &chemCompBond = db["chem_comp_bond"];
138  for (auto row : chemCompBond)
139  {
140  compound_bond bond;
141  std::string valueOrder;
142  cif::tie(bond.atom_id[0], bond.atom_id[1], valueOrder, bond.aromatic, bond.stereo_config) = row.get("atom_id_1", "atom_id_2", "value_order", "pdbx_aromatic_flag", "pdbx_stereo_config");
143  bond.type = from_string(valueOrder);
144  m_bonds.push_back(std::move(bond));
145  }
146 }
147 
148 compound::compound(cif::datablock &db, const std::string &id, const std::string &name, const std::string &type, const std::string &group)
149  : m_id(id)
150  , m_name(name)
151  , m_type(type)
152  , m_group(group)
153 {
154  auto &chemCompAtom = db["chem_comp_atom"];
155  for (auto row : chemCompAtom)
156  {
157  compound_atom atom;
158  std::string type_symbol;
159  cif::tie(atom.id, type_symbol, atom.charge, atom.x, atom.y, atom.z) =
160  row.get("atom_id", "type_symbol", "charge", "x", "y", "z");
161  atom.type_symbol = atom_type_traits(type_symbol).type();
162 
163  m_formal_charge += atom.charge;
164  m_formula_weight += atom_type_traits(atom.type_symbol).weight();
165 
166  m_atoms.push_back(std::move(atom));
167  }
168 
169  auto &chemCompBond = db["chem_comp_bond"];
170  for (auto row : chemCompBond)
171  {
172  compound_bond bond;
173  std::string btype;
174  cif::tie(bond.atom_id[0], bond.atom_id[1], btype, bond.aromatic) = row.get("atom_id_1", "atom_id_2", "type", "aromatic");
175 
176  using cif::iequals;
177 
178  if (iequals(btype, "single"))
179  bond.type = bond_type::sing;
180  else if (iequals(btype, "double"))
181  bond.type = bond_type::doub;
182  else if (iequals(btype, "triple"))
183  bond.type = bond_type::trip;
184  else if (iequals(btype, "deloc") or iequals(btype, "aromat") or iequals(btype, "aromatic"))
185  bond.type = bond_type::delo;
186  else
187  {
188  if (cif::VERBOSE > 0)
189  std::cerr << "Unimplemented chem_comp_bond.type " << btype << " in " << id << std::endl;
190  bond.type = bond_type::sing;
191  }
192  m_bonds.push_back(std::move(bond));
193  }
194 }
195 
196 compound_atom compound::get_atom_by_atom_id(const std::string &atom_id) const
197 {
198  compound_atom result = {};
199  for (auto &a : m_atoms)
200  {
201  if (a.id == atom_id)
202  {
203  result = a;
204  break;
205  }
206  }
207 
208  if (result.id != atom_id)
209  throw std::out_of_range("No atom " + atom_id + " in compound " + m_id);
210 
211  return result;
212 }
213 
214 bool compound::atoms_bonded(const std::string &atomId_1, const std::string &atomId_2) const
215 {
216  auto i = find_if(m_bonds.begin(), m_bonds.end(),
217  [&](const compound_bond &b)
218  {
219  return (b.atom_id[0] == atomId_1 and b.atom_id[1] == atomId_2) or (b.atom_id[0] == atomId_2 and b.atom_id[1] == atomId_1);
220  });
221 
222  return i != m_bonds.end();
223 }
224 
225 float compound::bond_length(const std::string &atomId_1, const std::string &atomId_2) const
226 {
227  auto i = find_if(m_bonds.begin(), m_bonds.end(),
228  [&](const compound_bond &b)
229  {
230  return (b.atom_id[0] == atomId_1 and b.atom_id[1] == atomId_2) or (b.atom_id[0] == atomId_2 and b.atom_id[1] == atomId_1);
231  });
232 
233  float result = std::numeric_limits<float>::max();
234 
235  if (i != m_bonds.end())
236  {
237  auto a = get_atom_by_atom_id(atomId_1);
238  auto b = get_atom_by_atom_id(atomId_2);
239 
240  result = distance(point{a.x, a.y, a.z}, point{b.x, b.y, b.z});
241  }
242 
243  return result;
244 }
245 
246 
247 // --------------------------------------------------------------------
248 // known amino acids and bases
249 
250 const std::map<std::string, char> compound_factory::kAAMap{
251  { "ALA", 'A' },
252  { "ARG", 'R' },
253  { "ASN", 'N' },
254  { "ASP", 'D' },
255  { "CYS", 'C' },
256  { "GLN", 'Q' },
257  { "GLU", 'E' },
258  { "GLY", 'G' },
259  { "HIS", 'H' },
260  { "ILE", 'I' },
261  { "LEU", 'L' },
262  { "LYS", 'K' },
263  { "MET", 'M' },
264  { "PHE", 'F' },
265  { "PRO", 'P' },
266  { "SER", 'S' },
267  { "THR", 'T' },
268  { "TRP", 'W' },
269  { "TYR", 'Y' },
270  { "VAL", 'V' },
271  { "GLX", 'Z' },
272  { "ASX", 'B' }
273 };
274 
275 const std::map<std::string, char> compound_factory::kBaseMap{
276  { "A", 'A' },
277  { "C", 'C' },
278  { "G", 'G' },
279  { "T", 'T' },
280  { "U", 'U' },
281  { "DA", 'A' },
282  { "DC", 'C' },
283  { "DG", 'G' },
284  { "DT", 'T' }
285 };
286 
287 // --------------------------------------------------------------------
288 // a factory class to generate compounds
289 
290 class compound_factory_impl : public std::enable_shared_from_this<compound_factory_impl>
291 {
292  public:
293  compound_factory_impl(std::shared_ptr<compound_factory_impl> next);
294 
295  compound_factory_impl(const fs::path &file, std::shared_ptr<compound_factory_impl> next);
296 
298  {
299  for (auto c : m_compounds)
300  delete c;
301  }
302 
303  compound *get(std::string id)
304  {
305  cif::to_upper(id);
306 
307  std::shared_lock lock(mMutex);
308 
309  compound *result = nullptr;
310 
311  // walk the list, see if any of us has the compound already
312  for (auto impl = shared_from_this(); impl; impl = impl->m_next)
313  {
314  for (auto cmp : impl->m_compounds)
315  {
316  if (cmp->id() == id)
317  {
318  result = cmp;
319  break;
320  }
321  }
322 
323  if (result)
324  break;
325  }
326 
327  if (result == nullptr and m_missing.count(id) == 0)
328  {
329  for (auto impl = shared_from_this(); impl; impl = impl->m_next)
330  {
331  result = impl->create(id);
332  if (result != nullptr)
333  break;
334  }
335 
336  if (result == nullptr)
337  m_missing.insert(id);
338  }
339 
340  return result;
341  }
342 
343  std::shared_ptr<compound_factory_impl> next() const
344  {
345  return m_next;
346  }
347 
348  bool is_known_peptide(const std::string &resName)
349  {
350  return m_known_peptides.count(resName) or
351  (m_next and m_next->is_known_peptide(resName));
352  }
353 
354  bool is_known_base(const std::string &resName)
355  {
356  return m_known_bases.count(resName) or
357  (m_next and m_next->is_known_base(resName));
358  }
359 
360  protected:
361  virtual compound *create(const std::string &id)
362  {
363  // For the base class we assume every compound is preloaded
364  return nullptr;
365  }
366 
367  std::shared_timed_mutex mMutex;
368 
369  std::vector<compound *> m_compounds;
370  std::set<std::string> m_known_peptides;
371  std::set<std::string> m_known_bases;
372  std::set<std::string> m_missing;
373  std::shared_ptr<compound_factory_impl> m_next;
374 };
375 
376 // --------------------------------------------------------------------
377 
378 compound_factory_impl::compound_factory_impl(std::shared_ptr<compound_factory_impl> next)
379  : m_next(next)
380 {
381  for (const auto &[key, value] : compound_factory::kAAMap)
382  m_known_peptides.insert(key);
383 
384  for (const auto &[key, value] : compound_factory::kBaseMap)
385  m_known_bases.insert(key);
386 }
387 
388 compound_factory_impl::compound_factory_impl(const fs::path &file, std::shared_ptr<compound_factory_impl> next)
389  : m_next(next)
390 {
391  cif::file cifFile(file);
392 
393  if (cifFile.contains("comp_list")) // So this is a CCP4 restraints file, special handling
394  {
395  auto &compList = cifFile["comp_list"];
396  auto &chemComp = compList["chem_comp"];
397 
398  for (const auto &[id, name, group] : chemComp.rows<std::string, std::string, std::string>("id", "name", "group"))
399  {
400  std::string type;
401 
402  // known groups are (counted from ccp4 monomer dictionary)
403 
404  // D-pyranose
405  // DNA
406  // L-PEPTIDE LINKING
407  // L-SACCHARIDE
408  // L-peptide
409  // L-pyranose
410  // M-peptide
411  // NON-POLYMER
412  // P-peptide
413  // RNA
414  // furanose
415  // non-polymer
416  // non_polymer
417  // peptide
418  // pyranose
419  // saccharide
420 
421  if (cif::iequals(id, "gly"))
422  type = "peptide linking";
423  else if (cif::iequals(group, "l-peptide") or cif::iequals(group, "L-peptide linking") or cif::iequals(group, "peptide") or cif::iequals(group, "p-peptide"))
424  type = "L-peptide linking";
425  else if (cif::iequals(group, "DNA"))
426  type = "DNA linking";
427  else if (cif::iequals(group, "RNA"))
428  type = "RNA linking";
429  else
430  type = "non-polymer";
431 
432  auto &db = cifFile["comp_" + id];
433 
434  m_compounds.push_back(new compound(db, id, name, type, group));
435  }
436  }
437  else
438  {
439  // A CCD components file, validate it first
440  try
441  {
442  cifFile.load_dictionary("mmcif_pdbx.dic");
443 
444  if (not cifFile.is_valid())
445  {
446  std::cerr << "The components file " << file << " is not valid" << std::endl;
447  if (cif::VERBOSE < 1)
448  std::cerr << "(use --verbose to see why)" << std::endl;
449  }
450  }
451  catch (const std::exception &e)
452  {
453  std::cerr << "When trying to load the components file " << file << " there was an exception:" << std::endl
454  << e.what() << std::endl;
455  }
456 
457  for (auto &db : cifFile)
458  m_compounds.push_back(new compound(db));
459  }
460 }
461 
462 // --------------------------------------------------------------------
463 // Version for the default compounds, based on the cached components.cif file from CCD
464 
466 {
467  public:
468  CCD_compound_factory_impl(std::shared_ptr<compound_factory_impl> next, const fs::path &file)
469  : compound_factory_impl(next)
470  , mCompoundsFile(file)
471  {
472  }
473 
474  CCD_compound_factory_impl(std::shared_ptr<compound_factory_impl> next)
475  : compound_factory_impl(next)
476  {
477  }
478 
479  compound *create(const std::string &id) override;
480 
481  cif::parser::datablock_index mIndex;
482  fs::path mCompoundsFile;
483 };
484 
485 compound *CCD_compound_factory_impl::create(const std::string &id)
486 {
487  compound *result = nullptr;
488 
489  std::unique_ptr<std::istream> ccd;
490 
491  if (mCompoundsFile.empty())
492  {
493  ccd = cif::load_resource("components.cif");
494  if (not ccd)
495  {
496  std::cerr << "Could not locate the CCD components.cif file, please make sure the software is installed properly and/or use the update-libcifpp-data to fetch the data." << std::endl;
497  return nullptr;
498  }
499  }
500  else
501  ccd.reset(new std::ifstream(mCompoundsFile));
502 
503  cif::file file;
504 
505  if (mIndex.empty())
506  {
507  if (cif::VERBOSE > 1)
508  {
509  std::cout << "Creating component index "
510  << "...";
511  std::cout.flush();
512  }
513 
514  cif::parser parser(*ccd, file);
515  mIndex = parser.index_datablocks();
516 
517  if (cif::VERBOSE > 1)
518  std::cout << " done" << std::endl;
519 
520  // reload the resource, perhaps this should be improved...
521  if (mCompoundsFile.empty())
522  {
523  ccd = cif::load_resource("components.cif");
524  if (not ccd)
525  throw std::runtime_error("Could not locate the CCD components.cif file, please make sure the software is installed properly and/or use the update-libcifpp-data to fetch the data.");
526  }
527  else
528  ccd.reset(new std::ifstream(mCompoundsFile));
529  }
530 
531  if (cif::VERBOSE > 1)
532  {
533  std::cout << "Loading component " << id << "...";
534  std::cout.flush();
535  }
536 
537  cif::parser parser(*ccd, file);
538  parser.parse_single_datablock(id, mIndex);
539 
540  if (cif::VERBOSE > 1)
541  std::cout << " done" << std::endl;
542 
543  if (not file.empty())
544  {
545  auto &db = file.front();
546  if (db.name() == id)
547  {
548  result = new compound(db);
549 
550  std::shared_lock lock(mMutex);
551  m_compounds.push_back(result);
552  }
553  }
554 
555  if (result == nullptr and cif::VERBOSE > 0)
556  std::cerr << "Could not locate compound " << id << " in the CCD components file" << std::endl;
557 
558  return result;
559 }
560 
561 // --------------------------------------------------------------------
562 // Version for the default compounds, based on the data found in CCP4's monomers lib
563 
565 {
566  public:
567  CCP4_compound_factory_impl(const fs::path &clibd_mon, std::shared_ptr<compound_factory_impl> next = nullptr);
568 
569  compound *create(const std::string &id) override;
570 
571  private:
572  cif::file m_file;
573  fs::path m_CLIBD_MON;
574 };
575 
576 CCP4_compound_factory_impl::CCP4_compound_factory_impl(const fs::path &clibd_mon, std::shared_ptr<compound_factory_impl> next)
577  : compound_factory_impl(next)
578  , m_file((clibd_mon / "list" / "mon_lib_list.cif").string())
579  , m_CLIBD_MON(clibd_mon)
580 {
581  const std::regex peptideRx("(?:[lmp]-)?peptide", std::regex::icase);
582 
583  auto &chemComps = m_file["comp_list"]["chem_comp"];
584 
585  for (const auto &[group, threeLetterCode] : chemComps.rows<std::string, std::string>("group", "three_letter_code"))
586  {
587  if (std::regex_match(group, peptideRx))
588  m_known_peptides.insert(threeLetterCode);
589  else if (cif::iequals(group, "DNA") or cif::iequals(group, "RNA"))
590  m_known_bases.insert(threeLetterCode);
591  }
592 }
593 
594 compound *CCP4_compound_factory_impl::create(const std::string &id)
595 {
596  compound *result = nullptr;
597 
598  auto &cat = m_file["comp_list"]["chem_comp"];
599 
600  auto rs = cat.find(cif::key("three_letter_code") == id);
601 
602  if (rs.size() == 1)
603  {
604  auto row = rs.front();
605 
606  std::string name, group;
607  uint32_t numberAtomsAll, numberAtomsNh;
608  cif::tie(name, group, numberAtomsAll, numberAtomsNh) =
609  row.get("name", "group", "number_atoms_all", "number_atoms_nh");
610 
611  fs::path resFile = m_CLIBD_MON / cif::to_lower_copy(id.substr(0, 1)) / (id + ".cif");
612 
613  if (not fs::exists(resFile) and (id == "COM" or id == "CON" or "PRN")) // seriously...
614  resFile = m_CLIBD_MON / cif::to_lower_copy(id.substr(0, 1)) / (id + '_' + id + ".cif");
615 
616  if (fs::exists(resFile))
617  {
618  cif::file cf(resFile.string());
619 
620  // locate the datablock
621  auto &db = cf["comp_" + id];
622 
623  std::string type;
624 
625  // known groups are (counted from ccp4 monomer dictionary)
626 
627  // D-pyranose
628  // DNA
629  // L-PEPTIDE LINKING
630  // L-SACCHARIDE
631  // L-peptide
632  // L-pyranose
633  // M-peptide
634  // NON-POLYMER
635  // P-peptide
636  // RNA
637  // furanose
638  // non-polymer
639  // non_polymer
640  // peptide
641  // pyranose
642  // saccharide
643 
644  if (cif::iequals(id, "gly"))
645  type = "peptide linking";
646  else if (cif::iequals(group, "l-peptide") or cif::iequals(group, "L-peptide linking") or cif::iequals(group, "peptide") or cif::iequals(group, "p-peptide"))
647  type = "L-peptide linking";
648  else if (cif::iequals(group, "DNA"))
649  type = "DNA linking";
650  else if (cif::iequals(group, "RNA"))
651  type = "RNA linking";
652  else
653  type = "non-polymer";
654 
655  m_compounds.push_back(new compound(db, id, name, type, group));
656  result = m_compounds.back();
657  }
658  }
659 
660  return result;
661 }
662 
663 // --------------------------------------------------------------------
664 
665 std::unique_ptr<compound_factory> compound_factory::s_instance;
666 thread_local std::unique_ptr<compound_factory> compound_factory::tl_instance;
667 bool compound_factory::s_use_thread_local_instance;
668 
669 void compound_factory::init(bool useThreadLocalInstanceOnly)
670 {
671  s_use_thread_local_instance = useThreadLocalInstanceOnly;
672 }
673 
674 compound_factory::compound_factory()
675  : m_impl(nullptr)
676 {
677  auto ccd = cif::load_resource("components.cif");
678  if (ccd)
679  m_impl = std::make_shared<CCD_compound_factory_impl>(m_impl);
680  else if (cif::VERBOSE > 0)
681  std::cerr << "CCD components.cif file was not found" << std::endl;
682 
683  const char *clibd_mon = getenv("CLIBD_MON");
684  if (clibd_mon != nullptr and fs::is_directory(clibd_mon))
685  m_impl = std::make_shared<CCP4_compound_factory_impl>(clibd_mon, m_impl);
686  else if (cif::VERBOSE > 0)
687  std::cerr << "CCP4 monomers library not found, CLIBD_MON is not defined" << std::endl;
688 }
689 
690 compound_factory::~compound_factory()
691 {
692 }
693 
694 compound_factory &compound_factory::instance()
695 {
696  if (s_use_thread_local_instance)
697  {
698  if (not tl_instance)
699  tl_instance.reset(new compound_factory());
700  return *tl_instance;
701  }
702  else
703  {
704  if (not s_instance)
705  s_instance.reset(new compound_factory());
706  return *s_instance;
707  }
708 }
709 
710 void compound_factory::clear()
711 {
712  if (s_use_thread_local_instance)
713  tl_instance.reset(nullptr);
714  else
715  s_instance.reset();
716 }
717 
718 void compound_factory::set_default_dictionary(const fs::path &inDictFile)
719 {
720  if (not fs::exists(inDictFile))
721  throw std::runtime_error("file not found: " + inDictFile.string());
722 
723  try
724  {
725  m_impl.reset(new CCD_compound_factory_impl(m_impl, inDictFile));
726  }
727  catch (const std::exception &)
728  {
729  std::throw_with_nested(std::runtime_error("Error loading dictionary " + inDictFile.string()));
730  }
731 }
732 
733 void compound_factory::push_dictionary(const fs::path &inDictFile)
734 {
735  if (not fs::exists(inDictFile))
736  throw std::runtime_error("file not found: " + inDictFile.string());
737 
738  try
739  {
740  m_impl.reset(new compound_factory_impl(inDictFile, m_impl));
741  }
742  catch (const std::exception &)
743  {
744  std::throw_with_nested(std::runtime_error("Error loading dictionary " + inDictFile.string()));
745  }
746 }
747 
748 void compound_factory::pop_dictionary()
749 {
750  if (m_impl)
751  m_impl = m_impl->next();
752 }
753 
754 const compound *compound_factory::create(std::string id)
755 {
756  return m_impl ? m_impl->get(id) : nullptr;
757 }
758 
759 bool compound_factory::is_known_peptide(const std::string &resName) const
760 {
761  return m_impl ? m_impl->is_known_peptide(resName) : kAAMap.count(resName) > 0;
762 }
763 
764 bool compound_factory::is_known_base(const std::string &resName) const
765 {
766  return m_impl ? m_impl->is_known_base(resName) : kBaseMap.count(resName) > 0;
767 }
768 
769 } // namespace cif
void to_upper(std::string &s)
Definition: text.cpp:128
CCD_compound_factory_impl(std::shared_ptr< compound_factory_impl > next)
Definition: compound.cpp:474
void replace_all(std::string &s, std::string_view what, std::string_view with)
Definition: text.cpp:134
bool is_known_base(const std::string &resName)
Definition: compound.cpp:354
doublereal * c
compound * create(const std::string &id) override
Definition: compound.cpp:485
bool is_known_peptide(const std::string &resName)
Definition: compound.cpp:348
CCP4_compound_factory_impl(const fs::path &clibd_mon, std::shared_ptr< compound_factory_impl > next=nullptr)
Definition: compound.cpp:576
CCD_compound_factory_impl(std::shared_ptr< compound_factory_impl > next, const fs::path &file)
Definition: compound.cpp:468
std::vector< compound * > m_compounds
Definition: compound.cpp:369
std::unique_ptr< std::istream > load_resource(std::filesystem::path name)
Definition: utilities.cpp:943
bool iequals(std::string_view a, std::string_view b)
Definition: text.cpp:59
#define i
doublereal * d
std::set< std::string > m_missing
Definition: compound.cpp:372
compound_factory_impl(std::shared_ptr< compound_factory_impl > next)
Definition: compound.cpp:378
doublereal * b
std::string to_lower_copy(std::string_view s)
Definition: text.cpp:120
compound * create(const std::string &id) override
Definition: compound.cpp:594
viol type
void max(Image< double > &op1, const Image< double > &op2)
std::set< std::string > m_known_peptides
Definition: compound.cpp:370
int VERBOSE
Definition: utilities.cpp:58
std::set< std::string > m_known_bases
Definition: compound.cpp:371
TYPE distance(struct Point_T *p, struct Point_T *q)
Definition: point.cpp:28
bool operator()(const compound_bond &a, const compound_bond &b) const
Definition: compound.cpp:96
std::shared_ptr< compound_factory_impl > m_next
Definition: compound.cpp:373
virtual compound * create(const std::string &id)
Definition: compound.cpp:361
std::shared_ptr< compound_factory_impl > next() const
Definition: compound.cpp:343
virtual ~compound_factory_impl()
Definition: compound.cpp:297
std::shared_timed_mutex mMutex
Definition: compound.cpp:367
#define pi
std::string to_string(bond_type bondType)
Definition: compound.cpp:43
bool operator()(const compound_atom &a, const compound_atom &b) const
Definition: compound.cpp:85
bond_type from_string(const std::string &bondType)
Definition: compound.cpp:59
cif::parser::datablock_index mIndex
Definition: compound.cpp:481
doublereal * a