def test_int_gen(self): struc = PymatgenTest.get_structure("VO2") int_gen = InterstitialGenerator(struc, "Li") ints = list(int_gen) self.assertEqual(len(ints), 4) multiplicities = [i.multiplicity for i in ints] self.assertEqual(multiplicities, [8, 8, 4, 4]) self.assertEqual(str(ints[0].site.specie), "Li") self.assertEqual(str(ints[1].site.specie), "Li") self.assertArrayAlmostEqual(ints[0].site.coords, (0.9106, 0.3078, 0.3078), decimal=4) self.assertArrayAlmostEqual(ints[1].site.coords, (1.5177, 1.7444, 0.3078,), decimal=4)
def _make_lammps(jdata, conf_dir, supercell, insert_ele, task_type): fp_params = jdata['vasp_params'] kspacing = fp_params['kspacing'] fp_params = jdata['lammps_params'] model_dir = fp_params['model_dir'] type_map = fp_params['type_map'] model_dir = os.path.abspath(model_dir) model_name = fp_params['model_name'] if not model_name and task_type == 'deepmd': models = glob.glob(os.path.join(model_dir, '*pb')) model_name = [os.path.basename(ii) for ii in models] assert len(model_name) > 0, "No deepmd model in the model_dir" else: models = [os.path.join(model_dir, ii) for ii in model_name] model_param = { 'model_name': fp_params['model_name'], 'param_type': fp_params['model_param_type'] } ntypes = len(type_map) conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') # get equi poscar equi_path = re.sub('confs', global_equi_name, conf_path) equi_path = os.path.join(equi_path, 'vasp-k%.2f' % kspacing) equi_contcar = os.path.join(equi_path, 'CONTCAR') #equi_path = os.path.join(equi_path, task_type) #equi_dump = os.path.join(equi_path, 'dump.relax') assert os.path.exists( equi_contcar), "Please compute the equilibrium state using vasp first" task_path = re.sub('confs', global_task_name, conf_path) task_path = os.path.join(task_path, task_type) os.makedirs(task_path, exist_ok=True) task_poscar = os.path.join(task_path, 'POSCAR') cwd = os.getcwd() os.chdir(task_path) if os.path.isfile('POSCAR'): os.remove('POSCAR') os.symlink(os.path.relpath(equi_contcar), 'POSCAR') #lammps.poscar_from_last_dump(equi_dump, task_poscar, type_map) os.chdir(cwd) # gen structure from equi poscar print("task poscar: ", task_poscar) ss = Structure.from_file(task_poscar) # gen defects vds = InterstitialGenerator(ss, insert_ele) dss = [] for jj in vds: dss.append(jj.generate_defect_structure(supercell)) # gen tasks cwd = os.getcwd() # make lammps.in, relax at 0 bar (scale = 1) if task_type == 'deepmd': fc = lammps.make_lammps_press_relax('conf.lmp', ntypes, 1, lammps.inter_deepmd, model_name) elif task_type == 'meam': fc = lammps.make_lammps_press_relax('conf.lmp', ntypes, 1, lammps.inter_meam, model_param) f_lammps_in = os.path.join(task_path, 'lammps.in') with open(f_lammps_in, 'w') as fp: fp.write(fc) # gen tasks copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) cwd = os.getcwd() if task_type == 'deepmd': os.chdir(task_path) for ii in model_name: if os.path.exists(ii): os.remove(ii) for (ii, jj) in zip(models, model_name): os.symlink(os.path.relpath(ii), jj) share_models = glob.glob(os.path.join(task_path, '*pb')) else: share_models = models for ii in range(len(dss)): struct_path = os.path.join( task_path, 'struct-%s-%s-%03d' % (insert_ele, copy_str, ii)) print('# generate %s' % (struct_path)) os.makedirs(struct_path, exist_ok=True) os.chdir(struct_path) for jj in ['conf.lmp', 'lammps.in'] + model_name: if os.path.isfile(jj): os.remove(jj) # make conf dss[ii].to('POSCAR', 'POSCAR') lammps.cvt_lammps_conf('POSCAR', 'conf.lmp') ptypes = vasp.get_poscar_types('POSCAR') lammps.apply_type_map('conf.lmp', type_map, ptypes) # link lammps.in os.symlink(os.path.relpath(f_lammps_in), 'lammps.in') # link models for (ii, jj) in zip(share_models, model_name): os.symlink(os.path.relpath(ii), jj) # save supercell np.savetxt('supercell.out', supercell, fmt='%d') os.chdir(cwd)
def _make_vasp(jdata, conf_dir, supercell, insert_ele): fp_params = jdata['vasp_params'] ecut = fp_params['ecut'] ediff = fp_params['ediff'] npar = fp_params['npar'] kpar = fp_params['kpar'] kspacing = fp_params['kspacing'] kgamma = fp_params['kgamma'] conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') # get equi poscar equi_path = re.sub('confs', global_equi_name, conf_path) equi_path = os.path.join(equi_path, 'vasp-k%.2f' % kspacing) equi_contcar = os.path.join(equi_path, 'CONTCAR') assert os.path.exists( equi_contcar), "Please compute the equilibrium state using vasp first" task_path = re.sub('confs', global_task_name, conf_path) task_path = os.path.join(task_path, 'vasp-k%.2f' % kspacing) os.makedirs(task_path, exist_ok=True) cwd = os.getcwd() os.chdir(task_path) if os.path.isfile('POSCAR'): os.remove('POSCAR') os.symlink(os.path.relpath(equi_contcar), 'POSCAR') os.chdir(cwd) task_poscar = os.path.join(task_path, 'POSCAR') # gen strcture print("task poscar: ", task_poscar) ss = Structure.from_file(task_poscar) # gen defects vds = InterstitialGenerator(ss, insert_ele) dss = [] for jj in vds: dss.append(jj.generate_defect_structure(supercell)) # gen incar fc = vasp.make_vasp_relax_incar(ecut, ediff, True, True, True, npar=npar, kpar=kpar, kspacing=kspacing, kgamma=kgamma) with open(os.path.join(task_path, 'INCAR'), 'w') as fp: fp.write(fc) # gen tasks copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) cwd = os.getcwd() for ii in range(len(dss)): struct_path = os.path.join( task_path, 'struct-%s-%s-%03d' % (insert_ele, copy_str, ii)) print('# generate %s' % (struct_path)) os.makedirs(struct_path, exist_ok=True) os.chdir(struct_path) for jj in ['POSCAR', 'POTCAR', 'INCAR']: if os.path.isfile(jj): os.remove(jj) # make conf dss[ii].to('POSCAR', 'POSCAR') # gen potcar with open('POSCAR', 'r') as fp: lines = fp.read().split('\n') ele_list = lines[5].split() os.chdir(cwd) potcar_map = jdata['potcar_map'] potcar_list = [] for ii in ele_list: assert os.path.exists(os.path.abspath( potcar_map[ii])), "No POTCAR in the potcar_map of %s" % (ii) potcar_list.append(os.path.abspath(potcar_map[ii])) os.chdir(struct_path) with open('POTCAR', 'w') as outfile: for fname in potcar_list: with open(fname) as infile: outfile.write(infile.read()) # link incar os.symlink(os.path.relpath(os.path.join(task_path, 'INCAR')), 'INCAR') # save supercell np.savetxt('supercell.out', supercell, fmt='%d') os.chdir(cwd)
def _make_meam_lammps(jdata, conf_dir, supercell, insert_ele, task_name): meam_potfile_dir = jdata['meam_potfile_dir'] meam_potfile_dir = os.path.abspath(meam_potfile_dir) meam_potfile = jdata['meam_potfile'] meam_potfile = [os.path.join(meam_potfile_dir, ii) for ii in meam_potfile] meam_potfile_name = jdata['meam_potfile'] type_map = jdata['meam_type_map'] ntypes = len(type_map) meam_param = { 'meam_potfile': jdata['meam_potfile'], 'meam_type': jdata['meam_param_type'] } conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') # get equi poscar equi_path = re.sub('confs', global_equi_name, conf_path) equi_path = os.path.join(equi_path, task_name) equi_dump = os.path.join(equi_path, 'dump.relax') task_path = re.sub('confs', global_task_name, conf_path) task_path = os.path.join(task_path, task_name) os.makedirs(task_path, exist_ok=True) task_poscar = os.path.join(task_path, 'POSCAR') cwd = os.getcwd() os.chdir(task_path) lammps.poscar_from_last_dump(equi_dump, task_poscar, type_map) os.chdir(cwd) # gen structure from equi poscar ss = Structure.from_file(task_poscar) # gen defects vds = InterstitialGenerator(ss, insert_ele) dss = [] for jj in vds: dss.append(jj.generate_defect_structure(supercell)) # gen tasks cwd = os.getcwd() # make lammps.in, relax at 0 bar (scale = 1) fc = lammps.make_lammps_press_relax('conf.lmp', ntypes, 1, lammps.inter_meam, meam_param) f_lammps_in = os.path.join(task_path, 'lammps.in') with open(f_lammps_in, 'w') as fp: fp.write(fc) # gen tasks copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) cwd = os.getcwd() for ii in range(len(dss)): struct_path = os.path.join( task_path, 'struct-%s-%s-%03d' % (insert_ele, copy_str, ii)) print('# generate %s' % (struct_path)) os.makedirs(struct_path, exist_ok=True) os.chdir(struct_path) for jj in ['conf.lmp', 'lammps.in'] + meam_potfile_name: if os.path.isfile(jj): os.remove(jj) # make conf dss[ii].to('POSCAR', 'POSCAR') lammps.cvt_lammps_conf('POSCAR', 'conf.lmp') ptypes = vasp.get_poscar_types('POSCAR') lammps.apply_type_map('conf.lmp', type_map, ptypes) # link lammps.in os.symlink(os.path.relpath(f_lammps_in), 'lammps.in') # link models for (ii, jj) in zip(meam_potfile, meam_potfile_name): os.symlink(os.path.relpath(ii), jj) # save supercell np.savetxt('supercell.out', supercell, fmt='%d') os.chdir(cwd)
def _make_vasp(jdata, conf_dir, supercell, insert_ele): fp_params = jdata['vasp_params'] ecut = fp_params['ecut'] ediff = fp_params['ediff'] npar = fp_params['npar'] kpar = fp_params['kpar'] kspacing = fp_params['kspacing'] kgamma = fp_params['kgamma'] conf_path = os.path.abspath(conf_dir) conf_poscar = os.path.join(conf_path, 'POSCAR') # get equi poscar equi_path = re.sub('confs', global_equi_name, conf_path) equi_path = os.path.join(equi_path, 'vasp-k%.2f' % kspacing) equi_contcar = os.path.join(equi_path, 'CONTCAR') task_path = re.sub('confs', global_task_name, conf_path) task_path = os.path.join(task_path, 'vasp-k%.2f' % kspacing) os.makedirs(task_path, exist_ok=True) cwd = os.getcwd() os.chdir(task_path) if os.path.isfile('POSCAR'): os.remove('POSCAR') os.symlink(os.path.relpath(equi_contcar), 'POSCAR') os.chdir(cwd) task_poscar = os.path.join(task_path, 'POSCAR') # gen strcture print("task poscar: ", task_poscar) ss = Structure.from_file(task_poscar) # gen defects vds = InterstitialGenerator(ss, insert_ele) dss = [] for jj in vds: dss.append(jj.generate_defect_structure(supercell)) # gen incar fc = vasp.make_vasp_relax_incar(ecut, ediff, True, True, True, 1, 1, kspacing=kspacing, kgamma=kgamma) with open(os.path.join(task_path, 'INCAR'), 'w') as fp: fp.write(fc) # gen tasks copy_str = "%sx%sx%s" % (supercell[0], supercell[1], supercell[2]) cwd = os.getcwd() for ii in range(len(dss)): struct_path = os.path.join( task_path, 'struct-%s-%s-%03d' % (insert_ele, copy_str, ii)) print('# generate %s' % (struct_path)) os.makedirs(struct_path, exist_ok=True) os.chdir(struct_path) for jj in ['POSCAR', 'POTCAR', 'INCAR']: if os.path.isfile(jj): os.remove(jj) # make conf dss[ii].to('POSCAR', 'POSCAR') # gen potcar _gen_potcar(jdata, 'POSCAR', 'POTCAR') # link incar os.symlink(os.path.relpath(os.path.join(task_path, 'INCAR')), 'INCAR') # save supercell np.savetxt('supercell.out', supercell, fmt='%d') os.chdir(cwd)
def make_confs(self, path_to_work, path_to_equi, refine=False): path_to_work = os.path.abspath(path_to_work) path_to_equi = os.path.abspath(path_to_equi) if 'start_confs_path' in self.parameter and os.path.exists( self.parameter['start_confs_path']): init_path_list = glob.glob( os.path.join(self.parameter['start_confs_path'], '*')) struct_init_name_list = [] for ii in init_path_list: struct_init_name_list.append(ii.split('/')[-1]) struct_output_name = path_to_work.split('/')[-2] assert struct_output_name in struct_init_name_list path_to_equi = os.path.abspath( os.path.join(self.parameter['start_confs_path'], struct_output_name, 'relaxation', 'relax_task')) task_list = [] cwd = os.getcwd() if self.reprod: print('interstitial reproduce starts') if 'init_data_path' not in self.parameter: raise RuntimeError( "please provide the initial data path to reproduce") init_data_path = os.path.abspath(self.parameter['init_data_path']) task_list = make_repro( init_data_path, self.init_from_suffix, path_to_work, self.parameter.get('reprod_last_frame', False)) os.chdir(cwd) else: if refine: print('interstitial refine starts') task_list = make_refine(self.parameter['init_from_suffix'], self.parameter['output_suffix'], path_to_work) init_from_path = re.sub( self.parameter['output_suffix'][::-1], self.parameter['init_from_suffix'][::-1], path_to_work[::-1], count=1)[::-1] task_list_basename = list(map(os.path.basename, task_list)) os.chdir(path_to_work) if os.path.isfile('element.out'): os.remove('element.out') if os.path.islink('element.out'): os.remove('element.out') os.symlink( os.path.relpath(os.path.join(init_from_path, 'element.out')), 'element.out') os.chdir(cwd) for ii in task_list_basename: init_from_task = os.path.join(init_from_path, ii) output_task = os.path.join(path_to_work, ii) os.chdir(output_task) if os.path.isfile('supercell.json'): os.remove('supercell.json') if os.path.islink('supercell.json'): os.remove('supercell.json') os.symlink( os.path.relpath( os.path.join(init_from_task, 'supercell.json')), 'supercell.json') os.chdir(cwd) else: equi_contcar = os.path.join(path_to_equi, 'CONTCAR') if not os.path.exists(equi_contcar): raise RuntimeError("please do relaxation first") ss = Structure.from_file(equi_contcar) # gen defects dss = [] insert_element_task = os.path.join(path_to_work, 'element.out') if os.path.isfile(insert_element_task): os.remove(insert_element_task) for ii in self.insert_ele: vds = InterstitialGenerator(ss, ii) for jj in vds: temp = jj.generate_defect_structure(self.supercell) smallest_distance = list( set(temp.distance_matrix.ravel()))[1] if 'conf_filters' in self.parameter and 'min_dist' in self.parameter[ 'conf_filters']: min_dist = self.parameter['conf_filters'][ 'min_dist'] if smallest_distance >= min_dist: dss.append(temp) with open(insert_element_task, 'a+') as fout: print(ii, file=fout) else: dss.append(temp) with open(insert_element_task, 'a+') as fout: print(ii, file=fout) # dss.append(jj.generate_defect_structure(self.supercell)) print('gen interstitial with supercell ' + str(self.supercell) + ' with element ' + str(self.insert_ele)) os.chdir(path_to_work) if os.path.isfile('POSCAR'): os.remove('POSCAR') if os.path.islink('POSCAR'): os.remove('POSCAR') os.symlink(os.path.relpath(equi_contcar), 'POSCAR') # task_poscar = os.path.join(output, 'POSCAR') for ii in range(len(dss)): output_task = os.path.join(path_to_work, 'task.%06d' % ii) os.makedirs(output_task, exist_ok=True) os.chdir(output_task) for jj in [ 'INCAR', 'POTCAR', 'POSCAR', 'conf.lmp', 'in.lammps' ]: if os.path.exists(jj): os.remove(jj) task_list.append(output_task) dss[ii].to('POSCAR', 'POSCAR') # np.savetxt('supercell.out', self.supercell, fmt='%d') dumpfn(self.supercell, 'supercell.json') os.chdir(cwd) return task_list
def generate_supercells( bulk_structure, grid_size = 4, supercell = (2, 2, 2), method = 'grid', positions=None ): """ This is a wrapper to various methods to generate different interstitial impurities. Parameters ---------- bulk_structure : Structure object A unitcell (magnetic or not) structure in form of Pymatgen Structure object grid_size : int A grid size in all lattice directions to generate uniform grid for interstitial impurities implemented by Pietro Bonfa. Default=4. supercell : tuple, numpy.ndarray Supercell size in a, b and c direction. Default = (2, 2, 2) method : str The method to generate interstial impurities. Default='grid' positions : None A numpy.ndarray of muon positions if `method="manual"`. Returns ------- structure_list : list A list of supercell structure containing interstitial impurities """ #magnetic_structure = CollinearMagneticStructureAnalyzer(bulk_structure, make_primitive=False) #if magnetic_structure.is_magnetic: # #spin_bulk_structure = magnetic_structure.get_structure_with_spin() # spin_bulk_structure = # spin_bulk_structure.make_supercell(supercell) site_properties_preservation = bulk_structure.copy() site_properties_preservation.make_supercell(supercell) structure_list = [] ## Manually set ? if method == 'manual': if positions is None: raise ValueError('Position must be specified in manual mode!') r = [] for position in positions: defect_site = PeriodicSite("H", position, bulk_structure.lattice, coords_are_cartesian=False) r.append(Interstitial(bulk_structure, defect_site, charge=0.)) elif method == 'tess': r = [] for position in tess_interstitials(bulk_structure): defect_site = PeriodicSite("H", position, bulk_structure.lattice, coords_are_cartesian=False) r.append(Interstitial(bulk_structure, defect_site, charge=0.)) elif method == 'infit': r = list(InterstitialGenerator( bulk_structure, 'H')) elif method == 'grid': r = [] for position in generate_uniform_grid(bulk_structure, grid_size): defect_site = PeriodicSite("H", position, bulk_structure.lattice, coords_are_cartesian=False) r.append(Interstitial(bulk_structure, defect_site, charge=0.)) else: r = list(VoronoiInterstitialGenerator( bulk_structure, 'H')) for i,v in enumerate(r): struct=v.generate_defect_structure(supercell=supercell) ## Preserve magnetic structure #if (magnetic_structure.is_magnetic): # spins = np.zeros(struct.num_sites) # # TODO: check non collinear... # for site1 in spin_bulk_structure: # for i, site2 in enumerate(struct): # if np.allclose(site1.coords, site2.coords, atol = site2.position_atol): # spins[i] = site1.specie.spin # break # # struct.add_spin_by_site(spins) for site1 in site_properties_preservation: for i, site2 in enumerate(struct): if np.allclose(site1.coords, site2.coords, atol = site2.position_atol): #spins[i] = site1.specie.spin struct[i].properties = site1.properties break # Remove symmetry if method != 'manual': # Here we assume, manual muon site are perturb. # Performs a random perturbation of the sites in the structure # to break symmetries. A distance of 1e-4 Angs. surely does nothing # However we can perturb the muon site with a random vector with # 0.1 Angs. distance struct.perturb(distance=0.0001) struct.translate_sites(-1, 0.1 * np.random.random(3), frac_coords=False) if struct.is_valid(): structure_list.append(struct) return structure_list
def __init__(self, structure, max_min_oxi=None, substitutions=None, oxi_states=None, cellmax=128, antisites_flag=True, include_interstitials=False, interstitial_elements=None, intersites=None, standardized=False, struct_type='semiconductor'): """ Args: structure (Structure): the bulk structure. max_min_oxi (dict): The minimal and maximum oxidation state of each element as a dict. For instance {"O":(-2,0)}. If not given, the oxi-states of pymatgen are considered. substitutions (dict): The allowed substitutions of elements as a dict. If not given, intrinsic defects are computed. If given, intrinsic (e.g., anti-sites) and extrinsic are considered explicitly specified. Example: {"Co":["Zn","Mn"]} means Co sites can be substituted by Mn or Zn. oxi_states (dict): The oxidation state of the elements in the compound e.g. {"Fe":2,"O":-2}. If not given, the oxidation state of each site is computed with bond valence sum. WARNING: Bond-valence method can fail for mixed-valence compounds. cellmax (int): Maximum number of atoms allowed in the supercell. antisites_flag (bool): If False, don't generate antisites. include_interstitials (bool): If true, do generate interstitial defect configurations (default: False). interstitial_elements ([str]): List of strings containing symbols of the elements that are to be considered for interstitial sites. The default (None) triggers self-interstitial generation, given that include_interstitials is True. intersites ([PeriodicSite]): A list of PeriodicSites in the bulk structure on which we put interstitials. Note that you still have to set flag include_interstitials to True in order to make use of this manual way of providing interstitial sites. If this is used, then no additional interstitials are generated beyond the list that is provided in intersites. standardized (bool): If True, use the primitive standard structure as unit cell for generating the defect configurations (default is False). The primitive standard structure is obtained from the SpacegroupAnalyzer class with a symprec of 0.01. struct_type (string): Options are 'semiconductor' and 'insulator'. If semiconductor is selected, charge states based on database of semiconductors is used to assign defect charges. For insulators, defect charges are conservatively assigned. """ max_min_oxi = max_min_oxi if max_min_oxi is not None else {} substitutions = substitutions if substitutions is not None else {} oxi_states = oxi_states if oxi_states is not None else {} interstitial_elements = interstitial_elements if interstitial_elements is not None else [] intersites = intersites if intersites is not None else [] self.defects = [] self.cellmax = cellmax self.substitutions = {} self.struct_type = struct_type for key, val in substitutions.items(): self.substitutions[key] = val spa = SpacegroupAnalyzer(structure, symprec=1e-2) prim_struct = spa.get_primitive_standard_structure() if standardized: self.struct = prim_struct else: self.struct = structure struct_species = self.struct.types_of_specie if self.struct_type == 'semiconductor': self.defect_charger = DefectChargerSemiconductor( self.struct, min_max_oxi=max_min_oxi) elif self.struct_type == 'insulator': self.defect_charger = DefectChargerInsulator(self.struct) elif self.struct_type == 'manual': self.defect_charger = DefectChargerUserCustom( self.struct, oxi_states=oxi_states) elif self.struct_type == 'ionic': self.defect_charger = DefectChargerIonic(self.struct) else: raise NotImplementedError if include_interstitials and interstitial_elements: for elem_str in interstitial_elements: if not Element.is_valid_symbol(elem_str): raise ValueError("invalid interstitial element" " \"{}\"".format(elem_str)) sc_scale = get_optimized_sc_scale(self.struct, cellmax) self.defects = {} sc = self.struct.copy() sc.make_supercell(sc_scale) self.defects['bulk'] = { 'name': 'bulk', 'supercell': { 'size': sc_scale, 'structure': sc } } # If interstitials are provided as a list of PeriodicSites, # make sure that the lattice has not changed. if include_interstitials and intersites: for intersite in intersites: #list of PeriodicSite objects if intersite.lattice != self.struct.lattice: raise RuntimeError( "Discrepancy between lattices" " underlying the input interstitials and" " the bulk structure; possibly because of" " standardizing the input structure.") vacancies = [] as_defs = [] sub_defs = [] VG = VacancyGenerator(self.struct) print("Setting up defects...") for i, vac in enumerate(VG): vac_site = vac.site vac_symbol = vac.site.specie.symbol vac_sc = vac.generate_defect_structure(sc_scale) #create a trivial defect structure to find where supercell transformation moves the lattice struct_for_defect_site = Structure( vac.bulk_structure.copy().lattice, [vac.site.specie], [vac.site.frac_coords], to_unit_cell=True, coords_are_cartesian=False) struct_for_defect_site.make_supercell(sc_scale) vac_sc_site = struct_for_defect_site[0] charges_vac = self.defect_charger.get_charges( 'vacancy', vac_symbol) vacancies.append({ 'name': "vac_{}_{}".format(i + 1, vac_symbol), 'unique_site': vac_site, 'bulk_supercell_site': vac_sc_site, 'defect_type': 'vacancy', 'site_specie': vac_symbol, 'site_multiplicity': vac.multiplicity, 'supercell': { 'size': sc_scale, 'structure': vac_sc }, 'charges': charges_vac }) if antisites_flag: for as_specie in set(struct_species): SG = SubstitutionGenerator(self.struct, as_specie) for i, sub in enumerate(SG): as_symbol = as_specie.symbol as_sc = sub.generate_defect_structure(sc_scale) # create a trivial defect structure to find where supercell transformation moves the defect struct_for_defect_site = Structure( sub.bulk_structure.copy().lattice, [sub.site.specie], [sub.site.frac_coords], to_unit_cell=True, coords_are_cartesian=False) struct_for_defect_site.make_supercell(sc_scale) as_sc_site = struct_for_defect_site[0] #get bulk_site (non sc) poss_deflist = sorted( sub.bulk_structure.get_sites_in_sphere( sub.site.coords, 0.01, include_index=True), key=lambda x: x[1]) if not len(poss_deflist): raise ValueError( "Could not find substitution site inside bulk structure for {}?" .format(sub.name)) defindex = poss_deflist[0][2] as_site = sub.bulk_structure[defindex] vac_symbol = as_site.specie charges_as = self.defect_charger.get_charges( 'antisite', vac_symbol, as_symbol) as_defs.append({ 'name': "as_{}_{}_on_{}".format(i + 1, as_symbol, vac_symbol), 'unique_site': as_site, 'bulk_supercell_site': as_sc_site, 'defect_type': 'antisite', 'site_specie': vac_symbol, 'substitution_specie': as_symbol, 'site_multiplicity': sub.multiplicity, 'supercell': { 'size': sc_scale, 'structure': as_sc }, 'charges': charges_as }) for vac_symbol, subspecie_list in self.substitutions.items(): for subspecie_symbol in subspecie_list: SG = SubstitutionGenerator(self.struct, subspecie_symbol) for i, sub in enumerate(SG): sub_symbol = sub.site.specie.symbol #get bulk_site (non sc) poss_deflist = sorted( sub.bulk_structure.get_sites_in_sphere( sub.site.coords, 0.1, include_index=True), key=lambda x: x[1]) if not len(poss_deflist): raise ValueError( "Could not find substitution site inside bulk structure for {}?" .format(sub.name)) defindex = poss_deflist[0][2] sub_site = self.struct[defindex] this_vac_symbol = sub_site.specie.symbol if (sub_symbol != subspecie_symbol) or (this_vac_symbol != vac_symbol): continue else: sub_sc = sub.generate_defect_structure(sc_scale) # create a trivial defect structure to find where supercell transformation moves the defect struct_for_defect_site = Structure( sub.bulk_structure.copy().lattice, [sub.site.specie], [sub.site.frac_coords], to_unit_cell=True, coords_are_cartesian=False) struct_for_defect_site.make_supercell(sc_scale) sub_sc_site = struct_for_defect_site[0] charges_sub = self.defect_charger.get_charges( 'substitution', vac_symbol, subspecie_symbol) sub_defs.append({ 'name': "sub_{}_{}_on_{}".format(i + 1, subspecie_symbol, vac_symbol), 'unique_site': sub_site, 'bulk_supercell_site': sub_sc_site, 'defect_type': 'substitution', 'site_specie': vac_symbol, 'substitution_specie': subspecie_symbol, 'site_multiplicity': sub.multiplicity, 'supercell': { 'size': sc_scale, 'structure': sub_sc }, 'charges': charges_sub }) self.defects['vacancies'] = vacancies self.defects['substitutions'] = sub_defs self.defects['substitutions'] += as_defs if include_interstitials: interstitials = [] if interstitial_elements: inter_elems = interstitial_elements else: inter_elems = [elem.symbol for elem in \ self.struct.composition.elements] if len(inter_elems) == 0: raise RuntimeError("empty element list for interstitials") if intersites: #manual specification of interstitials for i, intersite in enumerate(intersites): for elt in inter_elems: name = "inter_{}_{}".format(i + 1, elt) if intersite.lattice != self.struct.lattice: err_msg = "Lattice matching error occurs between provided interstitial and the bulk structure." if standardized: err_msg += "\nLikely because the standardized flag was used. Turn this flag off or reset " \ "your interstitial PeriodicSite to match the standardized form of the bulk structure." raise ValueError(err_msg) else: intersite_object = Interstitial( self.struct, intersite) # create a trivial defect structure to find where supercell transformation moves the defect site struct_for_defect_site = Structure( intersite_object.bulk_structure.copy().lattice, [intersite_object.site.specie], [intersite_object.site.frac_coords], to_unit_cell=True, coords_are_cartesian=False) struct_for_defect_site.make_supercell(sc_scale) site_sc = struct_for_defect_site[0] sc_with_inter = intersite_object.generate_defect_structure( sc_scale) charges_inter = self.defect_charger.get_charges( 'interstitial', elt) interstitials.append({ 'name': name, 'unique_site': intersite_object.site, 'bulk_supercell_site': site_sc, 'defect_type': 'interstitial', 'site_specie': intersite_object.site.specie.symbol, 'site_multiplicity': intersite_object.multiplicity, 'supercell': { 'size': sc_scale, 'structure': sc_with_inter }, 'charges': charges_inter }) else: print( "Searching for interstitial sites (this can take awhile)..." ) for elt in inter_elems: #TODO: Add ability to use other interstitial finding methods in pymatgen IG = InterstitialGenerator(self.struct, elt) for i, intersite_object in enumerate(IG): name = intersite_object.name # create a trivial defect structure to find where supercell transformation moves the defect site struct_for_defect_site = Structure( intersite_object.bulk_structure.copy().lattice, [intersite_object.site.specie], [intersite_object.site.frac_coords], to_unit_cell=True, coords_are_cartesian=False) struct_for_defect_site.make_supercell(sc_scale) site_sc = struct_for_defect_site[0] sc_with_inter = intersite_object.generate_defect_structure( sc_scale) charges_inter = self.defect_charger.get_charges( 'interstitial', elt) interstitials.append({ 'name': "inter_{}_{}".format( i + 1, elt), #TODO fix naming convention 'unique_site': intersite_object.site, 'bulk_supercell_site': site_sc, 'defect_type': 'interstitial', 'site_specie': intersite_object.site.specie.symbol, 'site_multiplicity': intersite_object.multiplicity, 'supercell': { 'size': sc_scale, 'structure': sc_with_inter }, 'charges': charges_inter }) self.defects['interstitials'] = interstitials print("\nNumber of jobs created:") tottmp = 0 for j in self.defects.keys(): if j == 'bulk': print(" bulk = 1") tottmp += 1 else: print(" {}:".format(j)) for lis in self.defects[j]: print(" {} = {}".format(lis['name'], len(lis['charges']))) tottmp += len(lis['charges']) print("Total (non dielectric) jobs created = {}\n".format(tottmp))
def make_confs(self, path_to_work, path_to_equi, refine=False): path_to_work = os.path.abspath(path_to_work) path_to_equi = os.path.abspath(path_to_equi) task_list = [] cwd = os.getcwd() print('gen interstitial with supercell ' + str(self.supercell) + ' with element ' + str(self.insert_ele)) equi_contcar = os.path.join(path_to_equi, 'CONTCAR') if not os.path.exists(equi_contcar): raise RuntimeError("please do relaxation first") ss = Structure.from_file(equi_contcar) # gen defects dss = [] for ii in self.insert_ele: vds = InterstitialGenerator(ss, ii) for jj in vds: temp = jj.generate_defect_structure(self.supercell) smallest_distance = list(set(temp.distance_matrix.ravel()))[1] if 'conf_filters' in self.parameter and 'min_dist' in self.parameter[ 'conf_filters']: min_dist = self.parameter['conf_filters']['min_dist'] if smallest_distance >= min_dist: dss.append(temp) else: dss.append(temp) # dss.append(jj.generate_defect_structure(self.supercell)) if refine: task_list = make_refine(self.parameter['init_from_suffix'], self.parameter['output_suffix'], path_to_work, len(dss)) for ii in task_list: os.chdir(ii) np.savetxt('supercell.out', self.supercell, fmt='%d') os.chdir(cwd) if self.reprod: if 'vasp_path' not in self.parameter: raise RuntimeError( "please provide the vasp_path for reproduction") vasp_path = os.path.abspath(self.parameter['vasp_path']) task_list = reproduce.make_repro(vasp_path, path_to_work) os.chdir(cwd) else: os.chdir(path_to_work) if os.path.isfile('POSCAR'): os.remove('POSCAR') os.symlink(os.path.relpath(equi_contcar), 'POSCAR') # task_poscar = os.path.join(output, 'POSCAR') for ii in range(len(dss)): output_task = os.path.join(path_to_work, 'task.%06d' % ii) os.makedirs(output_task, exist_ok=True) os.chdir(output_task) for jj in [ 'INCAR', 'POTCAR', 'POSCAR', 'conf.lmp', 'in.lammps' ]: if os.path.exists(jj): os.remove(jj) task_list.append(output_task) dss[ii].to('POSCAR', 'POSCAR') np.savetxt('supercell.out', self.supercell, fmt='%d') os.chdir(cwd) return task_list