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 |
|