| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 
 | from pymatgen import Structure,Elementimport numpy as np
 
 def atom_selection(struct,in_str=None):
 r'''
 select atoms by three different schemes:
 1. by atomic index
 2. by element symbol
 3. by fractional coordinates range
 '''
 tip="""
 select atoms by following ways:
 1. atomic index in POSCAR
 i.e. :  1 2 4-8 10 12-30
 i.e. :  1 2 4 8 10
 2. atomic label
 i.e. :  Si  O
 3. atomic position
 i.e. :  0 0.5 | 0.2 0.4 | 0.3 0.7
 this means atoms with 0<x<0.5,
 0.2<y<0.4 and 0.3<z<0.7 will be seleted
 or just specific the z coordinates,
 i.e. :  ||0.3 0.7
 """
 print(tip)
 
 def parse_index(in_str):
 atom_index=[]
 tmp_str=in_str.split()
 
 for i in tmp_str:
 if '-' not in i:
 atom_index.append(int(i))
 else:
 atom_index.extend(range(int(i.split('-')[0]),int(i.split('-')[1])+1))
 return [i-1 for i in atom_index]
 
 def parse_label(in_str):
 atom_label= [Element(elem) for elem in in_str.split()]
 
 atom_index=[]
 for i, site in enumerate(struct.sites):
 if site.specie in atom_label:
 atom_index.append(i)
 return atom_index
 
 def parse_range(in_str):
 
 def check_frac(coord,lim):
 con=[False]*3
 for i in range(3):
 con[i]=coord[i]>=lim[i][0] and coord[i]<=lim[i][1]
 if np.all(con):
 return True
 else:
 return False
 
 coord_range={}
 tmp_str=in_str.split();tmp1_str=' '.join(tmp_str);tmp2_str=tmp1_str.split("|")
 
 icount=0
 for i in tmp2_str:
 
 if i=='':
 coord_range[icount]=''
 else:
 coord_range[icount]=[float(x) for x in i.split()]
 icount+=1
 for key in coord_range.keys():
 if coord_range[key]=='':
 coord_range[key]=[0,1]
 atom_index=[]
 for i, site in enumerate(struct.sites):
 if check_frac(site.frac_coords,coord_range):
 atom_index.append(i)
 return atom_index
 
 if "|" in in_str.strip():
 atom_index_list=parse_range(in_str)
 else:
 for str in in_str.strip():
 if str.isalpha():
 atom_index_list=parse_label(in_str)
 return atom_index_list,in_str
 atom_index_list=parse_index(in_str)
 
 
 
 
 
 
 return atom_index_list,in_str
 
 def constrain(struct,in_str=None):
 natom=struct.num_sites
 atom_index,in_str=atom_selection(struct,in_str)
 selective_dynamics=[[True for col in range(3)] for row in range(natom)]
 for i in range(natom):
 if i in atom_index:
 selective_dynamics[i]=[False,False,False]
 tmp_struct=Structure(struct.lattice,struct.species,struct.frac_coords,site_properties={'selective_dynamics':selective_dynamics})
 return tmp_struct
 if __name__=='__main__':
 from pymatgen.io.vasp import Poscar
 st=Structure.from_file('L1-Te2.vasp')
 in_str='||0.0 0.5'
 cst=constrain(st,in_str=in_str)
 poscar=Poscar(cst)
 print(st)
 print(poscar)
 poscar.comment=poscar.comment+' |--> '+in_str
 poscar.write_file('Fixed.vasp')
 
 |