Statistiques
| Révision :

root / ase / calculators / qmx.py @ 3

Historique | Voir | Annoter | Télécharger (3,9 ko)

1
""" This is a QM:MM embedded system for ASE
2

3
torsten.kerber@ens-lyon.fr
4
"""
5

    
6
import ase
7
import ase.atoms
8
import numpy as np
9
from general import Calculator
10
from ase.embed import Embed
11
from ase.units import Hartree
12

    
13
from copy import deepcopy
14

    
15
import sys, os
16

    
17
class Qmx(Calculator):
18
    def __init__(self, calculator_high,  calculator_low):
19
        self._constraints=None
20
        self.calculator_low_cluster = calculator_low
21
        self.calculator_low_system = deepcopy(calculator_low)
22
        self.calculator_high = calculator_high            
23

    
24
    def get_energy_subsystem(self, path, calculator, atoms, force_consistent):
25
        # go to directory and calculate energies
26
        print "running energy in: ", path
27
        os.chdir(path)
28
        atoms.set_calculator(calculator)
29
        energy = atoms.get_potential_energy()
30
        os.chdir("..")
31
        return energy
32

    
33
    def get_forces_subsystem(self, path, calculator, atoms):
34
        # go to directory and calculate forces
35
        print "running forces in: ", path
36
        os.chdir(path)
37
        atoms.set_calculator(calculator)
38
        forces = atoms.get_forces()
39
        os.chdir("..")
40
        return forces
41

    
42
    def get_potential_energy(self, embed, force_consistent=False):
43
        # perform energy calculations
44
        e_sys_lo = self.get_energy_subsystem("system.low-level", self.calculator_low_system, embed.get_system(), force_consistent)
45
        e_cl_lo  = self.get_energy_subsystem("cluster.low-level", self.calculator_low_cluster, embed.get_cluster(), force_consistent)
46
        e_cl_hi  = self.get_energy_subsystem("cluster.high-level", self.calculator_high, embed.get_cluster(), force_consistent)
47
        # calculate energies
48
        energy = e_sys_lo - e_cl_lo + e_cl_hi
49
        # print energies
50
        print "%20s=%15s - %15s + %15s" %("E(C:S)", "E(S-MM)", "E(C-MM)", "E(C-QM)")
51
        print "%20f=%15f - %15f + %15f" %(energy, e_sys_lo, e_cl_lo, e_cl_hi)
52
        # set energies and return
53
        if force_consistent:
54
            self.energy_free = energy
55
            return self.energy_free
56
        else:
57
            self.energy_zero = energy
58
            return self.energy_zero
59

    
60
    def get_forces(self, embed):
61
        atom_map_sys_cl = embed.atom_map_sys_cl
62
        # get forces for the three systems
63
        f_sys_lo = self.get_forces_subsystem("system.low-level", self.calculator_low_system, embed.get_system())
64
        f_cl_lo  = self.get_forces_subsystem("cluster.low-level", self.calculator_low_cluster, embed.get_cluster())
65
        f_cl_hi  = self.get_forces_subsystem("cluster.high-level", self.calculator_high, embed.get_cluster())
66
        # forces correction for the atoms
67
        f_cl = f_cl_hi - f_cl_lo
68
        # number of atoms
69
        nat_sys = len(embed)
70
        # lo-sys + (hi-lo)
71
        for iat_sys in xrange(nat_sys):
72
            iat_cl = atom_map_sys_cl[iat_sys]
73
            if iat_cl > -1:
74
                f_sys_lo[iat_sys] += f_cl[iat_cl]
75

    
76
        # correct gradients
77
        # Reference: Eichler, Koelmel, Sauer, J. of Comput. Chem., 18(4). 1997, 463-477.
78
        for cell_L, iat_cl_sys, iat_sys, r, iat_link in embed.linkatoms:
79
            # calculate the bond distance (r_bond) at the border
80
            xyz = embed[iat_sys].get_position() - embed[iat_cl_sys].get_position() + cell_L
81
            
82
            # calculate the bond lenght and the factor f
83
            rbond = np.sqrt(np.dot(xyz, xyz))
84
            f = r / rbond
85
            #normalize xyz
86
            xyz /= rbond
87
            # receive the gradients for the link atom
88
            fL = f_cl[iat_link]
89
            # dot product fL, xyz
90
            fs = np.dot(xyz, fL)
91
            # apply corrections for each direction
92
            for idir in xrange(3):
93
                # correct the atom in the system
94
                f_sys_lo[iat_sys][idir] += f*fL[idir] - f*fs*xyz[idir]
95
                # correct the atom in the cluster
96
                f_sys_lo[iat_cl_sys][idir] += (1-f)*fL[idir] + f*fs*xyz[idir]
97
        return f_sys_lo