Prelude 1: Run_Adsorber.py - Running Adsorber

In this article, we will look at how to run the Adsorber program. This program is run though the Run_Adsorber.py script, which includes all the information required for Adsorber to adsorb species to surface sites of surfaces and clusters. You can find an example of Run_Adsorber.py files at github.com/GardenGroupUO/Adsorber under Examples.

Running the Adsorber Program

We will explain how the Run_Adsorber.py code works by running though the example shown below:

Run_Adsorber.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
from ase.build import molecule
from Adsorber import Adsorber_Program

# ------------------------------------------------------------------------------------------------------------------------------------
# Initial inputs for the Adsorber program
part_to_perform = 'Part B'

# General Variables
cluster_or_surface_model = 'cluster'

# Part A information
system_filename = '15-3-3629_with_vacuum_6.0_Ang.xyz'

# Part B information
path_to_VASP_optimised_non_adsorbate_system = 'Part_A_Non_Adsorbed_Files_For_VASP/system/OUTCAR'
cutoff = 3.5
surface_atoms = [11,25,28,13,3,8,6,23,22,59,34,62,66,1,0,4,30,15,14,16,5,12,29,2,7,10,24,26,70,35,47,50,60,63,48,39,41,44,54,68,76,71,32,31,74,42,56,52,43,40,46,61,53,45,57,72,73,77]

# ------------------------------------------------------------------------------------------------------------------------------------
# Give the Atoms objects for the atoms and molecules you want to adsorb to your cluster or surface model
adsorbed_species = []

COOH_symmetric = molecule('HCOOH') # note the carbon is index 1
COOH_symmetric.center(vacuum=10.0)
del COOH_symmetric[4] # remove the hydrogen atom
COOH_symmetric_axis = (0.1,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COOH_symmetric_adsorbed_species = {'name': 'COOH_symmetric', 'molecule': COOH_symmetric, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': COOH_symmetric_axis, 'rotations': rotations, 'sites_to_bind_adsorbate_to': ['Top_Sites','Bridge_Sites','Three_Fold_Sites']}
adsorbed_species.append(COOH_symmetric_adsorbed_species)

COOH_O_tilted = molecule('HCOOH') # note the carbon is index 1
COOH_O_tilted.center(vacuum=10.0)
del COOH_O_tilted[4] # remove the hydrogen atom
COOH_O_tilted_axis = (-0.4,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COOH_O_tilted_adsorbed_species = {'name': 'COOH_O_tilted', 'molecule': COOH_O_tilted, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': COOH_O_tilted_axis, 'rotations': rotations, 'sites_to_bind_adsorbate_to': 'Top_Sites'}
#adsorbed_species.append(COOH_O_tilted_adsorbed_species)

CO = molecule('CO') # note the carbon is index 1
CO.center(vacuum=10.0)
CO_axis = 'z'
distance_of_adatom_from_surface = 1.5
CO_adsorbed_species = {'name': 'CO', 'molecule': CO, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': CO_axis}
#adsorbed_species.append(CO_adsorbed_species)

# --------------------------------------------
# option1
COH = molecule('H2COH') # note the carbon is index 0
COH.center(vacuum=10.0)
del COH[4] # remove the hydrogen atom
del COH[3] # remove the hydrogen atom
COH_axis = '-x'
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COH_adsorbed_species = {'name': 'COH', 'molecule': COH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': COH_axis, 'rotations': rotations}
#adsorbed_species.append(COH_adsorbed_species)

#option2
CHO = molecule('HCO') # note the carbon is index 0
CHO.center(vacuum=10.0)
CHO_axis = (-(3.0**0.5)/2.0,-1.0/2.0,0)
rotations = 'automatic' #range(0,360,10)
CHO_adsorbed_species = {'name': 'CHO', 'molecule': CHO, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CHO_axis, 'rotations': rotations}
#adsorbed_species.append(CHO_adsorbed_species)
# --------------------------------------------
# option1
CH2O = molecule('H2CO') # note the carbon is index 1
CH2O.center(vacuum=10.0)
CH2O_axis = 'x'
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
CH2O_adsorbed_species = {'name': 'CH2O', 'molecule': CH2O, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': CH2O_axis, 'rotations': rotations}
#adsorbed_species.append(CH2O_adsorbed_species)

# option1
CHOH = molecule('H2COH') # note the carbon is index 0
CHOH.center(vacuum=10.0)
del CHOH[3]
CHOH_axis = (-1,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
CHOH_adsorbed_species = {'name': 'CHOH', 'molecule': CHOH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CHOH_axis, 'rotations': rotations}
#adsorbed_species.append(CHOH_adsorbed_species)
# --------------------------------------------
# new option 1
CH3O = molecule('CH3O') # note the oxygen is index 1
CH3O.center(vacuum=10.0)
CH3O_axis = '-y'
distance_of_adatom_from_surface = 1.5
CH3O_adsorbed_species = {'name': 'CH3O', 'molecule': CH3O, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': CH3O_axis}
#adsorbed_species.append(CH3O_adsorbed_species)

# new option 2
CH2OH = molecule('CH3OH') # carbon is index 0
CH2OH.center(vacuum=10.0)
del CH2OH[2] # remove the hydrogen atom
CH2OH_axis = (1,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
CH2OH_adsorbed_species = {'name': 'CH2OH', 'molecule': CH2OH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CH2OH_axis, 'rotations': rotations}
#adsorbed_species.append(CH2OH_adsorbed_species)
# --------------------------------------------
# new new option 1
CH2 = molecule('CH4') # carbon is index 0
CH2.center(vacuum=10.0)
del CH2[4] # remove the hydrogen atom
del CH2[3] # remove the hydrogen atom
CH2_axis = 'z'
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,180,10)
CH2_adsorbed_species = {'name': 'CH2', 'molecule': CH2, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CH2_axis, 'rotations': rotations}
#adsorbed_species.append(CH2_adsorbed_species)

CH3 = molecule('CH4') # carbon is index 0
CH3.center(vacuum=10.0)
del CH3[4] # remove the hydrogen atom
CH3_axis = (1,-1,1)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,120,10)
CH3_adsorbed_species = {'name': 'CH3', 'molecule': CH3, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CH3_axis, 'rotations': rotations}
#adsorbed_species.append(CH3_adsorbed_species)

# new new option 2
O = molecule('O')
O.center(vacuum=10.0)
distance_of_adatom_from_surface = 1.5
O_adsorbed_species = {'name': 'O', 'molecule': O, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface}
#adsorbed_species.append(O_adsorbed_species)

OH = molecule('OH') # note the oxygen is index 0
OH.center(vacuum=10.0)
OH_axis = '-z'
distance_of_adatom_from_surface = 1.5
OH_adsorbed_species = {'name': 'OH', 'molecule': OH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': OH_axis}
#adsorbed_species.append(OH_adsorbed_species)

C = molecule('C')
C.center(vacuum=10.0)
distance_of_adatom_from_surface = 1.5
C_adsorbed_species = {'name': 'C', 'molecule': C, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface}
#adsorbed_species.append(C_adsorbed_species)

# ------------------------------------------------------------------------------------------------------------------------------------
# Add here any other atoms and molecules that you need to locally optimise in VASP for energy calculations
Other_molecules_to_obtain_VASP_energies_for = []

graphene = molecule('C')
graphene.center(vacuum=10.0)
graphene_optimise_energy = {'name': 'graphene', 'molecule': graphene}
Other_molecules_to_obtain_VASP_energies_for.append(graphene_optimise_energy)

H2 = molecule('H2')
H2.center(vacuum=10.0)
H2_optimised_energy = {'name': 'H2', 'molecule': H2}
Other_molecules_to_obtain_VASP_energies_for.append(H2_optimised_energy)

H2O = molecule('H2O')
H2O.center(vacuum=10.0)
H2O_optimised_energy = {'name': 'H2O', 'molecule': H2O}
Other_molecules_to_obtain_VASP_energies_for.append(H2O_optimised_energy)

# ------------------------------------------------------------------------------------------------------------------------------------
# slurm informaion for making the submit.sl files for submitting VASP jobs in slurm

slurm_information = {}
slurm_information['project'] = 'uoo02568'
slurm_information['partition'] = 'large'
slurm_information['time'] = '72:00:00'
slurm_information['nodes'] = 1
slurm_information['ntasks_per_node'] = 12
slurm_information['mem-per-cpu'] = '1200MB'
slurm_information['email'] = 'yourslurmnotificationemailaddress@gmail.com'
slurm_information['vasp_version'] = 'VASP/5.3.5-intel-2017a-VTST-BEEF'
slurm_information['vasp_execution'] = 'vasp_cd'

# ------------------------------------------------------------------------------------------------------------------------------------
# Run the Adsorber program
Adsorber_Program(part_to_perform,cluster_or_surface_model,system_filename,path_to_VASP_optimised_non_adsorbate_system,cutoff,surface_atoms,adsorbed_species,slurm_information,Other_molecules_to_obtain_VASP_energies_for)

Lets go through each part of the Run_Adsorber.py file one by one to understand how to use it.

1) Things to import into this script

First you will want to import the Adsorber program, as well as any other methods that you want to use to import atoms and molecules to adsorb upon your cluster or surface. Here, we have imported the molecule method from the ase.build module.

1
2
from ase.build import molecule
from Adsorber import Adsorber_Program

2) Initial inputs for Adsorber

To begin, there are six inputs you will need to give to Adsorber. These are:

  • part_to_perform (str.): This variable indicates which Part of of Adsorber protocol you would like to perform. This is either 'Part A', 'Part B', or 'Part C'.

  • cluster_or_surface_model (str.): This tells Adsorber if you are wanting to adsorb atoms and clusters to the surface of a cluster or a surface model. If you are dealing with a cluster, set cluster_or_surface_model = 'cluster', else if you are dealing with a surface model, set cluster_or_surface_model = 'surface model' and make sure that your surface and vacuum point in the positive z direction. Also if you want to constrain any atoms in your model, this should be done in this file.

Part A options:

  • system_filename (str.): The name of the file of the cluster or the surface model that you will like to import into Adsorber. This file should be a .xyz or .traj file, but in reality any file type will do that ASE can read (see https://wiki.fysik.dtu.dk/ase/ase/io/io.html for more information on formats that ASE can read). For surfaces, you should have already performed surface convergence studies before proceeding with part A.

Part B options:

  • path_to_VASP_optimised_non_adsorbate_system (str.): This is the directory to your surface or cluster model without adsorbate after you have optimised it with VASP.

    • For clusters, this should be set to path_to_VASP_optimised_non_adsorbate_system = 'Part_A_Non_Adsorbed_Files_For_VASP/system/OUTCAR'

    • For surfaces, this should be pointed to the file that you want to bind your adsorbate to. This may be path_to_VASP_optimised_non_adsorbate_system = 'Part_A_Non_Adsorbed_Files_For_VASP/system/OUTCAR', or if you have surface converged your surface model, then to the file that represents the surface converged model.

  • cutoff (float or dict.): This is the maximum distance between atoms to be considered bonded or neighbouring. This is used to determine bridging, three-fold, and four-fold sites. This is given as a float for monoatomic cluster and surface systems, or for a multiatomic system if you are happy for the max bonding distance between any two elements to be the same. If you would like different element pairs to have different maximum bonding distances, this is given as a dictionary. For example, for a CuPd system: cutoff = {'Cu': 3.2, 'Pd': 3.6, ('Cu','Pd'): 3.4}

  • surface_atoms (list of ints): This is a list of the indices of all the surface atoms in your cluster or surface model. See How to Mark Surface Atoms in your Cluster/Surface model in Adsorber for how to determine which of your atoms are surface atoms and to get those clusters indices to add to the surface_atoms list. Note that if there are surface atoms that you do not want molecules to adsorb to, dont include them in this list.

This is given in this example as below:

 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Initial inputs for the Adsorber program
part_to_perform = 'Part B'

# General Variables
cluster_or_surface_model = 'cluster'

# Part A information
system_filename = '15-3-3629_with_vacuum_6.0_Ang.xyz'

# Part B information
path_to_VASP_optimised_non_adsorbate_system = 'Part_A_Non_Adsorbed_Files_For_VASP/system/OUTCAR'
cutoff = 3.5
surface_atoms = [11,25,28,13,3,8,6,23,22,59,34,62,66,1,0,4,30,15,14,16,5,12,29,2,7,10,24,26,70,35,47,50,60,63,48,39,41,44,54,68,76,71,32,31,74,42,56,52,43,40,46,61,53,45,57,72,73,77]

3) Add the Atoms and Molecules on to the Surface of your Cluster/Surface Model

We will now add all the atoms and molecules that you want to adsorb to the surface of your cluster or surface model. We first want to import all of these into this script. In ASE, there are a variety of molecules you can obtain from the molecule method in the ase.build module. This is imported into the Run_Adsorber.py script with the following

from ase.build import molecule

This is what we have done here. You can also import molecules from other .xyz or .traj files with the read method from ASE:

from ase.io import read

For each atom and molecule that you make you want to add it to a dictionary that has the following inputs:

  • name (str.): The name you want to give for this atom or molecule

  • molecule (ase.Atoms): The is the Atoms object for the atom or molecule, as obtained from the molecule or read method as mentioned above.

  • distance_of_adatom_from_surface (float): This is the binding distance that you would like the atom or molecule to be initially placed from the cluster or surface model before you perform further optimisation with DFT.

For single atoms, this is all that is needed. If you want to adsorb molecules that have two or more atoms in it, you want to give two or three additional inputs into this dictionary.

  • index (int.): This is the index of the atom in the molecule to adsorb to the surface for the cluster/surface model. See How to Bind Molecule to the Surface of your Cluster/Surface Model in Adsorber for more information on how to select the index of the atom in the molecule you would like to be adsorbed to the surface.

  • axis (str./list/tuple): This is the axis in your molecule that you would like to point away from the surface of the cluster/surface model, as well as to rotate your moleule around (if you would like to rotate your molecule around the axis). See How to Bind Molecule to the Surface of your Cluster/Surface Model in Adsorber for more information for how to specify this axis.

  • rotations (list/tuple, optional): These are the angles of rotation that you would like to rotate the molecules around the axis on the surface of your cluster/surface model. If you have a linear molecule that is alligned to the axis or you do not want to rotate your molecule around the axis, you do not need to add this as this is an optional input. See How to Bind Molecule to the Surface of your Cluster/Surface Model in Adsorber for more information about how to specify how to best rotate your molecule about the axis on the surface of your cluster/surface model.

An example of this is shown below:

20
21
22
23
24
25
26
27
28
29
30
# Give the Atoms objects for the atoms and molecules you want to adsorb to your cluster or surface model
adsorbed_species = []

COOH_symmetric = molecule('HCOOH') # note the carbon is index 1
COOH_symmetric.center(vacuum=10.0)
del COOH_symmetric[4] # remove the hydrogen atom
COOH_symmetric_axis = (0.1,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COOH_symmetric_adsorbed_species = {'name': 'COOH_symmetric', 'molecule': COOH_symmetric, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': COOH_symmetric_axis, 'rotations': rotations, 'sites_to_bind_adsorbate_to': ['Top_Sites','Bridge_Sites','Three_Fold_Sites']}
adsorbed_species.append(COOH_symmetric_adsorbed_species)

You want to make sure that you append each of your adsorbates to the adsorbed_species list. If you dont want to include certain adsorbates as you go about your studies, comment their adsorbed_species.append(...) line. For example, see line 39 below:

32
33
34
35
36
37
38
39
COOH_O_tilted = molecule('HCOOH') # note the carbon is index 1
COOH_O_tilted.center(vacuum=10.0)
del COOH_O_tilted[4] # remove the hydrogen atom
COOH_O_tilted_axis = (-0.4,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COOH_O_tilted_adsorbed_species = {'name': 'COOH_O_tilted', 'molecule': COOH_O_tilted, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': COOH_O_tilted_axis, 'rotations': rotations, 'sites_to_bind_adsorbate_to': 'Top_Sites'}
#adsorbed_species.append(COOH_O_tilted_adsorbed_species)

The full example of the atoms and molecules that have been adsorbed to this cluster (called 15-3-3629.xyz) is shown below:

 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# Give the Atoms objects for the atoms and molecules you want to adsorb to your cluster or surface model
adsorbed_species = []

COOH_symmetric = molecule('HCOOH') # note the carbon is index 1
COOH_symmetric.center(vacuum=10.0)
del COOH_symmetric[4] # remove the hydrogen atom
COOH_symmetric_axis = (0.1,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COOH_symmetric_adsorbed_species = {'name': 'COOH_symmetric', 'molecule': COOH_symmetric, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': COOH_symmetric_axis, 'rotations': rotations, 'sites_to_bind_adsorbate_to': ['Top_Sites','Bridge_Sites','Three_Fold_Sites']}
adsorbed_species.append(COOH_symmetric_adsorbed_species)

COOH_O_tilted = molecule('HCOOH') # note the carbon is index 1
COOH_O_tilted.center(vacuum=10.0)
del COOH_O_tilted[4] # remove the hydrogen atom
COOH_O_tilted_axis = (-0.4,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COOH_O_tilted_adsorbed_species = {'name': 'COOH_O_tilted', 'molecule': COOH_O_tilted, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': COOH_O_tilted_axis, 'rotations': rotations, 'sites_to_bind_adsorbate_to': 'Top_Sites'}
#adsorbed_species.append(COOH_O_tilted_adsorbed_species)

CO = molecule('CO') # note the carbon is index 1
CO.center(vacuum=10.0)
CO_axis = 'z'
distance_of_adatom_from_surface = 1.5
CO_adsorbed_species = {'name': 'CO', 'molecule': CO, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': CO_axis}
#adsorbed_species.append(CO_adsorbed_species)

# --------------------------------------------
# option1
COH = molecule('H2COH') # note the carbon is index 0
COH.center(vacuum=10.0)
del COH[4] # remove the hydrogen atom
del COH[3] # remove the hydrogen atom
COH_axis = '-x'
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
COH_adsorbed_species = {'name': 'COH', 'molecule': COH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': COH_axis, 'rotations': rotations}
#adsorbed_species.append(COH_adsorbed_species)

#option2
CHO = molecule('HCO') # note the carbon is index 0
CHO.center(vacuum=10.0)
CHO_axis = (-(3.0**0.5)/2.0,-1.0/2.0,0)
rotations = 'automatic' #range(0,360,10)
CHO_adsorbed_species = {'name': 'CHO', 'molecule': CHO, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CHO_axis, 'rotations': rotations}
#adsorbed_species.append(CHO_adsorbed_species)
# --------------------------------------------
# option1
CH2O = molecule('H2CO') # note the carbon is index 1
CH2O.center(vacuum=10.0)
CH2O_axis = 'x'
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
CH2O_adsorbed_species = {'name': 'CH2O', 'molecule': CH2O, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': CH2O_axis, 'rotations': rotations}
#adsorbed_species.append(CH2O_adsorbed_species)

# option1
CHOH = molecule('H2COH') # note the carbon is index 0
CHOH.center(vacuum=10.0)
del CHOH[3]
CHOH_axis = (-1,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
CHOH_adsorbed_species = {'name': 'CHOH', 'molecule': CHOH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CHOH_axis, 'rotations': rotations}
#adsorbed_species.append(CHOH_adsorbed_species)
# --------------------------------------------
# new option 1
CH3O = molecule('CH3O') # note the oxygen is index 1
CH3O.center(vacuum=10.0)
CH3O_axis = '-y'
distance_of_adatom_from_surface = 1.5
CH3O_adsorbed_species = {'name': 'CH3O', 'molecule': CH3O, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 1, 'axis': CH3O_axis}
#adsorbed_species.append(CH3O_adsorbed_species)

# new option 2
CH2OH = molecule('CH3OH') # carbon is index 0
CH2OH.center(vacuum=10.0)
del CH2OH[2] # remove the hydrogen atom
CH2OH_axis = (1,-1,0)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,360,10)
CH2OH_adsorbed_species = {'name': 'CH2OH', 'molecule': CH2OH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CH2OH_axis, 'rotations': rotations}
#adsorbed_species.append(CH2OH_adsorbed_species)
# --------------------------------------------
# new new option 1
CH2 = molecule('CH4') # carbon is index 0
CH2.center(vacuum=10.0)
del CH2[4] # remove the hydrogen atom
del CH2[3] # remove the hydrogen atom
CH2_axis = 'z'
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,180,10)
CH2_adsorbed_species = {'name': 'CH2', 'molecule': CH2, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CH2_axis, 'rotations': rotations}
#adsorbed_species.append(CH2_adsorbed_species)

CH3 = molecule('CH4') # carbon is index 0
CH3.center(vacuum=10.0)
del CH3[4] # remove the hydrogen atom
CH3_axis = (1,-1,1)
distance_of_adatom_from_surface = 1.5
rotations = 'automatic' #range(0,120,10)
CH3_adsorbed_species = {'name': 'CH3', 'molecule': CH3, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': CH3_axis, 'rotations': rotations}
#adsorbed_species.append(CH3_adsorbed_species)

# new new option 2
O = molecule('O')
O.center(vacuum=10.0)
distance_of_adatom_from_surface = 1.5
O_adsorbed_species = {'name': 'O', 'molecule': O, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface}
#adsorbed_species.append(O_adsorbed_species)

OH = molecule('OH') # note the oxygen is index 0
OH.center(vacuum=10.0)
OH_axis = '-z'
distance_of_adatom_from_surface = 1.5
OH_adsorbed_species = {'name': 'OH', 'molecule': OH, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface, 'index': 0, 'axis': OH_axis}
#adsorbed_species.append(OH_adsorbed_species)

C = molecule('C')
C.center(vacuum=10.0)
distance_of_adatom_from_surface = 1.5
C_adsorbed_species = {'name': 'C', 'molecule': C, 'distance_of_adatom_from_surface': distance_of_adatom_from_surface}
#adsorbed_species.append(C_adsorbed_species)

4) Obtain VASP energies for molecules that you do not want to adsorb to your cluster/surface model

You made also want to obtain locally optimised VASP energies of atoms and molecules for energy calculations later on in your studies. To do this, you want to add your atoms and molecules in the same way as before, such as with xyz files or using the molecule method in the ase.build module, as mentioned in 3) Add the Atoms and Molecules on to the Surface of your Cluster/Surface Model. For each atom and molecule that you make you want to add it to a dictionary that has the following inputs:

  • name (str.): The name you want to give for this atom or molecule

  • molecule (ase.Atoms): The is the Atoms object for the atom or molecule, as obtained from the molecule or read method as mentioned above.

Example of this are shown below for obtaining VASP minimised energies only of graphene, H 2 , and H 2 O:

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# Add here any other atoms and molecules that you need to locally optimise in VASP for energy calculations
Other_molecules_to_obtain_VASP_energies_for = []

graphene = molecule('C')
graphene.center(vacuum=10.0)
graphene_optimise_energy = {'name': 'graphene', 'molecule': graphene}
Other_molecules_to_obtain_VASP_energies_for.append(graphene_optimise_energy)

H2 = molecule('H2')
H2.center(vacuum=10.0)
H2_optimised_energy = {'name': 'H2', 'molecule': H2}
Other_molecules_to_obtain_VASP_energies_for.append(H2_optimised_energy)

H2O = molecule('H2O')
H2O.center(vacuum=10.0)
H2O_optimised_energy = {'name': 'H2O', 'molecule': H2O}
Other_molecules_to_obtain_VASP_energies_for.append(H2O_optimised_energy)

5) Information required to make submit.sl siles for submitting files to Slurm

Adsorber is able to create folders with the files required to run VASP jobs of your system for all of the adsorbed species and orientations that you would like to consider. Do you this, you will want to include a dictionary called slurm_information that contains all the information about the submit.sl file required to submit jobs to the Slurm workload Manager (https://slurm.schedmd.com/documentation.html). The following information is required in the slurm_information dictionary:

  • 'project' (str.): The name of the project to run this on.

  • 'partition' (str.): The partition to run this on.

  • 'time' (str.): The length of time to give these jobs. This is given in ‘HH:MM:SS’, where HH is the number of hours, MM is the number of minutes, and SS is the number of seconds to run Adsorber for.

  • 'nodes' (int): The number of nodes to use. Best to set this to 1.

  • 'ntasks_per_node' (int): The number of cpus to run these jobs across on a node for a VASP job.

  • 'mem-per-cpu' (str.): This is the memory that is used per cpu by the job.

  • 'email' (str.): This is the email address to send slurm messages to about this job. If you do not want to give an email, write here either None or ''.

  • 'vasp_version' (str.): This is the version of VASP that you want to use for your VASP job. Default: 'VASP/5.4.4-intel-2017a'

  • 'vasp_execution' (str.): This is the command that is required to run a VASP job. Default: 'vasp_std'

An example of a slurm_information dictionary in the Run_Adsorber.py script is shown below:

165
166
167
168
169
170
171
172
173
174
175
176
# slurm informaion for making the submit.sl files for submitting VASP jobs in slurm

slurm_information = {}
slurm_information['project'] = 'uoo02568'
slurm_information['partition'] = 'large'
slurm_information['time'] = '72:00:00'
slurm_information['nodes'] = 1
slurm_information['ntasks_per_node'] = 12
slurm_information['mem-per-cpu'] = '1200MB'
slurm_information['email'] = 'yourslurmnotificationemailaddress@gmail.com'
slurm_information['vasp_version'] = 'VASP/5.3.5-intel-2017a-VTST-BEEF'
slurm_information['vasp_execution'] = 'vasp_cd'

Run the Adsorber Program!

You have got to the end of all the parameter setting stuff! Now on to the fun stuff! The next part of the Run_Adsorber.py file will run the Adsorber program. This is written as follows in the Run_Adsorber.py script:

160
161
# Run the Adsorber program
Adsorber_Program(part_to_perform,cluster_or_surface_model,system_filename,path_to_VASP_optimised_non_adsorbate_system,cutoff,surface_atoms,adsorbed_species,slurm_information,Other_molecules_to_obtain_VASP_energies_for)