Statistiques
| Révision :

root / ase / embed.py @ 2

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

1 2 tkerber
from ase import Atom, Atoms
2 2 tkerber
from ase.data import covalent_radii, atomic_numbers
3 2 tkerber
4 2 tkerber
import numpy as np
5 2 tkerber
6 2 tkerber
class Embed(Atoms):
7 2 tkerber
    #--- constructor of the Embed class ---
8 2 tkerber
    def __init__(self, system=None, cluster=None):
9 2 tkerber
        super(Embed, self).__init__()
10 2 tkerber
        # define the atom map
11 2 tkerber
        self.atom_map_sys_cl = []
12 2 tkerber
        self.linkatoms = []
13 2 tkerber
        # cluster dimensions
14 2 tkerber
        self.xyz_cl_min = None
15 2 tkerber
        self.xyz_cl_max = None
16 2 tkerber
        # set the search radius for link atoms
17 2 tkerber
        self.d = 10
18 2 tkerber
        # define the systems for calculations
19 2 tkerber
        self.set_system(system)
20 2 tkerber
        self.set_cluster(cluster)
21 2 tkerber
        #
22 2 tkerber
        self.set_cell([10, 10, 10])
23 2 tkerber
        return
24 2 tkerber
25 2 tkerber
    #--- set the cluster ---
26 2 tkerber
    def set_cluster(self, atoms):
27 2 tkerber
        import copy
28 2 tkerber
        # set the min/max cluster dimensions
29 2 tkerber
        self.xyz_cl_min = atoms[0].get_position()
30 2 tkerber
        self.xyz_cl_max = atoms[0].get_position()
31 2 tkerber
        for atom in atoms:
32 2 tkerber
            # assign the label "Cluster (10)" in atom.TAG
33 2 tkerber
            atom.set_tag(10)
34 2 tkerber
            xyz=atom.get_position()
35 2 tkerber
            for i in xrange(3):
36 2 tkerber
                # set the min/max cluster dimensions
37 2 tkerber
                if xyz[i] < self.xyz_cl_min[i]:
38 2 tkerber
                    self.xyz_cl_min[i] = xyz[i]
39 2 tkerber
                if xyz[i] > self.xyz_cl_max[i]:
40 2 tkerber
                    self.xyz_cl_max[i] = xyz[i]
41 2 tkerber
42 2 tkerber
        # add self.d around min/max cluster dimensions
43 2 tkerber
        self.xyz_cl_min -= [self.d, self.d, self.d]
44 2 tkerber
        self.xyz_cl_max += [self.d, self.d, self.d]
45 2 tkerber
        # set the cluster for low and high level calculation
46 2 tkerber
        self.atoms_cluster = atoms
47 2 tkerber
        return
48 2 tkerber
49 2 tkerber
    #--- set the system ---
50 2 tkerber
    def set_system(self, atoms):
51 2 tkerber
        self.atoms_system = atoms
52 2 tkerber
        # assign the label "Cluster (10)" in atom.TAG
53 2 tkerber
        for atom in atoms:
54 2 tkerber
            atom.set_tag(0)
55 2 tkerber
        # update search radius for link atoms
56 2 tkerber
        dx = 0
57 2 tkerber
        for atom in atoms:
58 2 tkerber
            r = covalent_radii[atom.get_atomic_number()]
59 2 tkerber
            if (r > dx):
60 2 tkerber
                dx = r
61 2 tkerber
        self.d = dx * 2.1
62 2 tkerber
        return
63 2 tkerber
64 2 tkerber
    #--- return cluster ---
65 2 tkerber
    def get_cluster(self):
66 2 tkerber
        return self.atoms_cluster
67 2 tkerber
68 2 tkerber
    def get_system(self):
69 2 tkerber
        return self.atoms_system
70 2 tkerber
71 2 tkerber
    #--- Embedding ---
72 2 tkerber
    def embed(self):
73 2 tkerber
        # is the cluster and the host system definied ?
74 2 tkerber
        if self.atoms_cluster is None or self.atoms_system is None:
75 2 tkerber
            return
76 2 tkerber
        self.find_cluster()
77 2 tkerber
        self.set_linkatoms()
78 2 tkerber
        print "link atoms found: ", len(self.linkatoms)
79 2 tkerber
80 2 tkerber
    def find_cluster(self):
81 2 tkerber
        # set tolerance
82 2 tkerber
        d = 0.001
83 2 tkerber
        #atoms
84 2 tkerber
        xyzs_cl=[]
85 2 tkerber
        for atom_cl in self.atoms_cluster:
86 2 tkerber
            xyzs_cl.append(atom_cl.get_position())
87 2 tkerber
        xyzs_sys=[]
88 2 tkerber
        for atom_sys in self.atoms_system:
89 2 tkerber
            xyzs_sys.append(atom_sys.get_position())
90 2 tkerber
91 2 tkerber
        self.atom_map_sys_cl=np.zeros(len(self.atoms_system), int)
92 2 tkerber
        # loop over cluster atoms atom_sys
93 2 tkerber
        for iat_sys in xrange(len(self.atoms_system)):
94 2 tkerber
            # get the coordinates of the system atom atom_sys
95 2 tkerber
            xyz_sys = xyzs_sys[iat_sys]
96 2 tkerber
            # bSysOnly: no identical atom has been found
97 2 tkerber
            bSysOnly = True
98 2 tkerber
            # loop over system atoms atom_cl
99 2 tkerber
            for iat_cl in xrange(len(self.atoms_cluster)):
100 2 tkerber
                # difference vector between both atoms
101 2 tkerber
                xyz_diff = np.abs(xyzs_sys[iat_sys]-xyzs_cl[iat_cl])
102 2 tkerber
                # identical atoms
103 2 tkerber
                if xyz_diff[0] < d and xyz_diff[1] < d and xyz_diff[2] < d:
104 2 tkerber
                    # set tag (CLUSTER+HOST: 10) to atom_sys
105 2 tkerber
                    self.atoms_system[iat_sys].set_tag(10)
106 2 tkerber
                    # map the atom in the atom list
107 2 tkerber
                    self.atom_map_sys_cl[iat_sys]=iat_cl
108 2 tkerber
                    # atom has been identified
109 2 tkerber
                    bSysOnly = False
110 2 tkerber
                    break
111 2 tkerber
            if bSysOnly:
112 2 tkerber
                self.atom_map_sys_cl[iat_sys] = -1
113 2 tkerber
114 2 tkerber
    def set_linkatoms(self, tol=15., linkAtom=None, debug=False):
115 2 tkerber
        # local copies of xyz coordinates to avoid massive copying of xyz objects
116 2 tkerber
        xyzs_cl=[]
117 2 tkerber
        for atom_cl in self.atoms_cluster:
118 2 tkerber
            xyzs_cl.append(atom_cl.get_position())
119 2 tkerber
        xyzs_sys=[]
120 2 tkerber
        for atom_sys in self.atoms_system:
121 2 tkerber
            xyzs_sys.append(atom_sys.get_position())
122 2 tkerber
        # FIXME: mapping does not work when cluster atoms are outside of the box
123 2 tkerber
        # set the standard link atom
124 2 tkerber
        if linkAtom is None:
125 2 tkerber
            linkAtom ='H'
126 2 tkerber
        # number of atoms in the cluster and the system
127 2 tkerber
        nat_cl=len(self.atoms_cluster)
128 2 tkerber
        nat_sys=len(self.atoms_system)
129 2 tkerber
        # system has pbc?
130 2 tkerber
        pbc = self.get_pbc()
131 2 tkerber
        # set the bond table
132 2 tkerber
        bonds = []
133 2 tkerber
        # set the 27 cell_vec, starting with the (0,0,0) vector for the unit cell
134 2 tkerber
        cells_L = [(0.0,  0.0,  0.0)]
135 2 tkerber
        # get the cell vectors
136 2 tkerber
        cell = self.get_cell()
137 2 tkerber
        # TODO: check 0D, 1D, 2D, 3D
138 2 tkerber
        if False:
139 2 tkerber
         for ix in xrange(-1, 2):
140 2 tkerber
            for iy in xrange(-1, 2):
141 2 tkerber
                for iz in xrange(-1, 2):
142 2 tkerber
                    if ix == 0 and iy == 0 and iz == 0:
143 2 tkerber
                        continue
144 2 tkerber
145 2 tkerber
                    cells_L.append(np.dot([ix, iy, iz], cell))
146 2 tkerber
        # save the radius of system atoms
147 2 tkerber
        rs_sys = []
148 2 tkerber
        for atom in self.atoms_system:
149 2 tkerber
            rs_sys.append(covalent_radii[atom.get_atomic_number()])
150 2 tkerber
        # sum over cluster atoms (iat_cl)
151 2 tkerber
        for iat_cl in xrange(nat_cl):
152 2 tkerber
            # get the cluster atom
153 2 tkerber
            atom_cl=self.atoms_cluster[iat_cl]
154 2 tkerber
            # ignore link atoms
155 2 tkerber
            if atom_cl.get_tag() == 50:
156 2 tkerber
                continue
157 2 tkerber
            # xyz coordinates and covalent radius of the cluster atom iat_cl
158 2 tkerber
            xyz_cl = xyzs_cl[iat_cl]
159 2 tkerber
            r_cl = covalent_radii[atom_cl.get_atomic_number()]
160 2 tkerber
161 2 tkerber
            # sum over system atoms (iat_sys)
162 2 tkerber
            for iat_sys in xrange(nat_sys):
163 2 tkerber
                # avoid cluster atoms
164 2 tkerber
                if self.atoms_system[iat_sys].get_tag()==10:
165 2 tkerber
                    continue
166 2 tkerber
                # sum over all cell_L
167 2 tkerber
                for cell_L in cells_L:
168 2 tkerber
                    # xyz coordinates and covalent radius of the system atom iat_sys
169 2 tkerber
                    xyz_sys = xyzs_sys[iat_sys]+cell_L
170 2 tkerber
                    # go only in distance self.d around the cluster
171 2 tkerber
                    lcont = True
172 2 tkerber
                    for i in xrange(3):
173 2 tkerber
                        if (xyz_sys[i] < self.xyz_cl_min[i] or
174 2 tkerber
                            xyz_sys[i] > self.xyz_cl_max[i]):
175 2 tkerber
                            lcont = False
176 2 tkerber
                            break
177 2 tkerber
                    if not lcont:
178 2 tkerber
                        continue
179 2 tkerber
                    # xyz coordinates and covalent radius of the system atom iat_sys
180 2 tkerber
                    r_sys = rs_sys[iat_sys]
181 2 tkerber
                    # diff vector
182 2 tkerber
                    xyz_diff = xyz_sys - xyz_cl
183 2 tkerber
                    # distance between the atoms
184 2 tkerber
                    r = np.sqrt(np.dot(xyz_diff, xyz_diff))
185 2 tkerber
                    # ratio of the distance to the sum of covalent radius
186 2 tkerber
                    f = r / (r_cl + r_sys)
187 2 tkerber
                    if debug:
188 2 tkerber
                        print "Covalent radii = ",r_cl, r_sys
189 2 tkerber
                        print "Distance ", f
190 2 tkerber
                        print "tol = ",(1+tol/100.),(1-tol/100.),(1-2*tol/100.)
191 2 tkerber
                    if f <= (1+tol/100.) and f >= (1-2*tol/100.):
192 2 tkerber
                        s = cell_L, iat_cl, iat_sys, r_cl
193 2 tkerber
                        bonds.append(s)
194 2 tkerber
                        break
195 2 tkerber
                    if f <= (1-2*tol/100.):
196 2 tkerber
                        raise RuntimeError("QMX: The cluster atom", iat_cl, " and the system atom", iat_sys, "came too close")
197 2 tkerber
198 2 tkerber
        r_h = covalent_radii[atomic_numbers[linkAtom]]
199 2 tkerber
        for bond in bonds:
200 2 tkerber
            cell_L, iat_cl, iat_sys, r_cl = bond
201 2 tkerber
            # assign the tags for the border atoms
202 2 tkerber
            atom_sys.set_tag(1)
203 2 tkerber
            atom_cl.set_tag(11)
204 2 tkerber
            #difference vector for the link atom, scaling
205 2 tkerber
            xyz_diff = xyzs_sys[iat_sys] + cell_L - xyzs_cl[iat_cl]
206 2 tkerber
            r = (r_cl + r_h)
207 2 tkerber
            xyz_diff *=  r / np.sqrt(np.dot(xyz_diff, xyz_diff))
208 2 tkerber
            # determine position of the link atom
209 2 tkerber
            xyz_diff += xyzs_cl[iat_cl]
210 2 tkerber
            # create link atom
211 2 tkerber
            atom = Atom(symbol=linkAtom, position=xyz_diff, tag=50)
212 2 tkerber
            # add atom to cluster
213 2 tkerber
            self.atoms_cluster.append(atom)
214 2 tkerber
            # add atom to the linkatoms
215 2 tkerber
            s = cell_L, iat_cl, iat_sys, r, len(self.atoms_cluster)-1
216 2 tkerber
            self.linkatoms.append(s)
217 2 tkerber
        return
218 2 tkerber
219 2 tkerber
    def set_positions(self, positions_new):
220 2 tkerber
        # number of atoms
221 2 tkerber
        nat_sys=len(self.atoms_system)
222 2 tkerber
        # go over all pairs of atoms
223 2 tkerber
        for iat_sys in xrange(nat_sys):
224 2 tkerber
            xyz = positions_new[iat_sys]
225 2 tkerber
            iat_cl = self.atom_map_sys_cl[iat_sys]
226 2 tkerber
            self.atoms_system[iat_sys].set_position(xyz)
227 2 tkerber
            if iat_cl > -1:
228 2 tkerber
                self.atoms_cluster[iat_cl].set_position(xyz)
229 2 tkerber
230 2 tkerber
        for cell_L, iat_cl, iat_sys, r, iat in self.linkatoms:
231 2 tkerber
            # determine position of the link atom
232 2 tkerber
            xyz_cl = self.atoms_cluster[iat_cl].get_position()
233 2 tkerber
            xyz = self.atoms_system[iat_sys].get_position() - xyz_cl + cell_L
234 2 tkerber
            xyz *= r / np.sqrt(np.dot(xyz, xyz))
235 2 tkerber
            xyz += xyz_cl
236 2 tkerber
            # update xyz coordinates of the cluster
237 2 tkerber
            self.atoms_cluster[iat].set_position(xyz)
238 2 tkerber
239 2 tkerber
    def __getitem__(self, i):
240 2 tkerber
        return self.atoms_system.__getitem__(i)
241 2 tkerber
242 2 tkerber
    def get_positions(self):
243 2 tkerber
        return self.atoms_system.get_positions()
244 2 tkerber
245 2 tkerber
    def __add__(self, other):
246 2 tkerber
        return self.atoms_system.__add__(other)
247 2 tkerber
248 2 tkerber
    def __delitem__(self, i):
249 2 tkerber
        return self.atoms_system.__delitem__(i)
250 2 tkerber
251 2 tkerber
    def __len__(self):
252 2 tkerber
        return self.atoms_system.__len__()