Statistiques
| Branche: | Tag: | Révision :

dockonsurf / modules / add_adsorbate_euler+dissociation.py @ 86112fec

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

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3

    
4
import sys
5
import numpy as np
6
import ase
7
from ase import io
8
from ase.io import read
9
from ase.io import write
10
from ase import Atom
11
from ase import build
12
from ase.build import add_adsorbate
13
from ase import constraints
14
from ase.constraints import FixAtoms
15
from ase import neighborlist
16
from ase.neighborlist import NeighborList
17
from ase import utils
18
import ase_Fe1_Fe2
19

    
20
if len(sys.argv) < 7 :
21
    print "This script has to be used with at least 6 arguments."
22
    print "1. Name of the file containing the surface"
23
    print "2. Atom number of the atom of the surface where the adsorbate will be adsorbed"
24
    print "3. Name of the file containing the molecule to be adsorbed"
25
    print "4. Atom number of the atom of the molecule that will be adsorbed of the surface"
26
    print "5. Distance between the molecule and the surface"
27
    print "6. Name of the output file"
28
    print "Other arguments can be added before the name of the output file :"
29
    print "  Second atom of the molecule"
30
    print "  phi angle (rotation around z)"
31
    print "  theta angle (rotation around new x)"
32
    print "  psi angle (rotation around new z) "
33
    sys.exit(1)
34

    
35

    
36
#############################################################
37
# Définition de la fonction permettant de calculer les angles
38
#############################################################
39

    
40
def get_proper_angle(v1, v2, degrees=True):
41
    norm_dot = np.dot(v1/np.linalg.norm(v1), v2/np.linalg.norm(v2))
42
    angle = np.arccos(np.sign(norm_dot) if np.abs(norm_dot) >= 1 else norm_dot)
43
    return(angle*180/np.pi if degrees else angle)
44

    
45

    
46
##########################################
47
# Lecture des différents arguments de base
48
##########################################
49

    
50
surface_file = sys.argv[1]
51
atom_surface = int(sys.argv[2])
52
molecule_file = sys.argv[3]
53
atom_molecule = int(sys.argv[4])
54
distance = int(sys.argv[5])
55
if len(sys.argv) < 8 :
56
    output = sys.argv[6]
57

    
58
surface = read(surface_file)
59
molecule = read(molecule_file)
60

    
61
#################################
62
# Lecture des positions de atomes
63
#################################
64

    
65
atom_surf_1 = surface[atom_surface].position
66
x_atom_surf_1 = atom_surf_1[0]
67
y_atom_surf_1 = atom_surf_1[1]
68
z_atom_surf_1 = atom_surf_1[2]
69

    
70
atom_mol_1 = molecule[atom_molecule].position
71
x_atom_mol_1 = atom_mol_1[0]
72
y_atom_mol_1 = atom_mol_1[1]
73
z_atom_mol_1 = atom_mol_1[2]
74

    
75
nb_atom_mol = int(len(molecule))
76

    
77

    
78
#######################################################
79
# Cas avec un plus grand nombre d'arguments (rotations)
80
#######################################################
81

    
82

    
83
if len(sys.argv) > 7 :
84

    
85
    #######################
86
    # Lecture des arguments
87
    #######################
88

    
89
    atom_molecule_2 = int(sys.argv[6])
90
    phi = int(sys.argv[7])
91
    theta = int(sys.argv[8])
92
    psi = int(sys.argv[9])
93
    output = sys.argv[10]
94

    
95
    theta_min = theta - 0.01
96
    theta_max = theta + 0.01
97
    phi_min = phi - 0.01
98
    phi_max = phi + 0.01
99
    psi_min = psi - 0.01
100
    psi_max = psi + 0.01
101

    
102
    atom_mol_2 = molecule[atom_molecule_2].position
103
    x_atom_mol_2 = atom_mol_2[0]
104
    y_atom_mol_2 = atom_mol_2[1]
105
    z_atom_mol_2 = atom_mol_2[2]
106

    
107
    ##################################
108
    # Rotation avec les angles d'Euler
109
    ##################################
110

    
111
    #Initialisation : placement du second atome de la molecule sur Oy
112
    vect_y = [0, 1, 0]
113
    vect_atom_mol_2 = molecule[atom_molecule_2].position - molecule[atom_molecule].position
114
    angle_1 = get_proper_angle(vect_y, vect_atom_mol_2)
115
    if (angle_1 != 0) :
116
        vect_normal = np.cross(vect_y, vect_atom_mol_2)
117
        molecule.rotate(-angle_1, vect_normal, center=(x_atom_mol_1,y_atom_mol_1,z_atom_mol_1))
118
        vect_atom_mol_2_verif = molecule[atom_molecule_2].position - molecule[atom_molecule].position
119
        angle_1_verif = get_proper_angle(vect_atom_mol_2_verif, vect_y)
120
        angle_max = 0.01
121
        angle_min = -0.01
122
        if (angle_1_verif < angle_min or angle_1_verif > angle_max) :
123
            print 'Error in initialisation'
124

    
125
    #Rotation Euler
126
    molecule.euler_rotate(phi, theta, psi, center=(x_atom_mol_1,y_atom_mol_1,z_atom_mol_1))
127

    
128
    #Correction des collisions entre la molécule et la surface
129
    z_atom_surf_max = z_atom_surf_1 + 1
130

    
131
    collision = 0.5
132
    rotation_tot = 0
133
    nb_atom_collision_min = 0
134
    rotation_opt = 0
135
    rotation_modif = 5
136
    
137
    for i in range(0,nb_atom_mol) :
138
        atom_test = molecule[i].position
139
        z_atom_test = atom_test[2]
140
        z_atom_test_final = z_atom_test - z_atom_mol_1 + z_atom_surf_1 + distance
141
        if (z_atom_test_final < z_atom_surf_max) :
142
            collision = 1
143
            nb_atom_collision_min += 1
144
    if collision == 1 :
145
        print 'Collision between the molecule and the surface - modification of theta angle'
146

    
147
    vect_z = [0, 0, 1]
148

    
149
    while (collision == 1 and rotation_tot < 354) :
150
        vect_atom_mol_2_post_euler = molecule[atom_molecule_2].position - molecule[atom_molecule].position
151
        
152
        if (vect_atom_mol_2_post_euler[0] != 0 and vect_atom_mol_2_post_euler[1] != 0) :
153
            vect_rotation_theta = np.cross(vect_atom_mol_2_post_euler, vect_z)
154
        else :
155
            vect_rotation_theta = [0.0001, 0.0001 , 0]
156
        molecule.rotate(rotation_modif, vect_rotation_theta, center=(x_atom_mol_1,y_atom_mol_1,z_atom_mol_1))
157
        rotation_tot += 5
158
        
159
        collision = 0
160
        nb_atom_collision = 0
161

    
162
        for i in range(0,nb_atom_mol) :
163
            atom_test = molecule[i].position
164
            z_atom_test = atom_test[2]
165
            z_atom_test_final = z_atom_test - z_atom_mol_1 + z_atom_surf_1 + distance
166
            if (z_atom_test_final < z_atom_surf_max) :
167
                nb_atom_collision += 1
168
                collision = 1
169
        if (nb_atom_collision < nb_atom_collision_min) :
170
            nb_atom_collision_min = nb_atom_collision
171
            rotation_opt = rotation_tot
172

    
173
        if nb_atom_collision_min != 0 :
174
            rotation_tot_2 = 0
175
            rotation_opt_2 = 0
176

    
177
            while (collision == 1 and rotation_tot_2 < 354) :
178
                vect_atom_mol_2_post_euler = molecule[atom_molecule_2].position - molecule[atom_molecule].position
179
                molecule.rotate(rotation_modif, vect_atom_mol_2_post_euler, center=(x_atom_mol_1,y_atom_mol_1,z_atom_mol_1))
180
                rotation_tot_2 += 5
181
                
182
                collision = 0
183
                nb_atom_collision = 0
184

    
185
                for i in range(0,nb_atom_mol) :
186
                    atom_test = molecule[i].position
187
                    z_atom_test = atom_test[2]
188
                    z_atom_test_final = z_atom_test - z_atom_mol_1 + z_atom_surf_1 + distance
189
                    if (z_atom_test_final < z_atom_surf_max) :
190
                        nb_atom_collision += 1
191
                        collision = 1
192
                if (nb_atom_collision < nb_atom_collision_min) :
193
                    nb_atom_collision_min = nb_atom_collision
194
                    rotation_opt_2 = rotation_tot_2
195

    
196
    if collision == 0 :
197
        print 'Collision corrected'
198
    elif collision == 1 :
199
        print 'Error: the collision could not be corrected'
200
        pos1 = output.rfind('/')
201
        pos = pos1 + 1
202
        num_coll=output[pos:]
203
        j = output[:pos1]
204
        pos2 = j.rfind('/')
205
        molecule_directory = j[:pos2]
206
        fichier = open("%s/errors" % molecule_directory , "a")
207
        fichier.write("Adsorption %s : ERROR the collision could not be corrected\n" % num_coll )
208
        fichier.close()
209

    
210

    
211
##########################################
212
# Adsorption de la molecule sur la surface
213
##########################################
214

    
215
add_adsorbate(surface, molecule, distance, (x_atom_surf_1,y_atom_surf_1), mol_index=atom_molecule)
216

    
217
out=output+".xyz"
218
write(out, surface)
219

    
220

    
221
############################
222
# Dissociation si necessaire
223
############################
224

    
225
if collision == 0 :
226
    surface = read(surface_file)
227
    molecule_reminder = molecule
228
    
229
    list_cutoffs = utils.natural_cutoffs(molecule)
230
    nl=NeighborList(list_cutoffs, self_interaction=False, bothways=True)
231

    
232
    nl.update(molecule)
233
    neighbor_indices, offsets = nl.get_neighbors(atom_molecule)
234

    
235
    symbols = molecule.get_chemical_symbols()
236

    
237
    neighbors_symbols=[]
238
    for i in neighbor_indices:
239
            neighbors_symbols.append(symbols[i])
240

    
241
    nb_neighbors = len(neighbor_indices)
242

    
243
    diss=0
244
    for i in range(0,nb_neighbors):
245
        if neighbors_symbols[i] == "H":
246
            diss=1
247
            H_atom=neighbor_indices[i] #nb of the H atom
248
            print "Dissociation possible"
249

    
250
    if diss == 1:
251
        list_cutoffs_surface = utils.natural_cutoffs(surface)
252
        nl2=NeighborList(list_cutoffs_surface, self_interaction=False, bothways=True)
253
        nl2.update(surface)
254
        neighbor_indices_surf, offsets_surf = nl2.get_neighbors(atom_surface)
255
        symbols_surf = surface.get_chemical_symbols()
256
        for i in neighbor_indices_surf:
257
            surface = read(surface_file)
258
            molecule = molecule_reminder
259
            neighbor_surf_coord = surface[i].position
260
            coord_H_atom=molecule[H_atom].position
261
            if (neighbor_surf_coord[2] > z_atom_surf_1-1 and symbols_surf[i] == "O"):
262
                vector_H_diss=[neighbor_surf_coord[0]-coord_H_atom[0], neighbor_surf_coord[1]-coord_H_atom[1], neighbor_surf_coord[2]+1-coord_H_atom[2]]
263
                translation_matrix_dissociation=[]
264
                for k in range (0, nb_atom_mol):
265
                    if k != H_atom:
266
                        translation_matrix_dissociation.append([0,0,0])
267
                    else:
268
                        translation_matrix_dissociation.append(vector_H_diss)
269
                molecule.translate(translation_matrix_dissociation)
270
                add_adsorbate(surface, molecule, distance, (x_atom_surf_1,y_atom_surf_1), mol_index=atom_molecule)
271
                output_diss = output + "_diss_" + str(i) + ".xyz"
272
                write(output_diss, surface)
273
    
274

    
275

    
276

    
277

    
278