Statistiques
| Révision :

root / ase / calculators / gaussian.py @ 19

Historique | Voir | Annoter | Télécharger (5,57 ko)

1
"""
2
@author:       Torsten Kerber and Paul Fleurat-Lessard
3
@organization: Ecole Normale Superieure de Lyon
4
@contact:      Paul.Fleurat-Lessard@ens-lyon.fr
5

6
@data: June, 6, 2012
7

8
This work is supported by Award No. UK-C0017 made by King Abdullah University of Science and Technology(KAUST)
9
"""
10
import os, sys
11
import numpy as np
12

    
13
from ase.units import Hartree, Bohr
14
from ase.calculators.general import Calculator
15

    
16
str_keys = [
17
    'functional', # functional
18
    'basis',      # basis set
19
    'flags'       # more options
20
    'memory',     # RAM memory used
21
    'disk',       # disk space available
22
    'filename',   # name of the gaussian files
23
    'command'     # command to run Gaussian
24
    ]
25

    
26
int_keys = [
27
    'multiplicity', # multiplicity of the system
28
    'nproc',        # number of processors
29
    ]
30

    
31
class Gaussian(Calculator):
32
    def __init__(self, atoms=None, **kwargs):
33
        self.set_standard()
34
        
35
        self.set(**kwargs)
36
        self.atoms = atoms
37
        
38
        self.potential_energy = 0.0
39
        self.forces = None
40

    
41
        self.new_calculation = True
42
        if atoms != None:
43
            self.forces = np.zeros((len(atoms), 3))
44
        self.stress = None
45
        
46
    def set_standard(self):
47
        self.str_params = {}
48
        self.int_params = {}
49
        
50
        for key in str_keys:
51
            self.str_params['key'] = None
52
        
53
        for key in int_keys:
54
            self.int_params['key'] = None
55
        
56
        self.str_params['functional'] = "B3LYP"
57
        self.str_params['basis'] = '6-31G*'
58
        self.str_params['flags'] = ' Force '
59
        self.str_params['memory'] = '256MB'
60
        self.str_params['disk'] = '16GB'
61
        
62
        self.str_params['command'] = 'g09'
63
        self.str_params['filename'] = 'ASE-gaussian'
64

    
65
        self.int_params['multiplicity'] = 1
66
        self.int_params['nproc'] = 8
67
        
68
        
69
    def set(self, **kwargs):
70
        for key in kwargs:
71
            if self.str_params.has_key(key):
72
                self.str_params[key] = kwargs[key]
73
            if self.int_params.has_key(key):
74
                self.int_params[key] = kwargs[key]
75
                
76
                
77
    def set_atoms(self, atoms):
78
        if self.atoms != atoms:
79
            self.atoms = atoms.copy()
80
            self.new_calculation = True
81
    
82
    def write_file_line(self, file, line):
83
        file.write(line)
84
        file.write('\n')
85
    
86
    def write_input(self):
87
        name = self.str_params['filename']
88
        
89
        inputfile = open(name + '.com', 'w')
90
        self.write_file_line(inputfile, '%chk=' + name + '.chk')
91
        self.write_file_line(inputfile, '%mem=' + self.str_params['memory'])
92
        self.write_file_line(inputfile, '%nproc=' + ('%d' % self.int_params['nproc']))
93
        self.write_file_line(inputfile, 'MaxDisk=' + self.str_params['disk'])
94

    
95
        line = '#' + self.str_params['functional'] + '/' + self.str_params['basis'] + ' ' + self.str_params['flags']
96
        self.write_file_line(inputfile, line)
97
        
98
        self.write_file_line(inputfile, '')
99
        self.write_file_line(inputfile, 'Gaussian job created by ASE (supported by King Abdullah University of Science and Technology ,KAUST)')
100
        self.write_file_line(inputfile, '')
101

    
102
        line = '%d %d' % (sum(self.atoms.get_charges()), self.int_params['multiplicity'])
103
        self.write_file_line(inputfile, line)
104

    
105
        coords = self.atoms.get_positions()
106
        for i, at in enumerate(self.atoms.get_chemical_symbols()):
107
            line = at
108
            coord = coords[i]
109
            line += '  %16.5f %16.5f %16.5f'%(coord[0], coord[1], coord[2])
110
            self.write_file_line(inputfile, line)
111

    
112
        if self.atoms.get_pbc().any(): 
113
            cell = self.atoms.get_cell()
114
            line = ''
115
            for v in cell: 
116
                line += 'TV %8.3f %8.3f %8.3f\n'%(v[0], v[1], v[2])
117
            self.write_file_line(inputfile, line)
118
            
119
        self.write_file_line(inputfile, '')
120
        
121
    def update(self, atoms):
122
        if (self.atoms is None or self.atoms.positions.shape != atoms.positions.shape):
123
            self.atoms = atoms.copy()
124
            self.calculate(atoms)
125

    
126
    def calculate(self, atoms):
127
        self.write_input()
128
        line = self.str_params['command'] + ' ' + self.str_params['filename'] + '.com'
129
        exitcode = os.system(line)
130
        if exitcode != 0:
131
            raise RuntimeError('Gaussian exited with exit code: %d.  ' % exitcode)
132
        self.read_output()
133
        self.new_calculation = False
134
            
135
    def get_potential_energy(self, atoms=None, force_consistent=False):
136
        self.set_atoms(atoms)
137
        if self.new_calculation:
138
            self.calculate(atoms)
139
        return self.potential_energy
140

    
141
    def get_forces(self, atoms):
142
        self.set_atoms(atoms)
143
        if self.new_calculation:
144
            self.calculate(atoms)
145
        return self.forces
146

    
147
    def read_output(self):
148
        outfile = open(self.str_params['filename'] + '.log')
149
        lines = outfile.readlines()
150
        outfile.close()
151

    
152
        factor = Hartree
153
        for line in lines:
154
            if 'SCF Done' in line:
155
                line = line.split()
156
                self.potential_energy = float(line[4]) * factor
157

    
158
        factor = Hartree / Bohr
159
        nats = len(self.atoms)
160
        for iline, line in enumerate(lines):
161
            if 'Forces (Hartrees/Bohr)' in line:
162
                self.forces = np.zeros((nats, 3), float)
163
                for iat in range(nats):
164
                    line = lines[iline+iat+3].split()
165
                    for idir, val in enumerate(line[2:5]):
166
                        self.forces[iat, idir] = float(val) * factor
167
                break