Statistiques
| Révision :

root / ase / calculators / qmx.py @ 13

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

1
"""
2
This module is the EMBED module for ASE
3
implemented by T. Kerber
4

5
Torsten Kerber, ENS LYON: 2011, 07, 11
6

7
This work is supported by Award No. UK-C0017, made by King Abdullah
8
University of Science and Technology (KAUST)
9
"""
10
import ase
11
import ase.atoms
12
import numpy as np
13
from general import Calculator
14
from ase.embed import Embed
15
from ase.units import Hartree
16

    
17
from copy import deepcopy
18

    
19
import sys, os
20

    
21
class Qmx(Calculator):
22
    def __init__(self, calculator_high_cluster,  calculator_low_cluster,  calculator_low_system=None,  print_forces=False):
23
        self._constraints=None
24
        
25
        self.calculator_low_cluster = calculator_low_cluster
26
        self.calculator_low_system = calculator_low_system
27
        if self.calculator_low_system is None:
28
            self.calculator_low_system = deepcopy(calculator_low_cluster)
29
        self.calculator_high_cluster = calculator_high_cluster
30
        self.print_forces = print_forces
31

    
32
    def get_energy_subsystem(self, path, calculator, atoms, force_consistent):
33
        # go to directory and calculate energies
34
        print "running energy in: ", path
35
        os.chdir(path)
36
        atoms.set_calculator(calculator)
37
        energy = atoms.get_potential_energy()
38
        os.chdir("..")
39
        return energy
40

    
41
    def get_forces_subsystem(self, path, calculator, atoms):
42
        # go to directory and calculate forces
43
        print "running forces in: ", path
44
        os.chdir(path)
45
        atoms.set_calculator(calculator)
46
        forces = atoms.get_forces()
47
        os.chdir("..")
48
        return forces
49

    
50
    def get_potential_energy(self, embed, force_consistent=False):
51
        # perform energy calculations
52
        e_sys_lo = self.get_energy_subsystem("system.low-level", self.calculator_low_system, embed.get_system(), force_consistent)
53
        e_cl_lo  = self.get_energy_subsystem("cluster.low-level", self.calculator_low_cluster, embed.get_cluster(), force_consistent)
54
        e_cl_hi  = self.get_energy_subsystem("cluster.high-level", self.calculator_high_cluster, embed.get_cluster(), force_consistent)
55
        # calculate energies
56
        energy = e_sys_lo - e_cl_lo + e_cl_hi
57
        # print energies
58
        print "%20s = %15s - %15s + %15s" %("E(C:S)", "E(S-MM)", "E(C-MM)", "E(C-QM)")
59
        print "%20f = %15f - %15f + %15f" %(energy, e_sys_lo, e_cl_lo, e_cl_hi)
60
        # set energies and return
61
        if force_consistent:
62
            self.energy_free = energy
63
            return self.energy_free
64
        else:
65
            self.energy_zero = energy
66
            return self.energy_zero
67

    
68
    def get_forces(self, embed):
69
        atom_map_sys_cl = embed.atom_map_sys_cl
70
        # get forces for the three systems
71
        f_sys_lo = self.get_forces_subsystem("system.low-level", self.calculator_low_system, embed.get_system())
72
        f_cl_lo  = self.get_forces_subsystem("cluster.low-level", self.calculator_low_cluster, embed.get_cluster())
73
        f_cl_hi  = self.get_forces_subsystem("cluster.high-level", self.calculator_high_cluster, embed.get_cluster())
74

    
75
        # forces correction for the atoms
76
        f_cl = f_cl_hi - f_cl_lo
77

    
78
        if self.print_forces:
79
            cluster=embed.get_cluster()
80
            print "Forces: System LOW - Cluster LOW + Cluster HIGH"
81
            for iat_sys in xrange(len(embed)):
82
                print "%-2s (" % embed[iat_sys].get_symbol(),
83
                for idir in xrange(3):
84
                    print "%10.6f" % f_sys_lo[iat_sys][idir], 
85
                print ") <system LOW>"
86

    
87
                iat_cl = atom_map_sys_cl[iat_sys]
88
                if iat_cl > -1:
89
                    print "%s" % "-  (",
90
                    for idir in xrange(3):
91
                        print "%10.6f" % f_cl_lo[iat_cl][idir], 
92
                    print ") <cluster LOW>"
93
                    print "%s" % "+  (",
94
                    for idir in xrange(3):
95
                        print "%10.6f" % f_cl_hi[iat_cl][idir], 
96
                    print ") <cluster HIGH>"
97
                print
98
            print
99
    
100
        # lo-sys + (hi-lo)
101
        for iat_sys in xrange(len(embed)):
102
            iat_cl = atom_map_sys_cl[iat_sys]
103
            if iat_cl > -1:
104
                f_sys_lo[iat_sys] += f_cl[iat_cl]
105
        # some settings for the output
106
        i_change = np.zeros(len(embed), int)
107
        if self.print_forces:
108
            f_sys_lo_orig = f_sys_lo.copy()
109
        # correct gradients
110
        # Reference: Eichler, Koelmel, Sauer, J. of Comput. Chem., 18(4). 1997, 463-477.
111
        for cell_L, iat_cl_sys, iat_sys, r, iat_link in embed.linkatoms:
112
            # calculate the bond distance (r_bond) at the border
113
            xyz = embed[iat_sys].get_position() - embed[iat_cl_sys].get_position() + cell_L
114
            # calculate the bond lenght and the factor f
115
            rbond = np.sqrt(np.dot(xyz, xyz))
116
            f = r / rbond
117
            #normalize xyz
118
            xyz /= rbond
119
            # receive the gradients for the link atom
120
            fL = f_cl[iat_link]
121
            # dot product fL, xyz
122
            fs = np.dot(fL, xyz)
123
            # apply corrections for each direction
124
            i_change[iat_sys] = 1
125
            i_change[iat_cl_sys] = 1
126
            for idir in xrange(3):
127
                # correct the atom in the system
128
                f_sys_lo[iat_sys][idir] = f_sys_lo[iat_sys][idir] + f*fL[idir] - f*fs*xyz[idir]
129
                # correct the atom in the cluster
130
                f_sys_lo[iat_cl_sys][idir] = f_sys_lo[iat_cl_sys][idir] + (1-f)*fL[idir] + f*fs*xyz[idir]
131

    
132
        if self.print_forces:
133
            print " TOTAL FORCE (uncorrected : corrected) for link atoms"
134
            for iat_sys in xrange(len(embed)):
135
                print "%-2s (" % embed[iat_sys].get_symbol(),
136
                for idir in xrange(3):
137
                    print "%10.6f" % f_sys_lo_orig[iat_sys][idir], 
138
                print ") : (", 
139
                for idir in xrange(3):
140
                    print "%10.6f" % f_sys_lo[iat_sys][idir], 
141
                print ")", 
142
                if i_change[iat_sys]:
143
                    print " *", 
144
                print
145
            print
146
        
147
        return f_sys_lo