30
28
namespace OpenBabel
34
static int SINT = 0x00000001;
35
static unsigned char *STPTR = (unsigned char*)&SINT;
36
const bool SwabInt = (STPTR[0]!=0);
31
/** \class OBRotamerList rotamer.h <openbabel/rotamer.h>
33
A high-level class for rotamer / conformer generation, intended mainly
34
for use with the related class OBRotorList and the OBRotorRules database
36
Rotamers represent conformational isomers formed simply by rotation of
37
dihedral angles. On the other hand, conformers may include geometric
38
relaxation (i.e., slight modification of bond lengths, bond angles, etc.)
40
The following shows an example of generating 2 conformers using different
41
rotor states. Similar code could be used for systematic or Monte Carlo
42
conformer sampling when combined with energy evaluation (molecular
43
mechanics or otherwise).
46
OBRotorList rl; // used to sample all rotatable bonds via the OBRotorRules data
47
// If you want to "fix" any particular atoms (i.e., freeze them in space)
48
// then set up an OBBitVec of the fixed atoms and call
49
// rl.SetFixAtoms(bitvec);
52
// How many rotatable bonds are there?
53
cerr << " Number of rotors: " << rl.Size() << endl;
55
// indexed from 1, rotorKey[0] = 0
56
std::vector<int> rotorKey(rl.Size() + 1, 0);
58
// each entry represents the configuration of a rotor
59
// e.g. indexes into OBRotor::GetResolution() -- the different angles
60
// to sample for a rotamer search
61
for (unsigned int i = 0; i < rl.Size() + 1; ++i)
62
rotorKey[i] = 0; // could be anything from 0 .. OBRotor->GetResolution().size()
63
// -1 is for no rotation
65
// The OBRotamerList can generate conformations (i.e., coordinate sets)
66
OBRotamerList rotamers;
67
rotamers.SetBaseCoordinateSets(mol);
68
rotamers.Setup(mol, rl);
70
rotamers.AddRotamer(rotorKey);
71
rotorKey[1] = 2; // switch one rotor
72
rotamers.AddRotamer(rotorKey);
74
rotamers.ExpandConformerList(mol, mol.GetConformers());
76
// change the molecule conformation
77
mol.SetConformer(0); // rotorKey 0, 0, ...
80
mol.SetConformer(1); // rotorKey 0, 2, ...
87
static int SINT = 0x00000001;
88
static unsigned char *STPTR = (unsigned char*)&SINT;
89
const bool SwabInt = (STPTR[0]!=0);
39
inline double rint(double x)
92
inline double rint(double x)
41
94
return ( (x < 0.0) ? ceil(x-0.5) : floor(x+0.5));
45
void SetRotorToAngle(double *c,OBAtom **ref,double ang,vector<int> atoms);
98
void SetRotorToAngle(double *c,OBAtom **ref,double ang,vector<int> atoms);
49
102
unsigned char tmp[4],c;
50
103
memcpy(tmp,(char*)&i,sizeof(int));
57
110
memcpy((char*)&i,tmp,sizeof(int));
61
OBRotamerList::~OBRotamerList()
114
OBGenericData* OBRotamerList::Clone(OBBase* newparent) const
116
//Since the class contains OBAtom pointers, the new copy use
117
//these from the new molecule, newparent
118
OBMol* newmol = static_cast<OBMol*>(newparent);
120
OBRotamerList *new_rml = new OBRotamerList;
121
new_rml->_attr = _attr;
122
new_rml->_type = _type;
124
//Set base coordinates
129
for (k=0 ; k<NumBaseCoordinateSets() ; ++k)
131
c = new double [3*NumAtoms()];
132
cc = GetBaseCoordinateSet(k);
133
for (l=0 ; l<3*NumAtoms() ; ++l)
137
if (NumBaseCoordinateSets())
138
new_rml->SetBaseCoordinateSets(bc,NumAtoms());
140
//Set reference array
141
unsigned char *ref = new unsigned char [NumRotors()*4];
144
GetReferenceArray(ref);
145
new_rml->Setup(*newmol,ref,NumRotors());
150
unsigned char *rotamers = new unsigned char [(NumRotors()+1)*NumRotamers()];
153
vector<unsigned char*>::const_iterator kk;
155
for (kk = _vrotamer.begin();kk != _vrotamer.end();++kk)
157
memcpy(&rotamers[idx],(const unsigned char*)*kk,sizeof(unsigned char)*(NumRotors()+1));
158
idx += sizeof(unsigned char)*(NumRotors()+1);
160
new_rml->AddRotamers(rotamers,NumRotamers());
166
OBRotamerList::~OBRotamerList()
63
168
vector<unsigned char*>::iterator i;
64
for (i = _vrotamer.begin();i != _vrotamer.end();i++)
169
for (i = _vrotamer.begin();i != _vrotamer.end();++i)
67
172
vector<pair<OBAtom**,vector<int> > >::iterator j;
68
for (j = _vrotor.begin();j != _vrotor.end();j++)
173
for (j = _vrotor.begin();j != _vrotor.end();++j)
71
176
//Delete the interal base coordinate list
73
for (k=0 ; k<_c.size() ; k++)
178
for (k=0 ; k<_c.size() ; ++k)
77
void OBRotamerList::GetReferenceArray(unsigned char *ref)
182
void OBRotamerList::GetReferenceArray(unsigned char *ref)const
80
vector<pair<OBAtom**,vector<int> > >::iterator i;
81
for (j=0,i = _vrotor.begin();i != _vrotor.end();i++)
185
vector<pair<OBAtom**,vector<int> > >::const_iterator i;
186
for (j=0,i = _vrotor.begin();i != _vrotor.end();++i)
83
188
ref[j++] = (unsigned char)(i->first[0])->GetIdx();
84
189
ref[j++] = (unsigned char)(i->first[1])->GetIdx();
85
190
ref[j++] = (unsigned char)(i->first[2])->GetIdx();
86
191
ref[j++] = (unsigned char)(i->first[3])->GetIdx();
90
void OBRotamerList::Setup(OBMol &mol,OBRotorList &rl)
195
void OBRotamerList::Setup(OBMol &mol,OBRotorList &rl)
92
197
//clear the old stuff out if necessary
94
199
vector<unsigned char*>::iterator j;
95
for (j = _vrotamer.begin();j != _vrotamer.end();j++)
200
for (j = _vrotamer.begin();j != _vrotamer.end();++j)
97
202
_vrotamer.clear();
99
204
vector<pair<OBAtom**,vector<int> > >::iterator k;
100
for (k = _vrotor.begin();k != _vrotor.end();k++)
205
for (k = _vrotor.begin();k != _vrotor.end();++k)
104
209
//create the new list
187
292
v4.Set(c[idx],c[idx+1],c[idx+2]);
189
294
angle = CalcTorsionAngle(v1,v2,v3,v4);
192
while (angle > 360.0f)
297
while (angle > 360.0)
194
299
rot[size] = (unsigned char)rint(angle*res);
197
_vrotamer.push_back(rot);
200
void OBRotamerList::AddRotamer(int *arr)
203
double angle,res=255.0f/360.0f;
205
unsigned char *rot = new unsigned char [_vrotor.size()+1];
206
rot[0] = (unsigned char)arr[0];
208
for (i = 0;i < _vrotor.size();i++)
210
angle = _vres[i][arr[i+1]];
213
while (angle > 360.0f)
215
rot[i+1] = (unsigned char)rint(angle*res);
217
_vrotamer.push_back(rot);
220
void OBRotamerList::AddRotamer(unsigned char *arr)
223
double angle,res=255.0f/360.0f;
225
unsigned char *rot = new unsigned char [_vrotor.size()+1];
226
rot[0] = (unsigned char)arr[0];
228
for (i = 0;i < _vrotor.size();i++)
302
_vrotamer.push_back(rot);
305
void OBRotamerList::AddRotamer(int *arr)
308
double angle,res=255.0/360.0;
310
unsigned char *rot = new unsigned char [_vrotor.size()+1];
311
rot[0] = (unsigned char)arr[0];
313
for (i = 0;i < _vrotor.size();++i)
315
angle = _vres[i][arr[i+1]];
318
while (angle > 360.0)
320
rot[i+1] = (unsigned char)rint(angle*res);
322
_vrotamer.push_back(rot);
325
void OBRotamerList::AddRotamer(std::vector<int> arr)
328
double angle,res=255.0/360.0;
330
if (arr.size() != (_vrotor.size() + 1))
331
return; // wrong size key
333
unsigned char *rot = new unsigned char [_vrotor.size()+1];
334
rot[0] = (unsigned char)arr[0];
336
for (i = 0;i < _vrotor.size();++i)
338
angle = _vres[i][arr[i+1]];
341
while (angle > 360.0)
343
rot[i+1] = (unsigned char)rint(angle*res);
345
_vrotamer.push_back(rot);
348
void OBRotamerList::AddRotamer(unsigned char *arr)
351
double angle,res=255.0/360.0;
353
unsigned char *rot = new unsigned char [_vrotor.size()+1];
354
rot[0] = (unsigned char)arr[0];
356
for (i = 0;i < _vrotor.size();++i)
230
358
angle = _vres[i][(int)arr[i+1]];
233
while (angle > 360.0f)
361
while (angle > 360.0)
235
363
rot[i+1] = (unsigned char)rint(angle*res);
237
365
_vrotamer.push_back(rot);
240
void OBRotamerList::AddRotamers(unsigned char *arr,int nrotamers)
368
void OBRotamerList::AddRotamers(unsigned char *arr,int nrotamers)
242
370
unsigned int size;
245
373
size = (unsigned int)_vrotor.size()+1;
246
for (i = 0;i < nrotamers;i++)
374
for (i = 0;i < nrotamers;++i)
248
376
unsigned char *rot = new unsigned char [size];
249
377
memcpy(rot,&arr[i*size],sizeof(char)*size);
250
378
_vrotamer.push_back(rot);
254
void OBRotamerList::ExpandConformerList(OBMol &mol,vector<double*> &clist)
257
double angle,invres=360.0f/255.0f;
259
vector<double*> tmpclist;
260
vector<unsigned char*>::iterator i;
262
for (i = _vrotamer.begin();i != _vrotamer.end();i++)
265
double *c = new double [mol.NumAtoms()*3];
266
memcpy(c,clist[(int)conf[0]],sizeof(double)*mol.NumAtoms()*3);
268
for (j = 0;j < _vrotor.size();j++)
270
angle = invres*((double)conf[j+1]);
273
SetRotorToAngle(c,_vrotor[j].first,angle,_vrotor[j].second);
275
tmpclist.push_back(c);
382
void OBRotamerList::ExpandConformerList(OBMol &mol,vector<double*> &clist)
384
vector<double*> tmpclist = CreateConformerList(mol);
278
386
//transfer the conf list
279
387
vector<double*>::iterator k;
280
for (k = clist.begin();k != clist.end();k++)
388
for (k = clist.begin();k != clist.end();++k)
282
390
clist = tmpclist;
285
//! Create a conformer list using the internal base set of coordinates
286
vector<double*> OBRotamerList::CreateConformerList(OBMol& mol)
393
//! Create a conformer list using the internal base set of coordinates
394
vector<double*> OBRotamerList::CreateConformerList(OBMol& mol)
289
double angle,invres=360.0f/255.0f;
397
double angle,invres=360.0/255.0;
290
398
unsigned char *conf;
291
399
vector<double*> tmpclist;
292
400
vector<unsigned char*>::iterator i;
294
for (i = _vrotamer.begin();i != _vrotamer.end();i++)
402
for (i = _vrotamer.begin();i != _vrotamer.end();++i)
297
405
double *c = new double [mol.NumAtoms()*3];
298
406
memcpy(c,_c[(int)conf[0]],sizeof(double)*mol.NumAtoms()*3);
300
for (j = 0;j < _vrotor.size();j++)
408
for (j = 0;j < _vrotor.size();++j)
302
410
angle = invres*((double)conf[j+1]);
303
411
if (angle > 180.0)
305
413
SetRotorToAngle(c,_vrotor[j].first,angle,_vrotor[j].second);
307
415
tmpclist.push_back(c);
421
//! Change the current coordinate set
422
//! \since version 2.2
423
void OBRotamerList::SetCurrentCoordinates(OBMol &mol, std::vector<int> arr)
428
if (arr.size() != (_vrotor.size() + 1))
429
return; // wrong size key
431
double *rot = new double [_vrotor.size()+1];
434
double *c = mol.GetCoordinates();
435
for (i = 0;i < _vrotor.size();++i)
437
if (arr[i+1] == -1) // skip this rotor
440
angle = _vres[i][arr[i+1]];
443
while (angle > 360.0)
445
SetRotorToAngle(c,_vrotor[i].first,angle,_vrotor[i].second);
313
//Copies the coordinates in bc, NOT the pointers, into the object
314
void OBRotamerList::SetBaseCoordinateSets(vector<double*> bc, unsigned int N)
450
//Copies the coordinates in bc, NOT the pointers, into the object
451
void OBRotamerList::SetBaseCoordinateSets(vector<double*> bc, unsigned int N)
316
453
unsigned int i,j;
318
455
//Clear out old data
319
for (i=0 ; i<_c.size() ; i++)
456
for (i=0 ; i<_c.size() ; ++i)
324
461
double *c = NULL;
325
462
double *cc= NULL;
326
for (i=0 ; i<bc.size() ; i++)
463
for (i=0 ; i<bc.size() ; ++i)
328
465
c = new double [3*N];
330
for (j=0 ; j<3*N ; j++)
467
for (j=0 ; j<3*N ; ++j)
334
471
_NBaseCoords = N;
337
//! Rotate the coordinates of 'atoms'
338
//! such that tor == ang - atoms in 'tor' should be ordered such
339
//! that the 3rd atom is the pivot around which atoms rotate
340
//! ang is in degrees
341
void SetRotorToAngle(double *c, OBAtom **ref,double ang,vector<int> atoms)
343
double v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z;
344
double c1x,c1y,c1z,c2x,c2y,c2z,c3x,c3y,c3z;
345
double c1mag,c2mag,radang,costheta,m[9];
346
double x,y,z,mag,rotang,sn,cs,t,tx,ty,tz;
349
tor[0] = ref[0]->GetCIdx();
350
tor[1] = ref[1]->GetCIdx();
351
tor[2] = ref[2]->GetCIdx();
352
tor[3] = ref[3]->GetCIdx();
355
//calculate the torsion angle
357
v1x = c[tor[0]] - c[tor[1]]; v2x = c[tor[1]] - c[tor[2]];
358
v1y = c[tor[0]+1] - c[tor[1]+1]; v2y = c[tor[1]+1] - c[tor[2]+1];
359
v1z = c[tor[0]+2] - c[tor[1]+2]; v2z = c[tor[1]+2] - c[tor[2]+2];
360
v3x = c[tor[2]] - c[tor[3]];
361
v3y = c[tor[2]+1] - c[tor[3]+1];
362
v3z = c[tor[2]+2] - c[tor[3]+2];
364
c1x = v1y*v2z - v1z*v2y; c2x = v2y*v3z - v2z*v3y;
365
c1y = -v1x*v2z + v1z*v2x; c2y = -v2x*v3z + v2z*v3x;
366
c1z = v1x*v2y - v1y*v2x; c2z = v2x*v3y - v2y*v3x;
367
c3x = c1y*c2z - c1z*c2y;
368
c3y = -c1x*c2z + c1z*c2x;
369
c3z = c1x*c2y - c1y*c2x;
474
//! Rotate the coordinates of 'atoms'
475
//! such that tor == ang.
476
//! Atoms in 'tor' should be ordered such that the 3rd atom is
477
//! the pivot around which atoms rotate (ang is in degrees)
478
//! \todo This code is identical to OBMol::SetTorsion() and should be combined
479
void SetRotorToAngle(double *c, OBAtom **ref,double ang,vector<int> atoms)
481
double v1x,v1y,v1z,v2x,v2y,v2z,v3x,v3y,v3z;
482
double c1x,c1y,c1z,c2x,c2y,c2z,c3x,c3y,c3z;
483
double c1mag,c2mag,radang,costheta,m[9];
484
double x,y,z,mag,rotang,sn,cs,t,tx,ty,tz;
487
tor[0] = ref[0]->GetCIdx();
488
tor[1] = ref[1]->GetCIdx();
489
tor[2] = ref[2]->GetCIdx();
490
tor[3] = ref[3]->GetCIdx();
493
//calculate the torsion angle
495
v1x = c[tor[0]] - c[tor[1]]; v2x = c[tor[1]] - c[tor[2]];
496
v1y = c[tor[0]+1] - c[tor[1]+1]; v2y = c[tor[1]+1] - c[tor[2]+1];
497
v1z = c[tor[0]+2] - c[tor[1]+2]; v2z = c[tor[1]+2] - c[tor[2]+2];
498
v3x = c[tor[2]] - c[tor[3]];
499
v3y = c[tor[2]+1] - c[tor[3]+1];
500
v3z = c[tor[2]+2] - c[tor[3]+2];
502
c1x = v1y*v2z - v1z*v2y; c2x = v2y*v3z - v2z*v3y;
503
c1y = -v1x*v2z + v1z*v2x; c2y = -v2x*v3z + v2z*v3x;
504
c1z = v1x*v2y - v1y*v2x; c2z = v2x*v3y - v2y*v3x;
505
c3x = c1y*c2z - c1z*c2y;
506
c3y = -c1x*c2z + c1z*c2x;
507
c3z = c1x*c2y - c1y*c2x;
371
c1mag = c1x*c1x + c1y*c1y + c1z*c1z;
372
c2mag = c2x*c2x + c2y*c2y + c2z*c2z;
373
if (c1mag*c2mag < 0.01) costheta = 1.0; //avoid div by zero error
374
else costheta = (c1x*c2x + c1y*c2y + c1z*c2z)/(sqrt(c1mag*c2mag));
509
c1mag = c1x*c1x + c1y*c1y + c1z*c1z;
510
c2mag = c2x*c2x + c2y*c2y + c2z*c2z;
511
if (c1mag*c2mag < 0.01) costheta = 1.0; //avoid div by zero error
512
else costheta = (c1x*c2x + c1y*c2y + c1z*c2z)/(sqrt(c1mag*c2mag));
376
if (costheta < -0.999999) costheta = -0.999999f;
377
if (costheta > 0.999999) costheta = 0.999999f;
514
if (costheta < -0.999999) costheta = -0.999999;
515
if (costheta > 0.999999) costheta = 0.999999;
379
if ((v2x*c3x + v2y*c3y + v2z*c3z) > 0.0) radang = -acos(costheta);
380
else radang = acos(costheta);
383
// now we have the torsion angle (radang) - set up the rot matrix
386
//find the difference between current and requested
387
rotang = (DEG_TO_RAD*ang) - radang;
389
sn = sin(rotang); cs = cos(rotang);t = 1 - cs;
390
//normalize the rotation vector
391
mag = sqrt(v2x*v2x + v2y*v2y + v2z*v2z);
392
x = v2x/mag; y = v2y/mag; z = v2z/mag;
517
if ((v2x*c3x + v2y*c3y + v2z*c3z) > 0.0) radang = -acos(costheta);
518
else radang = acos(costheta);
521
// now we have the torsion angle (radang) - set up the rot matrix
524
//find the difference between current and requested
525
rotang = (DEG_TO_RAD*ang) - radang;
527
sn = sin(rotang); cs = cos(rotang);t = 1 - cs;
528
//normalize the rotation vector
529
mag = sqrt(v2x*v2x + v2y*v2y + v2z*v2z);
530
if (mag < 0.1) mag = 0.1; // avoid divide by zero error
531
x = v2x/mag; y = v2y/mag; z = v2z/mag;
394
//set up the rotation matrix
395
m[0]= t*x*x + cs; m[1] = t*x*y + sn*z; m[2] = t*x*z - sn*y;
396
m[3] = t*x*y - sn*z; m[4] = t*y*y + cs; m[5] = t*y*z + sn*x;
397
m[6] = t*x*z + sn*y; m[7] = t*y*z - sn*x; m[8] = t*z*z + cs;
400
//now the matrix is set - time to rotate the atoms
402
tx = c[tor[1]];ty = c[tor[1]+1];tz = c[tor[1]+2];
403
vector<int>::iterator i;int j;
404
for (i = atoms.begin();i != atoms.end();i++)
407
c[j] -= tx;c[j+1] -= ty;c[j+2]-= tz;
408
x = c[j]*m[0] + c[j+1]*m[1] + c[j+2]*m[2];
409
y = c[j]*m[3] + c[j+1]*m[4] + c[j+2]*m[5];
410
z = c[j]*m[6] + c[j+1]*m[7] + c[j+2]*m[8];
411
c[j] = x; c[j+1] = y; c[j+2] = z;
412
c[j] += tx;c[j+1] += ty;c[j+2] += tz;
416
int PackCoordinate(double c[3],double max[3])
533
//set up the rotation matrix
534
m[0]= t*x*x + cs; m[1] = t*x*y + sn*z; m[2] = t*x*z - sn*y;
535
m[3] = t*x*y - sn*z; m[4] = t*y*y + cs; m[5] = t*y*z + sn*x;
536
m[6] = t*x*z + sn*y; m[7] = t*y*z - sn*x; m[8] = t*z*z + cs;
539
//now the matrix is set - time to rotate the atoms
541
tx = c[tor[1]];ty = c[tor[1]+1];tz = c[tor[1]+2];
542
vector<int>::iterator i;int j;
543
for (i = atoms.begin();i != atoms.end();++i)
546
c[j] -= tx;c[j+1] -= ty;c[j+2]-= tz;
547
x = c[j]*m[0] + c[j+1]*m[1] + c[j+2]*m[2];
548
y = c[j]*m[3] + c[j+1]*m[4] + c[j+2]*m[5];
549
z = c[j]*m[6] + c[j+1]*m[7] + c[j+2]*m[8];
550
c[j] = x; c[j+1] = y; c[j+2] = z;
551
c[j] += tx;c[j+1] += ty;c[j+2] += tz;
555
int PackCoordinate(double c[3],double max[3])
421
560
tmp = ((int)(cf*max[0])) << 20;