18.1.1 C Array Wrappers

While the above methods may be all the beginning user may need, sometimes a more direct approach is needed for speed and memory-savings. In C++, arrays of floating point numbers are passed between routines as pointers to raw memory locations. While this procedure can lead to crashes and errors accessing memory outside the allocated space, it maximizes performance since no extra copies of the values have to be made and passed around. While it is possible to create a ``pointer to float'' or ``pointer to double'' in Python, it is opaque to the rest of the python code and can only be passed to other C routines. As a compromise, the PyOEChem wrappers introduce 2 classes that are very thin wrappers around C-style arrays. OEFloatArray wraps a float* pointer of a given size and OEDoubleArray wraps a double* pointer of a given size. These classes can be passed into any OEChem method that takes a float pointer or double pointer, resulting in much less overhead than the methods above, yet they provide a __len__() method so that the user can determine their size. And they provide __getitem__, __setitem__ access with bounds checking so that members can be accessed like members of a Python list, but an exception will be thrown if the user tries to access outside the size of the Array.

While not used for coordinate handling, Python-OEChem also creates OEIntArray for wrapping a C int*, OEUIntArray for wrapping a C unsigned int* and an OEUCharArray for wrapping a C unsiged char*.

Since floating point numbers in Python are usually stored as doubles, all the methods that follow are designed to use a OEDoubleArray.

For getting molecule or atom coordinates into a OEDoubleArray, you must first create an instance of the correct size. For an atom's coordinates you need an array of size 3:

xyz = OEDoubleArray(3)
mol.GetCoords(atom, xyz)
print 'x= ', xyz[0], 'y= ', xyz[1], 'z= ', xyz[2]

To get the coordinates of the entire molecule, create a OEDoubleArray 3 times the return from GetMaxAtomIdx(). Then to access the coordinates of a specific atom, index into the array using atom.GetIdx(). The next example gets all the coordinates into a single array and the prints them out, atom-by-atom.

coords = OEDoubleArray(3*mol.GetMaxAtomIdx())
mol.GetCoords(coords)

for atom in mol.GetAtoms():
    idx = 3*atom.GetIdx()
    print ( 'i= %3d  x= %8.4f  y= %8.4f  z= %8.4f' %
            (atom.GetIdx(),coords[idx],coords[idx+1],coords[idx+2]))

Setting coordinates using OEDoubleArrays is performed in a completely analogous fashion. For a single atom, create a OEDoubleArray of size 3, fill it with values (it defaults to all zeroes) and then pass it to SetCoords. This array could also be the result of a previous call to GetCoords. For a whole molecule, you again need an array size 3 time the return from GetMaxAtomIdx().

While these molecule member functions provide access to molecule coordinates, the next few sections describe various methods to manipulate these coordinates either inside OEDoubleArrays directly (low-level routines) or by operations directly on the coordinates inside the molecule object.