mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-04 21:54:27 +08:00
* add the _CIPNeighborRanks property * store CIP-ranked chiral neighbors * store CIP-ranked SP2 bond and atropisomer anchors * add a test * boost headers in test * add Atom::NOATOM * add NOATOM test * amend and clarify implicit H in Tetrahedral * rename property * rename property to _CIPNeighborOrder * deprecate Chirality::StereoInfo::NOATOM
226 lines
5.8 KiB
C++
226 lines
5.8 KiB
C++
//
|
|
//
|
|
// Copyright (C) 2020 Schrödinger, LLC
|
|
//
|
|
// @@ All Rights Reserved @@
|
|
// This file is part of the RDKit.
|
|
// The contents are covered by the terms of the BSD license
|
|
// which is included in the file license.txt, found at the root
|
|
// of the RDKit source tree.
|
|
//
|
|
#pragma once
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "../Descriptor.h"
|
|
#include "../Digraph.h"
|
|
#include "../CIPMol.h"
|
|
|
|
namespace RDKit {
|
|
|
|
class Atom;
|
|
class Bond;
|
|
|
|
namespace CIPLabeler {
|
|
|
|
// used to represent the index of implicit Hs
|
|
inline constexpr unsigned int IMPLICITH =
|
|
std::numeric_limits<unsigned int>::max();
|
|
|
|
class Rules;
|
|
|
|
class Configuration {
|
|
public:
|
|
template <typename T>
|
|
static int parity4(const std::vector<T> &trg, const std::vector<T> &ref) {
|
|
if (ref.size() != 4 || trg.size() != ref.size()) {
|
|
throw std::runtime_error("Parity vectors must have size 4.");
|
|
}
|
|
|
|
if (ref[0] == trg[0]) {
|
|
if (ref[1] == trg[1]) {
|
|
// a,b,c,d -> a,b,c,d
|
|
if (ref[2] == trg[2] && ref[3] == trg[3]) {
|
|
return 2;
|
|
}
|
|
// a,b,c,d -> a,b,d,c
|
|
if (ref[2] == trg[3] && ref[3] == trg[2]) {
|
|
return 1;
|
|
}
|
|
} else if (ref[1] == trg[2]) {
|
|
// a,b,c,d -> a,c,b,d
|
|
if (ref[2] == trg[1] && ref[3] == trg[3]) {
|
|
return 1;
|
|
}
|
|
// a,b,c,d -> a,c,d,b
|
|
if (ref[2] == trg[3] && ref[3] == trg[1]) {
|
|
return 2;
|
|
}
|
|
} else if (ref[1] == trg[3]) {
|
|
// a,b,c,d -> a,d,c,b
|
|
if (ref[2] == trg[2] && ref[3] == trg[1]) {
|
|
return 1;
|
|
}
|
|
// a,b,c,d -> a,d,b,c
|
|
if (ref[2] == trg[1] && ref[3] == trg[2]) {
|
|
return 2;
|
|
}
|
|
}
|
|
} else if (ref[0] == trg[1]) {
|
|
if (ref[1] == trg[0]) {
|
|
// a,b,c,d -> b,a,c,d
|
|
if (ref[2] == trg[2] && ref[3] == trg[3]) {
|
|
return 1;
|
|
}
|
|
// a,b,c,d -> b,a,d,c
|
|
if (ref[2] == trg[3] && ref[3] == trg[2]) {
|
|
return 2;
|
|
}
|
|
} else if (ref[1] == trg[2]) {
|
|
// a,b,c,d -> b,c,a,d
|
|
if (ref[2] == trg[0] && ref[3] == trg[3]) {
|
|
return 2;
|
|
}
|
|
// a,b,c,d -> b,c,d,a
|
|
if (ref[2] == trg[3] && ref[3] == trg[0]) {
|
|
return 1;
|
|
}
|
|
} else if (ref[1] == trg[3]) {
|
|
// a,b,c,d -> b,d,c,a
|
|
if (ref[2] == trg[2] && ref[3] == trg[0]) {
|
|
return 2;
|
|
}
|
|
// a,b,c,d -> b,d,a,c
|
|
if (ref[2] == trg[0] && ref[3] == trg[2]) {
|
|
return 1;
|
|
}
|
|
}
|
|
} else if (ref[0] == trg[2]) {
|
|
if (ref[1] == trg[1]) {
|
|
// a,b,c,d -> c,b,a,d
|
|
if (ref[2] == trg[0] && ref[3] == trg[3]) {
|
|
return 1;
|
|
}
|
|
// a,b,c,d -> c,b,d,a
|
|
if (ref[2] == trg[3] && ref[3] == trg[0]) {
|
|
return 2;
|
|
}
|
|
} else if (ref[1] == trg[0]) {
|
|
// a,b,c,d -> c,a,b,d
|
|
if (ref[2] == trg[1] && ref[3] == trg[3]) {
|
|
return 2;
|
|
}
|
|
// a,b,c,d -> c,a,d,b
|
|
if (ref[2] == trg[3] && ref[3] == trg[1]) {
|
|
return 1;
|
|
}
|
|
} else if (ref[1] == trg[3]) {
|
|
// a,b,c,d -> c,d,a,b
|
|
if (ref[2] == trg[0] && ref[3] == trg[1]) {
|
|
return 2;
|
|
}
|
|
// a,b,c,d -> c,d,b,a
|
|
if (ref[2] == trg[1] && ref[3] == trg[0]) {
|
|
return 1;
|
|
}
|
|
}
|
|
} else if (ref[0] == trg[3]) {
|
|
if (ref[1] == trg[1]) {
|
|
// a,b,c,d -> d,b,c,a
|
|
if (ref[2] == trg[2] && ref[3] == trg[0]) {
|
|
return 1;
|
|
}
|
|
// a,b,c,d -> d,b,a,c
|
|
if (ref[2] == trg[0] && ref[3] == trg[2]) {
|
|
return 2;
|
|
}
|
|
} else if (ref[1] == trg[2]) {
|
|
// a,b,c,d -> d,c,b,a
|
|
if (ref[2] == trg[1] && ref[3] == trg[0]) {
|
|
return 2;
|
|
}
|
|
// a,b,c,d -> d,c,a,b
|
|
if (ref[2] == trg[0] && ref[3] == trg[1]) {
|
|
return 1;
|
|
}
|
|
} else if (ref[1] == trg[0]) {
|
|
// a,b,c,d -> d,a,c,b
|
|
if (ref[2] == trg[2] && ref[3] == trg[1]) {
|
|
return 2;
|
|
}
|
|
// a,b,c,d -> d,a,b,c
|
|
if (ref[2] == trg[1] && ref[3] == trg[2]) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// We should never hit this, but the compiler still complains
|
|
// about a missing return statement.
|
|
return 0;
|
|
}
|
|
|
|
Configuration() = delete;
|
|
|
|
Configuration(const CIPMol &mol, Atom *focus);
|
|
|
|
Configuration(const CIPMol &mol, std::vector<Atom *> &&foci,
|
|
bool atropisomerMode = false);
|
|
|
|
virtual ~Configuration();
|
|
|
|
Atom *getFocus() const;
|
|
|
|
const std::vector<Atom *> &getFoci() const;
|
|
|
|
const std::vector<Atom *> &getCarriers() const;
|
|
|
|
Digraph &getDigraph();
|
|
|
|
virtual Descriptor label(Node *node, Digraph &digraph, const Rules &comp);
|
|
|
|
virtual Descriptor label(const Rules &comp) = 0;
|
|
|
|
virtual void setPrimaryLabel(Descriptor desc) = 0;
|
|
|
|
virtual bool hasPrimaryLabel() const = 0;
|
|
|
|
virtual void resetPrimaryLabel() const = 0;
|
|
|
|
protected:
|
|
Edge *findInternalEdge(const std::vector<Edge *> &edges, Atom *f1, Atom *f2);
|
|
|
|
bool isInternalEdge(const Edge *edge, Atom *f1, Atom *f2);
|
|
|
|
void removeInternalEdges(std::vector<Edge *> &edges, Atom *f1, Atom *f2);
|
|
|
|
bool isDuplicateOrHydrogenEdge(const Edge *edge);
|
|
|
|
void removeDuplicatesAndHs(std::vector<Edge *> &edges);
|
|
|
|
void setCarriers(std::vector<Atom *> &&carriers);
|
|
|
|
private:
|
|
/**
|
|
* Foci are the atoms on which the configuration is based,
|
|
* and which will carry the label. E.g., the chiral atom in
|
|
* a tetrahedral chirality, or the bond ends in a double bond.
|
|
*/
|
|
std::vector<Atom *> d_foci;
|
|
|
|
/**
|
|
* Carriers are the atoms neighboring the foci that define the
|
|
* configuration. E.g., for a chiral atom, its four neighbors
|
|
* define a parity; for a double bond, one neighbor on each
|
|
* side of the bond defines it as Cis or Trans.
|
|
*/
|
|
std::vector<Atom *> d_carriers;
|
|
|
|
Digraph d_digraph;
|
|
|
|
}; // namespace CIPLabeler
|
|
|
|
} // namespace CIPLabeler
|
|
} // namespace RDKit
|