mdkits 0.1a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mdkits might be problematic. Click here for more details.

mdkits/cli/convert.py ADDED
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from ase.io import write
4
+ import click
5
+ import os
6
+ from mdtool.util import encapsulated_ase, arg_type
7
+
8
+
9
+ @click.command(name='convert')
10
+ @click.option('-c', help='covert to cif', is_flag=True)
11
+ @click.option('-x', help='covert to xyz', is_flag=True)
12
+ @click.option('-d', help='covert to lammps data file', is_flag=True)
13
+ @click.option('-v', help='covert to vasp', is_flag=True)
14
+ @click.option('--coord', help='coord format', is_flag=True)
15
+ @click.option('--cp2k', help='convert to cp2k format(coord + cell)', is_flag=True)
16
+ @click.option('--center', help='center atoms', is_flag=True)
17
+ @click.option('--cell', type=arg_type.Cell, help='set cell from cp2k input file or a list of lattice: --cell x,y,z or x,y,z,a,b,c', default='input.inp', show_default=True)
18
+ @click.option('-o', type=str, help='specify the output file name without suffix', default='out', show_default=True)
19
+ @click.argument('file_name', type=click.Path(exists=True))
20
+ def main(c, x, d, v, coord, cp2k, center, cell, o, file_name):
21
+ """
22
+ convet structure file in some formats
23
+ """
24
+ atoms = encapsulated_ase.atoms_read_with_cell(file_name, cell=cell, coord_mode=coord)
25
+
26
+ if center:
27
+ atoms.center()
28
+
29
+ if c:
30
+ o += '.cif'
31
+ write(o, atoms, format='cif')
32
+
33
+ if x:
34
+ o += '.xyz'
35
+ write(o, atoms, format='extxyz')
36
+
37
+ if d:
38
+ o += '.data'
39
+ write(o, atoms, format='lammps-data', atom_style='atomic')
40
+
41
+ if v:
42
+ o = 'POSCAR'
43
+ write(o, atoms, format='vasp')
44
+
45
+
46
+ if cp2k:
47
+ o = 'coord.xyz'
48
+ write(o, atoms, format='xyz')
49
+ with open(o, 'r') as f:
50
+ lines = f.readlines()
51
+ with open(o, 'w') as f:
52
+ f.writelines(lines[2:])
53
+ with open('cell.inc', 'w') as f:
54
+ cell = atoms.cell.cellpar()
55
+ f.write(f"ABC [angstrom] {cell[0]} {cell[1]} {cell[2]}\n")
56
+ f.write(f"ALPHA_BETA_GAMMA {cell[3]} {cell[4]} {cell[5]}\n")
57
+
58
+
59
+ print(os.path.abspath(o))
60
+
61
+
62
+ if __name__ == '__main__':
63
+ main()
@@ -0,0 +1,479 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # is to generate cp2k input file
4
+ import argparse
5
+ import shutil
6
+ import os
7
+ from ase.io import read, write
8
+ from pymatgen.core.structure import Structure
9
+ from pymatgen.io.cp2k.inputs import (
10
+ Cp2kInput,
11
+ Section,
12
+ Keyword,
13
+ Cell,
14
+ Coord,
15
+ Kind
16
+ )
17
+
18
+
19
+ def insert_section(strs, section_name, section):
20
+
21
+ # to insert subsection to a high level section
22
+ insert = Cp2kInput.from_str(strs)
23
+ section.insert(insert.get_section(section_name))
24
+
25
+ return section
26
+
27
+
28
+ def add_keyword(keyword, section):
29
+
30
+ # to add keyword in a section
31
+ section.add(Keyword.from_str(keyword))
32
+
33
+
34
+ def Global(
35
+ run_type="ENEGRY",
36
+ project_name="cp2k",
37
+ print_level="MEDIUM",
38
+ walltime=107000
39
+ ):
40
+
41
+ # global section
42
+ Global = Section("GLOBAL")
43
+
44
+ add_keyword(f"RUN_TYPE {run_type}", Global)
45
+ add_keyword(f"PROJECT_NAME {project_name}", Global)
46
+ add_keyword(f"PRINT_LEVEL {print_level}", Global)
47
+ add_keyword(f"WALLTIME {walltime}", Global)
48
+
49
+ return Global
50
+
51
+
52
+ def motion(
53
+ constraint_list=None,
54
+ cell_opt=False,
55
+ geo_opt=False
56
+ ):
57
+
58
+ # motion section
59
+ motion = Section("MOTION")
60
+
61
+ ## constraint subsection
62
+ if constraint_list != None:
63
+ strs = f"""
64
+ &CONSTRAINT
65
+ &FIXED_ATOMS
66
+ LIST {constraint_list}
67
+ &END FIXED_ATOMS
68
+ &END CONSTRAINT
69
+ """
70
+ insert_section(strs, "CONSTRAINT", motion)
71
+
72
+ ## cell_opt subsection
73
+ if cell_opt:
74
+ strs = f"""
75
+ &CELL_OPT
76
+ OPTIMIZER BFGS
77
+ MAX_ITER 200
78
+ &END CELL_OPT
79
+ """
80
+ insert_section(strs, "CELL_OPT", motion)
81
+
82
+ ## geo_opt subsection
83
+ if geo_opt:
84
+ strs = f"""
85
+ &GEO_OPT
86
+ TYPE MINIMIZATION
87
+ OPTIMIZER BFGS
88
+ MAX_ITER 500
89
+ &END GEO_OPT
90
+ """
91
+ insert_section(strs, "GEO_OPT", motion)
92
+
93
+ return motion
94
+
95
+
96
+ def force_eval(
97
+ structure,
98
+ method="QUICKSTEP",
99
+ data_path="/public/software/cp2k-2022.1-intel/cp2k-2022.1/data",
100
+ charge=None,
101
+ ot=False,
102
+ hse=False
103
+ ):
104
+
105
+ # force_eval section
106
+ force_eval = Section("FORCE_EVAL")
107
+ add_keyword(f"METHOD {method}", force_eval)
108
+
109
+ ## dft subsection
110
+ dft = Section("DFT")
111
+ add_keyword(f"BASIS_SET_FILE_NAME {data_path}/BASIS_MOLOPT", dft)
112
+ add_keyword(f"POTENTIAL_FILE_NAME {data_path}/GTH_POTENTIALS", dft)
113
+ if isinstance(charge, int):
114
+ dft.add_keyword(f"CHARGE {charge}", dft)
115
+
116
+ ### mgrid subsubsection
117
+ strs = """
118
+ &MGRID
119
+ CUTOFF 400
120
+ &END MGRID
121
+ """
122
+ insert_section(strs, "MGRID", dft)
123
+
124
+ ### qs subsubsection
125
+ strs = """
126
+ &QS
127
+ EPS_DEFAULT 1.0E-13
128
+ EXTRAPOLATION ASPC
129
+ EXTRAPOLATION_ORDER 2
130
+ &END QS
131
+ """
132
+ insert_section(strs, "QS", dft)
133
+
134
+ ### scf subsubsection
135
+ if ot:
136
+ strs = """
137
+ &SCF
138
+ SCF_GUESS RESTART
139
+ EPS_SCF 3.0E-6
140
+ MAX_SCF 50
141
+
142
+ &OUTER_SCF
143
+ EPS_SCF 3.0E-6
144
+ MAX_SCF 20
145
+ &END OUTER_SCF
146
+
147
+ &OT
148
+ MINIMIZER DIIS
149
+ PRECONDITIONER FULL_SINGLE_INVERSE
150
+ &END OT
151
+ &END SCF
152
+ """
153
+ insert_section(strs, dft)
154
+ else:
155
+ strs = """
156
+ &SCF
157
+ SCF_GUESS RESTART
158
+ EPS_SCF 3.0E-7
159
+ MAX_SCF 500
160
+ ADDED_MOS 500
161
+ CHOLESKY INVERSE
162
+
163
+ &SMEAR ON
164
+ METHOD FERMI_DIRAC
165
+ &END SMEAR
166
+
167
+ &DIAGONALIZATION
168
+ ALGORITHM STANDARD
169
+ &END DIAGONALIZATION
170
+
171
+ &MIXING
172
+ METHOD BROYDEN_MIXING
173
+ ALPHA 0.15
174
+ BETA 1.0
175
+ NBROYDEN 16
176
+ &END MIXING
177
+
178
+ &PRINT
179
+
180
+ &RESTART
181
+ ADD_LAST NUMERIC
182
+
183
+ &EACH
184
+ QS_SCF 50
185
+ &END EACH
186
+ &END RESTART
187
+ &END PRINT
188
+ &END SCF
189
+ """
190
+ insert_section(strs, "SCF", dft)
191
+
192
+ ### xc subsubsection
193
+ if hse:
194
+ strs = f"""
195
+ &XC
196
+
197
+ &VDW_POTENTIAL
198
+ DISPERSION_FUNCTIONAL PAIR_POTENTIAL
199
+
200
+ &PAIR_POTENTIAL
201
+ TYPE DFTD3
202
+ PARAMETER_FILE_NAME {data_path}/dftd3.dat
203
+ REFERENCE_FUNCTIONAL PBE
204
+ &END PAIR_POTENTIAL
205
+ &END VDW_POTENTIAL
206
+
207
+ &XC_FUNCTIONAL
208
+
209
+ &XWPBE
210
+ SCALE_X -0.25
211
+ SCALE_X0 1.0
212
+ OMEGA 0.11
213
+ &END XWPBE
214
+
215
+ &PBE
216
+ SCALE_X 0.0
217
+ SCALE_C 1.0
218
+ &END PBE
219
+ &END XC_FUNCTIONAL
220
+
221
+ &HF
222
+ FRACTION 0.25
223
+
224
+ &INTERACTION_POTENTIAL
225
+ POTENTIAL_TYPE SHORTRANGE
226
+ OMEGA 0.11
227
+ T_C_G_DATA
228
+ &END INTERACTION_POTENTIAL
229
+
230
+ &SCREENING
231
+ EPS_SCHWARZ 1.0E-6
232
+ SCREEN_ON_INITIAL_P .FALSE.
233
+ &END SCREENING
234
+
235
+ &MEMORY
236
+ MAX_MEMORY 3000
237
+ EPS_STORAGE_SCALING 0.1
238
+ &END MEMORY
239
+
240
+ &PERIODIC
241
+ NUMPER_OF_SHELLS 0
242
+ &END PERIODIC
243
+ &END HF
244
+ &END XC
245
+ """
246
+ insert_section(strs, "XC", dft)
247
+ else:
248
+ strs = f"""
249
+ &XC
250
+
251
+ &XC_FUNCTIONAL PBE
252
+ &END XC_FUNCTIONAL
253
+
254
+ &VDW_POTENTIAL
255
+ DISPERSION_FUNCTIONAL PAIR_POTENTIAL
256
+
257
+ &PAIR_POTENTIAL
258
+ TYPE DFTD3
259
+ PARAMETER_FILE_NAME {data_path}/dftd3.dat
260
+ REFERENCE_FUNCTIONAL PBE
261
+ &END PAIR_POTENTIAL
262
+ &END VDW_POTENTIAL
263
+ &END XC
264
+ """
265
+ insert_section(strs, "XC", dft)
266
+
267
+ ### print subsubsection
268
+ strs = """
269
+ &PRINT
270
+
271
+ &E_DENSITY_CUBE
272
+ ADD_LAST NUMERIC
273
+
274
+ &EACH
275
+ GEO_OPT 0
276
+ &END EACH
277
+ &END E_DENSITY_CUBE
278
+
279
+ &PDOS
280
+ COMPONENTS .TRUE.
281
+ NLUMO -1
282
+ ADD_LAST NUMERIC
283
+
284
+ &EACH
285
+ MD 50
286
+ GEO_OPT 0
287
+ &END EACH
288
+ &END PDOS
289
+
290
+ &MO_CUBES
291
+ NHOMO 5
292
+ NLUMO 5
293
+ WRITE_CUBE F
294
+ ADD_LAST NUMERIC
295
+
296
+ &EACH
297
+ MD 50
298
+ GEO_OPT 0
299
+ &END EACH
300
+ &END MO_CUBES
301
+
302
+ &V_HARTREE_CUBE ON
303
+ STRIDE 8 8 1
304
+ APPEND T
305
+
306
+ &EACH
307
+ MD 50
308
+ GEO_OPT 0
309
+ &END EACH
310
+ &END V_HARTREE_CUBE
311
+ &END PRINT
312
+ """
313
+ insert_section(strs, "PRINT", dft)
314
+
315
+ force_eval.insert(dft)
316
+
317
+ ## subsys subsection
318
+ subsys = Section("SUBSYS")
319
+
320
+ ### cell subsubsection
321
+ cell = Cell(structure.lattice)
322
+ subsys.insert(cell)
323
+
324
+ ### coord subsubsection
325
+ coord = Section("COORD")
326
+ add_keyword("@INCLUDE ./coord.xyz", coord)
327
+ subsys.insert(coord)
328
+
329
+ ### kind subsubsection
330
+ for atom in structure.species:
331
+ kind = Kind(atom, basis_set=None, potential=None)
332
+ subsys.insert(kind)
333
+
334
+ force_eval.insert(subsys)
335
+
336
+
337
+ return force_eval
338
+
339
+
340
+ parser = argparse.ArgumentParser(description='generate cp2k input file')
341
+ parser.add_argument('input_file_name', type=str, help='input file name')
342
+ parser.add_argument('--cell', nargs="+", help='set cell, a list of lattice, [x, y, z] or [x, y, z, a, b, c]')
343
+ parser.add_argument('--bp', type=str, nargs="?", default=None, help='a file contains all basis_set and potential information')
344
+ ## function args of golbal
345
+ parser.add_argument('--run_type', type=str, nargs="?", default="ENEGRY", help='specie run_type keyword of global')
346
+ parser.add_argument('--project_name', type=str, nargs="?", default="cp2k", help='specie project_name keyword of global')
347
+ parser.add_argument('--print_level', type=str, nargs="?", default="MEDIUM", help='specie print_level keyword of global')
348
+ parser.add_argument('--walltime', type=int, nargs="?", default=107000, help='specie walltime keyword of global')
349
+ ## function args of motion
350
+ parser.add_argument('--constraint_list', type=str, nargs="?", default=None, help='specie constranit_list keyword of motion')
351
+ parser.add_argument('--cell_opt', type=bool, nargs="?", default=False, help='specie cell_opt section of motion')
352
+ parser.add_argument('--geo_opt', type=bool, nargs="?", default=False, help='specie geo_opt section of motion')
353
+ ## function args of force_eval
354
+ parser.add_argument('--method', type=str, nargs="?", default="QUICKSTEP", help='specie methon keyword of force_eval')
355
+ parser.add_argument('--charge', type=int, nargs="?", default=None, help='specie charge keyword of force_eval')
356
+ parser.add_argument('--ot', type=bool, nargs="?", default=False, help='specie scf type is ot(else is smear) of force_eval')
357
+ parser.add_argument('--hse', type=bool, nargs="?", default=False, help='specie xc type is hse(else is pbe) of force_eval')
358
+ args = parser.parse_args()
359
+
360
+
361
+
362
+ if args.input_file_name[-3:] == "xyz":
363
+ with open(args.input_file_name, 'r') as f:
364
+ data = f.readline().strip()
365
+ if not isinstance(int(data), int):
366
+ atom_number = sum(1 for line in f if line.strip)
367
+
368
+ add_line = f"{int(atom_number+1)}\n\n"
369
+ with open(args.input_file_name, 'r') as g:
370
+ gile = g.readlines()
371
+ gile.insert(0, add_line)
372
+ with open(args.input_file_name, 'w') as g:
373
+ g.writelines(gile)
374
+
375
+ if args.bp == None:
376
+ bp_dict = {
377
+ 'Pt': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q18'],
378
+ 'O': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q6'],
379
+ 'C': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q4'],
380
+ 'Cs': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q9'],
381
+ 'Li': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q3'],
382
+ 'Ne': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q8'],
383
+ 'Ru': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q16'],
384
+ 'Ag': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q11'],
385
+ 'Ir': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q17'],
386
+ 'C': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q4'],
387
+ 'H': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q1'],
388
+ 'F': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q7'],
389
+ 'Na': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q9'],
390
+ 'K': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q9'],
391
+ 'Cl': ['DZVP-MOLOPT-SR-GTH', 'GTH-PBE-q7']
392
+ }
393
+ else:
394
+ bp_dict = {}
395
+ with open(args.bp, 'r') as f:
396
+ for line in f:
397
+ key, value1, value2 = line.strip().split()
398
+ bp_dict[key] = [value1, value2]
399
+
400
+
401
+ if args.input_file_name[-3:] == "cif":
402
+ atoms = read(args.input_file_name)
403
+ atoms.write("POSCAR")
404
+ structure = Structure.from_file("POSCAR")
405
+ os.remove("POSCAR")
406
+
407
+ elif args.input_file_name[-3:] == "xyz":
408
+ atoms = read(args.input_file_name, format="xyz")
409
+ atoms.set_cell(args.cell)
410
+ atoms.write("POSCAR", format="vasp")
411
+ structure = Structure.from_file("POSCAR")
412
+ os.remove("POSCAR")
413
+
414
+ Global = Global(
415
+ run_type=args.run_type,
416
+ project_name=args.project_name,
417
+ print_level=args.print_level,
418
+ walltime=args.walltime
419
+ )
420
+ motion = motion(
421
+ constraint_list=args.constraint_list,
422
+ cell_opt=args.cell_opt,
423
+ geo_opt=args.geo_opt
424
+ )
425
+ force_eval = force_eval(
426
+ structure,
427
+ method=args.method,
428
+ charge=args.charge,
429
+ ot=args.ot,
430
+ hse=args.hse
431
+ )
432
+
433
+ used_bp_dict = {}
434
+ for atom in structure.species:
435
+ if str(atom) in bp_dict:
436
+ used_bp_dict[str(atom)] = bp_dict[str(atom)]
437
+
438
+ for key, value in used_bp_dict.items():
439
+ print(key, value)
440
+ add_keyword(f"BASIS_SET {value[0]}", force_eval.by_path(f"SUBSYS/{key}"))
441
+ add_keyword(f"POTENTIAL {value[1]}", force_eval.by_path(f"SUBSYS/{key}"))
442
+
443
+ if args.input_file_name[-3:] == "cif":
444
+ atoms = read(args.input_file_name)
445
+ atoms.write("temp.xyz")
446
+ with open("temp.xyz", 'r') as f:
447
+ coord = ''
448
+ for i, line in enumerate(f):
449
+ if i < 2:
450
+ continue
451
+ coord += f" {' '.join(line.split()[0:4])}\n"
452
+
453
+ with open("coord.xyz", 'w') as f:
454
+ f.write(coord)
455
+ os.remove("temp.xyz")
456
+
457
+ elif args.input_file_name[-3:] == "xyz":
458
+ with open(args.input_file_name, 'r') as f:
459
+ coord = ''
460
+ for i, line in enumerate(f):
461
+ if i < 2:
462
+ continue
463
+ coord += f" {' '.join(line.split()[0:4])}\n"
464
+
465
+ with open("coord.xyz", 'w') as f:
466
+ f.write(coord)
467
+
468
+
469
+ inp = Cp2kInput.from_str(
470
+ Global.get_str()+
471
+ motion.get_str()+
472
+ force_eval.get_str()
473
+ )
474
+ inp.write_file("input.inp")
475
+
476
+
477
+ # copy sub script
478
+ sub_script_path = "/public/home/jxxcr/script/sub_cp2k"
479
+ shutil.copy2(sub_script_path, ".")
mdkits/cli/cube.py ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env python3
2
+
3
+ ################################################
4
+ # averange cp2k output(or some else file correspond to ase.io.read_cube_data) hartree.cube to z coordinate with python
5
+ ## file path is need to pay attention
6
+ ## cycle parameter is need to pay attention
7
+ ## buck range is need to pay attention
8
+ ################################################
9
+
10
+ from numpy import empty, array, mean, append, concatenate
11
+ from argparse import ArgumentParser
12
+ from util import encapsulated_ase, os_operation
13
+
14
+
15
+ def array_type(string):
16
+ number_list = string.split(',')
17
+ number_array = array(number_list, dtype=float)
18
+ return number_array
19
+
20
+
21
+ def buck_potential(xaxe, potential, range):
22
+ mix = concatenate((xaxe.reshape(-1, 1), potential.reshape(-1, 1)), axis=1)
23
+ mask = (mix[:,0] >= range[0]) & (mix[:,0] <=range[1])
24
+ buck_potential = mix[mask]
25
+ ave_potential = mean(buck_potential[:,1])
26
+ return ave_potential
27
+
28
+
29
+ # set argument
30
+ parser = ArgumentParser(description='to handle cp2k output file hartree cube, name should be "hartree-*.cube"')
31
+ parser.add_argument('file_name', type=str, nargs='?', help='hartree cube file', default=os_operation.default_file_name('*-v_hartree-1_*.cube', last=True))
32
+ parser.add_argument('-b', '--buck_range', type=array_type, help='parameter to calculate mean value of buck', default=None)
33
+ parser.add_argument('-o', type=str, help='output file name, default is "out.put"', default='hartree.out')
34
+
35
+ args = parser.parse_args()
36
+
37
+
38
+ ## init output potential file's shape, and define a z axe
39
+ init_array = encapsulated_ase.ave_potential(args.file_name)
40
+ potential = empty((0, init_array[0].shape[0]))
41
+ z_coordinates = array((init_array[1])).reshape(-1, 1)
42
+
43
+ potential = encapsulated_ase.ave_potential(args.file_name)[0]
44
+
45
+ aved = mean(potential, axis=0)
46
+ total_potential = append(z_coordinates, potential.reshape(-1, 1), axis=1)
47
+
48
+ ## if buck range is exit, out put a difference of potential
49
+ if args.buck_range is not None:
50
+ buck_potential = buck_potential(z_coordinates, potential, args.buck_range)
51
+ print(buck_potential)
52
+ with open('hartree_potential.dat', 'w') as f:
53
+ f.write(f"{buck_potential}" + '\n')
54
+
55
+ ## write output
56
+ with open(args.o, 'w') as f:
57
+ for value in total_potential:
58
+ f.write(" ".join(map(str, value)) + '\n')
59
+
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env python3
2
+
3
+ from ase import io, build
4
+ import argparse
5
+ from util import encapsulated_ase
6
+
7
+
8
+ def parse_size(s):
9
+ return [int(x) for x in s.replace(',', ' ').split()]
10
+
11
+ def parse_size1(s):
12
+ return [float(x) for x in s.replace(',', ' ').split()]
13
+
14
+
15
+ def parse_argument():
16
+ parser = argparse.ArgumentParser(description='cut surface of structure')
17
+ parser.add_argument('filename', type=str, help='init structure filename')
18
+ parser.add_argument('--face', type=parse_size, help='face index')
19
+ parser.add_argument('--vacuum', type=float, help='designate vacuum of surface, default is None', default=0.0)
20
+ parser.add_argument('--size', type=parse_size, help='surface size')
21
+ parser.add_argument('--coord', help='coord format', action='store_true')
22
+ parser.add_argument('--cell', type=parse_size1, help='set xyz file cell, --cell x,y,z,a,b,c')
23
+
24
+ return parser.parse_args()
25
+
26
+
27
+ def main():
28
+ args = parse_argument()
29
+ atoms = encapsulated_ase.atoms_read_with_cell(args.filename, cell=args.cell, coord_mode=args.coord)
30
+ surface = build.surface(atoms, args.face, args.size[2], vacuum=args.vacuum/2)
31
+ super_cell = [[args.size[0], 0, 0], [0, args.size[1], 0], [0, 0, 1]]
32
+ super_surface = build.make_supercell(surface, super_cell)
33
+
34
+ super_surface.write(f"{args.filename.split('.')[-2].split('/')[-1]}_{args.face[0]}{args.face[1]}{args.face[2]}.cif")
35
+
36
+
37
+ if __name__ == '__main__':
38
+ main()