42
41
//do quick test to see if there are any possible chiral centers
43
42
bool mayHaveChiralCenter=false;
45
vector<OBNodeBase*>::iterator i;
44
vector<OBAtom*>::iterator i;
46
45
for (atom = BeginAtom(i);atom;atom = NextAtom(i))
47
if (atom->GetHyb() == 3 && atom->GetHvyValence() >= 3)
46
if (atom->GetHyb() == 3 && atom->GetHvyValence() >= 3)
49
mayHaveChiralCenter=true;
48
mayHaveChiralCenter=true;
53
52
if (!mayHaveChiralCenter)
57
vector<OBEdgeBase*>::iterator j;
56
vector<OBBond*>::iterator j;
58
57
for (bond = BeginBond(j);bond;bond = NextBond(j))
59
if (bond->IsWedge() || bond->IsHash())
60
(bond->GetBeginAtom())->SetChiral();
58
if (bond->IsWedge() || bond->IsHash())
59
(bond->GetBeginAtom())->SetChiral();
66
61
vector<unsigned int> vgid;
67
62
GetGIDVector(vgid);
68
63
vector<unsigned int> tlist;
69
64
vector<unsigned int>::iterator k;
70
#else //use Golender floating point method
73
GraphPotentials(*this,gp);
75
vector<double>::iterator k;
79
67
for (atom = BeginAtom(i);atom;atom = NextAtom(i))
80
if (atom->GetHyb() == 3 && atom->GetHvyValence() >= 3 && !atom->IsChiral())
68
if (atom->GetHyb() == 3 && atom->GetHvyValence() >= 3 && !atom->IsChiral())
85
for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
73
for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j))
87
for (k = tlist.begin();k != tlist.end();k++)
90
if (vgid[nbr->GetIdx()-1] == *k)
93
if (fabs(gp[nbr->GetIdx()]-*k) < 0.001)
101
tlist.push_back(vgid[nbr->GetIdx()-1]);
105
tlist.push_back(gp[nbr->GetIdx()]);
75
for (k = tlist.begin();k != tlist.end();++k)
76
if (vgid[nbr->GetIdx()-1] == *k)
80
tlist.push_back(vgid[nbr->GetIdx()-1]);
117
// Seems to make a vector chirality become filled with array of +/- 1 for chiral atoms.
118
void GetChirality(OBMol &mol, std::vector<int> &chirality)
91
// Seems to make a vector chirality become filled with array of +/- 1 for chiral atoms.
92
void GetChirality(OBMol &mol, std::vector<int> &chirality)
120
94
chirality.resize(mol.NumAtoms()+1);
121
95
fill(chirality.begin(),chirality.end(),0);
124
vector<OBNodeBase*>::iterator i;
98
vector<OBAtom*>::iterator i;
125
99
for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i))
126
if (atom->IsChiral())
128
if (!atom->HasChiralVolume())
130
double sv = CalcSignedVolume(mol,atom);
133
chirality[atom->GetIdx()-1] = -1;
134
atom->SetNegativeStereo();
138
chirality[atom->GetIdx()-1] = 1;
139
atom->SetPositiveStereo();
142
else // already calculated signed volume (e.g., imported from somewhere)
144
if (atom ->IsPositiveStereo())
145
chirality[atom->GetIdx()-1] = 1;
147
chirality[atom->GetIdx()-1] = -1;
100
if (atom->IsChiral())
102
if (!atom->HasChiralVolume())
104
double sv = CalcSignedVolume(mol,atom);
107
chirality[atom->GetIdx()-1] = -1;
108
atom->SetNegativeStereo();
112
chirality[atom->GetIdx()-1] = 1;
113
atom->SetPositiveStereo();
116
else // already calculated signed volume (e.g., imported from somewhere)
118
if (atom ->IsPositiveStereo())
119
chirality[atom->GetIdx()-1] = 1;
121
chirality[atom->GetIdx()-1] = -1;
152
int GetParity4Ref(vector<unsigned int> pref)
154
if(pref.size()!=4)return(-1); // should be given a vector of size 4.
156
for (int i=0;i<3;i++) // do the bubble sort this many times
158
for(int j=0;j<3;j++) // iterate across the array 4th element has no
159
{ // right hand neighbour so no need to sort
160
if (pref[j+1] < pref[j]) // compare the two neighbors
162
unsigned int tmp = pref[j]; // swap a[j] and a[j+1]
165
parity++; // parity odd will invert stereochem
126
int GetParity4Ref(vector<unsigned int> pref)
128
if(pref.size()!=4)return(-1); // should be given a vector of size 4.
130
for (int i=0;i<3;++i) // do the bubble sort this many times
132
for(int j=0;j<3;++j) // iterate across the array 4th element has no
133
{ // right hand neighbour so no need to sort
134
if (pref[j+1] < pref[j]) // compare the two neighbors
136
unsigned int tmp = pref[j]; // swap a[j] and a[j+1]
139
parity++; // parity odd will invert stereochem
169
143
return(parity%2);
172
bool CorrectChirality(OBMol &mol, OBAtom *atm, atomreftype i, atomreftype o)
146
bool CorrectChirality(OBMol &mol, OBAtom *atm, atomreftype i, atomreftype o)
174
148
if (!atm->HasChiralitySpecified()) // if no chirality defined can't do any more for 0D
177
151
int parityI=0,parityO=0;
178
152
OBChiralData* cd=(OBChiralData*)atm->GetData(OBGenericDataType::ChiralData);
179
153
if ((cd->GetAtom4Refs(input)).size()!=4)return(false); // must have 4 refs
180
154
parityI=GetParity4Ref(cd->GetAtom4Refs(i)); // Gets Atom4Refs used to define the chirality
181
155
parityO=GetParity4Ref(cd->GetAtom4Refs(o));//GetsOutput parity.
184
case SMILES: // SMILES always uses 1234 atom refs
185
parityO=0; // if parityO==parityI then clockwise in input = clockwise in output
187
case MOLV3000: // MOLV3000 uses 1234 unless an H then 123H
188
if (atm->GetHvyValence()==3)
191
int Hid=1000;// max Atom ID +1 should be used here
192
vector<int> nbr_atms;
193
vector<OBEdgeBase*>::iterator i;
194
for (nbr = atm->BeginNbrAtom(i);nbr;nbr = atm->NextNbrAtom(i))
196
if (nbr->IsHydrogen()){Hid=nbr->GetIdx();continue;}
197
nbr_atms.push_back(nbr->GetIdx());
199
sort(nbr_atms.begin(),nbr_atms.end());
200
nbr_atms.push_back(Hid);
202
for(int i=0;i<4;i++){tmp[i]=nbr_atms[i];}
203
parityO=GetParity4Ref(tmp);
205
else if (atm->GetHvyValence()==4)
158
case SMILES: // SMILES always uses 1234 atom refs
159
parityO=0; // if parityO==parityI then clockwise in input = clockwise in output
161
case MOLV3000: // MOLV3000 uses 1234 unless an H then 123H
162
if (atm->GetHvyValence()==3)
165
int Hid=1000;// max Atom ID +1 should be used here
166
vector<int> nbr_atms;
167
vector<OBBond*>::iterator i;
168
for (nbr = atm->BeginNbrAtom(i);nbr;nbr = atm->NextNbrAtom(i))
170
if (nbr->IsHydrogen()){Hid=nbr->GetIdx();continue;}
171
nbr_atms.push_back(nbr->GetIdx());
173
sort(nbr_atms.begin(),nbr_atms.end());
174
nbr_atms.push_back(Hid);
176
for(int i=0;i<4;++i){tmp[i]=nbr_atms[i];}
177
parityO=GetParity4Ref(tmp);
179
else if (atm->GetHvyValence()==4)
211
185
if (parityO==parityI)
212
{//cout << "Parity is the same"<<endl;
186
{//cout << "Parity is the same"<<endl;
215
189
else if(parityO!=parityI) // Need to invert the Chirality which has been set
216
{ //cout << "Parity is Opposite"<<endl;
190
{ //cout << "Parity is Opposite"<<endl;
217
191
if (atm->IsClockwise())
218
{atm->UnsetStereo();atm->SetAntiClockwiseStereo();}
192
{atm->UnsetStereo();atm->SetAntiClockwiseStereo();}
219
193
else if (atm->IsAntiClockwise())
220
{atm->UnsetStereo();atm->SetClockwiseStereo();}
194
{atm->UnsetStereo();atm->SetClockwiseStereo();}
228
//! Calculate the signed volume for an atom. If the atom has a valence of 3
229
//! the coordinates of an attached hydrogen are calculated
230
//! Puts attached Hydrogen last at the moment, like mol V3000 format.
231
double CalcSignedVolume(OBMol &mol,OBAtom *atm)
202
//! Calculate the signed volume for an atom. If the atom has a valence of 3
203
//! the coordinates of an attached hydrogen are calculated
204
//! Puts attached Hydrogen last at the moment, like mol V3000 format.
205
//! If ReZero=false (the default is true) always make pseudo z coords and leave them in mol
206
double CalcSignedVolume(OBMol &mol,OBAtom *atm, bool ReZeroZ)
234
209
vector<unsigned int> nbr_atms;
235
210
vector<vector3> nbr_crds;
236
211
bool use_central_atom = false,is2D=false;
237
double hbrad = etab.CorrectedBondRad(1,0);
212
// double hbrad = etab.CorrectedBondRad(1,0);
239
if (!mol.Has3D()) //give peudo Z coords if mol is 2D
241
vector3 v,vz(0.0,0.0,1.0);
214
if (!ReZeroZ || !mol.Has3D()) //give pseudo Z coords if mol is 2D
216
vector3 v,vz(0.0,0.0,1.0);
245
vector<OBEdgeBase*>::iterator i;
220
vector<OBBond*>::iterator i;
246
221
for (bond = atm->BeginBond(i);bond;bond = atm->NextBond(i))
248
223
nbr = bond->GetEndAtom();
251
v = nbr->GetVector();
226
v = nbr->GetVector();
237
nbr = bond->GetBeginAtom();
238
v = nbr->GetVector();
262
nbr = bond->GetBeginAtom();
263
v = nbr->GetVector();
275
250
if (atm->GetHvyValence() < 3)
278
stringstream errorMsg;
282
errorMsg << "Cannot calculate a signed volume for an atom with a heavy atom valence of " << atm->GetHvyValence() << endl;
283
obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obInfo);
252
stringstream errorMsg;
253
errorMsg << "Cannot calculate a signed volume for an atom with a heavy atom valence of " << atm->GetHvyValence() << endl;
254
obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obInfo);
287
258
// Create a vector with the coordinates of the neighbor atoms
288
259
// Also make a vector with Atom IDs
290
vector<OBEdgeBase*>::iterator bint;
261
vector<OBBond*>::iterator bint;
291
262
for (nbr = atm->BeginNbrAtom(bint);nbr;nbr = atm->NextNbrAtom(bint))
293
264
nbr_atms.push_back(nbr->GetIdx());
295
266
// sort the neighbor atoms to insure a consistent ordering
296
267
sort(nbr_atms.begin(),nbr_atms.end());
297
for (unsigned int i = 0; i < nbr_atms.size(); i++)
268
for (unsigned int i = 0; i < nbr_atms.size(); ++i)
299
270
OBAtom *tmp_atm = mol.GetAtom(nbr_atms[i]);
300
271
nbr_crds.push_back(tmp_atm->GetVector());
303
274
// If we have three heavy atoms we need to calculate the position of the fourth
304
275
if (atm->GetHvyValence() == 3)
306
double bondlen = hbrad+etab.CorrectedBondRad(atm->GetAtomicNum(),atm->GetHyb());
307
atm->GetNewBondVector(tmp_crd,bondlen);
308
nbr_crds.push_back(tmp_crd);
311
for(int j=0;j < nbr_crds.size();j++) // Checks for a neighbour having 0 co-ords (added hydrogen etc)
313
if (nbr_crds[j]==0 && use_central_atom==false)use_central_atom=true;
314
else if (nbr_crds[j]==0)
316
obErrorLog.ThrowError(__FUNCTION__, "More than 2 neighbours have 0 co-ords when attempting 3D chiral calculation", obInfo);
277
double bondlen = hbrad+etab.CorrectedBondRad(atm->GetAtomicNum(),atm->GetHyb());
278
atm->GetNewBondVector(tmp_crd,bondlen);
279
nbr_crds.push_back(tmp_crd);
282
for(unsigned int j=0;j < nbr_crds.size();++j) // Checks for a neighbour having 0 co-ords (added hydrogen etc)
284
// are the coordinates zero to 6 or more significant figures
285
if (nbr_crds[j].IsApprox(VZero, 1.0e-6) && use_central_atom==false)
286
use_central_atom=true;
287
else if (nbr_crds[j].IsApprox(VZero, 1.0e-6))
289
obErrorLog.ThrowError(__FUNCTION__, "More than 2 neighbours have 0 co-ords when attempting 3D chiral calculation", obInfo);
320
// If we have three heavy atoms we can use the chiral center atom itself for the fourth
321
// will always give same sign (for tetrahedron), magnitude will be smaller.
322
if(nbr_atms.size()==3 || use_central_atom==true)
324
nbr_crds.push_back(atm->GetVector());
325
nbr_atms.push_back(mol.NumAtoms()+1); // meed to add largest number on end to work
293
// If we have three heavy atoms we can use the chiral center atom itself for the fourth
294
// will always give same sign (for tetrahedron), magnitude will be smaller.
295
if(nbr_atms.size()==3 || use_central_atom==true)
297
nbr_crds.push_back(atm->GetVector());
298
nbr_atms.push_back(mol.NumAtoms()+1); // meed to add largest number on end to work
327
300
OBChiralData* cd=(OBChiralData*)atm->GetData(OBGenericDataType::ChiralData); //Set the output atom4refs to the ones used
330
cd = new OBChiralData;
303
cd = new OBChiralData;
304
cd->SetOrigin(perceived);
333
307
cd->SetAtom4Refs(nbr_atms,calcvolume);
335
//re-zero psuedo-coords
309
//re-zero pseudo-coords
340
vector<OBNodeBase*>::iterator k;
314
vector<OBAtom*>::iterator k;
341
315
for (atom = mol.BeginAtom(k);atom;atom = mol.NextAtom(k))
343
317
v = atom->GetVector();
345
319
atom->SetVector(v);
349
323
return(signed_volume(nbr_crds[0],nbr_crds[1],nbr_crds[2],nbr_crds[3]));
352
//! Calculate a signed volume given a set of 4 coordinates
353
double signed_volume(const vector3 &a, const vector3 &b, const vector3 &c, const vector3 &d)
326
//! Calculate a signed volume given a set of 4 coordinates
327
double signed_volume(const vector3 &a, const vector3 &b, const vector3 &c, const vector3 &d)
359
333
matrix3x3 m(A,B,C);
360
334
return(m.determinant());
363
//! \brief Calculate the Graph Potentials of a molecule
366
//! V.E. and Rozenblit, A.B. Golender
367
//! <em>Logical and Combinatorial Algorithms for Drug Design</em>. \n
368
//! For an example see:
369
//! Walters, W. P., Yalkowsky, S. H., \em JCICS, 1996, 36(5), 1015-1017.
370
//! <a href="http://dx.doi.org/10.1021/ci950278o">DOI: 10.1021/ci950278o</a>
371
void GraphPotentials(OBMol &mol, std::vector<double> &pot)
337
//! \brief Calculate the Graph Potentials of a molecule
340
//! V.E. and Rozenblit, A.B. Golender
341
//! <em>Logical and Combinatorial Algorithms for Drug Design</em>. \n
342
//! For an example see:
343
//! Walters, W. P., Yalkowsky, S. H., \em JCICS, 1996, 36(5), 1015-1017.
344
//! <a href="http://dx.doi.org/10.1021/ci950278o">DOI: 10.1021/ci950278o</a>
345
void GraphPotentials(OBMol &mol, std::vector<double> &pot)
375
349
vector<vector<double> > g,c,h;
379
353
mult_matrix(h,g,c);
380
354
pot.resize(mol.NumAtoms()+1);
382
for (unsigned int i = 0; i < mol.NumAtoms();i++)
387
//! Construct the matrix G, which puts each atoms valence+1
388
//! on the diagonal and and -1 on the off diagonal if two
389
//! atoms are connected.
390
void construct_g_matrix(OBMol &mol, std::vector<std::vector<double> > &m)
356
for (unsigned int i = 0; i < mol.NumAtoms();++i)
361
//! Construct the matrix G, which puts each atoms valence+1
362
//! on the diagonal and and -1 on the off diagonal if two
363
//! atoms are connected.
364
void construct_g_matrix(OBMol &mol, std::vector<std::vector<double> > &m)
392
366
unsigned int i,j;
394
368
OBAtom *atm1,*atm2;
395
vector<OBNodeBase*>::iterator aint,bint;
369
vector<OBAtom*>::iterator aint,bint;
397
371
m.resize(mol.NumAtoms());
398
for (i = 0; i < m.size(); i++)
399
m[i].resize(mol.NumAtoms());
372
for (i = 0; i < m.size(); ++i)
373
m[i].resize(mol.NumAtoms());
401
for (atm1 = mol.BeginAtom(aint),i=0;atm1;atm1 = mol.NextAtom(aint),i++)
402
for (atm2 = mol.BeginAtom(bint),j=0;atm2;atm2 = mol.NextAtom(bint),j++)
375
for (atm1 = mol.BeginAtom(aint),i=0;atm1;atm1 = mol.NextAtom(aint),++i)
376
for (atm2 = mol.BeginAtom(bint),j=0;atm2;atm2 = mol.NextAtom(bint),++j)
406
m[i][j] = atm1->GetValence() + 1;
407
m[i][j] += (double)atm1->GetAtomicNum()/10.0;
408
m[i][j] += (double)atm1->GetHyb()/100.0;
380
m[i][j] = atm1->GetValence() + 1;
381
m[i][j] += (double)atm1->GetAtomicNum()/10.0;
382
m[i][j] += (double)atm1->GetHyb()/100.0;
412
if (atm1->IsConnected(atm2))
386
if (atm1->IsConnected(atm2))
420
//! Construct the matrix C, which is simply a column vector
421
//! consisting of the valence for each atom
422
void construct_c_matrix(OBMol &mol,std::vector<std::vector<double > > &m)
394
//! Construct the matrix C, which is simply a column vector
395
//! consisting of the valence for each atom
396
void construct_c_matrix(OBMol &mol,std::vector<std::vector<double > > &m)
426
vector<OBNodeBase*>::iterator aint;
400
vector<OBAtom*>::iterator aint;
428
402
m.resize(mol.NumAtoms());
429
for (i = 0; i < m.size(); i++)
431
for (atm1 = mol.BeginAtom(aint),i=0;atm1;atm1 = mol.NextAtom(aint),i++)
403
for (i = 0; i < m.size(); ++i)
405
for (atm1 = mol.BeginAtom(aint),i=0;atm1;atm1 = mol.NextAtom(aint),++i)
433
407
m[i][0] = atm1->GetValence();
437
411
} // namespace OpenBabel