Coverage Report

Created: 2026-07-16 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openbabel/src/grid.cpp
Line
Count
Source
1
/**********************************************************************
2
grid.cpp - Handle grids of values.
3
4
Copyright (C) 1998-2001 by OpenEye Scientific Software, Inc.
5
Some portions Copyright (C) 2001-2006 by Geoffrey R. Hutchison
6
Some Portions Copyright (C) 2008 by Marcus D. Hanwell
7
8
This file is part of the Open Babel project.
9
For more information, see <http://openbabel.org/>
10
11
This program is free software; you can redistribute it and/or modify
12
it under the terms of the GNU General Public License as published by
13
the Free Software Foundation version 2 of the License.
14
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
GNU General Public License for more details.
19
***********************************************************************/
20
#include <openbabel/babelconfig.h>
21
22
#include <openbabel/mol.h>
23
#include <openbabel/atom.h>
24
#include <openbabel/grid.h>
25
26
using namespace std;
27
28
namespace OpenBabel
29
{
30
  void OBGrid::Init(OBMol &box)
31
0
  {
32
0
    OBAtom *atom;
33
0
    vector<OBAtom*>::iterator i;
34
35
0
    for (atom = box.BeginAtom(i); atom; atom = box.NextAtom(i)) {
36
0
      if (atom->GetIdx() == 1) {
37
0
        _xmin = atom->GetX();
38
0
        _xmax = atom->GetX();
39
0
        _ymin = atom->GetY();
40
0
        _ymax = atom->GetY();
41
0
        _zmin = atom->GetZ();
42
0
        _zmax = atom->GetZ();
43
0
      }
44
0
      else {
45
0
        if (atom->GetX() < _xmin)
46
0
          _xmin = atom->GetX();
47
0
        if (atom->GetX() > _xmax)
48
0
          _xmax = atom->GetX();
49
0
        if (atom->GetY() < _ymin)
50
0
          _ymin = atom->GetY();
51
0
        if (atom->GetY() > _ymax)
52
0
          _ymax = atom->GetY();
53
0
        if (atom->GetZ() < _zmin)
54
0
          _zmin = atom->GetZ();
55
0
        if (atom->GetZ() > _zmax)
56
0
          _zmax = atom->GetZ();
57
0
      }
58
0
    }
59
0
  }
60
61
  void OBFloatGrid::Init(OBMol &box, double spacing, double pad)
62
0
  {
63
0
    OBGrid::Init(box); // handle in the base class
64
65
0
    _xmin -= pad;
66
0
    _xmax += pad;
67
0
    _ymin -= pad;
68
0
    _ymax += pad;
69
0
    _zmin -= pad;
70
0
    _zmax += pad;
71
72
    /* store in Grid */
73
0
    _midx=0.5*(_xmax+_xmin);
74
0
    _midy=0.5*(_ymax+_ymin);
75
0
    _midz=0.5*(_zmax+_zmin);
76
0
    _xdim=static_cast<int>((_xmax-_xmin)/spacing) + 1;
77
0
    _ydim=static_cast<int>((_ymax-_ymin)/spacing) + 1;
78
0
    _zdim=static_cast<int>((_zmax-_zmin)/spacing) + 1;
79
0
    _spacing=spacing;
80
0
    _halfSpace=_spacing/2.0;
81
0
    _inv_spa=1.0/_spacing;
82
0
    _ival=nullptr;
83
84
    // Calculate the size needed, resize the vector and initialise it to 0.0
85
0
    int size = _xdim*_ydim*_zdim;
86
0
    _values.resize(size, 0.0);
87
0
  }
88
89
  void OBFloatGrid::SetLimits(const double origin[3], const double v1[3], const double v2[3],
90
                              const double v3[3])
91
0
  {
92
    // Convert to vectors and call the vector form of the function
93
0
    vector3 originv(origin[0], origin[1], origin[2]);
94
0
    vector3 x(v1[0], v1[1], v1[2]);
95
0
    vector3 y(v2[0], v2[1], v2[2]);
96
0
    vector3 z(v3[0], v3[1], v3[2]);
97
0
    SetLimits(originv, x, y, z);
98
0
  }
99
100
  void OBFloatGrid::SetLimits(const vector3& origin, const vector3& x,
101
                              const vector3& y, const vector3& z)
102
0
  {
103
    // Using vectors instead of arrays of doubles
104
0
    _xmin = origin.x();
105
0
    _ymin = origin.y();
106
0
    _zmin = origin.z();
107
108
    // Set the axes
109
0
    SetXAxis(x);
110
0
    SetYAxis(y);
111
0
    SetZAxis(z);
112
113
    // Now set the max and mid as well as spacing
114
0
    _xmax = _xmin + (_xdim-1) * (x.x() + y.x() + z.x());
115
0
    _ymax = _ymin + (_ydim-1) * (x.y() + y.y() + z.y());
116
0
    _zmax = _zmin + (_zdim-1) * (x.z() + y.z() + z.z());
117
    // FIXME If we want support for cubes aligned along arbitrary axes then
118
    // averaging the x, y and z directions will not work. Just use x for now.
119
0
    _spacing = (_xmax - _xmin)/(_xdim-1);
120
0
    _halfSpace= _spacing/2.0;
121
0
    _inv_spa=1.0/_spacing;
122
0
  }
123
124
  void OBFloatGrid::SetNumberOfPoints(int nx, int ny, int nz)
125
0
  {
126
0
    _xdim = nx;
127
0
    _ydim = ny;
128
0
    _zdim = nz;
129
0
    _values.resize(nx*ny*nz);
130
0
  }
131
132
  void OBFloatGrid::SetXAxis(vector3 v)
133
0
  {
134
0
    _xAxis = v;
135
0
  }
136
137
  void OBFloatGrid::SetYAxis(vector3 v)
138
0
  {
139
0
    _yAxis = v;
140
0
  }
141
142
  void OBFloatGrid::SetZAxis(vector3 v)
143
0
  {
144
0
    _zAxis = v;
145
0
  }
146
147
  double OBFloatGrid::Inject(double x, double y, double z)
148
0
  {
149
0
    if (_values.empty())
150
0
      return 0.0;
151
152
0
    if( x<=_xmin || x>=_xmax
153
0
        || y<=_ymin || y>=_ymax
154
0
        || z<=_zmin || z>=_zmax ) return 0.0;
155
156
0
    return(_values[CoordsToIndex(x, y, z)]);
157
0
  }
158
159
  void OBFloatGrid::IndexToCoords(int idx, double &x, double &y, double &z)
160
0
  {
161
0
    int grid_x, grid_y, grid_z;
162
163
0
    grid_z = idx % _zdim;
164
0
    grid_x = static_cast<int>(idx / (_ydim * _zdim));
165
0
    grid_y = static_cast<int>((idx - (grid_x * _ydim * _zdim)) / _zdim);
166
167
0
    x = (grid_x * _spacing + _xmin) + _halfSpace;
168
0
    y = (grid_y * _spacing + _ymin) + _halfSpace;
169
0
    z = (grid_z * _spacing + _zmin) + _halfSpace;
170
0
  }
171
172
  int OBFloatGrid::CoordsToIndex(double x, double y, double z)
173
0
  {
174
0
    int gx=static_cast<int>((x-_xmin)*_inv_spa);
175
0
    int gy=static_cast<int>((y-_ymin)*_inv_spa);
176
0
    int gz=static_cast<int>((z-_zmin)*_inv_spa);
177
178
0
    return((gx*_ydim*_zdim) + (gy*_zdim) + gz);
179
0
  }
180
181
  void OBFloatGrid::CoordsToIndex(int *idx,double *c)
182
0
  {
183
0
    idx[0]=static_cast<int>((c[0]-_xmin)*_inv_spa);
184
0
    idx[1]=static_cast<int>((c[1]-_ymin)*_inv_spa);
185
0
    idx[2]=static_cast<int>((c[2]-_zmin)*_inv_spa);
186
0
  }
187
188
  double OBFloatGrid::Interpolate(double x, double y, double z)
189
0
  {
190
0
    if (_values.empty())
191
0
      return 0.0;
192
193
0
    int n,igx,igy,igz;
194
0
    double yzdim;
195
0
    double gx,gy,gz,fgx,fgy,fgz;
196
0
    double ax,ay,az,bx,by,bz;
197
0
    double AyA,ByA,AyB,ByB,Az,Bz;
198
199
0
    if( x<=_xmin || x>=_xmax
200
0
        || y<=_ymin || y>=_ymax
201
0
        || z<=_zmin || z>=_zmax ) return 0.0;
202
203
0
    yzdim = _ydim*_zdim;
204
205
    /* calculate grid voxel and fractional offsets */
206
0
    gx=(x-_xmin-_halfSpace)*_inv_spa;
207
0
    if (gx<0)
208
0
      gx=0;
209
0
    igx=static_cast<int>(gx);
210
0
    fgx=gx-static_cast<double>(igx);
211
0
    gy=(y-_ymin-_halfSpace)*_inv_spa;
212
0
    if (gy<0)
213
0
      gy=0;
214
0
    igy=static_cast<int>(gy);
215
0
    fgy= gy - static_cast<double>(igy);
216
0
    gz=(z-_zmin-_halfSpace)*_inv_spa;
217
0
    if (gz<0)
218
0
      gz=0;
219
0
    igz=static_cast<int>(gz);
220
0
    fgz= gz - static_cast<double>(igz);
221
222
    // Calculate the index of the nearest point
223
0
    n=static_cast<int>(igx*yzdim + igy*_zdim + igz);
224
225
0
    if ((n+1+_zdim+yzdim) >= (yzdim*_xdim))
226
0
      return 0.0;
227
228
    /* calculate linear weightings */
229
0
    ax=1.0-fgx;
230
0
    bx=fgx;
231
0
    ay=1.0-fgy;
232
0
    by=fgy;
233
0
    az=1.0-fgz;
234
0
    bz=fgz;
235
236
    /* calculate interpolated value */
237
0
    AyA=az*_values[n           ]+bz*_values[(n+1)    ];
238
0
    ByA=az*_values[n+_zdim]+bz*_values[(n+1+_zdim)  ];
239
240
0
    Az=ay*AyA+by*ByA;
241
242
0
    AyB=az*_values[static_cast<int>(n     +yzdim)] +
243
0
        bz*_values[static_cast<int>(n+1     +yzdim)];
244
0
    ByB=az*_values[static_cast<int>(n+_zdim+yzdim)] +
245
0
        bz*_values[static_cast<int>(n+1+_zdim+yzdim)];
246
0
    Bz=ay*AyB+by*ByB;
247
248
0
    return(ax*Az+bx*Bz);
249
0
  }
250
251
  std::vector<double> OBFloatGrid::GetDataVector()
252
0
  {
253
0
    return _values;
254
0
  }
255
256
  void OBFloatGrid::SetVals(const std::vector<double> & vals)
257
0
  {
258
0
    _values.clear();
259
0
    _values = vals;
260
0
  }
261
262
  double OBFloatGrid::InterpolateDerivatives(double x,double y,double z,double *derivatives)
263
0
  {
264
0
    int n,igx,igy,igz;
265
0
    double yzdim;
266
0
    double gx,gy,gz,fgx,fgy,fgz;
267
0
    double ax,ay,az,bx,by,bz;
268
0
    double AyA,ByA,AyB,ByB,Az,Bz;
269
0
    double energy,fx,fy,fz;
270
271
0
    if( x<=_xmin || x>=_xmax
272
0
        || y<=_ymin || y>=_ymax
273
0
        || z<=_zmin || z>=_zmax ) return 0.0;
274
275
0
    yzdim = _ydim*_zdim;
276
277
    /* calculate grid voxel and fractional offsets */
278
0
    gx=(x-_xmin-_halfSpace)*_inv_spa;
279
0
    if (gx<0)
280
0
      gx=0;
281
0
    igx=static_cast<int>(gx);
282
0
    fgx=gx-(double)igx;
283
0
    gy=(y-_ymin-_halfSpace)*_inv_spa;
284
0
    if (gy<0)
285
0
      gy=0;
286
0
    igy=static_cast<int>(gy);
287
0
    fgy= gy - (double) igy;
288
0
    gz=(z-_zmin-_halfSpace)*_inv_spa;
289
0
    if (gz<0)
290
0
      gz=0;
291
0
    igz=static_cast<int>(gz);
292
0
    fgz= gz - (double) igz;
293
294
0
    n=static_cast<int>(igx*yzdim + igy*_zdim + igz);
295
    /* calculate linear weightings */
296
0
    ax=1.0-fgx;
297
0
    bx=fgx;
298
0
    ay=1.0-fgy;
299
0
    by=fgy;
300
0
    az=1.0-fgz;
301
0
    bz=fgz;
302
303
    /* calculate interpolated value */
304
0
    AyA=az*_values[n           ]+bx*_values[n+1    ];
305
0
    ByA=az*_values[n+_zdim]+bx*_values[(n+1+_zdim)  ];
306
307
0
    Az=ay*AyA+by*ByA;
308
309
0
    AyB=az*_values[static_cast<int>(n      +yzdim)]+
310
0
        bz*_values[static_cast<int>(n+1      +yzdim)];
311
0
    ByB=az*_values[static_cast<int>(n+_zdim+yzdim)]+
312
0
        bz*_values[static_cast<int>(n+1+_zdim+yzdim)];
313
0
    Bz=ay*AyB+by*ByB;
314
315
0
    energy = ax*Az+bx*Bz;
316
317
    //calculate derivatives
318
319
0
    fz=-Az+Bz;
320
321
0
    Az=-AyA+ByA;
322
0
    Bz=-AyB+ByB;
323
324
0
    fy=az*Az+bz*Bz;
325
326
0
    AyA=-_values[n           ]+_values[(n+1)     ];
327
0
    ByA=-_values[n+_zdim      ]+_values[(n+1+_zdim)];
328
329
0
    Az=ay*AyA+by*ByA;
330
331
0
    AyB=-_values[static_cast<int>(n      +yzdim)]+
332
0
         _values[static_cast<int>(n+1      +yzdim)];
333
0
    ByB=-_values[static_cast<int>(n+_zdim+yzdim)]+
334
0
         _values[static_cast<int>(n+1+_zdim+yzdim)];
335
336
0
    Bz=ay*AyB+by*ByB;
337
338
0
    fx=ax*Az+bx*Bz;
339
340
0
    derivatives[0] += fx;
341
0
    derivatives[1] += fy;
342
0
    derivatives[2] += fz;
343
344
0
    return(energy);
345
0
  }
346
347
  ostream& operator<< ( ostream &os, const  OBFloatGrid& fg)
348
0
  {
349
    //@todo: this code stores the data in way that depends on
350
    // the bit representation of floating-point numbers. One can say
351
    // it's OK because IEEE754 is a widely accepted standard, but then
352
    // one should at least make it write the data in an endianness-
353
    // independent way. Of course this comment applies also to
354
    // the operator>> below.
355
0
    os.write((const char*)&fg._xmin,sizeof(double));
356
0
    os.write((const char*)&fg._xmax,sizeof(double));
357
0
    os.write((const char*)&fg._ymin,sizeof(double));
358
0
    os.write((const char*)&fg._ymax,sizeof(double));
359
0
    os.write((const char*)&fg._zmin,sizeof(double));
360
0
    os.write((const char*)&fg._zmax,sizeof(double));
361
362
0
    os.write((const char*)&fg._midx,sizeof(double));
363
0
    os.write((const char*)&fg._midy,sizeof(double));
364
0
    os.write((const char*)&fg._midz,sizeof(double));
365
0
    os.write((const char*)&fg._inv_spa,sizeof(double));
366
0
    os.write((const char*)&fg._spacing,sizeof(double));
367
0
    os.write((const char*)&fg._xdim,sizeof(int));
368
0
    os.write((const char*)&fg._ydim,sizeof(int));
369
0
    os.write((const char*)&fg._zdim,sizeof(int));
370
0
    os.write((const char*)&fg._values[0],
371
0
             (sizeof(double)*(fg._xdim*fg._ydim*fg._zdim)));
372
373
0
    return(os);
374
0
  }
375
376
  istream& operator>> ( istream &is,OBFloatGrid& fg)
377
0
  {
378
0
    is.read((char*)&fg._xmin,sizeof(double));
379
0
    is.read((char*)&fg._xmax,sizeof(double));
380
0
    is.read((char*)&fg._ymin,sizeof(double));
381
0
    is.read((char*)&fg._ymax,sizeof(double));
382
0
    is.read((char*)&fg._zmin,sizeof(double));
383
0
    is.read((char*)&fg._zmax,sizeof(double));
384
385
0
    is.read((char*)&fg._midx,sizeof(double));
386
0
    is.read((char*)&fg._midy,sizeof(double));
387
0
    is.read((char*)&fg._midz,sizeof(double));
388
0
    is.read((char*)&fg._inv_spa,sizeof(double));
389
0
    is.read((char*)&fg._spacing,sizeof(double));
390
0
    is.read((char*)&fg._xdim,sizeof(int));
391
0
    is.read((char*)&fg._ydim,sizeof(int));
392
0
    is.read((char*)&fg._zdim,sizeof(int));
393
0
    int size = fg._xdim*fg._ydim*fg._zdim;
394
0
    fg._values.resize(size);
395
0
    size *= (int) sizeof(double);
396
397
0
    is.read((char*)&fg._values[0],size);
398
0
    fg._halfSpace= fg._spacing/2.0;
399
400
0
    return(is);
401
0
  }
402
403
  void OBProxGrid::Setup(OBMol &mol,OBMol &box,double cutoff,double res)
404
0
  {
405
0
    this->Init(box); // handle in the base class
406
407
0
    _inc = res; // 1/2 angstrom resolution
408
409
0
    _nxinc = (int) floor((_xmax - _xmin)/0.5);
410
0
    _nyinc = (int) floor((_ymax - _ymin)/0.5);
411
0
    _nzinc = (int) floor((_zmax - _zmin)/0.5);
412
0
    _maxinc = _nxinc*_nyinc*_nzinc;
413
414
0
    int j,size = _nxinc*_nyinc*_nzinc;
415
0
    cell.resize(size);
416
0
    for (unsigned int num = 0; num < cell.size(); ++num)
417
0
      cell[num].resize(0);
418
419
0
    cutoff *= cutoff; //don't do sqrts
420
421
0
    int k,l,m;
422
0
    double x,y,z,dx_2,dy_2;
423
0
    double *c = mol.GetCoordinates();
424
0
    size = mol.NumAtoms()*3;
425
426
0
    OBAtom *atom;
427
0
    vector<OBAtom*>::iterator i;
428
0
    for (atom = mol.BeginAtom(i),j=0;atom;atom = mol.NextAtom(i),j+=3)
429
0
      if (PointIsInBox(c[j],c[j+1],c[j+2]))
430
0
        for (x = _xmin+(_inc/2.0),k=0;k < _nxinc;x+=_inc,++k)
431
0
          if ((dx_2 = SQUARE(c[j]-x)) < cutoff)
432
0
            for (y = _ymin+(_inc/2.0),l=0;l < _nyinc;y+=_inc,++l)
433
0
              if ((dx_2+(dy_2 = SQUARE(c[j+1]-y))) < cutoff)
434
0
                for (z = _zmin+(_inc/2.0),m=0;m < _nzinc;z+=_inc,++m)
435
0
                  if ((dx_2+dy_2+SQUARE(c[j+2]-z)) < cutoff)
436
0
                    cell[(k*_nyinc*_nzinc)+(l*_nzinc)+m].push_back(atom->GetIdx());
437
438
0
    _inc = 1/_inc;
439
0
  }
440
441
  void OBProxGrid::Setup(OBMol &mol,OBMol &box,double cutoff,vector<bool> &use,
442
                         double res)
443
0
  {
444
0
    this->Init(box); // handle in the base class
445
446
0
    _inc = res; // 1/2 angstrom resolution
447
448
0
    _nxinc = (int) floor((_xmax - _xmin)/0.5);
449
0
    _nyinc = (int) floor((_ymax - _ymin)/0.5);
450
0
    _nzinc = (int) floor((_zmax - _zmin)/0.5);
451
0
    _maxinc = _nxinc*_nyinc*_nzinc;
452
453
0
    int j,size = _nxinc*_nyinc*_nzinc;
454
0
    cell.resize(size);
455
0
    cutoff *= cutoff; //don't do sqrts
456
457
0
    int k,l,m;
458
0
    double x,y,z,dx_2,dy_2;
459
0
    double *c = mol.GetCoordinates();
460
0
    size = mol.NumAtoms()*3;
461
462
0
    OBAtom *atom;
463
0
    vector<OBAtom*>::iterator i;
464
0
    for (atom = mol.BeginAtom(i),j=0;atom;atom = mol.NextAtom(i),j+=3)
465
0
      if (use[atom->GetIdx()])
466
0
        if (PointIsInBox(c[j],c[j+1],c[j+2]))
467
0
          for (x = _xmin+(_inc/2.0),k=0;k < _nxinc;x+=_inc,++k)
468
0
            if ((dx_2 = SQUARE(c[j]-x)) < cutoff)
469
0
              for (y = _ymin+(_inc/2.0),l=0;l < _nyinc;y+=_inc,++l)
470
0
                if ((dx_2+(dy_2 = SQUARE(c[j+1]-y))) < cutoff)
471
0
                  for (z = _zmin+(_inc/2.0),m=0;m < _nzinc;z+=_inc,++m)
472
0
                    if ((dx_2+dy_2+SQUARE(c[j+2]-z)) < cutoff)
473
0
                      cell[(k*_nyinc*_nzinc)+(l*_nzinc)+m].push_back(atom->GetIdx());
474
475
0
    _inc = 1/_inc;
476
0
  }
477
478
  vector<int> *OBProxGrid::GetProxVector(double x,double y,double z)
479
0
  {
480
0
    if (x < _xmin || x > _xmax)
481
0
      return nullptr;
482
0
    if (y < _ymin || y > _ymax)
483
0
      return nullptr;
484
0
    if (z < _zmin || z > _zmax)
485
0
      return nullptr;
486
487
0
    x -= _xmin;
488
0
    y -= _ymin;
489
0
    z -= _zmin;
490
0
    int i,j,k,idx;
491
0
    i = (int) (x*_inc);
492
0
    j = (int) (y*_inc);
493
0
    k = (int) (z*_inc);
494
0
    idx = (i*_nyinc*_nzinc)+(j*_nzinc)+k;
495
0
    if (idx >= _maxinc)
496
0
      return nullptr;
497
498
0
    return(&cell[idx]);
499
0
  }
500
501
  vector<int> *OBProxGrid::GetProxVector(double *c)
502
0
  {
503
0
    double x,y,z;
504
0
    x = c[0];
505
0
    y = c[1];
506
0
    z = c[2];
507
508
0
    return( GetProxVector(x, y, z) );
509
0
  }
510
511
} // end namespace OpenBabel
512
513
//! \file grid.cpp
514
//! \brief Handle grids of values.
515