OEGrid provides three ways to index data inside a grid. They are ordered here by speed of access, ie, grid elements perform simple pointer arithmetic where spatial coordinates require floating point computation.
Assuming grid is already filled with relevant values,
Listing 2.1 demonstrates how to retrieve the grid
value closest to the atoms in the molecule mol.
float xyz[3];
for (OEIter<OEAtomBase> atom = mol.GetAtoms(); atom; ++atom)
{
mol.GetCoords(atom, xyz);
if (grid.IsInGrid(xyz[0], xyz[1], xyz[2]))
{
float val = grid(xyz[0], xyz[1], xyz[2]);
// Do something with val
}
}
Since operator() returns a reference, the same code can be used
to assign values to grid points. This is demonstrated in
Listing 2.2.
float xyz[3];
for (OEIter<OEAtomBase> atom = mol.GetAtoms(); atom; ++atom)
{
mol.GetCoords(atom, xyz);
if (grid.IsInGrid(xyz[0], xyz[1], xyz[2]))
grid(xyz[0], xyz[1], xyz[2]) = atom.GetPartialCharge();
}
Note that in the preceding two code fragments bounds checking has been
explicitly performed by the IsInGrid method. Using
operator() without this bounds check can lead to a segmentation
fault. However, IsInGrid can become an expensive operation if
performed excessively. One way to avoid this is to make sure your grid
is big enough to enclose the object being worked on. For example:
using OEGetCenterAndExtents on the molecule and then using
OEMakeGridFromCenterAndExtents to construct the grid, as shown
in Listing 2.3.
//mol has already been defined as an OEGraphMol with relevant data float center[3]; float extents[3]; OEScalarGrid grid; float spacing = 0.75; OEGetCenterAndExtents(mol, center, extents); OEMakeGridFromCenterAndExtents(grid, center, extents, spacing);
Grid indices are faster than spatial coordinates because there is no
floating point arithmetic to perform. Grid indices make it easy to
quickly iterate over a small portion of the
grid. Listing 2.4 demonstrates iterating over all 27
gird points adjacent to and including the grid point given by the grid index (ix,
iy, iz).
unsigned int ix, iy, iz; // Some arbitrary grid point
// Make sure not to go past grid bounds
unsigned int mini = (ix == 0 ? 0 : ix - 1);
unsigned int minj = (iy == 0 ? 0 : iy - 1);
unsigned int mink = (iz == 0 ? 0 : iz - 1);
unsigned int maxi = min(ix + 1, grid.GetXDim());
unsigned int maxj = min(iy + 1, grid.GetYDim());
unsigned int maxk = min(iz + 1, grid.GetZDim());
for (unsigned int k = mink; k < maxk; k++)
for (unsigned int j = minj; j < maxj; j++)
for (unsigned int i = mini; i < maxi; i++)
float val = grid(i, j, k);
Grid values are actually stored in a large one dimensional block of memory. The fastest way to access all the data is to linearly scan through memory. Listing 2.5 demonstrates how to square every value in the grid.
for (unsigned int i = 0; i < grid.GetSize(); ++i) grid[i] = grid[i] * grid[i];
Direct access to the memory is given by the GetValues
method. Listing 2.6 demonstrates the quickest way to zero out
all the grid values.
memset(grid.GetValues(), 0, grid.GetSize()*sizeof(float));
Listing 2.7 shows how grid elements relate to three
dimensional indexes. This is meant to be an instructional piece of
code, not to be actually used. To make a copy of a grid
OEScalarGrid's copy constructor should be used.
OEScalarGrid grid;
// Fill grid with something relevant
OEScalarGrid cgrid;
OEGridCopyGeometry(cgrid, grid);
unsigned int el = 0;
for (unsigned int k = 0; k < grid.GetZDim(); k++)
for (unsigned int j = 0; j < grid.GetYDim(); j++)
for (unsigned int i = 0; i < grid.GetXDim(); i++)
{
cgrid[el] = grid(i, j, k);
el++;
}