Labels for atoms

WORK IN PROGRESS

This proposal describes how to introduce labels for the atoms in an Atoms object in a backwards compatible way.

Why?

Some atoms are special:

  • ghost atoms
  • atoms with a core hole
  • atoms that need a special basis set

and some atoms are not atoms at all (methyl group, …).

Proposal

Introduce labels and kinds. A label is a string and a kind is the combination of these three:

  • A chemical symbol or an atomic number. Default: None (same as 'X' or 0)
  • A label. Default ''
  • A mass. Default None (use standard value)
  • An integer tag. Default 0

A kind can be represented as a Kind object:

  • Kind(Z=None, symbol=None, label='', mass=None, tag=0)

or as a string:

  • 'symbol' (Kind(symbol='symbol'))
  • 'symbol:label' (Kind(symbol='symbol', label='label'))
  • 'label' (Kind(label='label'))

Examples:

  • Kind(Z=1, label='ghost') (same as 'H:ghost')
  • Kind(symbol='H') (same as 'H')
  • Kind(symbol='H', label='', mass=2.0)
  • 'methyl' (same as Kind(label='methyl'))

We add symbols, labels and kinds list-of-string like attributes to the Atoms object as well as new labels and kinds keyword arguments to the Atoms constructor. Currently, the first argument to the Atoms constructor (symbols) will accept a chemical formula as a string or a list of chemical symbols or atomic numbers. We extend this to also accept kinds.

Note

Not really related to this label issue, but since we are anyway adding new attributes, we should also add masses, tags, initial_magmoms, momenta, initial_charges and mass.

Examples

>>> a = Atoms(['N', 'C', Kind(label='methyl', mass=9.0)])
>>> a.positions[:, 0] = [0, 1.2, 2.6]
>>> a.masses[a.labels == 'methyl'] = 10
>>> a.numbers
array([7, 6, 0])
>>> a.symbols  # special list-like object tied to a
Symbols(['N', 'C', 'X'])
>>> a.get_chemical_symbols()  # simple list
['N', 'C', 'X']
>>> a.labels
Labels(['', '', 'methyl'])
>>> a.kinds
Kinds(['N', 'C', Kind(label='methyl', mass=10.0)])

Here are 50 H-D molecules:

>>> h = Atoms('H100', positions=...)
>>> h.labels[::2] = 'deuterium'
>>> h.masses[h.labels == 'deuterium'] = 2.0

or equivalently:

>>> h.kinds[::2] = Kind(symbol='H', label='deuterium', mass=2.0)

A DFT code could use the kinds to select pseudo-potentials:

>>> n2 = molecule('N2')
>>> n2.labels[0] = 'core-hole'
>>> n2.calc = DFT(xc='LDA',
...               pp={'N:core-hole': '~/mypps/N-LDA.core-hole.upf'})

List-like objects

New Labels, Kinds and Symbols list-like objects will be introduced that can handle all the indexing operations in a storage efficient way. A statement like a.symbols[0] = 'He' must somehow lead to a.numbers[0] == 2 and other magic.

Atom objects

Add Atom.label and Atom.kind.

I/O

???