Welcome aboard!
The "indices" are integer numbers, corresponding to the list of atoms given as the scattering region in the two-probe configuration. The first atom in this list is index 0, and so on.
To select many atoms, you can create the list from functions like "range" or "arange" (requires import of numpy). Lists have methods "insert" and "remove", so you can put in all atoms at first and then just remove a few. You can also easily concatenate lists. Note that
range(a,b) returns a list with
[a,a+1,a+2,...,b-1].
Thus, for instance, if we have 20 atoms, and wish to select the first 10 atoms and the last 5 (but no others), you can use
ix = range(0,11) + range(15,20)
"ix" is the variable we then pass to the keyword
geometric_constraints.
If we want to only allow one specific atom (say, number 12, being the 13th atom in the list) to move in the relaxation, we use
ix = range(0,20)
ix.remove(12)
You can make various, complex combinations of lists this way. We can also use numpy's arange, if we want to select, say, every second atom:
import numpy
ix = numpy.arange(0,20,2)
To avoid mistakes, by counting the number of atoms by hand, you can also extract the number of atoms directly from the two-probe configuration. Let's say we have a two-probe configuration where all atoms except the 15th (index 14) should be fixed:
twoprobe_configuration = TwoProbeConfiguration()
...
N = len(twoprobe_configuration.cartesianCoordinates())
ix = range(N) # range(N) = range(0,N)
ix.remove(14)
For a more advanced example, imagine we wish to relax a structure, keeping all Carbon atoms fixed.
twoprobe_configuration = TwoProbeConfiguration()
...
import numpy
ix = range(len(twoprobe_configuration.cartesianCoordinates()))
elements = numpy.array(twoprobe_configuration.elements())
for r in numpy.where(elements!=Carbon)[0]:
ix.remove(r)
Note the [ 0 ] after "where"!
The "where" command is very powerful. It also supports set unions, which is useful in case we want to keep all Gold and Carbon atoms fixed:
twoprobe_configuration = TwoProbeConfiguration()
...
import numpy
ix = range(len(twoprobe_configuration.cartesianCoordinates()))
elements = numpy.array(twoprobe_configuration.elements())
for r in numpy.where((elements!=Carbon) & (elements!=Gold))[0]:
ix.remove(r)
Here the extra set of parenthesis around the != statements are crucial!
All of this applies, of course, equally to relaxations of molecules and bulk systems, and it's also the same when you select atoms for MPSH projection.
NOTE: Normally in Python you can use negative indices to count backwards in a list. ATK does, however, not support that notation for the constrained atoms. If you specify negative indices in the list, they will simply be ignored (actually that's a small design flaw, it should raise an error or count backwards, not just silently ignore the negative values...).