Coverage Report

Created: 2026-01-25 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openbabel/include/openbabel/stereo/stereo.h
Line
Count
Source
1
/**********************************************************************
2
  stereo.h - OBStereo & OBStereoBase
3
4
  Copyright (C) 2009-2010 by Tim Vandermeersch
5
6
  This file is part of the Open Babel project.
7
  For more information, see <http://openbabel.org/>
8
9
  This program is free software; you can redistribute it and/or modify
10
  it under the terms of the GNU General Public License as published by
11
  the Free Software Foundation; either version 2 of the License, or
12
  (at your option) any later version.
13
14
  This program is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
  GNU General Public License for more details.
18
19
  You should have received a copy of the GNU General Public License
20
  along with this program; if not, write to the Free Software
21
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22
  02110-1301, USA.
23
 **********************************************************************/
24
#ifndef OB_STEREO_H
25
#define OB_STEREO_H
26
27
#include <openbabel/base.h> // OBGenericData
28
#include <openbabel/isomorphism.h> // Automorphisms
29
#include <vector>
30
#include <map>
31
#include <set>
32
#include <climits> // UINT_MAX
33
34
namespace OpenBabel {
35
36
  ///@addtogroup stereo Stereochemistry
37
  ///@{
38
39
  /**
40
   * @class OBStereo stereo.h <openbabel/stereo/stereo.h>
41
   * @brief Placeholder for enums & Ref/Refs related functions.
42
   *
43
   * The OBStereo struct contains a number of enums with predefined values.
44
   * These are OBStereo::BondDirection, OBStereo::Type, OBStereo::Shape,
45
   * OBStereo::View, OBStereo::Winding. There are enums
46
   * which only apply to certain types of stereochemistry but having them
47
   * in 1 place makes it easier to remember.
48
   *
49
   * The OBStereo struct also contains typedefs and functions which
50
   * are crucial to fully understand how to use the OBStereoBase derived
51
   * classes (i.e. OBTetrahedralStereo, OBCisTransStereo, ...). Ref variables
52
   * and Refs lists are a way to uniquely reference atoms in the molecule. In
53
   * most cases these Ref variables are the same as the unique atom ids
54
   * (OBAtom::GetId). However, 2 special cases are provided:
55
   *
56
   * - OBStereo::NoRef: An initial value for Ref variables. The constructors of
57
   *   the various Config structs set all refs to NoRef (Refs lists will remain
58
   *   empty). This value is considered invalid when comparing stereochemistry.
59
   * - OBStereo::ImplicitRef: Can be used to replace implicit hydrogen ids.
60
   *   Even with explicit hydrogens, it is still valid to replace the Ref of
61
   *   the hydrogen with ImplicitRef. This flexibility also applies to
62
   *   comparing stereochemistry. It is possible to compare stereochemistry
63
   *   (e.g. OBTetrahedral::Config::operator==) between a Config struct with
64
   *   an ImplicitRef and a Config struct where the Ref is the atom id of the
65
   *   explicit hydrogen. See actual documentation for details about operator==.
66
   *
67
   * There are utility functions which make it easier to handle Refs. The most
68
   * frequently used one is OBStereo::MakeRefs to create lists containing 3 or
69
   * 4 Ref values. Formats and library use normally doesn't need the other
70
   * functions.
71
   *
72
   * @sa OBStereoBase OBStereoFacade
73
   * @since version 2.3
74
   */
75
  struct OBAPI OBStereo
76
  {
77
    /**
78
     * The various types of stereochemistry
79
     */
80
    enum Type {
81
      CisTrans            = (1<<0), //!< cis/trans double bond
82
      ExtendedCisTrans    = (1<<1), //!< allene, biphenyl, ...
83
      SquarePlanar        = (1<<2), //!< Square-planar stereochemistry
84
      Tetrahedral         = (1<<3), //!< tetrahedral
85
      ExtendedTetrahedral = (1<<4), //!< extended tetrahedral
86
      TrigonalBipyramidal = (1<<5), //!< Trigonal-bipyramidal stereochemistry
87
      Octahedral          = (1<<6)  //!< Octahedral stereochemistry
88
    };
89
90
    /**
91
     * Bond directions used by StereoFrom0D() to translate to
92
     * internal CisTransStereo representation.
93
     */
94
    enum BondDirection { // Values taken from MDL format
95
      NotStereo =   0,
96
      UpBond =      1,
97
      DownBond =    6,
98
      UnknownDir =  4
99
    };
100
101
    /**
102
     * Shapes used by OBTetraPlanarStereo subclasses for
103
     * setting/getting reference ids.
104
     *
105
     * @image html SPshapes.png
106
     * @sa OBTetraPlanarStereo
107
     */
108
    enum Shape {
109
      ShapeU = 1,
110
      ShapeZ = 2,
111
      Shape4 = 3
112
    };
113
114
    /**
115
     * Views used by OBTetraNonPlanarStereo subclasses for
116
     * setting/getting reference ids.
117
     * @sa OBTetraNonPlanarStereo
118
     */
119
    enum View
120
    {
121
      ViewFrom = 1, //!< view from the atom (id parameter) towards the center atom
122
      ViewTowards = 2 //!< view from center atom towards the atom (id parameter)
123
    };
124
125
    /**
126
     * Windings used by OBTetraNonPlanar subclasses for
127
     * setting/getting reference ids.
128
     * @sa OBTetraNonPlanar
129
     */
130
    enum Winding {
131
      Clockwise = 1,     //!< Clockwise winding
132
      AntiClockwise = 2, //!< AntiClockwise winding (or CounterClockwise)
133
      UnknownWinding = 3 //!< The configuration is specified as unknown (squiggly line in depiction)
134
    };
135
136
    ///@name Ref & Refs types
137
    //@{
138
    /**
139
     * All stereo classes work with variables of the type Ref to uniquely
140
     * identify atoms. In most cases these Ref variables are the same as the
141
     * unique atom ids.
142
     *
143
     * @sa OBAtom::GetId() OBStereo
144
     */
145
    typedef unsigned long Ref;
146
    /**
147
     * Special case Ref values.
148
     */
149
    enum {
150
      NoRef = UINT_MAX,       //!< No Ref set (invalid Ref)
151
      ImplicitRef = UINT_MAX - 1  //!< Implicit Ref (i.e. hydrogen, N lone pair, ...).
152
    };
153
    /**
154
     * A list (std::vector) of Ref variables.
155
     */
156
    typedef std::vector<Ref> Refs;
157
    /**
158
     * Iterator (std::iterator) for a Refs list.
159
     */
160
    typedef Refs::iterator RefIter;
161
    /**
162
     * Iterator (std::iterator) for a const Refs list.
163
     */
164
    typedef Refs::const_iterator ConstRefIter;
165
    //@}
166
167
    ///@name Refs utility functions
168
    //@{
169
    /**
170
     * Create a Refs list filled with @p ref1, @p ref2, @p ref3 & @p ref4.
171
     * @p ref4 is not added to the returned Refs if it is equal to NoRef.
172
     *
173
     * @return A Refs list containing the specified Ref values.
174
     */
175
    static Refs MakeRefs(Ref ref1, Ref ref2, Ref ref3, Ref ref4 = NoRef)
176
60
    {
177
60
      Refs refs(3);
178
60
      refs[0] = ref1;
179
60
      refs[1] = ref2;
180
60
      refs[2] = ref3;
181
60
      if (ref4 != NoRef)
182
60
        refs.push_back(ref4);
183
60
      return refs;
184
60
    }
185
    /**
186
     * Check if @p refs1 and @p refs2 contain the same Ref values regardless
187
     * of their order.
188
     *
189
     * @code
190
     * OBStereo::ContainsSameRefs(OBStereo::MakeRefs(1, 2, 3), OBStereo::MakeRefs(2, 3, 1)) // true
191
     * OBStereo::ContainsSameRefs(OBStereo::MakeRefs(1, 2, 3), OBStereo::MakeRefs(3, 2, 1)) // true
192
     * OBStereo::ContainsSameRefs(OBStereo::MakeRefs(1, 2, 3), OBStereo::MakeRefs(3, 4, 1)) // false
193
     * @endcode
194
     *
195
     * @return True if @p refs1 and @p refs2 contain the same Ref values.
196
     */
197
    static bool ContainsSameRefs(const Refs &refs1, const Refs &refs2);
198
    /**
199
     * @return True if @p refs contains @p ref.
200
     */
201
    static bool ContainsRef(const Refs &refs, unsigned long ref);
202
    //@}
203
204
    ///@name Low-level functions used by implementation.
205
    //@{
206
    /**
207
     * Compute the inversion vector for @p refs and return the sum of it's
208
     * elements. The ith element in the inversion vector is the number of
209
     * element to the right of element i with a lower value.
210
     *
211
     * The number of inversions is the same as the number of interchanges
212
     * of consecutive elements.
213
     *
214
     * When working with 3 refs from a tetrahedral configuration:
215
     * @code
216
     * permutation   inversion vector    sum
217
     * -------------------------------------
218
     * 123           0 0 0               0 (even) -> clockwise
219
     * 132           0 1 0               1 (odd)  -> anti-clockwise
220
     * 213           1 0 0               1 (odd)  -> anti-clockwise
221
     * 231           1 1 0               2 (even) -> clockwise
222
     * 312           2 0 0               2 (even) -> clockwise
223
     * 321           2 1 0               3 (odd)  -> anti-clockwise
224
     * @endcode
225
     */
226
    static int NumInversions(const Refs &refs);
227
    /**
228
     * Permutate element @p i with @p j in @p refs.
229
     *
230
     * @param refs The sequence with N elements to permutate.
231
     * @param i Element i (0...N-1) will be mutated to j and vice versa.
232
     * @param j Element j (0...N-1) will be mutated to i and vice versa.
233
     *
234
     * @note This method does nothing if i equals j.
235
     */
236
    static void Permutate(Refs &refs, unsigned int i, unsigned int j);
237
    /**
238
     * Get @p refs with element @p i and @p j permutated.
239
     *
240
     * @param refs The sequence with N elements to permutate.
241
     * @param i Element @p i (0...N-1) will be mutated to @p j and vice versa.
242
     * @param j Element @p j (0...N-1) will be mutated to @p i and vice versa.
243
     *
244
     * @return @p refs with elements @p i and @p j permutated.
245
     *
246
     * @note This method does nothing if @p i equals @p j.
247
     */
248
    static Refs Permutated(const Refs &refs, unsigned int i, unsigned int j);
249
    //@}
250
251
  };
252
253
  /**
254
   * @struct OBStereoUnit stereo.h <openbabel/stereo/stereo.h>
255
   * @brief Struct representing a single stereogenic unit.
256
   * @since 2.3
257
   */
258
  struct OBStereoUnit
259
  {
260
    /**
261
     * Default constructor creating an invalid OBStereoUnit. The unit can be
262
     * made valid by setting the type, id and para data members.
263
     */
264
    OBStereoUnit() : type(static_cast<OBStereo::Type>(0)), id(OBStereo::NoRef), para(false)
265
0
    {
266
0
    }
267
268
    /**
269
     * Constructor specifying all data to create a valid OBStereoUnit.
270
     */
271
    OBStereoUnit(OBStereo::Type _type, unsigned long _id, bool _para = false) :
272
1.02k
        type(_type), id(_id), para(_para)
273
1.02k
    {
274
1.02k
    }
275
276
    OBStereo::Type type; //!< the type for this stereogenic unit
277
    unsigned long id; //!< the atom/bond (depends on type) unique id
278
    bool para; //!< para- (=ressemble) or true-stereocenter
279
  };
280
  /**
281
   * @brief A single set of OBStereoUnit objects.
282
   *
283
   * This type can be used to represent all stereogenic units in a molecule and
284
   * is used as return type of FinStereogenicUnits(). This set is also the input
285
   * for many functions requiring this information (e.g. StereoFrom2D, ...).
286
   */
287
  typedef std::vector<OBStereoUnit> OBStereoUnitSet;
288
  /**
289
   * @brief A set of sets of OBStereoUnit objects.
290
   *
291
   * This type is used for cases where there is some relationship between
292
   * individual OBStereoUnit objects.
293
   */
294
  typedef std::vector<OBStereoUnitSet> OBStereoUnitSetOfSets;
295
296
297
  // fwd decl
298
  class OBMol;
299
  /**
300
   * @class OBStereoBase stereo.h <openbabel/stereo/stereo.h>
301
   * @brief Base class for all stereochemistry classes.
302
   *
303
   * All stereochemistry classes are derived from OBStereoBase. This class
304
   * inherits from OBGenericData which allows the objects to be stored in
305
   * the molecule. The attribute (OBGenericData::GetAttribute) is set to
306
   * "StereoData" and the data type is OBGenericDataType::StereoData. The
307
   * pure virtual OBStereoBase::GetType function must be implemented by
308
   * derived classes to return a type defined in OBStereo::Type.
309
   *
310
   * Use the OBStereoFacade for easy access to the derived classes.
311
   *
312
   * OBStereoBase keeps track of the OBMol object. This must always be
313
   * a valid (not 0 or deleted) pointer and can only be set using the
314
   * constructor. Subclasses can use this to get more information on bonding
315
   * for example. Finally, OBStereoBase also keeps track of the specified
316
   * flag. By default, this is always set to true.
317
   *
318
   * @sa OBStereo OBStereoFacade
319
   * @since version 2.3
320
   */
321
  class OBAPI OBStereoBase : public OBGenericData
322
  {
323
    public:
324
      /**
325
       * Constructor. By default, the stereochemistry is specified. Use
326
       * SetSpecified(false) for unspecified/unknown stereochemistry.
327
       *
328
       * @param mol The molecule.
329
       */
330
      OBStereoBase(OBMol *mol) :
331
3.02k
        OBGenericData("StereoData", OBGenericDataType::StereoData, perceived),
332
3.02k
        m_mol(mol), m_specified(true)
333
3.02k
      {
334
3.02k
      }
335
      /**
336
       * Destructor.
337
       */
338
3.02k
      virtual ~OBStereoBase() { m_mol = nullptr; }
339
340
      ///@name Geniric (for all OBStereo::Type) stereochemistry
341
      //@{
342
      /**
343
       * Get the molecule. This can be used by subclasses when more
344
       * information is needed (e.g. OBCisTransStereo::GetCisRef, ...).
345
       */
346
0
      OBMol* GetMolecule() const { return m_mol; }
347
      /**
348
       * Reimplemented by subclasses to return the type defined in OBStereo::Type.
349
       */
350
      virtual OBStereo::Type GetType() const = 0;
351
      /**
352
       * Set whether the stereochemistry is specified. Comparing a specified
353
       * OBStereoBase derived class (or it's Config struct) with an unspecified
354
       * one, always returns true.
355
       */
356
0
      void SetSpecified(bool specified) { m_specified = specified; }
357
      /**
358
       * @return True if the stereochemistry is specified.
359
       */
360
0
      bool IsSpecified() const { return m_specified; }
361
      //@}
362
    private:
363
      OBMol *m_mol; //!< The parent molecule.
364
      bool m_specified; //!< True if the stereochemistry is specified, false if unknown/unspecified.
365
  };
366
367
  // fwd decl
368
  class OBTetrahedralStereo;
369
  class OBCisTransStereo;
370
  class OBSquarePlanarStereo;
371
  /**
372
   * @class OBStereoFacade stereo.h <openbabel/stereo/stereo.h>
373
   * @brief Facade to simplify retrieval of OBStereoBase derived objects.
374
   *
375
   * The OBStereoFacade helps with retrieving OBStereoBase derived objects
376
   * (i.e. OBTetrahedralStereo, OBCisTransStereo, ...) from an OBMol. This
377
   * is done by iterating over all OBGenericData objects with data type
378
   * OBGenericDataType::StereoData and checking the OBStereo::Type using
379
   * OBStereoBase::GetType.
380
   *
381
   * @sa OBStereo OBStereoBase
382
   * @since version 2.3
383
   */
384
  class OBAPI OBStereoFacade
385
  {
386
    public:
387
      /**
388
       * Constructor with @p mol and @p perceive parameter.
389
       *
390
       * @param mol The molecule.
391
       * @param perceive If true, PerceiveStereo will be called if the
392
       * OBMol::HasChiralityPerceived() flag is not set. (default is true)
393
       */
394
      OBStereoFacade(OBMol *mol, bool perceive = true) :
395
8.14k
          m_mol(mol), m_init(false), m_perceive(perceive)
396
8.14k
      {
397
8.14k
      }
398
399
      ///@name Tetrahedral stereochemistry
400
      ///@{
401
      /**
402
       * Get the number of tetrahedral stereocenters.
403
       */
404
      unsigned int NumTetrahedralStereo();
405
      /**
406
       * Get all the OBTetrahedralStereo objects.
407
       */
408
      std::vector<OBTetrahedralStereo*> GetAllTetrahedralStereo();
409
      /**
410
       * Check if atom with @p id is a tetrahedral center.
411
       * @return True if the atom with @p id has tetrahedral stereochemistry.
412
       */
413
      bool HasTetrahedralStereo(unsigned long atomId);
414
      /**
415
       * Get the OBTetrahedralStereo object with @p atomId as center. This
416
       * function returns 0 if there is no OBTetrahedralStereo object found
417
       * with the specified center.
418
       */
419
      OBTetrahedralStereo* GetTetrahedralStereo(unsigned long atomId);
420
      ///@}
421
422
      ///@name Cis/Trans stereochemistry
423
      ///@{
424
      /**
425
       * Get the number of cis/trans stereocenters.
426
       */
427
      unsigned int NumCisTransStereo();
428
      /**
429
       * Get all the OBCisTransStereo objects.
430
       */
431
      std::vector<OBCisTransStereo*> GetAllCisTransStereo();
432
      /**
433
       * Check if bond with @p id is a stereogenic cis/trans double bond.
434
       * @return True if the bond with @p id has cis/trans stereochemistry.
435
       */
436
      bool HasCisTransStereo(unsigned long bondId);
437
      /**
438
       * Get the OBTetrahedralStereo object with @p bondId as double bond.
439
       * This function returns 0 if there is no OBCisTransStereo object found
440
       * with the specified bond.
441
       */
442
      OBCisTransStereo* GetCisTransStereo(unsigned long bondId);
443
      ///@}
444
445
      ///@name SquarePlanar stereochemistry
446
      ///@{
447
      /**
448
       * Get the number of square-planar stereocenters.
449
       */
450
      unsigned int NumSquarePlanarStereo();
451
      /**
452
       * Get all the OBSquarePlanarStereo objects.
453
       */
454
      std::vector<OBSquarePlanarStereo*> GetAllSquarePlanarStereo();
455
      /**
456
       * Check if atom with @p id is a stereogenic square-planar atom.
457
       * @return True if the atom with @p id has square-planar stereochemistry.
458
       */
459
      bool HasSquarePlanarStereo(unsigned long atomId);
460
      /**
461
       * Get the OBSquarePlanarStereo object with @p atomId as center. This
462
       * function returns 0 if there is no OBSquarePlanarStereo object found
463
       * with the specified center.
464
       */
465
      OBSquarePlanarStereo* GetSquarePlanarStereo(unsigned long atomId);
466
      ///@}
467
468
      template<int StereoType>
469
      bool HasStereo(unsigned long id);
470
      template<typename T>
471
      T* GetStereo(unsigned long id);
472
473
474
    private:
475
      /**
476
       * Ensure the maps are initialized and initialize them only once.
477
       */
478
19.3k
      inline void EnsureInit() { if (!m_init) InitMaps(); }
479
      /**
480
       * Initialize @p m_tetrahedralMap and m_cistransMap to contain the
481
       * data objects. If @p m_perceive is true and chirality isn't perceived
482
       * yet, PerceiveStereo will be called.
483
       */
484
      void InitMaps();
485
486
      OBMol *m_mol;
487
      bool m_init;
488
      bool m_perceive;
489
      std::map<unsigned long, OBTetrahedralStereo*> m_tetrahedralMap;
490
      std::map<unsigned long, OBCisTransStereo*> m_cistransMap;
491
      std::map<unsigned long, OBSquarePlanarStereo*> m_squarePlanarMap;
492
  };
493
494
  // fwd decl
495
  class OBBond;
496
  ///@name High level functions
497
  ///@{
498
  /**
499
   * Convert 0D/2D/3D coordinates to OBStereo objects. The right function will
500
   * be selected based on the molecule's dimensionality
501
   * (i.e. OBMol::GetDimension()).
502
   *
503
   * @sa StereoFrom3D StereoFrom2D StereoFrom0D
504
   * @since version 2.3
505
   */
506
  OBAPI void PerceiveStereo(OBMol *mol, bool force = false);
507
  /**
508
   * Convert the 2D depiction of molecule @p mol to OBStereo objects.
509
   * This function makes use of the lower level functions
510
   * TetrahedralFrom2D(), CisTransFrom2D(), SquarePlanarFrom2D(), ...
511
   *
512
   * First, symmetry analysis taking stereochemistry into account is
513
   * performed iteratively (see OBGraphSym). Next the 2D coordinates,
514
   * OBBond::Wedge, OBBond::Hash, OBBond::WedgeOrHash and OBBond::CisOrTrans
515
   * are used to construct OBStereoBase derived objects to store the
516
   * stereochemistry. These objects will be added to @p mol.
517
   *
518
   * Unless perception is forced, this function does nothing if stereochemistry
519
   * has already been perceived (i.e. OBMol::HasChiralityPerceived()). Before
520
   * doing the actual perception, any data of the OBGenericDataType::StereoData
521
   * type will be deleted.
522
   *
523
     @verbatim
524
     Reference:
525
     [1] T. Cieplak, J.L. Wisniewski, A New Effective Algorithm for the
526
     Unambiguous Identification of the Stereochemical Characteristics of
527
     Compounds During Their Registration in Databases. Molecules 2000, 6,
528
     915-926, http://www.mdpi.org/molecules/papers/61100915/61100915.htm
529
     @endverbatim
530
   *
531
   * @param mol The molecule containing 2D coordinates.
532
   * @param updown A map of OBStereo::BondDirection for cis/trans bonds
533
   * @param force Force to run the perception even if the results are cached.
534
   *
535
   * @sa StereoFrom3D StereoFrom0D PerceiveStereo
536
   * @since version 2.3
537
   */
538
  OBAPI void StereoFrom2D(OBMol *mol,
539
    std::map<OBBond*, enum OBStereo::BondDirection> *updown = nullptr, bool force = false);
540
  /**
541
   * Convert the 3D coordinates of molecule @p mol to OBStereo objects. This
542
   * function makes use of the lower level functions TetrahedralFrom3D(),
543
   * CisTransFrom3D(), SquarePlanarFrom3D(), ...
544
   *
545
   * Unless perception is forced, this function does nothing if stereochemistry
546
   * has already been perceived (i.e. OBMol::HasChiralityPerceived()). Before
547
   * doing the actual perception, any data of the OBGenericDataType::StereoData
548
   * type will be deleted.
549
   *
550
   * @param mol The molecule containing 3D coordinates.
551
   * @param force Force to run the perception even if the results are cached.
552
   *
553
   * @sa StereoFrom3D StereoFrom0D PerceiveStereo
554
   * @since version 2.3
555
   */
556
  OBAPI void StereoFrom3D(OBMol *mol, bool force = false);
557
  /**
558
   * Add missing OBStereo objects. Unlike StereoFrom3D() and StereoFrom2D(), this
559
   * method only adds objects for previously unidentified objects since we
560
   * don't want to loose any information. The Config::specified flag for the
561
   * newly added structs is always set to false.
562
   *
563
   * For example, a smiles is read which has two tetrahedral centers. Only one has
564
   * stereochemisrty specified using a '@' character. StereoFrom0D() will detect the
565
   * second tetrahedral atom and add an OBTetrahedralStereo object to the molecule.
566
   *
567
   * @param mol The molecule.
568
   *
569
   * @sa StereoFrom3D StereoFrom2D PerceiveStereo
570
   * @since version 2.3
571
   */
572
  OBAPI void StereoFrom0D(OBMol *mol);
573
  ///@}
574
575
  ///@name Low level functions
576
  ///@{
577
  /**
578
   * Get a vector with all OBTetrahedralStereo objects for the molecule. This
579
   * function is used by StereoFrom3D() with the @p addToMol parameter is set
580
   * to true.
581
   *
582
   * The algorithm to convert the 3D coordinates to OBTetrahedralStereo object
583
   * uses the sign of the volume described by the 4 center atom neighbors. Given
584
   * 4 points \f$a\f$, \f$b\f$, \f$c\f$ and \f$d\f$, the signed volume \f$S_v\f$
585
   * is defined as:
586
   *
587
     \f[ S_v = \left| \begin{array}{ccc}
588
     x_b - x_a & y_b - y_a & z_b - z_a \\
589
     x_c - x_a & y_c - y_a & z_c - z_a \\
590
     x_d - x_a & y_d - y_a & z_d - z_a
591
     \end{array} \right| \f]
592
   *
593
   * The sign of \f$S_v\f$ changes when any of the points cross the plane defined
594
   * by the other 3 points. To make this less abstract one could say that
595
   * a change of sign is equal to inverting the tetrahedral stereochemistry.
596
   *
597
   * In case there are only 3 neighbor atoms for the tetrahedral center, the
598
   * center atom itself is used as 4th point. This only changes the magnitude
599
   * and not the sign of \f$S_v\f$ because the center atom is still on the same
600
   * side of the plane.
601
   *
602
   * This function is also used for symmetry analysis to handle cases where
603
   * there are two atoms in the same symmetry class that don't have the same
604
   * stereochemistry. In this situation, the @p addToMol parameter is set to
605
   * false and the returned objects will need to be deleted explicitly.
606
   *
607
   * @param mol The molecule.
608
   * @param stereoUnits The stereogenic units.
609
   * @param addToMol If true, the OBTetrahedralStereo objects will be added
610
   * to the molecule using OBBase::SetData().
611
   *
612
   * @sa StereoFrom3D FindStereogenicUnits
613
   * @since version 2.3
614
   */
615
  OBAPI std::vector<OBTetrahedralStereo*> TetrahedralFrom3D(OBMol *mol,
616
      const OBStereoUnitSet &stereoUnits, bool addToMol = true);
617
  /**
618
   * Get a vector with all OBTetrahedralStereo objects for the molecule. This
619
   * function is used by StereoFrom2D() with the @p addToMol parameter is set
620
   * to true.
621
   *
622
   * The algorithm to convert the 2D coordinates and bond properties
623
   * (i.e. OBBond::Wedge, OBBond::Hash, OBBond::WedgeOrHash and OBBond::CisOrTrans)
624
   * uses the sign of a triangle. Given 3 points \f$a\f$, \f$b\f$ and \f$c\f$, the
625
   * sign of the trianle \f$S_t\f$ is defined as:
626
   *
627
     \f[ S_t = (x_a - x_c) (y_b - y_c) - (y_a - y_c) (x_b - x_c) \f]
628
   *
629
   * This is equation 6 from on the referenced web page. The 3 points used
630
   * to calculate the triangle sign always remain in the same plane (i.e. z = 0).
631
   * The actual meaning of \f$S_t\f$ (i.e. assignment of OBStereo::Winding) depends
632
   * on the 4th atom. When the atom is in front of the plane, the sign should be
633
   * changed to have the same absolute meaning for an atom behind the plane and the
634
   * same triangle. It is important to note that none of the z coordinates is ever
635
   * changed, the molecule always stays 2D (unlike methods which set a pseudo-z
636
   * coordinate).
637
   *
638
   * @todo document bond property interpretation!
639
   *
640
   * This function is also used for symmetry analysis to handle cases where
641
   * there are two atoms in the same symmetry class that don't have the same
642
   * stereochemistry. In this situation, the @p addToMol parameter is set to
643
   * false and the returned objects will need to be deleted explicitly.
644
   *
645
     @verbatim
646
     Reference:
647
     [1] T. Cieplak, J.L. Wisniewski, A New Effective Algorithm for the
648
     Unambiguous Identification of the Stereochemical Characteristics of
649
     Compounds During Their Registration in Databases. Molecules 2000, 6,
650
     915-926, http://www.mdpi.org/molecules/papers/61100915/61100915.htm
651
     @endverbatim
652
   *
653
   * @param mol The molecule.
654
   * @param stereoUnits The stereogenic units.
655
   * @param addToMol If true, the OBTetrahedralStereo objects will be added
656
   * to the molecule using OBBase::SetData().
657
   *
658
   * @sa StereoFrom2D FindStereogenicUnits
659
   * @since version 2.3
660
   */
661
  OBAPI std::vector<OBTetrahedralStereo*> TetrahedralFrom2D(OBMol *mol,
662
      const OBStereoUnitSet &stereoUnits, bool addToMol = true);
663
  /**
664
   * Get a vector with all OBTetrahedralStereo objects for the molecule. This
665
   * function is used by StereoFrom0D() with the @p addToMol parameter is set
666
   * to true. There is no algorithm used here, all specified flags will be
667
   * set to false.
668
   *
669
   * This function is also used for symmetry analysis to handle cases where
670
   * there are two atoms in the same symmetry class that don't have the same
671
   * stereochemistry. In this situation, the @p addToMol parameter is set to
672
   * false and the returned objects will need to be deleted explicitly.
673
   *
674
   * @param mol The molecule.
675
   * @param stereoUnits The stereogenic units.
676
   * @param addToMol If true, the OBTetrahedralStereo objects will be added
677
   * to the molecule using OBBase::SetData().
678
   *
679
   * @sa StereoFrom0D FindStereogenicUnits
680
   * @since version 2.3
681
   */
682
  OBAPI std::vector<OBTetrahedralStereo*> TetrahedralFrom0D(OBMol *mol,
683
      const OBStereoUnitSet &stereoUnits, bool addToMol = true);
684
685
  /**
686
   * Get a vector with all OBCisTransStereo objects for the molecule. This
687
   * function is used by StereoFrom3D() with the @p addToMol parameter is set
688
   * to true.
689
   *
690
   * The algorithm to convert the 3D coordinates to OBCisTransStereo objects
691
   * considers the signed distance between the attached atoms and the plane
692
   * through the double bond at right angles to the plane of the attached
693
   * atoms. Bonds on the same side (cis) will share the same sign for the
694
   * signed distance.
695
   *
696
   * Missing atom coordinates (OBStereo::ImplicitRef) and their bond
697
   * vectors will be computed if needed.
698
   *
699
   @verbatim
700
         0      3     Get signed distance of 0 and 2 to the plane
701
          \    /      that goes through the double bond and is at
702
           C==C       right angles to the stereo bonds.
703
          /    \
704
         1      2     If the two signed distances have the same sign
705
                      then they are cis; if not, then trans.
706
   @endverbatim
707
   *
708
   * This function is also used for symmetry analysis to handle cases where
709
   * there are two atoms in the same symmetry class that don't have the same
710
   * stereochemistry. In this situation, the @p addToMol parameter is set to
711
   * false and the returned objects will need to be deleted explicitly.
712
   *
713
   * @param mol The molecule.
714
   * @param stereoUnits The stereogenic units.
715
   * @param addToMol If true, the OBCisTransStereo objects will be added
716
   * to the molecule using OBBase::SetData().
717
   *
718
   * @sa StereoFrom3D FindStereogenicUnits
719
   * @since version 2.3
720
   */
721
  OBAPI std::vector<OBCisTransStereo*> CisTransFrom3D(OBMol *mol,
722
      const OBStereoUnitSet &stereoUnits, bool addToMol = true);
723
  /**
724
   * Get a vector with all OBCisTransStereo objects for the molecule. This
725
   * function is used by StereoFrom2D() with the @p addToMol parameter is set
726
   * to true.
727
   *
728
   * This function is also used for symmetry analysis to handle cases where
729
   * there are two atoms in the same symmetry class that don't have the same
730
   * stereochemistry. In this situation, the @p addToMol parameter is set to
731
   * false and the returned objects will need to be deleted explicitly.
732
   *
733
   * The algorithm for converting the 2D coordinates uses the same triangle
734
   * sign as TetrahedralFrom2D(). Depending on sign of 2 triangles, the right
735
   * OBStereo::Shape is selected.
736
   @verbatim
737
      0      3
738
       \    /        2 triangles: 0-1-b & 2-3-a
739
        a==b    -->  same sign: U
740
       /    \        opposite sign: Z
741
      1      2
742
   @endverbatim
743
   *
744
   * @param mol The molecule.
745
   * @param stereoUnits The stereogenic units.
746
   * @param updown A map of OBStereo::BondDirection for cis/trans bonds
747
   * @param addToMol If true, the OBCisTransStereo objects will be added
748
   * to the molecule using OBBase::SetData().
749
   *
750
   * @sa StereoFrom2D FindStereogenicUnits
751
   * @since version 2.3
752
   */
753
  OBAPI std::vector<OBCisTransStereo*> CisTransFrom2D(OBMol *mol,
754
      const OBStereoUnitSet &stereoUnits,
755
      const std::map<OBBond*, enum OBStereo::BondDirection> *updown = nullptr, bool addToMol = true);
756
  /**
757
   * Convert a molecule's OBTetrahedralStereo objects to a series of hash or
758
   * wedge bonds. Note that the molecule itself is not modified; the result
759
   * is returned in the maps @p updown and @p from, which indicate
760
   * the origin and direction of each hash or wedge bond.
761
   *
762
   * When converting, the following guidelines are followed when trying to
763
   * find the best candidate bond to set up/down for each OBTetrahedralStereo
764
   * object:
765
   * -# Should not already be set
766
   * -# Should not be connected to a 2nd tet center
767
   *    (this is acceptable in theory as the wedge is only at one end, but
768
   *     in practice it may cause confusion and thus we avoid it)
769
   * -# Preferably is not in a cycle
770
   * -# Preferably is a terminal H
771
   *
772
   * If no bond can be found that matches rules 1 and 2 (and in theory this is possible)
773
   * then an error message is logged and the function returns false. (If you find an
774
   * example where this occurs, please file a bug.)
775
   *
776
   * @param mol The molecule.
777
   * @param updown A map of OBStereo::BondDirection for each hash/wedge bond
778
   * @param from A map of OBStereo::Ref indicating the origin of each hash/wedge bond
779
   * @return True or False depending on whether the conversion was successful
780
   * @since version 2.3
781
   */
782
  OBAPI bool TetStereoToWedgeHash(OBMol &mol,
783
      std::map<OBBond*, enum OBStereo::BondDirection> &updown,
784
      std::map<OBBond*, OBStereo::Ref> &from);
785
  /**
786
   * Return a set of double bonds corresponding to the OBCisTransStereo objects
787
   * for which the stereochemistry is undefined.
788
   *
789
   * Note that this functions just iterates over the existing OBCisTransStereo
790
   * objects - it does not try to identify new ones.
791
   *
792
   * @param mol The molecule
793
   * @return A set of bonds with unspecified cis/trans stereochemistry
794
   * @since version 2.3
795
   */
796
  OBAPI std::set<OBBond*> GetUnspecifiedCisTrans(OBMol& mol);
797
  /**
798
   * Convert any reference to @p atomId in a stereo object to an OBStereo::ImplicitRef.
799
   * This function is called from OBMol::DeleteHydrogens()
800
   * (via OBMol::DeleteHydrogen()) to remove any explicit references to a
801
   * hydrogen atom that has been deleted. However, the code is not specific
802
   * to hydrogen atoms and could be used for other atoms.
803
   *
804
   * @param mol The molecule
805
   * @param atomId The Id of the atom to be converted to an OBStereo::ImplicitRef
806
   * @since version 2.3
807
   */
808
  OBAPI void StereoRefToImplicit(OBMol& mol, OBStereo::Ref atomId);
809
  /**
810
   * Convert any reference to an OBStereo::ImplicitRef attached to @p centerId
811
   * in a stereo object to an explicit reference to @p newId.
812
   * This function is called from OBMol::AddHydrogens() and
813
   * OBMol::AddHydrogen() to convert any implicit references to a
814
   * hydrogen atom that has just been added. However, the code is not specific
815
   * to hydrogen atoms and could be used for other atoms.
816
   *
817
   * @param mol The molecule
818
   * @param centerId The Id of the atom to which the new explicit atom is attached
819
   * @param newId The Id of the atom which was previously an OBStereo::ImplicitRef
820
   * @since version 2.4
821
   */
822
  OBAPI void ImplicitRefToStereo(OBMol& mol, OBStereo::Ref centerId, OBStereo::Ref newId);
823
  /**
824
   * Get a vector with all OBCisTransStereo objects for the molecule. This
825
   * function is used by StereoFrom0D() with the @p addToMol parameter is set
826
   * to true. There is no algorithm used here, all specified flags will be
827
   * set to false.
828
   *
829
   * This function is also used for symmetry analysis to handle cases where
830
   * there are two atoms in the same symmetry class that don't have the same
831
   * stereochemistry. In this situation, the @p addToMol parameter is set to
832
   * false and the returned objects will need to be deleted explicitly.
833
   *
834
   * @param mol The molecule.
835
   * @param stereoUnits The stereogenic units.
836
   * @param addToMol If true, the OBCisTransStereo objects will be added
837
   * to the molecule using OBBase::SetData().
838
   *
839
   * @sa StereoFrom0D FindStereogenicUnits
840
   * @since version 2.3
841
   */
842
  OBAPI std::vector<OBCisTransStereo*> CisTransFrom0D(OBMol *mol,
843
      const OBStereoUnitSet &stereoUnits,
844
      bool addToMol = true);
845
  ///@}
846
847
848
  ///@name Stereogenic unit identification
849
  ///@{
850
  /**
851
   * Find the stereogenic units in a molecule using a set of rules.<sup>1</sup>
852
   *
853
   * The potential stereocenters are identified first. A potential tetrahedral
854
   * stereogenic atom is any atom meeting the following criteria:
855
   *
856
   * - sp3 hybridization
857
   * - at least 3 "heavy" neighbors
858
   *
859
   * Nitrogen is treated as a special case since the barrier of inversion is
860
   * low in many cases making the atom non-stereogenic. Only bridge-head
861
   * nitrogen atoms (i.e. nitrogen has 3 neighbors in rings) will be
862
   * considered stereogenic.
863
   *
864
   * Potential stereogenic double bonds are identified using another set of
865
   * simple criteria:
866
   *
867
   * - must be a double bond
868
   * - must not be in a ring
869
   * - both begin and end atom should have at least one single bond
870
   *
871
   * True stereocenters (i.e. stereocenters with topologically different
872
   * ligands) are identified first. For tetrahedral stereocenters, true
873
   * stereocenters will have 4 different neighbor atom symmetry classes
874
   * and this can be expressed using T1234 to classify these stereocenters.
875
   * For stereogenic bonds, a similar classification C12 can be used but
876
   * both begin and end atom have their own classification and the bond
877
   * is only a true stereocenter if both atoms are C12.
878
   *
879
   * Para stereocenters are all stereocenters where there are at least two
880
   * equivalent neighbor atom symmetry classes. These are T1123, T1112, T1111
881
   * and T1122 for tetrahedral stereocenters and C11 for double bonds. To
882
   * determine which of the remaining potential stereocenters really are
883
   * stereocenters, a set of rules is used.<sup>1</sup>
884
   *
885
   * Rule 1 is applied recusively:
886
   *
887
   * All rings are merged "mergedRings". A merged ring is simply a fragment consisting
888
   * of all atoms of a ring system (bridged, spiro, adjacent, ...). If two rings in the
889
   * SSSR set share an atom, they are merged.
890
   *
891
   * Each merged must at least have two para-stereocenters (or 1 true + 1 para) in order
892
   * for the para-stereocenter to be valid. This is repeated until no new stereocenters
893
   * are identified.
894
   *
895
   * rule 1a for double bonds:
896
   * - bond atom in ring has two identical symmetry classes for it's neighbor atoms (-> para)
897
   * - other bond atom:
898
   *   - has two different symmetry classes for it's neighbours -> new stereocenter
899
   *   - has two identical symmetry classes, but the ligand contains at least 1 true or para stereocenter -> new stereocenter
900
   *
901
   * rule 1b for tetracoord atoms:
902
   * - at least two neighbour symmetry classes are the same (-> para)
903
   * - other pair:
904
   *   - has two different symmetry classes for it's neighbours -> new stereocenter
905
   *   - has two identical symmetry classes, but the ligand contains at least 1 true or para stereocenter -> new stereocenter
906
   *
907
   * Rules 2 and 3 are applied sequential (i.e. only once).
908
   *
909
   * Rule 2a for tetracoordinate carbon:
910
   * - 1 or 2 pair identical ligands
911
   * - each ligand contains at least 1 true-stereocenter or 2 para-stereocenters (from rule 1)
912
   *
913
   * Rule 2b for tetracoordinate carbon:
914
   * - 3 or 4 identical ligands with at least
915
   *   - 2 true-stereocenters
916
   *   - 2 separate assemblies of para-stereocenters (from rule 1)
917
   *
918
   * Rule 3 for double bonds:
919
   * - 1 or 2 pair identical ligands (on begin and end atom)
920
   * - each pair contains at least 1 true-stereocenter or 2 para-stereocenters (from rule 1)
921
   *
922
   *
923
   * @verbatim
924
     Reference:
925
     [1] M. Razinger, K. Balasubramanian, M. Perdih, M. E. Munk, Stereoisomer
926
     Generation in Computer-Enhanced Structure Elucidation, J. Chem. Inf.
927
     Comput. Sci. 1993, 33, 812-825
928
     @endverbatim
929
   */
930
  OBAPI OBStereoUnitSet FindStereogenicUnits(OBMol *mol,
931
      const std::vector<unsigned int> &symClasses);
932
  /**
933
   * @brief Find the stereogenic units in a molecule making use of the automorphisms.
934
   *
935
   * The potential stereocenters are identified first. A potential tetrahedral
936
   * stereogenic atom is any atom meeting the following criteria:
937
   *
938
   * - sp3 hybridization
939
   * - at least 3 "heavy" neighbors
940
   *
941
   * Nitrogen is treated as a special case since the barrier of inversion is
942
   * low in many cases making the atom non-stereogenic. Only bridge-head
943
   * nitrogen atoms (i.e. nitrogen has 3 neighbors in rings) will be
944
   * considered stereogenic.
945
   *
946
   * Potential stereogenic double bonds are identified using another set of
947
   * simple criteria:
948
   *
949
   * - must be a double bond
950
   * - must not be in a ring
951
   * - both begin and end atom should have at least one single bond
952
   *
953
   * Once the potential stereocenters are found, the automorphisms are the key
954
   * to identifying real stereogenic units. Automorphisms can be seen as
955
   * permutations that permutate a graph back to the same graph. Such a
956
   * permutation can only exchange atoms with the same symmetry class and it
957
   * follows that the use of automorphisms takes symmetry into account. The
958
   * definitions below use a concept where the automorphisms cause inversions
959
   * of configuration to potential stereocenters. Such an inversion occurs
960
   * whenever an automorphism exchanges two equivalent (i.e. with the same
961
   * symmetry class) neighbor atoms attached to the potential stereogenic unit.
962
   *
963
   * @par Definition for tetrahedral stereocenters:
964
   * A potential stereocenter really is a stereocenter if there exists no automorphic
965
   * permutation causing an inversion of the configuration of only the potential
966
   * stereogenic unit under consideration.
967
   * If there exists at least one automorphic permutation causing an inversion of
968
   * the configuration, then the potential stereogenic center can be a stereogenic
969
   * center if the number of topologically equivalent neighbors (ligands) of the
970
   * potential stereogenic center is less than or equal to the number of different
971
   * configurations of these ligands.<sup>1</sup>
972
   *
973
   * The actual number of configurations needed for the ligands depends on the
974
   * classification (i.e. T1234, T1123, ...) of the stereo center. These classes
975
   * reflect the symmetry classes of the neighbor atoms of the center.
976
   *
977
   * - T1123: 1 true stereocenter OR 2 para stereocenters
978
   * - T1122: 1 true stereocenter OR 2 para stereocenters (for both)
979
   * - T1112: 2 true stereocenters OR 2 para stereocenter assemblies
980
   * - T1111: 2 true stereocenters OR 2 para stereocenter assemblies
981
   *
982
   * @par Definition for double bond stereocenters:
983
   * A potential stereogenic double bond really is a stereogenic bond if there
984
   * exists no automorphic permutation causing an inversion of the configuration
985
   * of only the potential stereogenic unit under consideration. The bond can still
986
   * be a stereogenic bond if there exists such an automorphism when the number of
987
   * configurations of the pair of topologically equivalent geminal ligands, which
988
   * are exchanged by the automorphism, is greater than or equal to two (i.e. the
989
   * number of topologically equivalent geminal ligands.<sup>1</sup>
990
   *
991
   * For stereogenic bonds, there is only one case but both begin and end atom
992
   * have to be checked.
993
   *
994
   * - C11: 1 true stereocenter OR 1 para stereocenter
995
   *
996
   * These criteria are analogous to the rules from the Razinger paper on
997
   * stereoisomer generation. Since the existence of stereocenters can depend
998
   * on the existence of other stereocenters (in the ligands), the stereocenters
999
   * are found by iterating until no new stereocenters are found.
1000
   *
1001
   * @verbatim
1002
     Reference:
1003
     [1] M. Perdih, M. Razinger, Stereochemistry and Sequence Rules:
1004
     A Proposal for Modification of Cahn-Ingold-Prelog System,
1005
     Tetrahedron: Asymmetry, 1994, Vol. 5, No. 5, 835-861
1006
     @endverbatim
1007
   */
1008
  OBAPI OBStereoUnitSet FindStereogenicUnits(OBMol *mol,
1009
      const std::vector<unsigned int> &symClasses,
1010
      const Automorphisms &automorphisms);
1011
  ///@}
1012
1013
  /**
1014
   * @page Stereochemistry
1015
   * @section overview Overview of classes
1016
   *
1017
   * There are many molecules which contain stereogenic elements. However,
1018
   * certain cases (i.e. tetrahedral, cis/trans) are more common than others
1019
   * (i.e. allene, biphenyl, octrahedral, ...). For the common stereogenic
1020
   * units, classes are provided. The inheritance of these classes resembles
1021
   * the way they are split into groups.
1022
   *
1023
   * - OBStereoBase
1024
   *   - OBTetraNonPlanarStereo
1025
   *     - OBTetrahedralStereo
1026
   *     - OBExtendedTetrahedralStereo
1027
   *   - OBTetraPlanarStereo
1028
   *     - OBCisTransStereo
1029
   *     - OBExtendedCisTransStereo
1030
   *     - OBSquarePlanarStereo
1031
   *   - OBAxialStereo
1032
   *     - OBTrigonalBipyrimidalStereo
1033
   *     - OBOctahedralStereo
1034
   *
1035
   * @image html tetranonplanar.png
1036
   * @image html tetraplanar.png
1037
   *
1038
   * All specific classes (i.e. OBTetrahedralStereo, ...) have embedded Config
1039
   * structs which define the actual stereochemistry. All these Config structs
1040
   * use OBStereo::Ref values to reference or uniquely identify atoms. Make sure
1041
   * to read about OBStereo::Ref and the related functions (in OBStereo). OBStereo
1042
   * is also a placeholder for various enums with predefined values for parameters
1043
   * etc. These enums are used throughout the different stereo classes but having
1044
   * these enums in a single location makes it easier to remember. When working
1045
   * with stereo classes, you normally don't need to use any of the parent classes
1046
   * directly. Only OBStereo and the specific class are needed.
1047
   *
1048
   * @section usage Basic usage
1049
   *
1050
   * The OBStereoFacade hides the complexity of working with stereochemistry. When
1051
   * using openbabel as a library, this is by far the easiest way to access
1052
   * stereochemistry information.
1053
   * The header for the specific OBStereo::Type type is all you need to include.
1054
   * These are:
1055
   * - @em openbabel/stereo/tetrahedral.h
1056
   * - @em openbabel/stereo/cistrans.h
1057
   * - @em openbabel/stereo/squareplanar.h
1058
   *
1059
   * All these headers also include @em openbabel/stereo/stereo.h providing
1060
   * declarations for OBStereo & OBStereoFacade.
1061
   *
1062
     @code
1063
     #include <iostream>
1064
     #include <openbabel/mol.h>
1065
     #include <openbabel/obconversion.h>
1066
1067
     #include <openbabel/stereo/tetrahedral.h>
1068
1069
     using namespace OpenBabel;
1070
1071
     int main()
1072
     {
1073
       OBMol mol;
1074
       OBConversion conv;
1075
       conv.SetInFormat("smi");
1076
       conv.ReadString(&mol, "C[C@H](Cl)Br");
1077
1078
       OBStereoFacade facade(&mol);
1079
1080
       FOR_ATOMS_OF_MOL(atom, mol) {
1081
         if (facade.HasTetrahedralStereo(atom->GetId()))
1082
           std::cout << facade.GetTetrahedralStereo(atom->GetId()) << std::endl;
1083
       }
1084
     }
1085
     @endcode
1086
   *
1087
   * All specific stereo classes and their embedded Config struct have an
1088
   * operator<< function which allows them to be used with std::ostream objects
1089
   * (e.g. std::cout, std::err, ...). These functions are often useful when
1090
   * debugging code.
1091
   *
1092
   * @section details Details on implementation
1093
   *
1094
   * The detection of stereogenic units start with symmetry analysis. However, a
1095
   * complete symmetry analysis also needs to take stereochemistry into account.
1096
   * In practice, this means stereochemistry will be found iteratively. At each
1097
   * iteration, the current atom symmetry classes are used to identify stereogenic
1098
   * units. The details about how the symmetry classes are used depends on the type
1099
   * (OBStereo::Type) of stereogenic unit. For tetrahedral centers, having 3 heavy
1100
   * atom neighbors with different symmetry classes or 4 neighbors with different
1101
   * symmetry classes means the atom is chiral. See FindStereogenicUnits() for
1102
   * details.
1103
   *
1104
   * After identifying the stereogenic units, Config structs with all the
1105
   * information on the spacial arrangement of the groups still have to be
1106
   * created. This involves interpreting various ways to represent
1107
   * stereochemisrty:
1108
   *
1109
   * - 3D coordinates: StereoFrom3D()
1110
   * - 2D coordinates: StereoFrom2D()
1111
   * - 0D coordinates: StereoFrom0D()
1112
   *
1113
   * Both StereoFrom3D() and StereoFrom2D() delete all existing stereochemistry objects
1114
   * before adding new ones. For molecules with 3D coordinates, it is evident that
1115
   * all information is specified by the coordinates itself. However, if a file format
1116
   * uses stereo parity flags, Config structs must be constructed using lower level
1117
   * functions and StereoFrom3D() should not be called. In these cases information
1118
   * could be lost by calling StereoFrom3D() after reading the file (the stereo flag might have
1119
   * indicated the stereochemistry was unspecified or the flag might not match the
1120
   * coordinates). In the case of 2D molecules, the coordinates together with bond
1121
   * properties (OBBond::Hash, OBBond::Wedge, OBBond::WedgeOrHash and
1122
   * OBBond::CisOrTrans) define the stereochemistry. Again, lower level functions
1123
   * can be used when stereo flags need to be used.
1124
   *
1125
   * StereoFrom0D() works slightly different than 3D/2D. Here, deleting the
1126
   * stereochemistry would always result in lost information. Instead StereoFrom0D()
1127
   * only adds new objects for stereogenic units which were previously not found.
1128
   * For example, a smiles is read which has two tetrahedral centers. Only one has
1129
   * stereochemistry specified using a '@' character. StereoFrom0D() will detect the
1130
   * second tetrahedral atom and add an OBTetrahedralStereo object to the molecule.
1131
   * The Config::specified flag for the newly added structs is always set to false.
1132
   *
1133
   * Assuming the format code has correctly set the molecule dimensions (OBMol::GetDimesions),
1134
   * PerceiveStereo() will automatically select the correct function to call.
1135
   * When StereoFrom3D(), StereoFrom2D() or StereoFrom0D() are not used, make sure to always
1136
   * set OBMol::HasChiralityPerceived() before returning from the format's ReadMolecule().
1137
   *
1138
   *
1139
   * @section formats Guidelines for formats
1140
   * @subsection input Reading files
1141
   *
1142
   * - Read the section above
1143
   * - The MDL format (mdlformat.cpp) is a good example for 2D/3D formats with or
1144
   *   without parity flags.
1145
   * - The SMILES format (smilesformat.cpp) is a good example for 0D formats.
1146
   *
1147
   * @subsection output Writing files
1148
   *
1149
   * For many file formats no additional code is needed. For example, if a 3D format
1150
   * doesn't require stereo parity flags, writing the coordinates is enough. For 2D
1151
   * file formats it will often suffice to write the coordinates and bond properties.
1152
   * If parity flags are needed, the OBStereoFacade class can be used to retrieve the
1153
   * objects for all types of stereochemistry supported by the file format.
1154
   *
1155
   *
1156
   *
1157
   *
1158
   *
1159
   * @since version 2.3
1160
   */
1161
1162
  ///@}  addtogroup
1163
}
1164
1165
#endif
1166
1167
//! \file stereo.h
1168
//! \brief Process molecular stereochemistry information.