1
+ #!/usr/bin/python==========v2.7.5==========
2
+ # CS.py===============v2.1.4===============
3
+ # ========'To apply a compressive-shear biaxial stress field========
4
+ # == to the unit cell and calculate the compressive-shear stress.'==
5
+ # (Contains cases where compressive stress is present.)
6
+ # Authors: Ren Yabin, Yang Bo
7
+ # Emails: <s1345358@126.com>, <boyang@hebut.edu.cn>
8
+ # Licence: Apache License 2.0
9
+
10
+ import math
11
+ import os
12
+ import sys
13
+
14
+ # Rotation coordinates.
15
+ def order ():
16
+ fo = open (fname1 , 'r' )
17
+ line = fo .readlines ()
18
+ fo .close ()
19
+ # line.insert(7, 'Selective dynamics\n')
20
+ numatom = 0
21
+ for k in range (0 , len (line [6 ].split ())):
22
+ numatom += int (line [6 ].split ()[k ])
23
+ L0 = []
24
+ L = []
25
+ for ii in range (2 , 5 ):
26
+ L0 .append (line [ii ].split ())
27
+ for i in range (8 , numatom + 8 ):
28
+ L .append (line [i ].split ()[0 :3 ])
29
+ # if L0[2][2] >= 6:
30
+ L0 [0 ][0 ], L0 [1 ][0 ], L0 [1 ][1 ], L0 [2 ][1 ], L0 [2 ][2 ] = L0 [2 ][2 ], L0 [2 ][1 ], L0 [0 ][0 ], L0 [1 ][0 ], L0 [1 ][1 ]
31
+ for ij in range (0 , len (L )):
32
+ L [ij ][0 ], L [ij ][1 ], L [ij ][2 ] = L [ij ][2 ], L [ij ][0 ], L [ij ][1 ]
33
+ # def takeSecond(elem):
34
+ # return elem[0]
35
+ # L.sort(key=takeSecond)
36
+ for ij in range (0 , 3 ):
37
+ L0 [ij ] = ' ' + ' ' .join (L0 [ij ][:]) + '\n '
38
+ for i in range (0 , numatom ):
39
+ L [i ] = ' ' + ' ' .join (L [i ][:]) + '\n '
40
+ line [2 :5 ] = L0
41
+ line [8 :] = L
42
+ fo = open ('POSorder' , 'w' )
43
+ fo .writelines (line )
44
+ fo .close ()
45
+
46
+ # Applying compression-shear biaxial strain.
47
+ def cs (dds , step ):
48
+ fo = open (fname1 , 'r' )
49
+ line = fo .readlines ()
50
+ fo .close ()
51
+ A = line [2 ].split ()
52
+ Aa = (1 + float (dds ))* float (A [0 ])
53
+ Ac = float (ds )* float (step )* Aa
54
+ # print(line)
55
+ L = ' ' + str (format (Aa , '.16f' ))+ ' ' + A [1 ]+ ' ' + str (format (Ac , '.16f' ))+ '\n '
56
+ line [2 ] = L
57
+ fo = open (fname2 , 'w' )
58
+ fo .writelines (line )
59
+ fo .close ()
60
+ os .system (cp_pos )
61
+ # return
62
+
63
+ # Initial unit cell base vector rotation.
64
+ def revolve (name1 , name2 , theta0 ):
65
+ fo = open (name1 , 'r' )
66
+ line = fo .readlines ()
67
+ fo .close ()
68
+ B = line [3 ].split ()
69
+ C = line [4 ].split ()
70
+ modB = math .sqrt (float (B [1 ])** 2 + float (B [2 ])** 2 )
71
+ modC = math .sqrt (float (C [1 ])** 2 + float (C [2 ])** 2 )
72
+ if float (B [1 ]) >= 0 :
73
+ thetab = math .acos (float (B [2 ])/ modB )
74
+ else :
75
+ thetab = - math .acos (float (B [2 ])/ modB )
76
+ if float (C [1 ]) >= 0 :
77
+ thetac = math .acos (float (C [2 ])/ modC )
78
+ else :
79
+ thetac = - math .acos (float (C [2 ])/ modC )
80
+ Bb = modB * math .sin (thetab - theta0 )
81
+ Bc = modB * math .cos (thetab - theta0 )
82
+ Cb = modC * math .sin (thetac - theta0 )
83
+ Cc = modC * math .cos (thetac - theta0 )
84
+ # print(line)
85
+ LB = ' ' + B [0 ]+ ' ' + str (format (Bb , '.16f' ))+ ' ' + str (format (Bc , '.16f' ))+ '\n '
86
+ LC = ' ' + C [0 ]+ ' ' + str (format (Cb , '.16f' ))+ ' ' + str (format (Cc , '.16f' ))+ '\n '
87
+ line [3 ] = LB
88
+ line [4 ] = LC
89
+ fo = open (name2 , 'w' )
90
+ fo .writelines (line )
91
+ fo .close ()
92
+ # return
93
+
94
+ # Control compressive stress.
95
+ def sigma_ctrl (sigma0 ):
96
+ sigma_ = str (sigma0 )
97
+ dds1 = dds0 # Variable initialization
98
+ if sigma_ != '0' :
99
+ os .system (cp_cont )
100
+ sigma = float (sigma0 )
101
+ k = 0
102
+ # ============ Pressure control program ============ Dichotomy converges compressive stress.
103
+ for i1 in range (0 , 10000 ):
104
+ k += 1
105
+ for i2 in range (1 , 10 ):
106
+ fon = open ('OUTCAR' )
107
+ for line in fon :
108
+ if 'in kB' in line :
109
+ ttt = line .split ()
110
+ fon .close ()
111
+ t0 = float (ttt [2 ])/ 10
112
+ # --------------------
113
+ if abs (dds1 ) >= 0.02 :
114
+ dds1 = 0.02 # Set the strain maximum
115
+ if t0 > sigma :
116
+ dds1 = abs (dds1 ) # Compress
117
+ else :
118
+ dds1 = - abs (dds1 ) # Tensile
119
+ cs (dds1 , i )
120
+ if ifthread == 1 : # dual-thread mode
121
+ os .system (cmd [7 ].rstrip ('\n ' )+ ' & python Thread.py' )
122
+ else :
123
+ os .system (cmd [7 ]) # stress-xxxz
124
+ check (dds , i )
125
+ # --------------------
126
+ fon1 = open ('OUTCAR' )
127
+ for line in fon1 :
128
+ if 'in kB' in line :
129
+ ttt1 = line .split ()
130
+ fon1 .close ()
131
+ t1 = float (ttt1 [2 ])/ 10
132
+ cun = 'cp CONTCAR OUTCAR OSZICAR ' + Name + '/' + str (i )+ '/' + str (k )
133
+ cun_ = 'cp -r Temp ' + Name + '/' + str (i )+ '/' + str (k )
134
+ try :
135
+ os .mkdir (Name + '/' + str (i )+ '/' + str (k ))
136
+ except :
137
+ pass
138
+ os .system (cun )
139
+ if ifthread == 1 :
140
+ os .system (cun_ )
141
+ # -------------------- If the result of the two calculations crosses the sigma setting value, the loop jumps out.
142
+ if t0 >= sigma and t1 <= sigma :
143
+ break
144
+ elif t0 <= sigma and t1 >= sigma :
145
+ break
146
+ os .system (cp_cont )
147
+ if i2 == 2 :
148
+ dds1 = abs (dds1 )* 4 # If the standard is not met after 2 calculations,
149
+ break # the strain is multiplied by 2 and cycled again.
150
+ # --------------------
151
+ if abs (t1 - sigma ) <= e :
152
+ break
153
+ else :
154
+ os .system (cp_cont )
155
+ dds1 = abs (dds1 )/ 2
156
+ # ==================================================
157
+ else :
158
+ pass
159
+
160
+ # Check patch program.
161
+ def check (dds , step ):
162
+ for i in range (100 ):
163
+ fo1 = open ('OUTCAR' , 'r' )
164
+ t1t = []
165
+ for line in fo1 :
166
+ if 'in kB' in line :
167
+ t1t .append (float (line .split ()[2 ])/ 10 )
168
+ fo1 .close ()
169
+ t01 = float (max (t1t ))
170
+ if t01 > float (sigma )+ 15 : # Eliminate potentially erroneous data.
171
+ if dds >= 0.014 :
172
+ dds = 0.014
173
+ cs (dds , step )
174
+ if ifthread == 1 :
175
+ os .system (cmd [7 ].rstrip ('\n ' )+ ' & python Thread.py' )
176
+ else :
177
+ os .system (cmd [7 ])
178
+ dds = dds * 2
179
+ else :
180
+ os .system (cp_cont )
181
+ break
182
+ # return
183
+ # In the calculation of the mechanical behavior of diamond, there may be a situation that
184
+ # compressive stress inhibits the graphitization of the structure.
185
+ # This subroutine is designed to check and correct this situation (the correction threshold is 15GPa).
186
+ # It may not be used by other materials you calculate.
187
+
188
+ # Introduction to the 'input.dat' file.
189
+ try :
190
+ fin = open ("input.dat" )
191
+ except :
192
+ fin = open ("input.dat" , 'w' )
193
+ fin .write ("<< cellname\t \t sigma_0\t iforder\t ifthread\t ifanimation >>\n " )
194
+ fin .write ("POSCAR\t POSCAR_new\t 20\t 1\t 0\t 1\n " )
195
+ fin .write ("<< ds/epsilon_xz\t dds/epsilon_xx\t e=absolute_error_range/GPa >>\n " )
196
+ fin .write ("0.01\t 0.002\t 0.2\n " )
197
+ fin .write ("<< theta\t start\t end\t rad/*math.pi/means:0pi/12->8pi/12_interval=1pi/12 >>\n " )
198
+ fin .write ("1/12\t 0\t 8\n " )
199
+ fin .write ("0\t 100\t #start&end_step\n " )
200
+ fin .write ("mpirun -np 24 /opt/software/vasp.5.4.4.xxxz/bin/vasp_std >out.log\n " )
201
+ fin .write ("mpirun -np 24 /opt/software/vasp.5.4.4.xz/bin/vasp_std >out.log\n " )
202
+ fin .write ("#==================== Parameter Description: ====================\n " )
203
+ fin .write (" # This is a necessary input file. Lines starting with '#' are comments, while the other lines denote parameters.\n " )
204
+ fin .write (" # ATTENTION: This program applies a compressive-shear biaxial stress field based on VASP software calculation. To use this program successfully, you need to install VASP software locally. This includes the software 'vasp.5.4.4.xxxz' for the unrelaxed strain tensor epsilon_xx and epsilon_xz denoted in line 8, and the software 'vasp.5.4.4.xz' for the unrelaxed strain tensor epsilon_xz denoted in line 9.\n " )
205
+ fin .write (" # Line 2 parameter settings: Please do not modify the first two parameters. The third parameter sets the set compressive stress parameter 'sigma_0', with units in GPa. If set to '0', it computes simple shear without compressive stress. The fourth parameter determines whether to perform coordinate transformation on the crystal cell, with '1' denoting convert the crystal plane from z-axis to x-axis. If not needed, set to '0'. Parameters 5 and 6 determine whether to enable double-thread mode and animation archives of CONTCAR, respectively. Set to '1' to enable, or '0' to disable, consistent with the iforder setting.\n " )
206
+ fin .write (" # Line 4 parameter settings: The first parameter specifies the increment in 'epsilon_xz' for shear direction and defaults to 0.01. The second parameter denotes the increment in 'epsilon_xx' for compressive direction and defaults to 0.002. The third parameter sets the absolute error limit of the set compressive stress 'sigma_0' at 0.2 GPa.\n " )
207
+ fin .write (" # Line 6 parameter settings: The sixth line defines the rotation angle and rotation range of the crystal direction. The 1st parameter, 'theta' (in radians), is set as a fraction. E.g., '1/12' denotes pi/12 (i.e., 15 degrees). The second and third parameters specify the start and end ranges of rotation, e.g., 0 and 8 represents rotates 8 times in total, calculating 9 crystal directions with an interval size of pi/12, starting from 0pi/12 and ending at 8pi/12. Attention: Do not set angles or any parameters in this line to negative values, or the program will report an 'error' while creating folders, which prevents the program from running!!!\n " )
208
+ fin .write (" # Line 7 parameter settings: This line denotes the number of steps for initial and final shear strain. It defaults to 0 and 100, respectively. You can set 'start_step' to a non-zero number to continue the previous calculations. For instance, if the first calculation stopped at step 30, you can perform subsequent calculations by extracting the results of Step 30 in the second calculation, instead of starting from 0 again, by setting the 'start_step' to 30. If start and end steps are equal, the program skips shear calculations and proceeds to data extraction.\n " )
209
+ fin .write (" # Lines 8 and 9 contain command lines for calling VASP software. The 8th line calls the strain tensor epsilon_xx and epsilon_xz non-relaxation 'vasp.5.4.4.xxxz', whereas the 9th line calls the strain tensor epsilon_xz non-relaxation 'vasp.5.4.4.xz' for calculations involving simple shear stress field and when the compressive stress is set to 0. Modify the statements after '24' based on your software installation location.\n " )
210
+ fin .write (" # If you are using a remote supercomputing server, the number of 'cores' in lines 8 and 9 should match those in the PBS file; otherwise, the program may fail to calculate.\n " )
211
+ fin .write ("# Thank you for using! Feedback is always welcome!" )
212
+ fin .close ()
213
+ print ("'input.dat' file is missing, please resubmit!" )
214
+ sys .exit ()
215
+
216
+ filename = ['POSCAR' ,'POSCAR0' ,'INCAR' ,'POTCAR' ,'KPOINTS' ,'animation.py' ,'Thread.py' ]
217
+ ifexit = 0
218
+ if os .path .exists (filename [0 ]) == False and os .path .exists (filename [1 ]) == False :
219
+ print ("'" + filename [0 ]+ "' file is missing, please resubmit!" )
220
+ ifexit = 1
221
+ for n in range (2 ,len (filename )):
222
+ if os .path .exists (filename [n ]) == False :
223
+ ifexit = 1
224
+ print ("'" + filename [n ]+ "' file is missing, please resubmit!" )
225
+ if ifexit == 1 :
226
+ sys .exit ()
227
+
228
+ # ================== Main program ==================
229
+ fin_tmp = []
230
+ cmd = []
231
+ for line in fin :
232
+ fin_tmp .append (line .split ())
233
+ cmd .append (line )
234
+ fin .close ()
235
+ # print(cmd[4])
236
+ fname1 = fin_tmp [1 ][0 ]
237
+ fname2 = fin_tmp [1 ][1 ]
238
+ sigma = fin_tmp [1 ][2 ]
239
+ iforder = int (fin_tmp [1 ][3 ])
240
+ ifthread = int (fin_tmp [1 ][4 ])
241
+ ifanimation = int (fin_tmp [1 ][5 ])
242
+ ds = float (fin_tmp [3 ][0 ])
243
+ dds0 = float (fin_tmp [3 ][1 ])
244
+ e = float (fin_tmp [3 ][2 ])
245
+ thetar = fin_tmp [5 ][0 ]
246
+ start0 = int (fin_tmp [5 ][1 ])
247
+ end0 = int (fin_tmp [5 ][2 ])
248
+ start_step0 = int (fin_tmp [6 ][0 ])
249
+ end_step = int (fin_tmp [6 ][1 ])
250
+ if '/' in thetar :
251
+ theta1 = float (thetar [0 :thetar .find ('/' )]) / float (thetar [thetar .find ('/' ) + 1 :])
252
+ if os .path .exists ('POSCAR0' ) == True :
253
+ os .system ('cp POSCAR0 POSCAR' )
254
+ else :
255
+ os .system ('cp POSCAR POSCAR0' )
256
+ cp_pos = 'cp ' + fname2 + ' ' + fname1
257
+ cp_cont = 'cp CONTCAR POSCAR'
258
+ name_cs = 'cs.dat' # Data file name
259
+
260
+ if iforder == 1 :
261
+ order () # Rotation coordinates.
262
+
263
+ for j in range (int (start0 ), int (end0 )+ 1 ): # Crystal steering range.
264
+ Name = str (j * int (thetar [0 :thetar .find ('/' )])) + 'pi' + str (thetar [thetar .find ('/' ) + 1 :])
265
+ try :
266
+ os .mkdir (Name )
267
+ except :
268
+ pass
269
+ name_revolve = 'POSCAR_' + str (Name [0 :Name .find ('p' )])
270
+ if int (start_step0 ) == 0 :
271
+ theta0 = j * theta1 * math .pi
272
+ if iforder == 1 :
273
+ os .system ('cp POSorder POSCAR' )
274
+ else :
275
+ os .system ('cp POSCAR0 POSCAR' )
276
+ revolve (fname1 , name_revolve , theta0 )
277
+ cp_revolve = 'cp ' + name_revolve + ' ' + fname1
278
+ os .system (cp_revolve )
279
+ start_step = start_step0
280
+ else : # If the starting point is not 0, you can continue the previous calculation.
281
+ cp_next = 'cp ' + Name + '/' + str (start_step0 )+ '/' + 'CONTCAR ' + fname1
282
+ os .system (cp_next )
283
+ start_step = int (start_step0 )+ 1 # The starting point of continuous calculation is step0 + 1.
284
+ # ========================================
285
+ for i in range (int (start_step ), int (end_step )+ 1 ): # One crystal orientation calculation.
286
+ dds = float (dds0 )
287
+ cs (dds , i )
288
+ if str (sigma ) == '0' :
289
+ os .system (cmd [8 ]) # stress-xz
290
+ else :
291
+ if ifthread == 1 : # dual-thread mode
292
+ os .system (cmd [7 ].rstrip ('\n ' )+ ' & python Thread.py' )
293
+ else :
294
+ os .system (cmd [7 ]) # stress-xxxz
295
+ check (dds , i )
296
+ cun0 = 'cp CONTCAR OUTCAR OSZICAR ' + Name + '/' + str (i )+ '/0'
297
+ cun0_ = 'cp -r Temp ' + Name + '/' + str (i )+ '/0'
298
+ try :
299
+ os .mkdir (Name + '/' + str (i ))
300
+ except :
301
+ pass
302
+ try :
303
+ os .mkdir (Name + '/' + str (i )+ '/0' )
304
+ except :
305
+ pass
306
+ os .system (cun0 )
307
+ if ifthread == 1 :
308
+ os .system (cun0_ )
309
+ sigma_ctrl (sigma )
310
+ cp_command = 'cp CONTCAR POSCAR OUTCAR OSZICAR ' + name_revolve + ' ' + Name + '/' + str (i )
311
+ os .system (cp_command )
312
+ os .system (cp_cont )
313
+ # ========================================
314
+ datna = Name + '/' + name_cs
315
+ fstr2 = open (datna , 'w' )
316
+ fstr2 .write ('strain\t xx\t xz\n ' )
317
+ for k in range (0 , int (end_step )+ 1 ):
318
+ open2 = Name + '/' + '%s/OUTCAR' % k
319
+ fon = open (open2 )
320
+ for line in fon :
321
+ if 'in kB' in line :
322
+ t = line .split ()
323
+ fon .close ()
324
+ tt = [float (t [2 ]), float (t [7 ])]
325
+ li = str (format (float (ds )* k , '.3f' ))+ '\t ' + str (format (tt [0 ]/ 10 , '.5f' ))+ '\t ' + str (format (tt [1 ]/ 10 , '.5f' ))+ '\n '
326
+ fstr2 .write (li )
327
+ fstr2 .close ()
328
+ cp_csdat = 'cp ' + datna + ' ' + str (Name [0 :Name .find ('p' )]) + name_cs
329
+ os .system (cp_csdat )
330
+ # ==================================================
331
+
332
+ # Save 'CONTCAR' animation.
333
+ if ifanimation == 1 :
334
+ os .system ('python animation.py' )
335
+
336
+ # Summarize all results
337
+ LL = []
338
+ for i in range (0 , 50 ):
339
+ name = str (i ) + name_cs
340
+ if os .path .exists (name ) == True :
341
+ fin = open (name )
342
+ line1 = fin .readlines ()
343
+ fin .close ()
344
+ L = [[str (i ), str (i ), str (i )]]
345
+ for j in range (0 , len (line1 )):
346
+ L .append (line1 [j ].split ())
347
+ bol = LL == []
348
+ if bol == False :
349
+ for jj in range (0 , len (L )):
350
+ del L [jj ][0 ]
351
+ for ij in range (0 , len (L )):
352
+ if bol == True :
353
+ LL .append (L [ij ])
354
+ else :
355
+ for ji in range (0 , len (L [0 ])):
356
+ LL [ij ].append (L [ij ][ji ])
357
+ print ('Calculating...' )
358
+ else :
359
+ pass
360
+ print ('Calculation Complete' )
361
+
362
+ line = []
363
+ for i in range (0 , len (LL )):
364
+ for j in range (0 , len (LL [i ])):
365
+ if j == 0 :
366
+ ss = str (LL [i ][j ])
367
+ else :
368
+ ss = ss + '\t ' + str (LL [i ][j ])
369
+ ss = ss + '\n '
370
+ line .append (ss )
371
+ fon = open (name_cs , 'w' )
372
+ fon .writelines (line )
373
+ fon .close ()
374
+
375
+ # Changelog #
376
+ # -------- (move.py) v0.0 --------
377
+ # v0.0.0, 1st Written Mar 14, 2022. Original version. Modified for the first time.
378
+ # v0.1.0, 1st Overhaul Mar 15, 2022. For moving atoms.
379
+ # -------- (move.py) v1.0 --------
380
+ # v1.0.0, 2nd Overhaul May 28, 2022. In order to apply the compressive-shear biaxial stress field to the model and calculate the stress.
381
+ # v1.0.1, 2nd written Jul 1, 2022. Program optimization.
382
+ # v1.0.2, 3rd written Jul 4, 2022. Program optimization.
383
+ # v1.0.3, 4th written Aug 2, 2022. Bug fixes.
384
+ # v1.0.4, 5th written Aug 16, 2022. Program optimization.
385
+ # --------- (cs.py) v2.0 ---------
386
+ # v2.0.0, 3rd Overhaul Aug 23, 2022. Program renaming & optimization.
387
+ # v2.0.1, 2nd written Sep 6, 2022. Bug fixes.
388
+ # v2.0.2, 3rd written Sep 7, 2022. Bug fixes.
389
+ # --------- (CS.py) v2.1 ---------
390
+ # v2.1.0, 4th written Feb 22, 2023. Program structure adjustment and optimization.
391
+ # v2.1.1, 5th written Feb 28, 2023. Bug fixes & program optimization.
392
+ # v2.1.2, 6th written Mar 2, 2023. Program optimization. Add a dual-thread mode to view the specific situation of structural changes.
393
+ # v2.1.3, 7th written Mar 5, 2023. Bug fixes & program optimization. Eliminate potentially erroneous data.
394
+ # v2.1.4, 8th written Mar 27, 2023. Program optimization.
395
+ # ...
0 commit comments