Statistiques
| Révision :

root / ase / calculators / qmx.py @ 5

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

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

3 2 tkerber
torsten.kerber@ens-lyon.fr
4 2 tkerber
"""
5 2 tkerber
6 2 tkerber
import ase
7 2 tkerber
import ase.atoms
8 2 tkerber
import numpy as np
9 2 tkerber
from general import Calculator
10 2 tkerber
from ase.embed import Embed
11 3 tkerber
from ase.units import Hartree
12 2 tkerber
13 3 tkerber
from copy import deepcopy
14 3 tkerber
15 2 tkerber
import sys, os
16 2 tkerber
17 2 tkerber
class Qmx(Calculator):
18 5 tkerber
    def __init__(self, calculator_high_cluster,  calculator_low_cluster,  calculator_low_system=None,  print_forces=False):
19 2 tkerber
        self._constraints=None
20 5 tkerber
21 5 tkerber
        self.calculator_low_cluster = calculator_low_cluster
22 5 tkerber
        self.calculator_low_system = calculator_low_system
23 5 tkerber
        if self.calculator_low_system is None:
24 5 tkerber
            self.calculator_low_system = deepcopy(calculator_low_cluster)
25 5 tkerber
        self.calculator_high_cluster = calculator_high_cluster
26 5 tkerber
        self.print_forces = print_forces
27 3 tkerber
28 2 tkerber
    def get_energy_subsystem(self, path, calculator, atoms, force_consistent):
29 3 tkerber
        # go to directory and calculate energies
30 3 tkerber
        print "running energy in: ", path
31 2 tkerber
        os.chdir(path)
32 3 tkerber
        atoms.set_calculator(calculator)
33 3 tkerber
        energy = atoms.get_potential_energy()
34 2 tkerber
        os.chdir("..")
35 2 tkerber
        return energy
36 3 tkerber
37 2 tkerber
    def get_forces_subsystem(self, path, calculator, atoms):
38 3 tkerber
        # go to directory and calculate forces
39 3 tkerber
        print "running forces in: ", path
40 2 tkerber
        os.chdir(path)
41 3 tkerber
        atoms.set_calculator(calculator)
42 3 tkerber
        forces = atoms.get_forces()
43 2 tkerber
        os.chdir("..")
44 2 tkerber
        return forces
45 3 tkerber
46 2 tkerber
    def get_potential_energy(self, embed, force_consistent=False):
47 3 tkerber
        # perform energy calculations
48 3 tkerber
        e_sys_lo = self.get_energy_subsystem("system.low-level", self.calculator_low_system, embed.get_system(), force_consistent)
49 3 tkerber
        e_cl_lo  = self.get_energy_subsystem("cluster.low-level", self.calculator_low_cluster, embed.get_cluster(), force_consistent)
50 5 tkerber
        e_cl_hi  = self.get_energy_subsystem("cluster.high-level", self.calculator_high_cluster, embed.get_cluster(), force_consistent)
51 2 tkerber
        # calculate energies
52 2 tkerber
        energy = e_sys_lo - e_cl_lo + e_cl_hi
53 3 tkerber
        # print energies
54 5 tkerber
        print "%20s = %15s - %15s + %15s" %("E(C:S)", "E(S-MM)", "E(C-MM)", "E(C-QM)")
55 5 tkerber
        print "%20f = %15f - %15f + %15f" %(energy, e_sys_lo, e_cl_lo, e_cl_hi)
56 3 tkerber
        # set energies and return
57 2 tkerber
        if force_consistent:
58 2 tkerber
            self.energy_free = energy
59 2 tkerber
            return self.energy_free
60 2 tkerber
        else:
61 2 tkerber
            self.energy_zero = energy
62 2 tkerber
            return self.energy_zero
63 2 tkerber
64 2 tkerber
    def get_forces(self, embed):
65 2 tkerber
        atom_map_sys_cl = embed.atom_map_sys_cl
66 2 tkerber
        # get forces for the three systems
67 3 tkerber
        f_sys_lo = self.get_forces_subsystem("system.low-level", self.calculator_low_system, embed.get_system())
68 3 tkerber
        f_cl_lo  = self.get_forces_subsystem("cluster.low-level", self.calculator_low_cluster, embed.get_cluster())
69 5 tkerber
        f_cl_hi  = self.get_forces_subsystem("cluster.high-level", self.calculator_high_cluster, embed.get_cluster())
70 5 tkerber
71 2 tkerber
        # forces correction for the atoms
72 2 tkerber
        f_cl = f_cl_hi - f_cl_lo
73 5 tkerber
74 5 tkerber
        if self.print_forces:
75 5 tkerber
            cluster=embed.get_cluster()
76 5 tkerber
            print "Forces: System LOW - Cluster LOW + Cluster HIGH"
77 5 tkerber
            for iat_sys in xrange(len(embed)):
78 5 tkerber
                print "%-2s (" % embed[iat_sys].get_symbol(),
79 5 tkerber
                for idir in xrange(3):
80 5 tkerber
                    print "%10.6f" % f_sys_lo[iat_sys][idir],
81 5 tkerber
                print ") <system LOW>"
82 5 tkerber
83 5 tkerber
                iat_cl = atom_map_sys_cl[iat_sys]
84 5 tkerber
                if iat_cl > -1:
85 5 tkerber
                    print "%s" % "-  (",
86 5 tkerber
                    for idir in xrange(3):
87 5 tkerber
                        print "%10.6f" % f_cl_lo[iat_cl][idir],
88 5 tkerber
                    print ") <cluster LOW>"
89 5 tkerber
                    print "%s" % "+  (",
90 5 tkerber
                    for idir in xrange(3):
91 5 tkerber
                        print "%10.6f" % f_cl_hi[iat_cl][idir],
92 5 tkerber
                    print ") <cluster HIGH>"
93 5 tkerber
                print
94 5 tkerber
            print
95 5 tkerber
96 2 tkerber
        # lo-sys + (hi-lo)
97 5 tkerber
        for iat_sys in xrange(len(embed)):
98 2 tkerber
            iat_cl = atom_map_sys_cl[iat_sys]
99 2 tkerber
            if iat_cl > -1:
100 2 tkerber
                f_sys_lo[iat_sys] += f_cl[iat_cl]
101 5 tkerber
        # some settings for the output
102 5 tkerber
        i_change = np.zeros(len(embed), int)
103 5 tkerber
        if self.print_forces:
104 5 tkerber
            f_sys_lo_orig = f_sys_lo.copy()
105 2 tkerber
        # correct gradients
106 2 tkerber
        # Reference: Eichler, Koelmel, Sauer, J. of Comput. Chem., 18(4). 1997, 463-477.
107 3 tkerber
        for cell_L, iat_cl_sys, iat_sys, r, iat_link in embed.linkatoms:
108 2 tkerber
            # calculate the bond distance (r_bond) at the border
109 3 tkerber
            xyz = embed[iat_sys].get_position() - embed[iat_cl_sys].get_position() + cell_L
110 2 tkerber
            # calculate the bond lenght and the factor f
111 2 tkerber
            rbond = np.sqrt(np.dot(xyz, xyz))
112 2 tkerber
            f = r / rbond
113 2 tkerber
            #normalize xyz
114 2 tkerber
            xyz /= rbond
115 2 tkerber
            # receive the gradients for the link atom
116 3 tkerber
            fL = f_cl[iat_link]
117 3 tkerber
            # dot product fL, xyz
118 5 tkerber
            fs = np.dot(fL, xyz)
119 3 tkerber
            # apply corrections for each direction
120 5 tkerber
            i_change[iat_sys] = 1
121 5 tkerber
            i_change[iat_cl_sys] = 1
122 2 tkerber
            for idir in xrange(3):
123 2 tkerber
                # correct the atom in the system
124 5 tkerber
                f_sys_lo[iat_sys][idir] = f_sys_lo[iat_sys][idir] + f*fL[idir] - f*fs*xyz[idir]
125 2 tkerber
                # correct the atom in the cluster
126 5 tkerber
                f_sys_lo[iat_cl_sys][idir] = f_sys_lo[iat_cl_sys][idir] + (1-f)*fL[idir] + f*fs*xyz[idir]
127 5 tkerber
128 5 tkerber
        if self.print_forces:
129 5 tkerber
            print " TOTAL FORCE (uncorrected : corrected) for link atoms"
130 5 tkerber
            for iat_sys in xrange(len(embed)):
131 5 tkerber
                print "%-2s (" % embed[iat_sys].get_symbol(),
132 5 tkerber
                for idir in xrange(3):
133 5 tkerber
                    print "%10.6f" % f_sys_lo_orig[iat_sys][idir],
134 5 tkerber
                print ") : (",
135 5 tkerber
                for idir in xrange(3):
136 5 tkerber
                    print "%10.6f" % f_sys_lo[iat_sys][idir],
137 5 tkerber
                print ")",
138 5 tkerber
                if i_change[iat_sys]:
139 5 tkerber
                    print " *",
140 5 tkerber
                print
141 5 tkerber
            print
142 5 tkerber
143 2 tkerber
        return f_sys_lo