RDKit
Open-source cheminformatics and machine learning.
Atom.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2021 Greg Landrum and other RDKit contributors
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 /*! \file Atom.h
11 
12  \brief Defines the Atom class and associated typedefs
13 
14 */
15 #include <RDGeneral/export.h>
16 #ifndef _RD_ATOM_H
17 #define _RD_ATOM_H
18 
19 // Std stuff
20 #include <iostream>
21 
22 // ours
23 #include <RDGeneral/Invariant.h>
24 #include <Query/QueryObjects.h>
25 #include <RDGeneral/types.h>
26 #include <RDGeneral/RDProps.h>
27 #include <GraphMol/details.h>
28 
29 namespace RDKit {
30 class ROMol;
31 class RWMol;
32 class AtomMonomerInfo;
33 
34 //! The class for representing atoms
35 /*!
36 
37  <b>Notes:</b>
38  - many of the methods of Atom require that the Atom be associated
39  with a molecule (an ROMol).
40  - each Atom maintains a Dict of \c properties:
41  - Each \c property is keyed by name and can store an
42  arbitrary type.
43  - \c Properties can be marked as \c calculated, in which case
44  they will be cleared when the \c clearComputedProps() method
45  is called.
46  - Because they have no impact upon chemistry, all \c property
47  operations are \c const, this allows extra flexibility for
48  clients who need to store extra data on Atom objects.
49  - Atom objects are lazy about computing their explicit and implicit valence
50  values. These will not be computed until their values are requested.
51 
52  <b>Chirality:</b>
53 
54  The chirality of an Atom is determined by two things:
55  - its \c chiralTag
56  - the input order of its bonds (see note below for handling of
57  implicit Hs)
58 
59  For tetrahedral coordination, the \c chiralTag tells you what
60  direction you have to rotate to get from bond 2 to bond 3 while looking
61  down bond 1. This is pretty much identical to the SMILES representation of
62  chirality.
63 
64  NOTE: if an atom has an implicit H, the bond to that H is considered to be
65  at the *end* of the list of other bonds.
66 
67 */
69  friend class MolPickler; //!< the pickler needs access to our privates
70  friend class ROMol;
71  friend class RWMol;
72 
73  public:
74  // FIX: grn...
76 
77  //! store hybridization
78  typedef enum {
79  UNSPECIFIED = 0, //!< hybridization that hasn't been specified
80  S,
81  SP,
82  SP2,
83  SP3,
86  OTHER //!< unrecognized hybridization
87  } HybridizationType;
88 
89  //! store type of chirality
90  typedef enum {
91  CHI_UNSPECIFIED = 0, //!< chirality that hasn't been specified
92  CHI_TETRAHEDRAL_CW, //!< tetrahedral: clockwise rotation (SMILES \@\@)
93  CHI_TETRAHEDRAL_CCW, //!< tetrahedral: counter-clockwise rotation (SMILES
94  //\@)
95  CHI_OTHER //!< some unrecognized type of chirality
96  } ChiralType;
97 
98  Atom();
99  //! construct an Atom with a particular atomic number
100  explicit Atom(unsigned int num);
101  //! construct an Atom with a particular symbol (looked up in the
102  /// PeriodicTable)
103  explicit Atom(const std::string &what);
104  Atom(const Atom &other);
105  Atom &operator=(const Atom &other);
106  // NOTE: the move methods are somewhat fraught for atoms associated with
107  // molecules since the molecule will still be pointing to the original object
108  Atom(Atom &&other) = default;
109  Atom &operator=(Atom &&other) = default;
110 
111  virtual ~Atom();
112 
113  //! makes a copy of this Atom and returns a pointer to it.
114  /*!
115  <b>Note:</b> the caller is responsible for <tt>delete</tt>ing the result
116  */
117  virtual Atom *copy() const;
118 
119  //! returns our atomic number
120  int getAtomicNum() const { return d_atomicNum; }
121  //! sets our atomic number
122  void setAtomicNum(int newNum) { d_atomicNum = newNum; }
123 
124  //! returns our symbol (determined by our atomic number)
125  std::string getSymbol() const;
126 
127  //! returns whether or not this instance belongs to a molecule
128  bool hasOwningMol() const { return dp_mol != nullptr; }
129 
130  //! returns a reference to the ROMol that owns this instance
131  ROMol &getOwningMol() const {
132  PRECONDITION(dp_mol, "no owner");
133  return *dp_mol;
134  }
135 
136  //! returns our index within the ROMol
137  unsigned int getIdx() const { return d_index; }
138  //! sets our index within the ROMol
139  /*!
140  <b>Notes:</b>
141  - this makes no sense if we do not have an owning molecule
142  - the index should be <tt>< this->getOwningMol()->getNumAtoms()</tt>
143  */
144  void setIdx(unsigned int index) { d_index = index; }
145  //! overload
146  template <class U>
147  void setIdx(const U index) {
148  setIdx(rdcast<unsigned int>(index));
149  }
150  //! returns the explicit degree of the Atom (number of bonded
151  //! neighbors in the graph)
152  /*!
153  <b>Notes:</b>
154  - requires an owning molecule
155  */
156  unsigned int getDegree() const;
157 
158  //! returns the total degree of the Atom (number of bonded
159  //! neighbors + number of Hs)
160  /*!
161  <b>Notes:</b>
162  - requires an owning molecule
163  */
164  unsigned int getTotalDegree() const;
165 
166  //! \brief returns the total number of Hs (implicit and explicit) that
167  //! this Atom is bound to
168  /*!
169  <b>Notes:</b>
170  - requires an owning molecule
171  */
172  unsigned int getTotalNumHs(bool includeNeighbors = false) const;
173 
174  //! \brief returns the total valence (implicit and explicit)
175  //! for an atom
176  /*!
177  <b>Notes:</b>
178  - requires an owning molecule
179  */
180  unsigned int getTotalValence() const;
181 
182  //! returns the number of implicit Hs this Atom is bound to
183  /*!
184  <b>Notes:</b>
185  - requires an owning molecule
186  */
187  unsigned int getNumImplicitHs() const;
188 
189  //! returns the explicit valence (including Hs) of this atom
190  int getExplicitValence() const;
191 
192  //! returns the implicit valence for this Atom
193  /*!
194  <b>Notes:</b>
195  - requires an owning molecule
196  */
197  int getImplicitValence() const;
198 
199  //! returns the number of radical electrons for this Atom
200  /*!
201  <b>Notes:</b>
202  - requires an owning molecule
203  */
204  unsigned int getNumRadicalElectrons() const { return d_numRadicalElectrons; }
205  void setNumRadicalElectrons(unsigned int num) { d_numRadicalElectrons = num; }
206 
207  //! returns the formal charge of this atom
208  int getFormalCharge() const { return d_formalCharge; }
209  //! set's the formal charge of this atom
210  void setFormalCharge(int what) { d_formalCharge = what; }
211 
212  //! \brief sets our \c noImplicit flag, indicating whether or not
213  //! we are allowed to have implicit Hs
214  void setNoImplicit(bool what) { df_noImplicit = what; }
215  //! returns the \c noImplicit flag
216  bool getNoImplicit() const { return df_noImplicit; }
217 
218  //! sets our number of explicit Hs
219  void setNumExplicitHs(unsigned int what) { d_numExplicitHs = what; }
220  //! returns our number of explicit Hs
221  unsigned int getNumExplicitHs() const { return d_numExplicitHs; }
222 
223  //! sets our \c isAromatic flag, indicating whether or not we are aromatic
224  void setIsAromatic(bool what) { df_isAromatic = what; }
225  //! returns our \c isAromatic flag
226  bool getIsAromatic() const { return df_isAromatic; }
227 
228  //! returns our mass
229  double getMass() const;
230 
231  //! sets our isotope number
232  void setIsotope(unsigned int what);
233  //! returns our isotope number
234  unsigned int getIsotope() const { return d_isotope; }
235 
236  //! sets our \c chiralTag
237  void setChiralTag(ChiralType what) { d_chiralTag = what; }
238  //! inverts our \c chiralTag
240  //! returns our \c chiralTag
242  return static_cast<ChiralType>(d_chiralTag);
243  }
244 
245  //! sets our hybridization
246  void setHybridization(HybridizationType what) { d_hybrid = what; }
247  //! returns our hybridization
249  return static_cast<HybridizationType>(d_hybrid);
250  }
251 
252  // ------------------------------------
253  // Some words of explanation before getting down into
254  // the query stuff.
255  // These query functions are really only here so that they
256  // can have real functionality in subclasses (like QueryAtoms).
257  // Since pretty much it's gonna be a mistake to call any of these
258  // (ever), we're saddling them all with a precondition which
259  // is guaranteed to fail. I'd like to have them be pure virtual,
260  // but that doesn't work since we need to be able to instantiate
261  // Atoms.
262  // ------------------------------------
263 
264  // This method can be used to distinguish query atoms from standard atoms:
265  virtual bool hasQuery() const { return false; }
266 
267  virtual std::string getQueryType() const {return "";}
268 
269  //! NOT CALLABLE
270  virtual void setQuery(QUERYATOM_QUERY *what);
271 
272  //! NOT CALLABLE
273  virtual QUERYATOM_QUERY *getQuery() const;
274  //! NOT CALLABLE
275  virtual void expandQuery(
276  QUERYATOM_QUERY *what,
278  bool maintainOrder = true);
279 
280  //! returns whether or not we match the argument
281  /*!
282  <b>Notes:</b>
283  The general rule is that if a property on this atom has a non-default
284  value,
285  the property on the other atom must have the same value.
286  The exception to this is H counts, which are ignored. These turns out to
287  be
288  impossible to handle generally, so rather than having odd and
289  hard-to-explain
290  exceptions, we ignore them entirely.
291 
292  Here are the rules for atom-atom matching:
293  | This | Other | Match | Reason
294  | CCO | CCO | Yes |
295  | CCO | CC[O-] | Yes |
296  | CC[O-] | CCO | No | Charge
297  | CC[O-] | CC[O-] | Yes |
298  | CC[OH] | CC[O-] | Yes |
299  | CC[OH] | CCOC | Yes |
300  | CCO | CCOC | Yes |
301  | CCC | CCC | Yes |
302  | CCC | CC[14C] | Yes |
303  | CC[14C] | CCC | No | Isotope
304  | CC[14C] | CC[14C] | Yes |
305  | C | OCO | Yes |
306  | [CH] | OCO | Yes |
307  | [CH2] | OCO | Yes |
308  | [CH3] | OCO | No | Radical
309  | C | O[CH2]O | Yes |
310  | [CH2] | O[CH2]O | Yes |
311  */
312  virtual bool Match(Atom const *what) const;
313 
314  //! returns the perturbation order for a list of integers
315  /*!
316 
317  This value is associated with chirality.
318 
319  \param probe a list of bond indices. This must be the same
320  length as our number of incoming bonds (our degree).
321 
322  \return the number of swaps required to convert the ordering
323  of the probe list to match the order of our incoming bonds:
324  e.g. if our incoming bond order is: <tt>[0,1,2,3]</tt>
325  \verbatim
326  getPerturbationOrder([1,0,2,3]) = 1
327  getPerturbationOrder([1,2,3,0]) = 3
328  getPerturbationOrder([1,2,0,3]) = 2
329  \endverbatim
330 
331  See the class documentation for a more detailed description
332  of our representation of chirality.
333 
334  <b>Notes:</b>
335  - requires an owning molecule
336 
337  */
338  int getPerturbationOrder(const INT_LIST &probe) const;
339 
340  //! calculates any of our lazy \c properties
341  /*!
342  <b>Notes:</b>
343  - requires an owning molecule
344  - the current lazy \c properties are implicit and explicit valence
345  */
346  void updatePropertyCache(bool strict = true);
347 
349 
350  //! calculates and returns our explicit valence
351  /*!
352  <b>Notes:</b>
353  - requires an owning molecule
354  */
355  int calcExplicitValence(bool strict = true);
356 
357  //! calculates and returns our implicit valence
358  /*!
359  <b>Notes:</b>
360  - requires an owning molecule
361  */
362  int calcImplicitValence(bool strict = true);
363 
364  AtomMonomerInfo *getMonomerInfo() { return dp_monomerInfo; }
365  const AtomMonomerInfo *getMonomerInfo() const { return dp_monomerInfo; }
366  //! takes ownership of the pointer
367  void setMonomerInfo(AtomMonomerInfo *info) { dp_monomerInfo = info; }
368 
369  //! Set the atom map Number of the atom
370  void setAtomMapNum(int mapno, bool strict = true) {
371  PRECONDITION(
372  !strict || (mapno >= 0 && mapno < 1000),
373  "atom map number out of range [0..1000], use strict=false to override");
374  if (mapno) {
375  setProp(common_properties::molAtomMapNumber, mapno);
376  } else if (hasProp(common_properties::molAtomMapNumber)) {
378  }
379  }
380  //! Gets the atom map Number of the atom, if no atom map exists, 0 is
381  //! returned.
382  int getAtomMapNum() const {
383  int mapno = 0;
384  getPropIfPresent(common_properties::molAtomMapNumber, mapno);
385  return mapno;
386  }
387 
388  protected:
389  //! sets our owning molecule
390  void setOwningMol(ROMol *other);
391  //! sets our owning molecule
392  void setOwningMol(ROMol &other) { setOwningMol(&other); }
393 
396  std::uint8_t d_numExplicitHs;
397  std::int8_t d_formalCharge;
398  std::uint8_t d_atomicNum;
399  // NOTE that these cannot be signed, they are calculated using
400  // a lazy scheme and are initialized to -1 to indicate that the
401  // calculation has not yet been done.
402  std::int8_t d_implicitValence, d_explicitValence;
403  std::uint8_t d_numRadicalElectrons;
404  std::uint8_t d_chiralTag;
405  std::uint8_t d_hybrid;
406 
407  std::uint16_t d_isotope;
409 
412  void initAtom();
413  void initFromOther(const Atom &other);
414 };
415 
416 //! Set the atom's MDL integer RLabel
417 /// Setting to 0 clears the rlabel. Rlabel must be in the range [0..99]
418 RDKIT_GRAPHMOL_EXPORT void setAtomRLabel(Atom *atm, int rlabel);
420 
421 //! Set the atom's MDL atom alias
422 /// Setting to an empty string clears the alias
423 RDKIT_GRAPHMOL_EXPORT void setAtomAlias(Atom *atom, const std::string &alias);
424 RDKIT_GRAPHMOL_EXPORT std::string getAtomAlias(const Atom *atom);
425 
426 //! Set the atom's MDL atom value
427 /// Setting to an empty string clears the value
428 /// This is where recursive smarts get stored in MolBlock Queries
429 RDKIT_GRAPHMOL_EXPORT void setAtomValue(Atom *atom, const std::string &value);
430 RDKIT_GRAPHMOL_EXPORT std::string getAtomValue(const Atom *atom);
431 
432 //! Sets the supplemental label that will follow the atom when writing
433 /// smiles strings.
435  const std::string &label);
437 }; // namespace RDKit
438 //! allows Atom objects to be dumped to streams
439 RDKIT_GRAPHMOL_EXPORT std::ostream &operator<<(std::ostream &target,
440  const RDKit::Atom &at);
441 
442 namespace RDKit {
443 //! returns true if the atom is to the left of C
444 RDKIT_GRAPHMOL_EXPORT bool isEarlyAtom(int atomicNum);
445 //! returns true if the atom is aromatic or has an aromatic bond
447 
448 } // namespace RDKit
449 #endif
RDKIT_GRAPHMOL_EXPORT std::ostream & operator<<(std::ostream &target, const RDKit::Atom &at)
allows Atom objects to be dumped to streams
#define PRECONDITION(expr, mess)
Definition: Invariant.h:109
Pulls in all the query types.
Base class for all queries.
Definition: Query.h:45
The abstract base class for atom-level monomer info.
Definition: MonomerInfo.h:26
The class for representing atoms.
Definition: Atom.h:68
ChiralType getChiralTag() const
returns our chiralTag
Definition: Atom.h:241
void setNumExplicitHs(unsigned int what)
sets our number of explicit Hs
Definition: Atom.h:219
void initAtom()
void setHybridization(HybridizationType what)
sets our hybridization
Definition: Atom.h:246
Atom & operator=(const Atom &other)
Queries::Query< int, Atom const *, true > QUERYATOM_QUERY
Definition: Atom.h:75
bool needsUpdatePropertyCache() const
ROMol & getOwningMol() const
returns a reference to the ROMol that owns this instance
Definition: Atom.h:131
virtual void expandQuery(QUERYATOM_QUERY *what, Queries::CompositeQueryType how=Queries::COMPOSITE_AND, bool maintainOrder=true)
NOT CALLABLE.
atomindex_t d_index
Definition: Atom.h:408
bool getNoImplicit() const
returns the noImplicit flag
Definition: Atom.h:216
Atom(unsigned int num)
construct an Atom with a particular atomic number
unsigned int getIdx() const
returns our index within the ROMol
Definition: Atom.h:137
unsigned int getNumExplicitHs() const
returns our number of explicit Hs
Definition: Atom.h:221
unsigned int getNumRadicalElectrons() const
returns the number of radical electrons for this Atom
Definition: Atom.h:204
bool df_isAromatic
Definition: Atom.h:394
const AtomMonomerInfo * getMonomerInfo() const
Definition: Atom.h:365
void setNoImplicit(bool what)
sets our noImplicit flag, indicating whether or not we are allowed to have implicit Hs
Definition: Atom.h:214
Atom(const Atom &other)
ROMol * dp_mol
Definition: Atom.h:410
virtual void setQuery(QUERYATOM_QUERY *what)
NOT CALLABLE.
virtual std::string getQueryType() const
Definition: Atom.h:267
int getExplicitValence() const
returns the explicit valence (including Hs) of this atom
HybridizationType
store hybridization
Definition: Atom.h:78
@ SP3
Definition: Atom.h:83
@ SP3D2
Definition: Atom.h:85
@ SP
Definition: Atom.h:81
@ SP2
Definition: Atom.h:82
@ SP3D
Definition: Atom.h:84
int getImplicitValence() const
returns the implicit valence for this Atom
void updatePropertyCache(bool strict=true)
calculates any of our lazy properties
Atom(Atom &&other)=default
void setIdx(unsigned int index)
sets our index within the ROMol
Definition: Atom.h:144
void setAtomicNum(int newNum)
sets our atomic number
Definition: Atom.h:122
unsigned int getTotalNumHs(bool includeNeighbors=false) const
returns the total number of Hs (implicit and explicit) that this Atom is bound to
void initFromOther(const Atom &other)
int calcExplicitValence(bool strict=true)
calculates and returns our explicit valence
void setIsotope(unsigned int what)
sets our isotope number
std::uint16_t d_isotope
Definition: Atom.h:407
void setOwningMol(ROMol &other)
sets our owning molecule
Definition: Atom.h:392
void invertChirality()
inverts our chiralTag
std::uint8_t d_atomicNum
Definition: Atom.h:398
virtual Atom * copy() const
makes a copy of this Atom and returns a pointer to it.
int getAtomicNum() const
returns our atomic number
Definition: Atom.h:120
int calcImplicitValence(bool strict=true)
calculates and returns our implicit valence
ChiralType
store type of chirality
Definition: Atom.h:90
@ CHI_TETRAHEDRAL_CW
tetrahedral: clockwise rotation (SMILES @@)
Definition: Atom.h:92
@ CHI_TETRAHEDRAL_CCW
tetrahedral: counter-clockwise rotation (SMILES
Definition: Atom.h:93
unsigned int getNumImplicitHs() const
returns the number of implicit Hs this Atom is bound to
bool df_noImplicit
Definition: Atom.h:395
virtual QUERYATOM_QUERY * getQuery() const
NOT CALLABLE.
AtomMonomerInfo * getMonomerInfo()
Definition: Atom.h:364
int getPerturbationOrder(const INT_LIST &probe) const
returns the perturbation order for a list of integers
AtomMonomerInfo * dp_monomerInfo
Definition: Atom.h:411
int getAtomMapNum() const
Definition: Atom.h:382
void setAtomMapNum(int mapno, bool strict=true)
Set the atom map Number of the atom.
Definition: Atom.h:370
virtual bool hasQuery() const
Definition: Atom.h:265
void setFormalCharge(int what)
set's the formal charge of this atom
Definition: Atom.h:210
std::int8_t d_formalCharge
Definition: Atom.h:397
std::uint8_t d_hybrid
Definition: Atom.h:405
std::string getSymbol() const
returns our symbol (determined by our atomic number)
virtual bool Match(Atom const *what) const
returns whether or not we match the argument
void setChiralTag(ChiralType what)
sets our chiralTag
Definition: Atom.h:237
void setMonomerInfo(AtomMonomerInfo *info)
takes ownership of the pointer
Definition: Atom.h:367
HybridizationType getHybridization() const
returns our hybridization
Definition: Atom.h:248
bool getIsAromatic() const
returns our isAromatic flag
Definition: Atom.h:226
unsigned int getTotalValence() const
returns the total valence (implicit and explicit) for an atom
Atom(const std::string &what)
std::uint8_t d_numRadicalElectrons
Definition: Atom.h:403
void setIsAromatic(bool what)
sets our isAromatic flag, indicating whether or not we are aromatic
Definition: Atom.h:224
int getFormalCharge() const
returns the formal charge of this atom
Definition: Atom.h:208
Atom & operator=(Atom &&other)=default
double getMass() const
returns our mass
unsigned int getIsotope() const
returns our isotope number
Definition: Atom.h:234
unsigned int getTotalDegree() const
std::int8_t d_explicitValence
Definition: Atom.h:402
void setIdx(const U index)
overload
Definition: Atom.h:147
void setNumRadicalElectrons(unsigned int num)
Definition: Atom.h:205
bool hasOwningMol() const
returns whether or not this instance belongs to a molecule
Definition: Atom.h:128
void setOwningMol(ROMol *other)
sets our owning molecule
std::uint8_t d_chiralTag
Definition: Atom.h:404
std::uint8_t d_numExplicitHs
Definition: Atom.h:396
virtual ~Atom()
unsigned int getDegree() const
handles pickling (serializing) molecules
Definition: MolPickler.h:68
RWMol is a molecule class that is intended to be edited.
Definition: RWMol.h:32
#define RDKIT_GRAPHMOL_EXPORT
Definition: export.h:217
CompositeQueryType
Definition: QueryObjects.h:36
@ COMPOSITE_AND
Definition: QueryObjects.h:36
RDKIT_RDGENERAL_EXPORT const std::string molAtomMapNumber
Std stuff.
Definition: Abbreviations.h:18
std::list< int > INT_LIST
Definition: types.h:283
RDKIT_GRAPHMOL_EXPORT std::string getAtomValue(const Atom *atom)
RDKIT_GRAPHMOL_EXPORT std::string getAtomAlias(const Atom *atom)
RDKIT_GRAPHMOL_EXPORT void setAtomRLabel(Atom *atm, int rlabel)
RDKIT_GRAPHMOL_EXPORT bool isAromaticAtom(const Atom &atom)
returns true if the atom is aromatic or has an aromatic bond
RDKIT_GRAPHMOL_EXPORT std::string getSupplementalSmilesLabel(const Atom *atom)
RDKIT_GRAPHMOL_EXPORT void setAtomAlias(Atom *atom, const std::string &alias)
RDKIT_GRAPHMOL_EXPORT int getAtomRLabel(const Atom *atm)
RDKIT_GRAPHMOL_EXPORT void setAtomValue(Atom *atom, const std::string &value)
RDKIT_GRAPHMOL_EXPORT bool isEarlyAtom(int atomicNum)
returns true if the atom is to the left of C
std::uint32_t atomindex_t
Definition: details.h:14
RDKIT_GRAPHMOL_EXPORT void setSupplementalSmilesLabel(Atom *atom, const std::string &label)