RDKit
Open-source cheminformatics and machine learning.
Loading...
Searching...
No Matches
SingleConformerAlignment.h
Go to the documentation of this file.
1//
2// Copyright (C) 2026 David Cosgrove 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// Original author: David Cosgrove (CozChemIx Limited)
11//
12// This is the class that does optimises a moving molecule (fit)
13// to maximise its Gaussian overlap with the reference molecule (ref).
14// The optimiser is a modified BFGS taken in large part, but re-arranged
15// for readability, from the PubChem shape overlay code
16// https://github.com/ncbi/pubchem-align3d/blob/main/shape_neighbor.cpp
17
18#ifndef RDKIT_SINGLECONFORMERALIGNMENT_GUARD
19#define RDKIT_SINGLECONFORMERALIGNMENT_GUARD
20
21#include <array>
22
24#include <boost/dynamic_bitset.hpp>
26
27#include <RDGeneral/export.h>
30
31namespace RDKit {
32namespace GaussianShape {
35 /// @brief Do the overlay for a single conformer of fit against a single
36 /// conformer of ref. The output in scores is the rotation and translation
37 /// that moves fit to optimise its score with ref.
38 /// @param ref - the reference molecule as 1D array of 3 * N entries. Each
39 /// block of 3 is the coords
40 /// @param refAlphas - the alpha values for the reference
41 /// @param refTypes - the feature types for molecule ref
42 /// @param refCarbonRadii - whether each atom has a carbon radius
43 /// @param nRefShape - the number of atoms in ref
44 /// @param nRefColor - the number of features in ref
45 /// @param refShapeVol - overlap volume of ref with itself
46 /// @param refColorVol - color overlap of ref with itself
47 /// @param fit - the fit molecule as 1D array of 3 * N entries. Each
48 /// block of 3 is the coords.
49 /// @param fitAlphas - the alpha values for the fit
50 /// @param fitTypes - the feature types for fit molecule
51 /// @param fitCarbonRadii - whether each atom has a carbon radius
52 /// @param nFitShape - the number of atoms in fit
53 /// @param nFitColor - the number of features in fit
54 /// @param fitShapeVol - overlap volume of fit with itself
55 /// @param fitColorVol - color overlap of fit with itself
56 /// @param optimMode - optimisation mode
57 /// @param simAlpha - for the Tversky similarity, the alpha value
58 /// @param simBeta - for the Tversky similarity, the beta value
59 /// @param mixingParam - how to mix the 2 Tversky values
60 /// @param useCutoff - whether to use a distance cutoff in the volume
61 /// calculation
62 /// @param distCutoff - the cutoff to use if we're doing it.
63 /// @param maxIts - maximum number of iterations for optimiser
64 /// of optimiser
66 const std::vector<double> &ref, const std::vector<double> &refAlphas,
67 const int *refTypes, const boost::dynamic_bitset<> *refCarbonRadii,
68 int nRefShape, int nRefColor, double refShapeVol, double refColorVol,
69 const std::vector<double> &fit, const std::vector<double> &fitAlphas,
70 const int *fitTypes, const boost::dynamic_bitset<> *fitCarbonRadii,
71 int nFitShape, int nFitColor, double fitShapeVol, double fitColorVol,
72 const std::array<double, 7> &initQuatTrans, OptimMode optimMode,
73 double simAlpha, double simBeta, double mixingParam, bool useCutoff,
74 double distCutoff, double shapeConvergenceCriterion, unsigned int maxIts);
75
79 delete;
81 delete;
83
84 void setQuatTrans(const std::array<double, 7> &quatTrans) {
85 d_quatTrans = quatTrans;
86 }
87
88 // Get the final transformation by adding the initial transformation
89 // and the optimised final answer.
91
92 // Calculate the combined, shape, and color Tversky scores as appropriate,
93 // plus the volume of the shape and color overlaps, in that order.
94 // Assumes that ref and fit are already in the correct configurations.
95 // If includeColor is passed in true, it will compute the color score
96 // irrespective of the value in d_optimMode. We still want the color
97 // score even if doing SHAPE_ONLY optimisation, for example.
98 std::array<double, 5> calcScores(const double *ref, const double *fit,
99 bool includeColor = false);
100 // This one applies the current quatTrans to the coords and then calculates
101 // the score.
102 std::array<double, 5> calcScores(bool includeColor = false);
103 // This one computes the scores from the given overlap volumes. Color score
104 // only calculated if the color volumes are non-zero.
105 std::array<double, 5> calcScores(const double shapeOvVol,
106 const double colorOvVol,
107 bool includeColor = true) const;
108
109 // Apply the quatTrans to the ref and fit shapes and put the results
110 // into their tmp equivalents. Ref is translated by the -ve of the
111 // translation, fit is rotated by the rotation bit.
112 void applyQuatTrans(const std::array<double, 7> &quatTrans);
113
114 // Calculate the overlap volume between A and B after the given "quaternion"
115 // has been applied. The "quaternion" is 7 elements, the first 4 the
116 // quaternion the last 3 the translation that currently form the
117 // transformation that overlays B onto A.
118 void calcVolumeAndGradients(const std::array<double, 7> &quatTrans,
119 double &shapeOvlpVol, double &colorOvlpVol,
120 std::array<double, 7> &gradients);
121
122 /// @brief Do the overlay, feeding the results into scores.
123 /// @return scores - the output scores and transformation to reproduce the
124 /// overlay - an array of size 20. Only the first 16 are used here. They are:
125 /// 0 - the combo score
126 /// 1 - the shape Tversky score
127 /// 2 - the color Tversky score
128 /// 3 - the shape overlap volume
129 /// 4 - the color overlap volume
130 /// 5 - the shape volume of fit
131 /// 6 - the shape volume of ref
132 /// 7 - the color volume of fit
133 /// 8 - the color volume of ref
134 /// 9-12 - the quaternion to rotate fit onto ref. Applied first.
135 /// 13-15 - the translation to move fit onto ref. Applied second.
136 /// 16-19 - not used at present, returned as zeros.
137 /// Returns false if it didn't finish with the allowed maximum number of
138 /// iterations.
139 bool doOverlay(std::array<double, 20> &scores, unsigned int cycle);
140
141 // Find the quaternion and translation that maximises the volume
142 // overlap appropriate to d_optimMode. Returns false if it didn't finish with
143 // the allowed maximum number of iterations.
144 bool optimise(unsigned int maxIters);
145
146 std::vector<double> d_ref;
147 std::vector<double> d_refAlphas;
148 std::vector<double> d_refTemp;
149 const int *d_refTypes;
150 const boost::dynamic_bitset<> *d_refCarbonRadii;
151 const int d_nRefShape;
152 const int d_nRefColor;
153 const double d_refShapeVol;
154 const double d_refColorVol;
155 std::vector<double> d_fit;
156 std::vector<double> d_fitAlphas;
157 std::vector<double> d_fitTemp;
158 const int *d_fitTypes;
159 const boost::dynamic_bitset<> *d_fitCarbonRadii;
160 const int d_nFitShape;
161 const int d_nFitColor;
164 std::array<double, 7> d_initQuatTrans;
165 const OptimMode d_optimMode;
166 const double d_simAlpha;
167 const double d_simBeta;
168 const double d_mixingParam;
169 const bool d_useCutoff;
170 const double d_distCutoff2;
172 const unsigned int d_maxIts;
173 // The quaternion/translation as the optimisation proceeds
174 std::array<double, 7> d_quatTrans{1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
175 // The step sizes of the quaternion and translation during the
176 // optimisation. Taken from the PubChem code.
177 double d_qStepSize{-0.001};
178 double d_tStepSize{-0.01};
179 // Scratch space for the gradients dr/dQ of the fit molecule.
180 std::vector<double> d_gradConverters;
181};
182
183// Compute the volume overlap and optionally "quaternion" gradients for the
184// overlap volume of ref and fit, wrt fit. fit is the original coords of
185// the fit molecule, fitTemp is those subject to any transformation applied
186// by the quaternion we're using to optimise the overlap volume. If
187// gradients is null, they won't be calculated. They are assumed to be
188// initialised correctly.
189// This is for the atoms/shape features. Negative alphas are skipped.
191 const double *ref, const double *refAlphas, int numRefPts,
192 const boost::dynamic_bitset<> *refCarbonRadii, const double *fit,
193 const double *fitAlphas, int numFitPts,
194 const boost::dynamic_bitset<> *fitCarbonRadii,
195 std::vector<double> &gradConverters, const bool useCutoff,
196 const double distCutoff2, const double *quat = nullptr,
197 double *gradients = nullptr);
198// This one is for the features, and only calculates values if the types
199// of 2 features match. Negative alphas are skipped.
201 const double *ref, const double *refAlphas, int numRefPts,
202 const int *refTypes, const double *fit, const double *fitAlphas,
203 int numFitPts, const int *fitTypes, int numFitShape,
204 std::vector<double> &gradConverters, const bool useCutoff,
205 const double distCutoff2, const double *quat, double *gradients);
206
207} // namespace GaussianShape
208} // namespace RDKit
209
210#endif // RDKIT_SINGLECONFORMERALIGNMENT_GUARD
#define RDKIT_GAUSSIANSHAPE_EXPORT
Definition export.h:233
RDKIT_GAUSSIANSHAPE_EXPORT double calcVolAndGrads(const double *ref, const double *refAlphas, int numRefPts, const boost::dynamic_bitset<> *refCarbonRadii, const double *fit, const double *fitAlphas, int numFitPts, const boost::dynamic_bitset<> *fitCarbonRadii, std::vector< double > &gradConverters, const bool useCutoff, const double distCutoff2, const double *quat=nullptr, double *gradients=nullptr)
Std stuff.
std::array< double, 5 > calcScores(const double *ref, const double *fit, bool includeColor=false)
void setQuatTrans(const std::array< double, 7 > &quatTrans)
SingleConformerAlignment & operator=(SingleConformerAlignment &&other)=delete
SingleConformerAlignment(const SingleConformerAlignment &other)=delete
std::array< double, 5 > calcScores(bool includeColor=false)
void applyQuatTrans(const std::array< double, 7 > &quatTrans)
SingleConformerAlignment & operator=(const SingleConformerAlignment &other)=delete
SingleConformerAlignment(const std::vector< double > &ref, const std::vector< double > &refAlphas, const int *refTypes, const boost::dynamic_bitset<> *refCarbonRadii, int nRefShape, int nRefColor, double refShapeVol, double refColorVol, const std::vector< double > &fit, const std::vector< double > &fitAlphas, const int *fitTypes, const boost::dynamic_bitset<> *fitCarbonRadii, int nFitShape, int nFitColor, double fitShapeVol, double fitColorVol, const std::array< double, 7 > &initQuatTrans, OptimMode optimMode, double simAlpha, double simBeta, double mixingParam, bool useCutoff, double distCutoff, double shapeConvergenceCriterion, unsigned int maxIts)
Do the overlay for a single conformer of fit against a single conformer of ref. The output in scores ...
bool doOverlay(std::array< double, 20 > &scores, unsigned int cycle)
Do the overlay, feeding the results into scores.
SingleConformerAlignment(SingleConformerAlignment &&other)=delete
std::array< double, 5 > calcScores(const double shapeOvVol, const double colorOvVol, bool includeColor=true) const
void getFinalQuatTrans(RDGeom::Transform3D &xform) const
void calcVolumeAndGradients(const std::array< double, 7 > &quatTrans, double &shapeOvlpVol, double &colorOvlpVol, std::array< double, 7 > &gradients)