Structure optimization

In this tutorial we consider structure optimization of the H2 molecule. For that, we will calculate the atomization energy of the molecule both for the experimentally determined geometry and for the structure relaxed using the GPAW calculator.

In a previous tutorial we have calculated atomization energies. As a short recap, the following script will calculate the atomization energy of a hydrogen molecule with the geometry from experiment:

from ase import Atoms
from gpaw import GPAW

a = 10.  # Size of unit cell (Angstrom)
c = a / 2

# Hydrogen atom:
atom = Atoms('H',
             positions=[(c, c, c)],
             magmoms=[0],
             cell=(a, a + 0.0001, a + 0.0002))  # break cell symmetry

# gpaw calculator:
calc = GPAW(mode='pw',
            xc='PBE',
            hund=True,
            txt='H.out')
atom.calc = calc

e1 = atom.get_potential_energy()
calc.write('H.gpw')

# Hydrogen molecule:
d = 0.74  # experimental bond length
molecule = Atoms('H2',
                 positions=([c - d / 2, c, c],
                            [c + d / 2, c, c]),
                 cell=(a, a, a))

calc = calc.new(hund=False,  # no hund rule for molecules
                txt='H2.out')

molecule.calc = calc
e2 = molecule.get_potential_energy()
calc.write('H2.gpw')

Above, we calculated the atomization energy for H2 using the experimental bond length of 0.74 Å. In this tutorial, we ask an ASE optimizer to iteratively find the structural energy minimum, where all atomic forces are below 0.05 eV/Å. The following script will do the job:

# web-page: optimization.txt

from gpaw import restart
from ase.parallel import paropen as open
from ase.optimize import QuasiNewton


molecule, calc = restart('H2.gpw', txt='H2-relaxed.txt')

e2 = molecule.get_potential_energy()
d0 = molecule.get_distance(0, 1)

with open('optimization.txt', 'w') as fd:
    print('experimental bond length:', file=fd)
    print(f'hydrogen molecule energy: {e2:5.2f} eV', file=fd)
    print(f'bondlength              : {d0:5.2f} Ang', file=fd)

    # Find the theoretical bond length:
    relax = QuasiNewton(molecule, logfile='qn.log')
    relax.run(fmax=0.05)

    e2 = molecule.get_potential_energy()
    d0 = molecule.get_distance(0, 1)

    print(file=fd)
    print('PBE energy minimum:', file=fd)
    print(f'hydrogen molecule energy: {e2:5.2f} eV', file=fd)
    print(f'bondlength              : {d0:5.2f} Ang', file=fd)

The result is:

experimental bond length:
hydrogen molecule energy: -6.65 eV
bondlength              :  0.74 Ang

PBE energy minimum:
hydrogen molecule energy: -6.65 eV
bondlength              :  0.75 Ang

To save time you could have told the minimizer to keep one atom fixed, and only relaxing the other. This is achieved through the use of constraints:

molecule.set_constraint(FixAtoms(mask=[0, 1]))

The keyword mask contains list of booleans for each atom indicating whether the atom’s position should be fixed or not. See the ase.constraints module on the ASE page for more information and examples for setting constraints.