Statistiques
| Révision :

root / ase / utils / adsorb.py @ 13

Historique | Voir | Annoter | Télécharger (4,51 ko)

1
#!/usr/bin/env python
2

    
3
# Copyright 2010 CAMd
4
# (see accompanying license files for details).
5
 
6
from optparse import OptionParser
7

    
8
import numpy as np
9

    
10
from ase.lattice.surface import fcc111, hcp0001, bcc110, add_adsorbate
11
from ase.structure import estimate_lattice_constant
12
from ase.data import reference_states, atomic_numbers, covalent_radii
13
from ase.io import write
14
from ase.visualize import view
15
from ase.atoms import Atoms, string2symbols
16
from ase.data.molecules import molecule
17

    
18
def build():
19
    p = OptionParser(usage='%prog  [options] [ads@]surf [output file]',
20
                     version='%prog 0.1',
21
                     description='Example ads/surf: CO@2x2Ru0001')
22
    p.add_option('-l', '--layers', type='int',
23
                 default=4,
24
                 help='Number of layers.')
25
    p.add_option('-v', '--vacuum', type='float',
26
                 default=5.0,
27
                 help='Vacuum.')
28
    p.add_option('-x', '--crystal-structure',
29
                 help='Crystal structure.',
30
                 choices=['sc', 'fcc', 'bcc', 'hcp'])
31
    p.add_option('-a', '--lattice-constant', type='float',
32
                 help='Lattice constant in Angstrom.')
33
    p.add_option('--c-over-a', type='float',
34
                 help='c/a ratio.')
35
    p.add_option('--height', type='float',
36
                 help='Height of adsorbate over surface.')
37
    p.add_option('--distance', type='float',
38
                 help='Distance between adsorbate and nearest surface atoms.')
39
    p.add_option('--site',
40
                 help='Adsorption site.',
41
                 choices=['fcc', 'hcc', 'hollow', 'bridge'])
42
    p.add_option('-M', '--magnetic-moment', type='float', default=0.0,
43
                 help='Magnetic moment.')
44
    p.add_option('-G', '--gui', action='store_true',
45
                 help="Pop up ASE's GUI.")
46

    
47
    opt, args = p.parse_args()
48

    
49
    if not 1 <= len(args) <= 2:
50
        p.error("incorrect number of arguments")
51

    
52
    if '@' in args[0]:
53
        ads, surf = args[0].split('@')
54
    else:
55
        ads = None
56
        surf = args[0]
57

    
58
    if surf[0].isdigit():
59
        i1 = surf.index('x')
60
        n = int(surf[:i1])
61
        i2 = i1 + 1
62
        while surf[i2].isdigit():
63
            i2 += 1
64
        m = int(surf[i1 + 1:i2])
65
        surf = surf[i2:]
66
    else:
67
        n = 1
68
        m = 1
69

    
70
    if surf[-1].isdigit():
71
        if surf[1].isdigit():
72
            face = surf[1:]
73
            surf = surf[0]
74
        else:
75
            face = surf[2:]
76
            surf = surf[:2]
77
    else:
78
        face = None
79

    
80
    Z = atomic_numbers[surf]
81
    state = reference_states[Z]
82

    
83
    if opt.crystal_structure:
84
        x = opt.crystal_structure
85
    else:
86
        x = state['symmetry'].lower()
87
    
88
    if opt.lattice_constant:
89
        a = opt.lattice_constant
90
    else:
91
        a = estimate_lattice_constant(surf, x, opt.c_over_a)
92

    
93
    if x == 'fcc':
94
        if face is None:
95
            face = '111'
96
        slab = fcc111(surf, (n, m, opt.layers), a, opt.vacuum)
97
        r = a / np.sqrt(2) / 2
98
    elif x == 'bcc':
99
        if face is None:
100
            face = '110'
101
        slab = bcc110(surf, (n, m, opt.layers), a, opt.vacuum)
102
        r = a * np.sqrt(3) / 4
103
    elif x == 'hcp':
104
        if face is None:
105
            face = '0001'
106
        slab = hcp0001(surf, (n, m, opt.layers), a, a * opt.c_over_a,
107
                       opt.vacuum)
108
        r = a / 2
109
    else:
110
        raise NotImplementedError
111

    
112
    magmom = opt.magnetic_moment
113
    if magmom is None:
114
        magmom = {'Ni': 0.6, 'Co': 1.2, 'Fe': 2.3}.get(surf, 0.0)
115
    slab.set_initial_magnetic_moments([magmom] * len(slab))
116
    
117
    slab.pbc = 1
118

    
119
    name = '%dx%d%s%s' % (n, m, surf, face) 
120

    
121
    if ads:
122
        site = 'ontop'
123
        if '-' in ads:
124
            site, ads = ads.split('-')
125

    
126
        name = site + '-' + ads + '@' + name
127
        symbols = string2symbols(ads)
128
        nads = len(symbols) 
129
        if nads == 1:
130
            ads = Atoms(ads)
131
        else:
132
            ads = molecule(ads)
133

    
134
        add_adsorbate(slab, ads, 0.0, site)
135

    
136
        d = opt.distance
137
        if d is None:
138
            d = r + covalent_radii[ads[0].number] / 2
139
        
140
        h = opt.height
141
        if h is None:
142
            R = slab.positions
143
            y = ((R[:-nads] - R[-nads])**2).sum(1).min()**0.5
144
            print y
145
            h = (d**2 - y**2)**0.5
146
            print h
147
        else:
148
            assert opt.distance is None
149
        
150
        slab.positions[-nads:, 2] += h
151

    
152
    if len(args) == 2:
153
        write(args[1], slab)
154
    elif not opt.gui:
155
        write(name + '.traj', slab)
156
        
157
    if opt.gui:
158
        view(slab)
159

    
160

    
161
if __name__ == '__main__':
162
    build()