Beispiel #1
0
def vac_antisite_def_struct_gen(c_size=15,
                                mpid="",
                                struct=None,
                                write_file=True):
    """
    Vacancy, antisite generator

    Args:
         c_size: cell size
         struct: Structure object or
         mpid: materials project id
    Returns:
            def_str: defect structures in Poscar object format
    """
    def_str = []
    if struct == None:
        with MPRester() as mp:
            struct = mp.get_structure_by_material_id(mpid)
        if mpid == "":
            print("Provide structure")
    c_size = c_size
    prim_struct_sites = len(struct.sites)
    struct = SpacegroupAnalyzer(struct).get_conventional_standard_structure()
    dim1 = int((float(c_size) / float(max(abs(struct.lattice.matrix[0]))))) + 1
    dim2 = int(float(c_size) / float(max(abs(struct.lattice.matrix[1])))) + 1
    dim3 = int(float(c_size) / float(max(abs(struct.lattice.matrix[2])))) + 1
    cellmax = max(dim1, dim2, dim3)
    conv_struct_sites = len(struct.sites)
    conv_prim_rat = int(conv_struct_sites / prim_struct_sites)
    sc_scale = [dim1, dim2, dim3]
    print("sc_scale", sc_scale)

    tmp = struct.copy()
    tmp.make_supercell(sc_scale)
    sc_tmp = tmp  # Poscar(tmp).structure .make_supercell(list(sc_scale))
    scs = list(VacancyGenerator(struct))
    supercell = Poscar(sc_tmp)
    supercell.comment = str("bulk") + str("@") + str("cellmax") + str(cellmax)
    def_str.append(supercell)
    if write_file == True:
        supercell.write_file("POSCAR-" + str("bulk") + str(".vasp"))

    for i in range(len(scs)):
        sc = scs[i].generate_defect_structure(sc_scale)
        poscar = Poscar(sc)  # mpvis.get_poscar(sc)
        pmg_name = str(scs[i].name).split("_")
        sitespecie = pmg_name[1]
        mult = pmg_name[2].split("mult")[1]
        name = (str("vacancy_") + str(i + 1) + str("_mult-") + str(mult) +
                str("_sitespecie-") + str(sitespecie) + str("@cellmax") +
                str(cellmax))
        poscar.comment = str(name)
        def_str.append(poscar)
        if write_file == True:
            filename = (str("POSCAR-") + str("vacancy_") + str(i + 1) +
                        str("_mult-") + str(mult) + str("_sitespecie-") +
                        str(sitespecie) + str(".vasp"))
            poscar.write_file(filename)

    return def_str
Beispiel #2
0
    def test_charge_gen(self):
        struc = PymatgenTest.get_structure("VO2")

        # assemble set of defects to get charges for
        vac_gen = VacancyGenerator(struc)
        vacs = list(vac_gen)
        full_subs = []
        for sub_elt in ["V", "O", "S"]:
            sub_gen = SubstitutionGenerator(struc, sub_elt)
            full_subs.extend(list(sub_gen))
        int_gen = VoronoiInterstitialGenerator(struc, "H")
        inters = list(int_gen)
        defect_list = list(set().union(vacs, full_subs, inters))

        # test simple charges
        true_charges = {
            "Vac_O_mult4": 2,
            "Int_H_Voronoi1_mult8": 0,
            "Int_H_Voronoi2_mult8": 0,
            "Vac_V_mult2": -4,
            "Sub_S_on_V_mult2": 0,
            "Int_H_Voronoi3_mult4": 0,
            "Int_H_Voronoi4_mult4": 0,
            "Sub_O_on_V_mult2": -2,
            "Sub_S_on_O_mult4": 0,
            "Sub_V_on_O_mult4": 1,
        }
        for defect in defect_list:
            scg = SimpleChargeGenerator(defect)
            charged_defects_list = list(scg)
            def_name = charged_defects_list[0].name
            charge = charged_defects_list[0].charge
            self.assertEqual(len(charged_defects_list), 1)
            self.assertEqual(true_charges[def_name], charge)
Beispiel #3
0
 def test_vacancy_gen_charges(self):
     # Ensure correct BV charges are assigned
     struc = PymatgenTest.get_structure("VO2")
     vac_gen = VacancyGenerator(struc, include_bv_charge=True)
     for vac in vac_gen:
         if str(vac.site.specie) == "V":
             self.assertEqual(vac.charge, -4)
         if str(vac.site.specie) == "O":
             self.assertEqual(vac.charge, 2)
Beispiel #4
0
    def test_vacancy_gen(self):
        struc = PymatgenTest.get_structure("VO2")
        vac_gen = VacancyGenerator(struc)

        vacs = list(vac_gen)
        self.assertEqual(len(vacs), 2)

        multiplicities = {str(v.site.specie): v.multiplicity for v in vacs}
        self.assertEqual(multiplicities, {"O": 4, "V": 2})
Beispiel #5
0
    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 vacancy with supercell ' + str(self.supercell))

        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)
        vds = VacancyGenerator(ss)
        dss = []
        for jj in vds:
            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
Beispiel #6
0
def make_lammps(jdata, conf_dir, task_type, supercell):
    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')
    assert os.path.exists(
        equi_contcar), "Please compute the equilibrium state using vasp first"
    # equi_path = re.sub('confs', global_equi_name, conf_path)
    # equi_path = os.path.join(equi_path, 'lmp')
    # 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_type)
    os.makedirs(task_path, exist_ok=True)
    # gen task poscar
    task_poscar = os.path.join(task_path, 'POSCAR')
    # lammps.poscar_from_last_dump(equi_dump, task_poscar, deepmd_type_map)
    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)
    # gen structure from equi poscar
    ss = Structure.from_file(task_poscar)
    # gen defects
    vds = VacancyGenerator(ss)
    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-%03d' % (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)
Beispiel #7
0
def make_vasp(jdata, conf_dir, supercell=[1, 1, 1]):
    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
    ss = Structure.from_file(task_poscar)
    # gen defects
    vds = VacancyGenerator(ss)
    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 potcar
    with open(task_poscar, 'r') as fp:
        lines = fp.read().split('\n')
        ele_list = lines[5].split()
    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]))
    with open(os.path.join(task_path, 'POTCAR'), 'w') as outfile:
        for fname in potcar_list:
            with open(fname) as infile:
                outfile.write(infile.read())
    # 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-%03d' % (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')
        # link incar, potcar, kpoints
        os.symlink(os.path.relpath(os.path.join(task_path, 'INCAR')), 'INCAR')
        os.symlink(os.path.relpath(os.path.join(task_path, 'POTCAR')),
                   'POTCAR')
        # save supercell
        np.savetxt('supercell.out', supercell, fmt='%d')
    os.chdir(cwd)
Beispiel #8
0
def make_deepmd_lammps(jdata, conf_dir, supercell):
    fp_params = jdata['vasp_params']
    kspacing = fp_params['kspacing']
    deepmd_model_dir = jdata['deepmd_model_dir']
    deepmd_type_map = jdata['deepmd_type_map']
    ntypes = len(deepmd_type_map)
    deepmd_model_dir = os.path.abspath(deepmd_model_dir)
    deepmd_models = glob.glob(os.path.join(deepmd_model_dir, '*pb'))
    deepmd_models_name = [os.path.basename(ii) for ii in deepmd_models]

    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 = re.sub('confs', global_equi_name, conf_path)
    # equi_path = os.path.join(equi_path, 'lmp')
    # 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, 'deepmd')
    os.makedirs(task_path, exist_ok=True)
    # gen task poscar
    task_poscar = os.path.join(task_path, 'POSCAR')
    # lammps.poscar_from_last_dump(equi_dump, task_poscar, deepmd_type_map)
    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)
    # gen structure from equi poscar
    ss = Structure.from_file(task_poscar)
    # gen defects
    vds = VacancyGenerator(ss)
    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_deepmd,
                                        deepmd_models_name)
    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-%03d' % (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'] + deepmd_models_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', deepmd_type_map, ptypes)
        # link lammps.in
        os.symlink(os.path.relpath(f_lammps_in), 'lammps.in')
        # link models
        for (ii, jj) in zip(deepmd_models, deepmd_models_name):
            os.symlink(os.path.relpath(ii), jj)
        # save supercell
        np.savetxt('supercell.out', supercell, fmt='%d')
    os.chdir(cwd)
Beispiel #9
0
    def update_vacancy_edges(self, threshold=0.5, batch_size=100,
                             edge_calculator=edg.pairwise_squared_similarity,
                             featurizer=FRAMEWORK_FEATURIZER):
        '''
        solve for directed, boolean edges based on similarity with a vacancy

        Notes:
            Transformation limited method (featurization of vacancy structures)

        Args:
            threshold (float) distance threshold to connect an edge
            batch_size (int) batch size for computing pairwise distances when
                generating graph edges. subject to memory constraints
            edge_calculator (func) a sub-pairwise distance calculator that
                returns an N x M adjacency matrix
            featurizer (BaseFeaturizer) an instance of a structural featurizer
        '''

        # loads a batch of verticies without defined edges
        self.destination.from_storage(
            filter={'vacancy_edges':
                    {'$exists': False}},
            projection={'material_id': 1},
            limit=batch_size)

        if len(self.destination.memory.index) == 0:

            return 0  # returns False when update is complete

        else:

            # gets the source vertex ids for the current batch
            source_ids = self.destination.memory['material_id'].values
            self.destination.memory = None  # cleanup memory

            # gets the potential destination vertex ids and their features
            self._load_structure_features()
            all_ids = self.source.memory.index.values
            all_vectors = self.source.memory.values
            vector_labels = np.array(
                [s.split('.')[1] for s in self.source.memory.columns.values])
            self.source.memory = None  # cleanup memory

            # calculates feature vectors for each (source) vacancy structure
            self._load_structures(list(source_ids))
            source_structures = self.source.memory['structure'].values
            self.source.memory = None  # cleanup memory

            vacancy_structures = []
            for material_id, structure in zip(source_ids, source_structures):
                structure = Structure.from_dict(structure)
                for site_i, vacancy in enumerate(VacancyGenerator(structure)):
                    vacancies = [
                        material_id,
                        str(site_i),
                        vacancy.generate_defect_structure(supercell=(1, 1, 1))
                    ]
                    vacancy_structures.append(vacancies)
            vacancy_structures = DataFrame(
                data=vacancy_structures,
                columns=['source_id', 'site_index', 'structure'])

            vacancy_vectors = featurizer.featurize_dataframe(
                vacancy_structures, 'structure', ignore_errors=True,
                pbar=False, inplace=False)[vector_labels].values

            # determine edge matrix and coresponding adjacency list
            edge_matrix = edge_calculator(
                all_vectors, vacancy_vectors, threshold)
            adjacency_list = defaultdict(dict)
            for j in range(edge_matrix.shape[1]):
                source_id = vacancy_structures['source_id'][j]
                site_index = vacancy_structures['site_index'][j]
                adjacency_list[source_id][site_index] = list(
                    all_ids[edge_matrix[:, j]])

            # store edges in graph space
            self.destination.memory = DataFrame.from_records(
                list(adjacency_list.items()),
                columns=['material_id', 'vacancy_edges'])
            self.destination.to_storage(identifier='material_id')

            return 1  # return True to continue the update
Beispiel #10
0
    def make_confs(self, path_to_work, path_to_equi, refine=False):
        path_to_work = os.path.abspath(path_to_work)
        if os.path.exists(path_to_work):
            dlog.warning('%s already exists' % path_to_work)
        else:
            os.makedirs(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('vacancy 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('vacancy 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))

                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)
                vds = VacancyGenerator(ss)
                dss = []
                for jj in vds:
                    dss.append(jj.generate_defect_structure(self.supercell))

                print('gen vacancy with supercell ' + str(self.supercell))
                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
Beispiel #11
0
    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))