This index can be used to distinguish one object from another, as it
is unique amongst all objects of the same type of the same molecule.
Indices are also stable, meaning a given object will have the same
index throughout its lifetime, independent of any other molecule
manipulations, e.g., reordering the molecule
(OEMolBase.OrderAtoms), or the creation or deletion
of other objects (OEMolBase.NewAtom or
OEMolBase.DeleteAtom). The exception is the
following methods.

Indices are ideal for indexing into densely packed arrays of
information about the molecule. Many OEChem TK functions use them to
this end, e.g., OEAddMols,
OESubsetMol, or
OEDetermineComponents. The coordinates of a molecule
are retrieved as an array of floating point values indexed by the atom
indices. The following example demonstrates how to use the atom
indices for a rudimentary XYZ file format writer.

Listing 1: Rudimentary XYZ writer

packageopeneye.docexamples.oechem;importopeneye.oechem.*;publicclassXYZWriter{publicstaticvoidmain(Stringargv[]){if(argv.length!=1)oechem.OEThrow.Usage("XYZWriter <input>");oemolistreamifs=newoemolistream();if(!ifs.open(argv[0]))oechem.OEThrow.Fatal("Unable to open "+argv[0]);OEGraphMolmol=newOEGraphMol();while(oechem.OEReadMolecule(ifs,mol)){System.out.println(mol.NumAtoms());System.out.println(mol.GetTitle());floatcoords[]=newfloat[mol.GetMaxAtomIdx()*3];mol.GetCoords(coords);for(OEAtomBaseatom:mol.GetAtoms()){intidx=atom.GetIdx();System.out.printf("%-3s%11.5f%11.5f%11.5f\n",oechem.OEGetAtomicSymbol(atom.GetAtomicNum()),coords[idx*3],coords[idx*3+1],coords[idx*3+2]);}}ifs.close();}}

Computers are very efficient at doing this sort of sequential
lookup. Whenever an efficient temporary data structure is needed to
track information about a molecule indices should be used.

Note that atom, bond, and conformer indices are not guaranteed to be
sequential, or even created sequentially, and hence atom indices can
not and should not be used to retrieve all of the atoms of a molecule.
Even typing the following idiom may invalidate any chance of support
and eliminate any glimmer of respect from OpenEye Scientific Software
or the computational chemistry/cheminformatics community.

Warning

// Never ever, ever do this!!!for(inti=0;i<=mol.NumAtoms();++i){OEAtomBaseatom=mol.GetAtom(newOEHasAtomIdx(i));// pretend atom is valid}

There are far more efficient methods of crashing computer software
that should be used instead.

The common misconception is that OEChem TK indices should be stored in
order to reference back to an atom in the molecule. This leads to the
idiom used in Listing2 which is technically
legal OEChem TK, however, is just as insidious as the previous code
snippet. The code is supposed to mimic a common technique to cache
particular atoms based on some expensive to calculate property. The
property in this instance is whether the atom is alpha beta
unsaturated.

Warning

Listing 2: Evil atom cache

packageopeneye.docexamples.oechem;importjava.util.*;importopeneye.oechem.*;publicclassAtomSubsetEvil{publicstaticvoidmain(Stringargv[]){OEGraphMolmol=newOEGraphMol();// initialized somehowArrayList<Integer>acache=newArrayList<Integer>();// cache of atomsfor(OEAtomBaseatom:mol.GetAtoms(newOEHasAlphaBetaUnsat()))acache.add(atom.GetIdx());// evil!// pretend this code is deep in some inner loop that needs to go fastfor(intaidx:acache){OEAtomBasecatom=mol.GetAtom(newOEHasAtomIdx(aidx));// O(n) lookup!// do something with the cached atom "catom"catom.SetName("Hello World");}}}

The OEMolBase.GetAtom method performs a linear,
\(O(mol.NumAtoms())\), search over the molecule looking for the
first atom that matches the predicate. This leads to a multiplicative
effect when looping over multiple atoms, calling
GetAtom for each atom. The
resulting algorithm is quadratic \(O(mol.NumAtoms()^2)\), possibly
destroying any benefits of caching the user’s expensive per atom
calculation.

The proper way to store references to atoms for later use is to
store the OEAtomBase itself. It is guaranteed that
these atoms will be valid for the lifetime of the molecule.

Listing3 demonstrates the proper way to
create a cache of atoms. It is important to remember that the
OEAtomBases in the container are only
valid while the molecule exists. Using the atoms after the molecule is
destroyed is undefined behavior (usually a segmentation fault).

Listing 3: Atom caching

packageopeneye.docexamples.oechem;importjava.util.*;importopeneye.oechem.*;publicclassAtomSubsetGood{publicstaticvoidmain(Stringargv[]){OEGraphMolmol=newOEGraphMol();// initialized somehowArrayList<OEAtomBase>acache=newArrayList<OEAtomBase>();// cache of atomsfor(OEAtomBaseatom:mol.GetAtoms(newOEHasAlphaBetaUnsat()))acache.add(atom);// pretend this code is deep in some inner loop that needs to go fastfor(OEAtomBasecatom:acache){// do something with the cached atom "catom"catom.SetName("Hello World");}}}