1 // $Id$
2 //
3 //  Copyright (C) 2001-2006 Rational Discovery LLC
4 //
5 //   @@ All Rights Reserved @@
6 //  This file is part of the RDKit.
7 //  The contents are covered by the terms of the BSD license
8 //  which is included in the file license.txt, found at the root
9 //  of the RDKit source tree.
10 //
11 #include "PeriodicTable.h"
12 #include <string>
13 #include <boost/tokenizer.hpp>
14 typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
15 #include <sstream>
16 #include <locale>
17 
18 #ifdef RDK_BUILD_THREADSAFE_SSS
19 #include <mutex>
20 #endif
21 
22 namespace RDKit {
23 
24 class std::unique_ptr<PeriodicTable> PeriodicTable::ds_instance = nullptr;
25 
PeriodicTable()26 PeriodicTable::PeriodicTable() {
27   // it is assumed that the atomic atomData string constains atoms
28   // in sequence and no atoms are missing in between
29   byanum.clear();
30   byname.clear();
31 
32   boost::char_separator<char> eolSep("\n");
33   tokenizer tokens(periodicTableAtomData, eolSep);
34   for (tokenizer::iterator token = tokens.begin(); token != tokens.end();
35        ++token) {
36     if (*token != " ") {
37       atomicData adata(*token);
38       std::string enam = adata.Symbol();
39       byname[enam] = adata.AtomicNum();
40       // there are, for backwards compatibility reasons, some duplicate rows for
41       // atomic numbers in the atomic_data data structure. It's ok to have
42       // multiple symbols map to the same atomic number (above), but we need to
43       // be sure that we only store one entry per atomic number.
44       // Note that this only works because the first atom in the adata list is
45       // the dummy atom (atomic number 0). This was #2784
46       if (rdcast<size_t>(adata.AtomicNum()) == byanum.size()) {
47         byanum.push_back(adata);
48       }
49     }
50   }
51 
52   unsigned int lidx = 0;
53   std::istringstream istr;
54   istr.imbue(std::locale("C"));
55   while (isotopesAtomData[lidx] != "" && isotopesAtomData[lidx] != "EOS") {
56     tokenizer lines(isotopesAtomData[lidx++], eolSep);
57     boost::char_separator<char> spaceSep(" \t");
58     for (tokenizer::iterator line = lines.begin(); line != lines.end();
59          ++line) {
60       if (*line != " ") {
61         tokenizer tokens(*line, spaceSep);
62         tokenizer::iterator token = tokens.begin();
63         int anum;
64         istr.clear();
65         istr.str(*token);
66         istr >> anum;
67         atomicData &adata = byanum[anum];
68         ++token;
69         if (token == tokens.end()) {
70           continue;
71         }
72         ++token;
73         if (token == tokens.end()) {
74           continue;
75         }
76         unsigned int isotope;
77         istr.clear();
78         istr.str(*token);
79         istr >> isotope;
80         ++token;
81         if (token == tokens.end()) {
82           continue;
83         }
84         double mass;
85         istr.clear();
86         istr.str(*token);
87         istr >> mass;
88         ++token;
89         if (token == tokens.end()) {
90           continue;
91         }
92         double abundance;
93         istr.clear();
94         istr.str(*token);
95         istr >> abundance;
96         adata.d_isotopeInfoMap[isotope] = std::make_pair(mass, abundance);
97       }
98     }
99   }
100 }
101 
initInstance()102 void PeriodicTable::initInstance() {
103   ds_instance = std::unique_ptr<PeriodicTable>(new PeriodicTable());
104 }
105 
getTable()106 PeriodicTable *PeriodicTable::getTable() {
107 #ifdef RDK_BUILD_THREADSAFE_SSS
108   static std::once_flag pt_init_once;
109   std::call_once(pt_init_once, initInstance);
110 #else
111   if (!ds_instance) {
112     initInstance();
113   }
114 #endif
115   return ds_instance.get();
116 }
117 
118 }  // namespace RDKit
119