Coverage Report

Created: 2026-09-28 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rdkit/Code/GraphMol/PeriodicTable.h
Line
Count
Source
1
//
2
//  Copyright (C) 2001-2011 Rational Discovery LLC
3
//
4
//   @@ All Rights Reserved @@
5
//  This file is part of the RDKit.
6
//  The contents are covered by the terms of the BSD license
7
//  which is included in the file license.txt, found at the root
8
//  of the RDKit source tree.
9
//
10
#include <RDGeneral/export.h>
11
#ifndef _RD_PERIODIC_TABLE_H
12
#define _RD_PERIODIC_TABLE_H
13
14
#include <map>
15
#include <vector>
16
#include <RDGeneral/types.h>
17
#include "atomic_data.h"
18
19
namespace RDKit {
20
21
//! singleton class for retrieving information about atoms
22
/*!
23
  Use the singleton like this:
24
25
  \verbatim
26
  const PeriodicTable *tbl = PeriodicTable::getTable();
27
  tbl->getAtomicWeight(6); // get atomic weight for Carbon
28
  tbl->getAtomicWeight("C"); // get atomic weight for Carbon
29
  \endverbatim
30
31
*/
32
class RDKIT_GRAPHMOL_EXPORT PeriodicTable {
33
 public:
34
  //! returns a pointer to the singleton PeriodicTable
35
  /*
36
      \return a pointer to the singleton ParamCollection
37
38
      <b>Notes:</b>
39
        - do <b>not</b> delete the pointer returned here
40
        - if the singleton PeriodicTable has already been instantiated and
41
          the singleton will be returned, otherwise the singleton will
42
          be constructed.
43
44
   */
45
  static PeriodicTable *getTable();
46
  PeriodicTable(const PeriodicTable &) = delete;
47
  PeriodicTable &operator=(const PeriodicTable &) = delete;
48
49
0
  ~PeriodicTable() {
50
0
    byanum.clear();
51
0
    byname.clear();
52
0
  }
53
54
  //! returns the atomic weight
55
1.67k
  double getAtomicWeight(UINT atomicNumber) const {
56
1.67k
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
57
1.67k
    double mass = byanum[atomicNumber].Mass();
58
1.67k
    return mass;
59
1.67k
  }
60
  //! \overload
61
0
  double getAtomicWeight(const std::string &elementSymbol) const {
62
0
    PRECONDITION(byname.count(elementSymbol), "Element not found");
63
0
    int anum = byname.find(elementSymbol)->second;
64
0
    double mass = byanum[anum].Mass();
65
0
    return mass;
66
0
  }
67
  //! \overload
68
0
  double getAtomicWeight(const char *elementSymbol) const {
69
0
    return getAtomicWeight(std::string(elementSymbol));
70
0
  }
71
72
  //! returns the atomic number
73
230k
  int getAtomicNumber(const char *elementSymbol) const {
74
230k
    std::string symb(elementSymbol);
75
76
230k
    return getAtomicNumber(symb);
77
230k
  }
78
  //! overload
79
392k
  int getAtomicNumber(const std::string &elementSymbol) const {
80
    // this little optimization actually makes a measurable difference
81
    // in molecule-construction time
82
392k
    int anum = -1;
83
392k
    if (elementSymbol == "C") {
84
45.9k
      anum = 6;
85
346k
    } else if (elementSymbol == "N") {
86
9.41k
      anum = 7;
87
336k
    } else if (elementSymbol == "O") {
88
4.46k
      anum = 8;
89
332k
    } else {
90
332k
      auto iter = byname.find(elementSymbol);
91
332k
      if (iter != byname.end()) {
92
253k
        anum = iter->second;
93
253k
      }
94
332k
    }
95
392k
    POSTCONDITION(anum > -1, "Element '" + elementSymbol + "' not found");
96
313k
    return anum;
97
392k
  }
98
99
  //! returns the atomic symbol
100
780
  std::string getElementSymbol(UINT atomicNumber) const {
101
780
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
102
780
    return byanum[atomicNumber].Symbol();
103
780
  }
104
105
  //! returns the full element name
106
0
  std::string getElementName(UINT atomicNumber) const {
107
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
108
0
    return byanum[atomicNumber].Name();
109
0
  }
110
111
  //! returns the atom's van der Waals radius
112
0
  double getRvdw(UINT atomicNumber) const {
113
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
114
0
    return byanum[atomicNumber].Rvdw();
115
0
  }
116
  //! \overload
117
0
  double getRvdw(const std::string &elementSymbol) const {
118
0
    PRECONDITION(byname.count(elementSymbol),
119
0
                 "Element '" + elementSymbol + "' not found");
120
0
    return getRvdw(byname.find(elementSymbol)->second);
121
0
  }
122
  //! \overload
123
0
  double getRvdw(const char *elementSymbol) const {
124
0
    return getRvdw(std::string(elementSymbol));
125
0
  }
126
127
  //! returns the atom's covalent radius
128
0
  double getRcovalent(UINT atomicNumber) const {
129
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
130
0
    return byanum[atomicNumber].Rcov();
131
0
  }
132
  //! \overload
133
0
  double getRcovalent(const std::string &elementSymbol) const {
134
0
    PRECONDITION(byname.count(elementSymbol),
135
0
                 "Element '" + elementSymbol + "' not found");
136
0
    return getRcovalent(byname.find(elementSymbol)->second);
137
0
  }
138
  //! \overload
139
0
  double getRcovalent(const char *elementSymbol) const {
140
0
    return getRcovalent(std::string(elementSymbol));
141
0
  }
142
143
  //! returns the atom's bond radius
144
0
  double getRb0(UINT atomicNumber) const {
145
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
146
0
    return byanum[atomicNumber].Rb0();
147
0
  }
148
  //! \overload
149
0
  double getRb0(const std::string &elementSymbol) const {
150
0
    PRECONDITION(byname.count(elementSymbol),
151
0
                 "Element '" + elementSymbol + "' not found");
152
0
    return getRb0(byname.find(elementSymbol)->second);
153
0
  }
154
  //! \overload
155
0
  double getRb0(const char *elementSymbol) const {
156
0
    return getRb0(std::string(elementSymbol));
157
0
  }
158
159
  //! returns the atom's default valence
160
21.0M
  int getDefaultValence(UINT atomicNumber) const {
161
21.0M
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
162
21.0M
    return byanum[atomicNumber].DefaultValence();
163
21.0M
  }
164
  //! \overload
165
0
  int getDefaultValence(const std::string &elementSymbol) const {
166
0
    PRECONDITION(byname.count(elementSymbol),
167
0
                 "Element '" + elementSymbol + "' not found");
168
0
    return getDefaultValence(byname.find(elementSymbol)->second);
169
0
  }
170
  //! \overload
171
0
  int getDefaultValence(const char *elementSymbol) const {
172
0
    return getDefaultValence(std::string(elementSymbol));
173
0
  }
174
175
  //! returns a vector of all stable valences. For atoms where
176
  //! we really don't have any idea what a reasonable maximum
177
  //! valence is (like transition metals), the vector ends with -1
178
44.2M
  const INT_VECT &getValenceList(UINT atomicNumber) const {
179
44.2M
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
180
44.2M
    return byanum[atomicNumber].ValenceList();
181
44.2M
  }
182
  //! \overload
183
0
  const INT_VECT &getValenceList(const std::string &elementSymbol) const {
184
0
    PRECONDITION(byname.count(elementSymbol),
185
0
                 "Element '" + elementSymbol + "' not found");
186
0
    return getValenceList(byname.find(elementSymbol)->second);
187
0
  }
188
  //! \overload
189
0
  const INT_VECT &getValenceList(const char *elementSymbol) const {
190
0
    return getValenceList(std::string(elementSymbol));
191
0
  }
192
193
  //! returns the number of outer shell electrons
194
1.23M
  int getNouterElecs(UINT atomicNumber) const {
195
1.23M
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
196
1.23M
    return byanum[atomicNumber].NumOuterShellElec();
197
1.23M
  }
198
  //! \overload
199
0
  int getNouterElecs(const std::string &elementSymbol) const {
200
0
    PRECONDITION(byname.count(elementSymbol),
201
0
                 "Element '" + elementSymbol + "' not found");
202
0
    return getNouterElecs(byname.find(elementSymbol)->second);
203
0
  }
204
  //! \overload
205
0
  int getNouterElecs(const char *elementSymbol) const {
206
0
    return getNouterElecs(std::string(elementSymbol));
207
0
  }
208
209
  //! returns the number of the most common isotope
210
21.1k
  int getMostCommonIsotope(UINT atomicNumber) const {
211
21.1k
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
212
21.1k
    return byanum[atomicNumber].MostCommonIsotope();
213
21.1k
  }
214
  //! \overload
215
0
  int getMostCommonIsotope(const std::string &elementSymbol) const {
216
0
    PRECONDITION(byname.count(elementSymbol),
217
0
                 "Element '" + elementSymbol + "' not found");
218
0
    return getMostCommonIsotope(byname.find(elementSymbol)->second);
219
0
  }
220
  //! \overload
221
0
  int getMostCommonIsotope(const char *elementSymbol) const {
222
0
    return getMostCommonIsotope(std::string(elementSymbol));
223
0
  }
224
225
  //! returns the mass of the most common isotope
226
0
  double getMostCommonIsotopeMass(UINT atomicNumber) const {
227
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
228
0
    return byanum[atomicNumber].MostCommonIsotopeMass();
229
0
  }
230
  //! \overload
231
0
  double getMostCommonIsotopeMass(const std::string &elementSymbol) const {
232
0
    PRECONDITION(byname.count(elementSymbol),
233
0
                 "Element '" + elementSymbol + "' not found");
234
0
    return getMostCommonIsotopeMass(byname.find(elementSymbol)->second);
235
0
  }
236
  //! \overload
237
0
  double getMostCommonIsotopeMass(const char *elementSymbol) const {
238
0
    return getMostCommonIsotopeMass(std::string(elementSymbol));
239
0
  }
240
241
  //! returns the mass of a particular isotope; zero if that
242
  //! isotope is unknown.
243
0
  double getMassForIsotope(UINT atomicNumber, UINT isotope) const {
244
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
245
0
    const std::map<unsigned int, std::pair<double, double>> &m =
246
0
        byanum[atomicNumber].d_isotopeInfoMap;
247
0
    std::map<unsigned int, std::pair<double, double>>::const_iterator item =
248
0
        m.find(isotope);
249
0
    if (item == m.end()) {
250
0
      return 0.0;
251
0
    } else {
252
0
      return item->second.first;
253
0
    }
254
0
  }
255
  //! \overload
256
  double getMassForIsotope(const std::string &elementSymbol,
257
0
                           UINT isotope) const {
258
0
    PRECONDITION(byname.count(elementSymbol),
259
0
                 "Element '" + elementSymbol + "' not found");
260
0
    return getMassForIsotope(byname.find(elementSymbol)->second, isotope);
261
0
  }
262
  //! \overload
263
0
  double getMassForIsotope(const char *elementSymbol, UINT isotope) const {
264
0
    return getMassForIsotope(std::string(elementSymbol), isotope);
265
0
  }
266
  //! returns the abundance of a particular isotope; zero if that
267
  //! isotope is unknown.
268
0
  double getAbundanceForIsotope(UINT atomicNumber, UINT isotope) const {
269
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
270
0
    const std::map<unsigned int, std::pair<double, double>> &m =
271
0
        byanum[atomicNumber].d_isotopeInfoMap;
272
0
    std::map<unsigned int, std::pair<double, double>>::const_iterator item =
273
0
        m.find(isotope);
274
0
    if (item == m.end()) {
275
0
      return 0.0;
276
0
    } else {
277
0
      return item->second.second;
278
0
    }
279
0
  }
280
  //! \overload
281
  double getAbundanceForIsotope(const std::string &elementSymbol,
282
0
                                UINT isotope) const {
283
0
    PRECONDITION(byname.count(elementSymbol),
284
0
                 "Element '" + elementSymbol + "' not found");
285
0
    return getAbundanceForIsotope(byname.find(elementSymbol)->second, isotope);
286
0
  }
287
  //! \overload
288
0
  double getAbundanceForIsotope(const char *elementSymbol, UINT isotope) const {
289
0
    return getAbundanceForIsotope(std::string(elementSymbol), isotope);
290
0
  }
291
292
  //! convenience function to determine which atom is more electronegative
293
  /*!
294
295
     check if atom with atomic number \c anum1 is more
296
     electronegative than the one with \c anum2
297
     this is rather lame but here is how we do it
298
       - the atom with the higher number of outer shell electrons
299
         is considered more electronegative
300
       - if the # of outer shell elecs are the same
301
         the atom with the lower atomic weight is more electronegative
302
303
  */
304
563
  bool moreElectroNegative(UINT anum1, UINT anum2) const {
305
563
    PRECONDITION(anum1 < byanum.size(), "Atomic number not found");
306
563
    PRECONDITION(anum2 < byanum.size(), "Atomic number not found");
307
    // FIX: the atomic_data needs to have real electronegativity values
308
563
    UINT ne1 = getNouterElecs(anum1);
309
563
    UINT ne2 = getNouterElecs(anum2);
310
563
    if (ne1 > ne2) {
311
62
      return true;
312
62
    }
313
501
    if (ne1 == ne2) {
314
306
      if (anum1 < anum2) {
315
2
        return true;
316
2
      }
317
306
    }
318
499
    return false;
319
501
  }
320
321
  //! returns the maximum recognized atomic number
322
19.1M
  UINT getMaxAtomicNumber() const { return byanum.size() - 1; }
323
  //! returns the row of the periodic table
324
0
  UINT getRow(UINT atomicNumber) const {
325
0
    PRECONDITION(atomicNumber < byanum.size(), "Atomic number not found");
326
0
    return byanum[atomicNumber].Row();
327
0
  }
328
  //! \overload
329
0
  UINT getRow(const std::string &elementSymbol) const {
330
0
    PRECONDITION(byname.count(elementSymbol),
331
0
                 "Element '" + elementSymbol + "' not found");
332
0
    return getRow(byname.find(elementSymbol)->second);
333
0
  }
334
  //! \overload
335
0
  UINT getRow(const char *elementSymbol) const {
336
0
    return getRow(std::string(elementSymbol));
337
0
  }
338
339
 private:
340
  PeriodicTable();
341
  static void initInstance();
342
343
  static class std::unique_ptr<PeriodicTable> ds_instance;
344
345
  std::vector<atomicData> byanum;
346
  STR_UINT_MAP byname;
347
};
348
};  // namespace RDKit
349
350
#endif