root / ase / calculators / qmx.py @ 2
Historique | Voir | Annoter | Télécharger (3,69 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 | 2 | tkerber | |
12 | 2 | tkerber | import sys, os |
13 | 2 | tkerber | |
14 | 2 | tkerber | class Qmx(Calculator): |
15 | 2 | tkerber | def __init__(self, calculator_low, calculator_high): |
16 | 2 | tkerber | self.string_params = {}
|
17 | 2 | tkerber | |
18 | 2 | tkerber | self.forces=np.zeros((2,2)) |
19 | 2 | tkerber | self._constraints=None |
20 | 2 | tkerber | |
21 | 2 | tkerber | self.calculator_low = calculator_low
|
22 | 2 | tkerber | self.calculator_high = calculator_high
|
23 | 2 | tkerber | |
24 | 2 | tkerber | def get_energy_subsystem(self, path, calculator, atoms, force_consistent): |
25 | 2 | tkerber | os.chdir(path) |
26 | 2 | tkerber | calculator.set_atoms(atoms) |
27 | 2 | tkerber | energy = calculator.get_potential_energy(atoms) |
28 | 2 | tkerber | os.chdir("..")
|
29 | 2 | tkerber | return energy
|
30 | 2 | tkerber | |
31 | 2 | tkerber | def get_forces_subsystem(self, path, calculator, atoms): |
32 | 2 | tkerber | os.chdir(path) |
33 | 2 | tkerber | calculator.set_atoms(atoms) |
34 | 2 | tkerber | forces = calculator.get_forces(atoms) |
35 | 2 | tkerber | os.chdir("..")
|
36 | 2 | tkerber | return forces
|
37 | 2 | tkerber | |
38 | 2 | tkerber | |
39 | 2 | tkerber | def get_potential_energy(self, embed, force_consistent=False): |
40 | 2 | tkerber | # perform energy calculations
|
41 | 2 | tkerber | e_sys_lo = self.get_energy_subsystem("system.low-level", self.calculator_low, embed.get_system(), force_consistent) |
42 | 2 | tkerber | e_cl_lo = self.get_energy_subsystem("cluster.low-level", self.calculator_low, embed.get_cluster(), force_consistent) |
43 | 2 | tkerber | e_cl_hi = self.get_energy_subsystem("cluster.high-level", self.calculator_high, embed.get_cluster(), force_consistent) |
44 | 2 | tkerber | # calculate energies
|
45 | 2 | tkerber | energy = e_sys_lo - e_cl_lo + e_cl_hi |
46 | 2 | tkerber | print "%20s=%15s - %15s + %15s" %("E(C:S)", "E(S-MM)", "E(C-MM)", "E(C-QM)") |
47 | 2 | tkerber | print "%20f=%15f - %15f + %15f" %(energy, e_sys_lo, e_cl_lo, e_cl_hi) |
48 | 2 | tkerber | if force_consistent:
|
49 | 2 | tkerber | self.energy_free = energy
|
50 | 2 | tkerber | return self.energy_free |
51 | 2 | tkerber | else:
|
52 | 2 | tkerber | self.energy_zero = energy
|
53 | 2 | tkerber | return self.energy_zero |
54 | 2 | tkerber | |
55 | 2 | tkerber | def get_forces(self, embed): |
56 | 2 | tkerber | atom_map_sys_cl = embed.atom_map_sys_cl |
57 | 2 | tkerber | # get forces for the three systems
|
58 | 2 | tkerber | f_sys_lo = self.get_forces_subsystem("system.low-level", self.calculator_low, embed.get_system()) |
59 | 2 | tkerber | f_cl_lo = self.get_forces_subsystem("cluster.low-level", self.calculator_low, embed.get_cluster()) |
60 | 2 | tkerber | f_cl_hi = self.get_forces_subsystem("cluster.high-level", self.calculator_high, embed.get_cluster()) |
61 | 2 | tkerber | # forces correction for the atoms
|
62 | 2 | tkerber | f_cl = f_cl_hi - f_cl_lo |
63 | 2 | tkerber | #number of atoms
|
64 | 2 | tkerber | nat_sys = len(embed)
|
65 | 2 | tkerber | # lo-sys + (hi-lo)
|
66 | 2 | tkerber | for iat_sys in xrange(nat_sys): |
67 | 2 | tkerber | iat_cl = atom_map_sys_cl[iat_sys] |
68 | 2 | tkerber | if iat_cl > -1: |
69 | 2 | tkerber | f_sys_lo[iat_sys] += f_cl[iat_cl] |
70 | 2 | tkerber | |
71 | 2 | tkerber | # correct gradients
|
72 | 2 | tkerber | # Reference: Eichler, Koelmel, Sauer, J. of Comput. Chem., 18(4). 1997, 463-477.
|
73 | 2 | tkerber | for cell_L, iat_cl, iat_sys, r, iat_link in embed.linkatoms: |
74 | 2 | tkerber | # calculate the bond distance (r_bond) at the border
|
75 | 2 | tkerber | xyz = embed[iat_sys].get_position() - embed.get_cluster()[iat_cl].get_position() + cell_L |
76 | 2 | tkerber | |
77 | 2 | tkerber | # calculate the bond lenght and the factor f
|
78 | 2 | tkerber | rbond = np.sqrt(np.dot(xyz, xyz)) |
79 | 2 | tkerber | f = r / rbond |
80 | 2 | tkerber | #normalize xyz
|
81 | 2 | tkerber | xyz /= rbond |
82 | 2 | tkerber | |
83 | 2 | tkerber | # receive the gradients for the link atom
|
84 | 2 | tkerber | fH = f_cl[iat_link] |
85 | 2 | tkerber | # Skalarprodukt fH, xyz
|
86 | 2 | tkerber | fs = np.dot(xyz, fH) |
87 | 2 | tkerber | |
88 | 2 | tkerber | for idir in xrange(3): |
89 | 2 | tkerber | # correct the atom in the system
|
90 | 2 | tkerber | f_sys_lo[iat_sys][idir] += f*fH[idir] - f*fs*xyz[idir] |
91 | 2 | tkerber | # correct the atom in the cluster
|
92 | 2 | tkerber | f_sys_lo[iat_cl][idir] += (1-f)*fH[idir] + f*fs*xyz[idir]
|
93 | 2 | tkerber | return f_sys_lo
|
94 | 2 | tkerber | |
95 | 2 | tkerber | def set_atoms(self, atoms): |
96 | 2 | tkerber | return
|
97 | 2 | tkerber | |
98 | 2 | tkerber |