mirror of
https://github.com/openbabel/openbabel.git
synced 2026-11-03 20:57:03 -06:00
516 lines
14 KiB
C++
516 lines
14 KiB
C++
/**********************************************************************
|
|
grid.cpp - Handle grids of values.
|
|
|
|
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
|
|
Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
|
|
Some Portions Copyright (C) 2008 by Marcus D. Hanwell
|
|
|
|
This file is part of the Open Babel project.
|
|
For more information, see <http://openbabel.org/>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
***********************************************************************/
|
|
#include <openbabel/babelconfig.h>
|
|
|
|
#include <openbabel/mol.h>
|
|
#include <openbabel/atom.h>
|
|
#include <openbabel/grid.h>
|
|
|
|
using namespace std;
|
|
|
|
namespace OpenBabel
|
|
{
|
|
void OBGrid::Init(OBMol &box)
|
|
{
|
|
OBAtom *atom;
|
|
vector<OBAtom*>::iterator i;
|
|
|
|
for (atom = box.BeginAtom(i); atom; atom = box.NextAtom(i)) {
|
|
if (atom->GetIdx() == 1) {
|
|
_xmin = atom->GetX();
|
|
_xmax = atom->GetX();
|
|
_ymin = atom->GetY();
|
|
_ymax = atom->GetY();
|
|
_zmin = atom->GetZ();
|
|
_zmax = atom->GetZ();
|
|
}
|
|
else {
|
|
if (atom->GetX() < _xmin)
|
|
_xmin = atom->GetX();
|
|
if (atom->GetX() > _xmax)
|
|
_xmax = atom->GetX();
|
|
if (atom->GetY() < _ymin)
|
|
_ymin = atom->GetY();
|
|
if (atom->GetY() > _ymax)
|
|
_ymax = atom->GetY();
|
|
if (atom->GetZ() < _zmin)
|
|
_zmin = atom->GetZ();
|
|
if (atom->GetZ() > _zmax)
|
|
_zmax = atom->GetZ();
|
|
}
|
|
}
|
|
}
|
|
|
|
void OBFloatGrid::Init(OBMol &box, double spacing, double pad)
|
|
{
|
|
OBGrid::Init(box); // handle in the base class
|
|
|
|
_xmin -= pad;
|
|
_xmax += pad;
|
|
_ymin -= pad;
|
|
_ymax += pad;
|
|
_zmin -= pad;
|
|
_zmax += pad;
|
|
|
|
/* store in Grid */
|
|
_midx=0.5*(_xmax+_xmin);
|
|
_midy=0.5*(_ymax+_ymin);
|
|
_midz=0.5*(_zmax+_zmin);
|
|
_xdim=static_cast<int>((_xmax-_xmin)/spacing) + 1;
|
|
_ydim=static_cast<int>((_ymax-_ymin)/spacing) + 1;
|
|
_zdim=static_cast<int>((_zmax-_zmin)/spacing) + 1;
|
|
_spacing=spacing;
|
|
_halfSpace=_spacing/2.0;
|
|
_inv_spa=1.0/_spacing;
|
|
_ival=nullptr;
|
|
|
|
// Calculate the size needed, resize the vector and initialise it to 0.0
|
|
int size = _xdim*_ydim*_zdim;
|
|
_values.resize(size, 0.0);
|
|
}
|
|
|
|
void OBFloatGrid::SetLimits(const double origin[3], const double v1[3], const double v2[3],
|
|
const double v3[3])
|
|
{
|
|
// Convert to vectors and call the vector form of the function
|
|
vector3 originv(origin[0], origin[1], origin[2]);
|
|
vector3 x(v1[0], v1[1], v1[2]);
|
|
vector3 y(v2[0], v2[1], v2[2]);
|
|
vector3 z(v3[0], v3[1], v3[2]);
|
|
SetLimits(originv, x, y, z);
|
|
}
|
|
|
|
void OBFloatGrid::SetLimits(const vector3& origin, const vector3& x,
|
|
const vector3& y, const vector3& z)
|
|
{
|
|
// Using vectors instead of arrays of doubles
|
|
_xmin = origin.x();
|
|
_ymin = origin.y();
|
|
_zmin = origin.z();
|
|
|
|
// Set the axes
|
|
SetXAxis(x);
|
|
SetYAxis(y);
|
|
SetZAxis(z);
|
|
|
|
// Now set the max and mid as well as spacing
|
|
_xmax = _xmin + (_xdim-1) * (x.x() + y.x() + z.x());
|
|
_ymax = _ymin + (_ydim-1) * (x.y() + y.y() + z.y());
|
|
_zmax = _zmin + (_zdim-1) * (x.z() + y.z() + z.z());
|
|
// FIXME If we want support for cubes aligned along arbitrary axes then
|
|
// averaging the x, y and z directions will not work. Just use x for now.
|
|
_spacing = (_xmax - _xmin)/(_xdim-1);
|
|
_halfSpace= _spacing/2.0;
|
|
_inv_spa=1.0/_spacing;
|
|
}
|
|
|
|
void OBFloatGrid::SetNumberOfPoints(int nx, int ny, int nz)
|
|
{
|
|
_xdim = nx;
|
|
_ydim = ny;
|
|
_zdim = nz;
|
|
_values.resize(nx*ny*nz);
|
|
}
|
|
|
|
void OBFloatGrid::SetXAxis(vector3 v)
|
|
{
|
|
_xAxis = v;
|
|
}
|
|
|
|
void OBFloatGrid::SetYAxis(vector3 v)
|
|
{
|
|
_yAxis = v;
|
|
}
|
|
|
|
void OBFloatGrid::SetZAxis(vector3 v)
|
|
{
|
|
_zAxis = v;
|
|
}
|
|
|
|
double OBFloatGrid::Inject(double x, double y, double z)
|
|
{
|
|
if (_values.empty())
|
|
return 0.0;
|
|
|
|
if( x<=_xmin || x>=_xmax
|
|
|| y<=_ymin || y>=_ymax
|
|
|| z<=_zmin || z>=_zmax ) return 0.0;
|
|
|
|
return(_values[CoordsToIndex(x, y, z)]);
|
|
}
|
|
|
|
void OBFloatGrid::IndexToCoords(int idx, double &x, double &y, double &z)
|
|
{
|
|
int grid_x, grid_y, grid_z;
|
|
|
|
grid_z = idx % _zdim;
|
|
grid_x = static_cast<int>(idx / (_ydim * _zdim));
|
|
grid_y = static_cast<int>((idx - (grid_x * _ydim * _zdim)) / _zdim);
|
|
|
|
x = (grid_x * _spacing + _xmin) + _halfSpace;
|
|
y = (grid_y * _spacing + _ymin) + _halfSpace;
|
|
z = (grid_z * _spacing + _zmin) + _halfSpace;
|
|
}
|
|
|
|
int OBFloatGrid::CoordsToIndex(double x, double y, double z)
|
|
{
|
|
int gx=static_cast<int>((x-_xmin)*_inv_spa);
|
|
int gy=static_cast<int>((y-_ymin)*_inv_spa);
|
|
int gz=static_cast<int>((z-_zmin)*_inv_spa);
|
|
|
|
return((gx*_ydim*_zdim) + (gy*_zdim) + gz);
|
|
}
|
|
|
|
void OBFloatGrid::CoordsToIndex(int *idx,double *c)
|
|
{
|
|
idx[0]=static_cast<int>((c[0]-_xmin)*_inv_spa);
|
|
idx[1]=static_cast<int>((c[1]-_ymin)*_inv_spa);
|
|
idx[2]=static_cast<int>((c[2]-_zmin)*_inv_spa);
|
|
}
|
|
|
|
double OBFloatGrid::Interpolate(double x, double y, double z)
|
|
{
|
|
if (_values.empty())
|
|
return 0.0;
|
|
|
|
int n,igx,igy,igz;
|
|
double yzdim;
|
|
double gx,gy,gz,fgx,fgy,fgz;
|
|
double ax,ay,az,bx,by,bz;
|
|
double AyA,ByA,AyB,ByB,Az,Bz;
|
|
|
|
if( x<=_xmin || x>=_xmax
|
|
|| y<=_ymin || y>=_ymax
|
|
|| z<=_zmin || z>=_zmax ) return 0.0;
|
|
|
|
yzdim = _ydim*_zdim;
|
|
|
|
/* calculate grid voxel and fractional offsets */
|
|
gx=(x-_xmin-_halfSpace)*_inv_spa;
|
|
if (gx<0)
|
|
gx=0;
|
|
igx=static_cast<int>(gx);
|
|
fgx=gx-static_cast<double>(igx);
|
|
gy=(y-_ymin-_halfSpace)*_inv_spa;
|
|
if (gy<0)
|
|
gy=0;
|
|
igy=static_cast<int>(gy);
|
|
fgy= gy - static_cast<double>(igy);
|
|
gz=(z-_zmin-_halfSpace)*_inv_spa;
|
|
if (gz<0)
|
|
gz=0;
|
|
igz=static_cast<int>(gz);
|
|
fgz= gz - static_cast<double>(igz);
|
|
|
|
// Calculate the index of the nearest point
|
|
n=static_cast<int>(igx*yzdim + igy*_zdim + igz);
|
|
|
|
if ((n+1+_zdim+yzdim) >= (yzdim*_xdim))
|
|
return 0.0;
|
|
|
|
/* calculate linear weightings */
|
|
ax=1.0-fgx;
|
|
bx=fgx;
|
|
ay=1.0-fgy;
|
|
by=fgy;
|
|
az=1.0-fgz;
|
|
bz=fgz;
|
|
|
|
/* calculate interpolated value */
|
|
AyA=az*_values[n ]+bz*_values[(n+1) ];
|
|
ByA=az*_values[n+_zdim]+bz*_values[(n+1+_zdim) ];
|
|
|
|
Az=ay*AyA+by*ByA;
|
|
|
|
AyB=az*_values[static_cast<int>(n +yzdim)] +
|
|
bz*_values[static_cast<int>(n+1 +yzdim)];
|
|
ByB=az*_values[static_cast<int>(n+_zdim+yzdim)] +
|
|
bz*_values[static_cast<int>(n+1+_zdim+yzdim)];
|
|
Bz=ay*AyB+by*ByB;
|
|
|
|
return(ax*Az+bx*Bz);
|
|
}
|
|
|
|
std::vector<double> OBFloatGrid::GetDataVector()
|
|
{
|
|
return _values;
|
|
}
|
|
|
|
void OBFloatGrid::SetVals(const std::vector<double> & vals)
|
|
{
|
|
_values.clear();
|
|
_values = vals;
|
|
}
|
|
|
|
double OBFloatGrid::InterpolateDerivatives(double x,double y,double z,double *derivatives)
|
|
{
|
|
int n,igx,igy,igz;
|
|
double yzdim;
|
|
double gx,gy,gz,fgx,fgy,fgz;
|
|
double ax,ay,az,bx,by,bz;
|
|
double AyA,ByA,AyB,ByB,Az,Bz;
|
|
double energy,fx,fy,fz;
|
|
|
|
if( x<=_xmin || x>=_xmax
|
|
|| y<=_ymin || y>=_ymax
|
|
|| z<=_zmin || z>=_zmax ) return 0.0;
|
|
|
|
yzdim = _ydim*_zdim;
|
|
|
|
/* calculate grid voxel and fractional offsets */
|
|
gx=(x-_xmin-_halfSpace)*_inv_spa;
|
|
if (gx<0)
|
|
gx=0;
|
|
igx=static_cast<int>(gx);
|
|
fgx=gx-(double)igx;
|
|
gy=(y-_ymin-_halfSpace)*_inv_spa;
|
|
if (gy<0)
|
|
gy=0;
|
|
igy=static_cast<int>(gy);
|
|
fgy= gy - (double) igy;
|
|
gz=(z-_zmin-_halfSpace)*_inv_spa;
|
|
if (gz<0)
|
|
gz=0;
|
|
igz=static_cast<int>(gz);
|
|
fgz= gz - (double) igz;
|
|
|
|
n=static_cast<int>(igx*yzdim + igy*_zdim + igz);
|
|
/* calculate linear weightings */
|
|
ax=1.0-fgx;
|
|
bx=fgx;
|
|
ay=1.0-fgy;
|
|
by=fgy;
|
|
az=1.0-fgz;
|
|
bz=fgz;
|
|
|
|
/* calculate interpolated value */
|
|
AyA=az*_values[n ]+bx*_values[n+1 ];
|
|
ByA=az*_values[n+_zdim]+bx*_values[(n+1+_zdim) ];
|
|
|
|
Az=ay*AyA+by*ByA;
|
|
|
|
AyB=az*_values[static_cast<int>(n +yzdim)]+
|
|
bz*_values[static_cast<int>(n+1 +yzdim)];
|
|
ByB=az*_values[static_cast<int>(n+_zdim+yzdim)]+
|
|
bz*_values[static_cast<int>(n+1+_zdim+yzdim)];
|
|
Bz=ay*AyB+by*ByB;
|
|
|
|
energy = ax*Az+bx*Bz;
|
|
|
|
//calculate derivatives
|
|
|
|
fz=-Az+Bz;
|
|
|
|
Az=-AyA+ByA;
|
|
Bz=-AyB+ByB;
|
|
|
|
fy=az*Az+bz*Bz;
|
|
|
|
AyA=-_values[n ]+_values[(n+1) ];
|
|
ByA=-_values[n+_zdim ]+_values[(n+1+_zdim)];
|
|
|
|
Az=ay*AyA+by*ByA;
|
|
|
|
AyB=-_values[static_cast<int>(n +yzdim)]+
|
|
_values[static_cast<int>(n+1 +yzdim)];
|
|
ByB=-_values[static_cast<int>(n+_zdim+yzdim)]+
|
|
_values[static_cast<int>(n+1+_zdim+yzdim)];
|
|
|
|
Bz=ay*AyB+by*ByB;
|
|
|
|
fx=ax*Az+bx*Bz;
|
|
|
|
derivatives[0] += fx;
|
|
derivatives[1] += fy;
|
|
derivatives[2] += fz;
|
|
|
|
return(energy);
|
|
}
|
|
|
|
ostream& operator<< ( ostream &os, const OBFloatGrid& fg)
|
|
{
|
|
//@todo: this code stores the data in way that depends on
|
|
// the bit representation of floating-point numbers. One can say
|
|
// it's OK because IEEE754 is a widely accepted standard, but then
|
|
// one should at least make it write the data in an endianness-
|
|
// independent way. Of course this comment applies also to
|
|
// the operator>> below.
|
|
os.write((const char*)&fg._xmin,sizeof(double));
|
|
os.write((const char*)&fg._xmax,sizeof(double));
|
|
os.write((const char*)&fg._ymin,sizeof(double));
|
|
os.write((const char*)&fg._ymax,sizeof(double));
|
|
os.write((const char*)&fg._zmin,sizeof(double));
|
|
os.write((const char*)&fg._zmax,sizeof(double));
|
|
|
|
os.write((const char*)&fg._midx,sizeof(double));
|
|
os.write((const char*)&fg._midy,sizeof(double));
|
|
os.write((const char*)&fg._midz,sizeof(double));
|
|
os.write((const char*)&fg._inv_spa,sizeof(double));
|
|
os.write((const char*)&fg._spacing,sizeof(double));
|
|
os.write((const char*)&fg._xdim,sizeof(int));
|
|
os.write((const char*)&fg._ydim,sizeof(int));
|
|
os.write((const char*)&fg._zdim,sizeof(int));
|
|
os.write((const char*)&fg._values[0],
|
|
(sizeof(double)*(fg._xdim*fg._ydim*fg._zdim)));
|
|
|
|
return(os);
|
|
}
|
|
|
|
istream& operator>> ( istream &is,OBFloatGrid& fg)
|
|
{
|
|
is.read((char*)&fg._xmin,sizeof(double));
|
|
is.read((char*)&fg._xmax,sizeof(double));
|
|
is.read((char*)&fg._ymin,sizeof(double));
|
|
is.read((char*)&fg._ymax,sizeof(double));
|
|
is.read((char*)&fg._zmin,sizeof(double));
|
|
is.read((char*)&fg._zmax,sizeof(double));
|
|
|
|
is.read((char*)&fg._midx,sizeof(double));
|
|
is.read((char*)&fg._midy,sizeof(double));
|
|
is.read((char*)&fg._midz,sizeof(double));
|
|
is.read((char*)&fg._inv_spa,sizeof(double));
|
|
is.read((char*)&fg._spacing,sizeof(double));
|
|
is.read((char*)&fg._xdim,sizeof(int));
|
|
is.read((char*)&fg._ydim,sizeof(int));
|
|
is.read((char*)&fg._zdim,sizeof(int));
|
|
int size = fg._xdim*fg._ydim*fg._zdim;
|
|
fg._values.resize(size);
|
|
size *= (int) sizeof(double);
|
|
|
|
is.read((char*)&fg._values[0],size);
|
|
fg._halfSpace= fg._spacing/2.0;
|
|
|
|
return(is);
|
|
}
|
|
|
|
void OBProxGrid::Setup(OBMol &mol,OBMol &box,double cutoff,double res)
|
|
{
|
|
this->Init(box); // handle in the base class
|
|
|
|
_inc = res; // 1/2 angstrom resolution
|
|
|
|
_nxinc = (int) floor((_xmax - _xmin)/0.5);
|
|
_nyinc = (int) floor((_ymax - _ymin)/0.5);
|
|
_nzinc = (int) floor((_zmax - _zmin)/0.5);
|
|
_maxinc = _nxinc*_nyinc*_nzinc;
|
|
|
|
int j,size = _nxinc*_nyinc*_nzinc;
|
|
cell.resize(size);
|
|
for (unsigned int num = 0; num < cell.size(); ++num)
|
|
cell[num].resize(0);
|
|
|
|
cutoff *= cutoff; //don't do sqrts
|
|
|
|
int k,l,m;
|
|
double x,y,z,dx_2,dy_2;
|
|
double *c = mol.GetCoordinates();
|
|
size = mol.NumAtoms()*3;
|
|
|
|
OBAtom *atom;
|
|
vector<OBAtom*>::iterator i;
|
|
for (atom = mol.BeginAtom(i),j=0;atom;atom = mol.NextAtom(i),j+=3)
|
|
if (PointIsInBox(c[j],c[j+1],c[j+2]))
|
|
for (x = _xmin+(_inc/2.0),k=0;k < _nxinc;x+=_inc,++k)
|
|
if ((dx_2 = SQUARE(c[j]-x)) < cutoff)
|
|
for (y = _ymin+(_inc/2.0),l=0;l < _nyinc;y+=_inc,++l)
|
|
if ((dx_2+(dy_2 = SQUARE(c[j+1]-y))) < cutoff)
|
|
for (z = _zmin+(_inc/2.0),m=0;m < _nzinc;z+=_inc,++m)
|
|
if ((dx_2+dy_2+SQUARE(c[j+2]-z)) < cutoff)
|
|
cell[(k*_nyinc*_nzinc)+(l*_nzinc)+m].push_back(atom->GetIdx());
|
|
|
|
_inc = 1/_inc;
|
|
}
|
|
|
|
void OBProxGrid::Setup(OBMol &mol,OBMol &box,double cutoff,vector<bool> &use,
|
|
double res)
|
|
{
|
|
this->Init(box); // handle in the base class
|
|
|
|
_inc = res; // 1/2 angstrom resolution
|
|
|
|
_nxinc = (int) floor((_xmax - _xmin)/0.5);
|
|
_nyinc = (int) floor((_ymax - _ymin)/0.5);
|
|
_nzinc = (int) floor((_zmax - _zmin)/0.5);
|
|
_maxinc = _nxinc*_nyinc*_nzinc;
|
|
|
|
int j,size = _nxinc*_nyinc*_nzinc;
|
|
cell.resize(size);
|
|
cutoff *= cutoff; //don't do sqrts
|
|
|
|
int k,l,m;
|
|
double x,y,z,dx_2,dy_2;
|
|
double *c = mol.GetCoordinates();
|
|
size = mol.NumAtoms()*3;
|
|
|
|
OBAtom *atom;
|
|
vector<OBAtom*>::iterator i;
|
|
for (atom = mol.BeginAtom(i),j=0;atom;atom = mol.NextAtom(i),j+=3)
|
|
if (use[atom->GetIdx()])
|
|
if (PointIsInBox(c[j],c[j+1],c[j+2]))
|
|
for (x = _xmin+(_inc/2.0),k=0;k < _nxinc;x+=_inc,++k)
|
|
if ((dx_2 = SQUARE(c[j]-x)) < cutoff)
|
|
for (y = _ymin+(_inc/2.0),l=0;l < _nyinc;y+=_inc,++l)
|
|
if ((dx_2+(dy_2 = SQUARE(c[j+1]-y))) < cutoff)
|
|
for (z = _zmin+(_inc/2.0),m=0;m < _nzinc;z+=_inc,++m)
|
|
if ((dx_2+dy_2+SQUARE(c[j+2]-z)) < cutoff)
|
|
cell[(k*_nyinc*_nzinc)+(l*_nzinc)+m].push_back(atom->GetIdx());
|
|
|
|
_inc = 1/_inc;
|
|
}
|
|
|
|
vector<int> *OBProxGrid::GetProxVector(double x,double y,double z)
|
|
{
|
|
if (x < _xmin || x > _xmax)
|
|
return nullptr;
|
|
if (y < _ymin || y > _ymax)
|
|
return nullptr;
|
|
if (z < _zmin || z > _zmax)
|
|
return nullptr;
|
|
|
|
x -= _xmin;
|
|
y -= _ymin;
|
|
z -= _zmin;
|
|
int i,j,k,idx;
|
|
i = (int) (x*_inc);
|
|
j = (int) (y*_inc);
|
|
k = (int) (z*_inc);
|
|
idx = (i*_nyinc*_nzinc)+(j*_nzinc)+k;
|
|
if (idx >= _maxinc)
|
|
return nullptr;
|
|
|
|
return(&cell[idx]);
|
|
}
|
|
|
|
vector<int> *OBProxGrid::GetProxVector(double *c)
|
|
{
|
|
double x,y,z;
|
|
x = c[0];
|
|
y = c[1];
|
|
z = c[2];
|
|
|
|
return( GetProxVector(x, y, z) );
|
|
}
|
|
|
|
} // end namespace OpenBabel
|
|
|
|
//! \file grid.cpp
|
|
//! \brief Handle grids of values.
|
|
|