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