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