1 | #!@PYTHON@
|
---|
2 | #
|
---|
3 | # Removes random atoms from a TREMOLO data file
|
---|
4 |
|
---|
5 | import sys, random, math, re
|
---|
6 |
|
---|
7 | # check arguments
|
---|
8 | if len(sys.argv) < 5:
|
---|
9 | print "Usage: "+sys.argv[0]+" <datafile> <NoDefects> <OffsetElement> <OffsetXYZ> <BondDistance>"
|
---|
10 | sys.exit(1)
|
---|
11 |
|
---|
12 | input = open(sys.argv[1], "r")
|
---|
13 | output = open(sys.argv[1]+".defect", "w")
|
---|
14 | defectcount=int(sys.argv[2])
|
---|
15 | OffsetElement=int(sys.argv[3])
|
---|
16 | OffsetXYZ=int(sys.argv[4])
|
---|
17 | DISTANCE=float(sys.argv[5])
|
---|
18 | THRESHOLD=.4
|
---|
19 | CUTOFF=DISTANCE+THRESHOLD
|
---|
20 |
|
---|
21 | # 1. parse lines into array
|
---|
22 | lines=[]
|
---|
23 | comments=[]
|
---|
24 | nr=0
|
---|
25 | for line in input:
|
---|
26 | if "#" in line:
|
---|
27 | comments.append(line)
|
---|
28 | continue
|
---|
29 | lines.append(line.split())
|
---|
30 | nr=len(lines)
|
---|
31 | input.close()
|
---|
32 | print "I have scanned "+str(nr)+" lines in "+sys.argv[1]+" with "+str(len(comments))+" comments."
|
---|
33 |
|
---|
34 | # 2a. parse atoms coordinates into list and find bounding box
|
---|
35 | max=[ 0., 0., 0. ]
|
---|
36 | min=[ 0., 0., 0. ]
|
---|
37 | AllAtoms=[]
|
---|
38 |
|
---|
39 | for n in range(len(lines)):
|
---|
40 | atom=lines[n]
|
---|
41 | #print"reading atom"
|
---|
42 | for i in range(3):
|
---|
43 | #print float(atom[i+1])
|
---|
44 | if float(atom[i+OffsetXYZ]) < min[i]:
|
---|
45 | min[i] = float(atom[i+1])
|
---|
46 | if float(atom[i+OffsetXYZ]) > max[i]:
|
---|
47 | max[i] = float(atom[i+OffsetXYZ])
|
---|
48 | AllAtoms.append([n, atom[OffsetElement], float(atom[OffsetXYZ]), float(atom[OffsetXYZ+1]), float(atom[OffsetXYZ+2])])
|
---|
49 | print "Found Box bounds [%f,%f]x[%f,%f]x[%f,%f]." % (min[0],max[0],min[1],max[1],min[2],max[2])
|
---|
50 |
|
---|
51 | # 2b. get number of linked cells
|
---|
52 | cells_x=int(math.ceil((max[0]-min[0])/CUTOFF))
|
---|
53 | cells_y=int(math.ceil((max[1]-min[1])/CUTOFF))
|
---|
54 | cells_z=int(math.ceil((max[2]-min[2])/CUTOFF))
|
---|
55 | print "Number of cells in each axis direction (%f,%f,%f)." % (cells_x, cells_y, cells_z)
|
---|
56 |
|
---|
57 | # 2c. create 3 dim array to fit in box, each cell has size CUTOFF Ang
|
---|
58 | cell=[]
|
---|
59 | for i in range(cells_x):
|
---|
60 | cell.append([])
|
---|
61 | for j in range(cells_y):
|
---|
62 | cell[i].append([])
|
---|
63 | for k in range(cells_z):
|
---|
64 | cell[i][j].append([0])
|
---|
65 |
|
---|
66 | # 2d. parse every atom into appropriate cell
|
---|
67 | n=0
|
---|
68 | for atom in AllAtoms:
|
---|
69 | x=int(math.floor((atom[2]-min[0])/CUTOFF))
|
---|
70 | y=int(math.floor((atom[3]-min[1])/CUTOFF))
|
---|
71 | z=int(math.floor((atom[4]-min[2])/CUTOFF))
|
---|
72 | cell[x][y][z][0] +=1
|
---|
73 | cell[x][y][z].append(atom[0]) # append index to AllAtoms list
|
---|
74 | n=n+1
|
---|
75 | print str(n)+" of "+str(len(AllAtoms))+" atoms were incarcerated."
|
---|
76 |
|
---|
77 | # 2e. go through every cell, check neighbours
|
---|
78 | atom1=[0,0.,0.,0.]
|
---|
79 | atom2=[0,0.,0.,0.]
|
---|
80 | v=0
|
---|
81 | NumBonds=0
|
---|
82 | Bonds=[]
|
---|
83 | for i in range(cells_x):
|
---|
84 | for j in range(cells_y):
|
---|
85 | for k in range(cells_z):
|
---|
86 | v=cell[i][j][k][0]
|
---|
87 | #go through every atom in cell
|
---|
88 | for l in range(1, v+1):
|
---|
89 | atom1=cell[i][j][k][l]
|
---|
90 | # go through cell and all lower neighbours
|
---|
91 | for e in range(i-1,i+2):
|
---|
92 | #if on border continue periodic
|
---|
93 | if e>=cells_x or e<0:
|
---|
94 | #e=e-cells_x
|
---|
95 | continue
|
---|
96 | for r in range(j-1,j+2):
|
---|
97 | #if on border continue periodic
|
---|
98 | if r>=cells_y or r<0:
|
---|
99 | #r=r-cells_y
|
---|
100 | continue
|
---|
101 | for t in range(k-1,k+2):
|
---|
102 | #if on border continue periodic
|
---|
103 | if t>=cells_z or t<0:
|
---|
104 | #t=t-cells_z
|
---|
105 | continue
|
---|
106 | #efficiency in linked cell: ommit four boxes in middle layer
|
---|
107 | #if (i==e and r==j+1):
|
---|
108 | # continue
|
---|
109 | #if (i==e and r==j+1 and t==k+1):
|
---|
110 | # continue
|
---|
111 | w=cell[e][r][t][0]
|
---|
112 | #go through all atoms in cell
|
---|
113 | for m in range(1, w+1):
|
---|
114 | atom2=cell[e][r][t][m]
|
---|
115 | #when in same cell: ommit identical particles
|
---|
116 | if (AllAtoms[atom1][0]>=AllAtoms[atom2][0]):
|
---|
117 | continue
|
---|
118 | dist=0
|
---|
119 | for h in range(3):
|
---|
120 | dist += (AllAtoms[atom1][2+h] - AllAtoms[atom2][2+h])*(AllAtoms[atom1][2+h] - AllAtoms[atom2][2+h])
|
---|
121 | dist=math.sqrt(dist)
|
---|
122 |
|
---|
123 | # add bond
|
---|
124 | if (dist >= (DISTANCE-THRESHOLD)) and (dist <= (DISTANCE+THRESHOLD)):
|
---|
125 | Bonds.append([atom1, atom2])
|
---|
126 | NumBonds+=1
|
---|
127 | print str(NumBonds)+" bonds with partners distanced within ["+str(DISTANCE-THRESHOLD)+","+str(DISTANCE+THRESHOLD)+"] angstroem were found."
|
---|
128 |
|
---|
129 | # 3. check whether we have sufficient bonds and choose desired number
|
---|
130 | if NumBonds < defectcount:
|
---|
131 | print "Not enough bonds for the desired number of defects."
|
---|
132 | sys.exit(1)
|
---|
133 |
|
---|
134 | # 4. flip random but unique bonds by 90 degrees
|
---|
135 | vector1=[0., 0., 0.]
|
---|
136 | vector2=[0., 0., 0.]
|
---|
137 | for n in range(defectcount):
|
---|
138 | # 4a. determine random bond and its bonding partners
|
---|
139 | atom3=-1
|
---|
140 | while atom3==-1: # pick a unique bond
|
---|
141 | i=random.randrange(0,NumBonds)
|
---|
142 | atom1=Bonds[i][0]
|
---|
143 | atom2=Bonds[i][1]
|
---|
144 | atom3=-1
|
---|
145 | if (atom1 == -1) or (atom2 == -1):
|
---|
146 | continue
|
---|
147 | # 4b. obtain a third atom to describe the plane fully
|
---|
148 | for j in range(NumBonds):
|
---|
149 | if ((Bonds[j][0] != atom2) and (Bonds[j][1] == atom1)) or ((Bonds[j][0] != atom1) and (Bonds[j][1] == atom2)):
|
---|
150 | atom3=Bonds[j][0]
|
---|
151 | break
|
---|
152 | if ((Bonds[j][1] != atom2) and (Bonds[j][0] == atom1)) or ((Bonds[j][1] != atom1) and (Bonds[j][0] == atom2)):
|
---|
153 | atom3=Bonds[j][1]
|
---|
154 | break
|
---|
155 | if (atom3 == -1):
|
---|
156 | continue
|
---|
157 | print "Flipping bond "+str(i)+"."
|
---|
158 | Bonds[i][0]=-1
|
---|
159 | Bonds[i][1]=-1
|
---|
160 | # 4c. determine in-plane vectors and orthonormalize
|
---|
161 | for i in range(3):
|
---|
162 | vector1[i]=AllAtoms[atom1][2+i]
|
---|
163 | vector2[i]=AllAtoms[atom1][2+i]
|
---|
164 | for i in range(3):
|
---|
165 | vector1[i]-=AllAtoms[atom2][2+i]
|
---|
166 | vector2[i]-=AllAtoms[atom3][2+i]
|
---|
167 | BondNorm=0
|
---|
168 | for i in range(3):
|
---|
169 | BondNorm+=vector1[i]*vector1[i]
|
---|
170 | BondNorm=math.sqrt(BondNorm)
|
---|
171 | for i in range(3):
|
---|
172 | vector1[i]/=BondNorm
|
---|
173 | norm=0
|
---|
174 | for i in range(3):
|
---|
175 | norm+=vector1[i]*vector2[i]
|
---|
176 | for i in range(3):
|
---|
177 | vector2[i]-=norm*vector1[i]
|
---|
178 | norm=0
|
---|
179 | for i in range(3):
|
---|
180 | norm+=vector2[i]*vector2[i]
|
---|
181 | norm=math.sqrt(norm)
|
---|
182 | for i in range(3):
|
---|
183 | vector2[i]/=norm
|
---|
184 | vector4=[0., 0, 0.]
|
---|
185 | for i in range(3):
|
---|
186 | vector4[i]=(AllAtoms[atom1][2+i]+AllAtoms[atom2][2+i])/2.
|
---|
187 | vector2[i]*=BondNorm/2.
|
---|
188 |
|
---|
189 | # 4b. rotate the bonding nuclei and store in array lines!
|
---|
190 | for i in range(3):
|
---|
191 | lines[atom1][OffsetXYZ+i]="%e" % (vector4[i]+vector2[i])
|
---|
192 | lines[atom2][OffsetXYZ+i]="%e" % (vector4[i]-vector2[i])
|
---|
193 |
|
---|
194 | # 5. store AllAtoms to file
|
---|
195 | for line in comments:
|
---|
196 | output.write("%s" % (line))
|
---|
197 | for line in lines:
|
---|
198 | for n in range(len(line)):
|
---|
199 | output.write("%s\t" % (line[n]))
|
---|
200 | output.write("\n")
|
---|
201 | output.close()
|
---|
202 |
|
---|
203 | # 6. exit
|
---|
204 | print "All done."
|
---|
205 |
|
---|
206 | sys.exit(0)
|
---|