Exemple #1
0
def do_symmetric_surface(test_dir, in_plane_supercell=[1,1], pert_pos=0.0):
    assert len(supercell) == 2

    surf = ase.io.read(test_dir+"/surface.xyz", format="extxyz")
    surf *= list(in_plane_supercell) + [1]

    if pert_pos > 0.0:
        surf.rattle(pert_pos)

    bulk = rescale_to_relaxed_bulk(surf)
    bulk_Zs = bulk.get_atomic_numbers()
    evaluate(bulk)
    bulk_cell = bulk.get_cell()
    bulk_E = bulk.get_potential_energy()

    try:
        model.reset_config()
    except AttributeError:
        pass

    print("got relaxed bulk cell ", bulk_cell)
    print("got rescaled surf cell ", surf.get_cell())

    # relax surface system
    tol = 1.0e-2
    surf = relax_config(surf, relax_pos=True, relax_cell=False, tol=tol, save_traj=True,
                        config_label="surface", from_base_model=True, save_config=True, try_restart=True)

    ase.io.write(os.path.join("..",run_root+"-relaxed.xyz"),  surf, format='extxyz')

    # check stoichiometry and number of bulk cell energies to subtract
    surf_Zs = surf.get_atomic_numbers()
    Z0 = bulk_Zs[0]
    n_bulk_cells = float(sum(surf_Zs == Z0))/float(sum(bulk_Zs == Z0))
    if len(set(bulk_Zs)) == 1:
        n_dmu = None
    else:
        n_dmu = {}
        for Z in set(bulk_Zs):
            # make sure types are JSON compatible
            n_dmu[int(Z)] = float(n_bulk_cells*sum(bulk_Zs == Z) - sum(surf_Zs == Z))

    # calculate surface energy
    area = np.linalg.norm(np.cross(surf.get_cell()[0,:],surf.get_cell()[1,:]))

    print("got surface cell potential energy", surf.get_potential_energy())
    print("got bulk potential energy",bulk_E*n_bulk_cells)
    print("got area",area)

    return { "bulk_struct_test" : surf.info["bulk_struct_test"],
             "Ef" : (surf.get_potential_energy() - bulk_E*n_bulk_cells)/(2.0*area),
             "dmu" : n_dmu, 'filename' : run_root+"-relaxed.xyz" }
Exemple #2
0
def do_farthest_inequiv_pairs(test_dir, tol=1.0e-2):
    print("doing do_farthest_antisite_pairs")
    bulk_supercell = ase.io.read(os.path.join(test_dir, "bulk_supercell.xyz"),
                                 format="extxyz")
    print("got bulk_supercell ", len(bulk_supercell))

    bulk = rescale_to_relaxed_bulk(bulk_supercell)
    # relax bulk supercell positions in case it's only approximate (as it must be for different models), but stick
    # to relaxed bulk's lattice constants as set by rescale_to_relaxed_bulk
    bulk_supercell = relax_config(bulk_supercell,
                                  relax_pos=True,
                                  relax_cell=False,
                                  tol=tol,
                                  save_traj=True,
                                  config_label="rescaled_bulk",
                                  from_base_model=True,
                                  save_config=True)

    ase.io.write(os.path.join("..", run_root + "-rescaled-bulk.xyz"),
                 bulk_supercell,
                 format='extxyz')

    print("got bulk primitive cell ", bulk.get_cell())
    print("got rescaled bulk_supercell cell ", bulk_supercell.get_cell())

    if 'arb_supercell' in bulk_supercell.info:
        print("making bulk supercell from",
              bulk_supercell.info['arb_supercell'].reshape((3, 3)))
        bulk_supersupercell = ase.build.make_supercell(
            bulk_supercell, bulk_supercell.info['arb_supercell'].reshape(
                (3, 3)))
        print("got supersupercell with ", len(bulk_supersupercell),
              "atoms, cell\n", bulk_supersupercell.get_cell())

        bulk_supersupercell.info.update(bulk_supercell.info)
        bulk_supercell = bulk_supersupercell

    sym_data = spglib.get_symmetry_dataset(bulk_supercell, symprec=0.01)
    equiv_at = set([
        tuple(iZ)
        for iZ in zip(sym_data["equivalent_atoms"], bulk_supercell.numbers)
    ])

    # print("equiv_at", equiv_at)

    antisite_list = []
    for i1, Z1 in equiv_at:
        for i2_proto, Z2 in equiv_at:
            if Z1 <= Z2:
                continue
            # print("check i", i1, i2_proto, "Z", Z1, Z2)

            i2s = np.where(sym_data["equivalent_atoms"] == i2_proto)[0]
            i2_dists = bulk_supercell.get_distances(i1, i2s, mic=True)
            farthest_ind = np.argmax(i2_dists)
            i2 = i2s[farthest_ind]

            antisite_list.append((i1, i2))

    # print("antisite_list", antisite_list) ##

    evaluate(bulk_supercell)
    bulk_supercell_pe = bulk_supercell.get_potential_energy()
    properties = {
        "bulk_struct_test": bulk_supercell.info["bulk_struct_test"],
        "bulk_E_per_atom": bulk_supercell_pe / len(bulk_supercell),
        "defects": {}
    }

    for i1, i2 in antisite_list:
        (label, unrelaxed_filename, Ef0, relaxed_filename, Ef, Z1,
         Z2) = do_one_antisite_pair(bulk_supercell, bulk_supercell_pe, i1, i2,
                                    tol)

        properties["defects"][label] = {
            'Ef0': Ef0,
            'Ef': Ef,
            'unrelaxed_filename': unrelaxed_filename,
            'relaxed_filename': relaxed_filename,
            'atom_inds': (int(i1), int(i2)),
            'Zs': (int(Z1), int(Z2))
        }

    print("returning properties", properties)
    return properties
Exemple #3
0
def do_all_interstitials(test_dir, nn_cutoff=0.0, tol=1.0e-2):
    print("doing do_all_interstitials")
    bulk_supercell = ase.io.read(os.path.join(test_dir, "bulk_supercell.xyz"),
                                 format="extxyz")
    print("got bulk_supercell ", len(bulk_supercell))

    bulk = rescale_to_relaxed_bulk(bulk_supercell)
    # relax bulk supercell positions in case it's only approximate (as it must be for different models), but stick
    # to relaxed bulk's lattice constants as set by rescale_to_relaxed_bulk
    bulk_supercell = relax_config(bulk_supercell,
                                  relax_pos=True,
                                  relax_cell=False,
                                  tol=tol,
                                  save_traj=True,
                                  config_label="relaxed_bulk",
                                  from_base_model=True,
                                  save_config=True)

    ase.io.write(os.path.join("..", run_root + "-rescaled-bulk.xyz"),
                 bulk_supercell,
                 format='extxyz')

    print("got bulk primitive cell ", bulk.get_cell())
    print("got rescaled bulk_supercell cell ", bulk_supercell.get_cell())

    try:  # Cartesian 3-vector
        interstitial_pos_l = [
            np.array([float(x) for x in bulk_supercell.info["interstitials"]])
        ]
        if len(interstitial_pos_l) != 3:
            raise ValueError("not a 3-vector")
    except:
        interstitial_pos_type = bulk_supercell.info["interstitials"].split()[0]
        if interstitial_pos_type == "mean":
            neighbor_indices = [
                int(i)
                for i in bulk_supercell.info["interstitials"].split()[1:]
            ]
            if len(neighbor_indices) < 2:
                raise ValueError(
                    "interstitial position type mean, but {} < 2 indices".
                    format(len(neighbor_indices)))
            interstitial_pos_l = [
                np.sum(bulk_supercell.get_positions()[neighbor_indices],
                       axis=0) / float(len(neighbor_indices))
            ]
        elif interstitial_pos_type == "inequivalent":
            if 'arb_supercell' in bulk_supercell.info:
                print("making bulk supercell from",
                      bulk_supercell.info['arb_supercell'].reshape((3, 3)))
                bulk_supersupercell = ase.build.make_supercell(
                    bulk_supercell,
                    bulk_supercell.info['arb_supercell'].reshape((3, 3)))
                print("got supersupercell with ", len(bulk_supersupercell),
                      "atoms, cell\n", bulk_supersupercell.get_cell())
            voids = find_voids(bulk_supercell)
            interstitial_pos_l = [(v[1], v[2], v[3]) for v in voids]

            bulk_supersupercell.info.update(bulk_supercell.info)
            bulk_supercell = bulk_supersupercell
        else:
            raise ValueError("Unknown interstitial position type in '" +
                             bulk_supercell.info["interstitials"] + "'")

    evaluate(bulk_supercell)
    bulk_supercell_pe = bulk_supercell.get_potential_energy()
    properties = {
        "bulk_struct_test": bulk_supercell.info["bulk_struct_test"],
        "bulk_E_per_atom": bulk_supercell_pe / len(bulk_supercell),
        "defects": {}
    }

    Z_list = ([bulk_supercell.info["Zs"]] if isinstance(
        bulk_supercell.info["Zs"],
        (int, np.integer)) else bulk_supercell.info["Zs"])

    for interstitial_Z in Z_list:
        try:
            relax_radial = bulk_supercell.info['relax_radial_{}'.format(
                interstitial_Z)]
        except:
            relax_radial = 0.0
        try:
            relax_symm_break = bulk_supercell.info[
                'relax_symm_break_{}'.format(interstitial_Z)]
        except:
            relax_symm_break = 0.0

        for interst_i, interst_pos in enumerate(interstitial_pos_l):
            label = f'Z_{interstitial_Z}_pos_{interst_i}'
            (unrelaxed_filename, Ef0,
             relaxed_filename, Ef, interstitial_i) = do_one_interstitial(
                 bulk_supercell, bulk_supercell_pe, interstitial_Z,
                 interst_pos, label, relax_radial, relax_symm_break, nn_cutoff,
                 tol)

            properties["defects"][label] = {
                'Ef0': Ef0,
                'Ef': Ef,
                'unrelaxed_filename': unrelaxed_filename,
                'relaxed_filename': relaxed_filename,
                'atom_ind': int(interstitial_i),
                'Z': int(interstitial_Z),
                'pos_index': interst_i
            }
            if len(set(bulk_supercell.get_atomic_numbers())) != 1:
                properties["defects"][label]['dmu'] = [-1, int(interstitial_Z)]

    return properties
def do_interstitial(test_dir, nn_cutoff=0.0, tol=1.0e-2):
    print("doing do_interstitial")
    bulk_supercell = ase.io.read(os.path.join(test_dir, "bulk_supercell.xyz"),
                                 format="extxyz")
    print("got bulk_supercell ", len(bulk_supercell))

    bulk = rescale_to_relaxed_bulk(bulk_supercell)
    # relax bulk supercell positions in case it's only approximate (as it must be for different models), but stick
    # to relaxed bulk's lattice constants as set by rescale_to_relaxed_bulk
    bulk_supercell = relax_config(bulk_supercell,
                                  relax_pos=True,
                                  relax_cell=False,
                                  tol=tol,
                                  traj_file=None,
                                  config_label="relaxed_bulk",
                                  from_base_model=True,
                                  save_config=True)

    evaluate(bulk_supercell)
    bulk_supercell_pe = bulk_supercell.get_potential_energy()

    ase.io.write(os.path.join("..", run_root + "-rescaled-bulk.xyz"),
                 bulk_supercell,
                 format='extxyz')

    print("got bulk primitive cell ", bulk.get_cell())
    print("got rescaled bulk_supercell cell ", bulk_supercell.get_cell())

    properties = {
        "bulk_struct_test": bulk_supercell.info["bulk_struct_test"],
        "bulk_E_per_atom": bulk_supercell_pe / len(bulk_supercell),
        "defects": {}
    }

    try:  # Cartesian 3-vector
        interstitial_pos = np.array(
            [float(x) for x in bulk_supercell.info["interstitial_position"]])
        if len(interstitial_pos) != 3:
            raise ValueError("not a 3-vector")
    except:
        interstitial_pos_type = bulk_supercell.info[
            "interstitial_position"].split()[0]
        if interstitial_pos_type == "mean":
            neighbor_indices = [
                int(i) for i in
                bulk_supercell.info["interstitial_position"].split()[1:]
            ]
            if len(neighbor_indices) < 2:
                raise ValueError(
                    "interstitial position type mean, but {} < 2 indices".
                    format(len(neighbor_indices)))
            interstitial_pos = np.sum(
                bulk_supercell.get_positions()[neighbor_indices],
                axis=0) / float(len(neighbor_indices))
        else:
            raise ValueError("Unknown interstitial position type in '" +
                             bulk_supercell.info["interstitial_position"] +
                             "'")

    if isinstance(bulk_supercell.info["Zs"], list):
        Z_list = bulk_supercell.info["Zs"]
    else:
        Z_list = [bulk_supercell.info["Zs"]]
    for interstitial_Z in Z_list:

        try:
            relax_radial = bulk_supercell.info['relax_radial_{}'.format(
                interstitial_Z)]
        except:
            relax_radial = 0.0
        try:
            relax_symm_break = bulk_supercell.info[
                'relax_symm_break_{}'.format(interstitial_Z)]
        except:
            relax_symm_break = 0.0

        (label, unrelaxed_filename, Ef0,
         relaxed_filename, Ef, interstitial_i) = do_one_interstitial(
             bulk_supercell, bulk_supercell_pe, interstitial_Z,
             interstitial_pos, relax_radial, relax_symm_break, nn_cutoff, tol)

    properties["defects"][label] = {
        'Ef0': Ef0,
        'Ef': Ef,
        'unrelaxed_filename': unrelaxed_filename,
        'relaxed_filename': relaxed_filename,
        'atom_ind': int(interstitial_i),
        'Z': int(interstitial_Z)
    }
    if len(set(bulk_supercell.get_atomic_numbers())) != 1:
        properties["defects"][label]['dmu'] = [-1, interstitial_Z]

    return properties
def do_all_vacancies(test_dir, nn_cutoff=0.0, tol=1.0e-2):
    print("doing do_all_vacancies")
    bulk_supercell = ase.io.read(os.path.join(test_dir,"bulk_supercell.xyz"), format="extxyz")
    print("got bulk_supercell ", len(bulk_supercell))

    bulk = rescale_to_relaxed_bulk(bulk_supercell)
    # relax bulk supercell positions in case it's only approximate (as it must be for different models), but stick
    # to relaxed bulk's lattice constants as set by rescale_to_relaxed_bulk
    bulk_supercell = relax_config(bulk_supercell, relax_pos=True, relax_cell=False, tol=tol, save_traj=True,
        config_label="rescaled_bulk", from_base_model=True, save_config=True)

    ase.io.write(os.path.join("..",run_root+"-rescaled-bulk.xyz"),  bulk_supercell, format='extxyz')

    print("got bulk primitive cell ", bulk.get_cell())
    print("got rescaled bulk_supercell cell ", bulk_supercell.get_cell())

    if bulk_supercell.info['vacancies'] == "inequivalent":
        sym_data = spglib.get_symmetry_dataset(bulk_supercell, symprec=0.01)
        prim_vacancy_list = np.unique(sym_data["equivalent_atoms"])
        print("orig cell vacancy_list", prim_vacancy_list)
        if 'arb_supercell' in bulk_supercell.info:
            print("making bulk supercell from", bulk_supercell.info['arb_supercell'].reshape((3,3)) )
            bulk_supersupercell = ase.build.make_supercell(bulk_supercell,bulk_supercell.info['arb_supercell'].reshape((3,3)) )
            print("got supersupercell with ",len(bulk_supersupercell),"atoms, cell\n",bulk_supersupercell.get_cell())
            vacancy_list = []
            for i in prim_vacancy_list:
                p = bulk_supercell.get_positions()[i]
                dv = bulk_supersupercell.get_positions() - p
                dv_scaled = np.dot(dv, bulk_supersupercell.get_reciprocal_cell().T)
                dv -= np.dot(np.round(dv_scaled), bulk_supersupercell.get_cell())
                i_closest = np.argmin(np.linalg.norm(dv, axis=1))
                print("found closest in new cell", i_closest, "distance in orig cell lattice coords", np.dot((bulk_supersupercell.get_positions()[i_closest]-p), \
                                                                                                             bulk_supercell.get_reciprocal_cell().T))
                vacancy_list.append(i_closest)
            bulk_supersupercell.info.update(bulk_supercell.info)
            bulk_supercell = bulk_supersupercell
        else:
            vacancy_list = prim_vacancy_list
        print("final vacancy_list", vacancy_list)
    else:
        try:
            vacancy_list = [ int(i) for i in bulk_supercell.info['vacancies'] ]
        except:
            vacancy_list = [ int(bulk_supercell.info['vacancies']) ]

    evaluate(bulk_supercell)
    bulk_supercell_pe = bulk_supercell.get_potential_energy()
    properties = { "bulk_struct_test" : bulk_supercell.info["bulk_struct_test"], "bulk_E_per_atom" : bulk_supercell_pe / len(bulk_supercell), "defects" : {} }

    for vac_i in vacancy_list:
        # maybe set up a system to read these from xyz file?
        try:
            relax_radial = bulk_supercell.info['relax_radial_{}'.format(vac_i)]
        except:
            relax_radial = 0.0
        try:
            relax_symm_break = bulk_supercell.info['relax_symm_break_{}'.format(vac_i)]
        except:
            relax_symm_break = 0.0
        (label, unrelaxed_filename, Ef0, relaxed_filename, Ef, vac_Z, vac_pos) = do_one_vacancy(bulk_supercell, bulk_supercell_pe, vac_i, relax_radial, relax_symm_break, nn_cutoff, tol)

        properties["defects"][label] = { 'Ef0' : Ef0, 'Ef' : Ef, 'unrelaxed_filename' : unrelaxed_filename,'relaxed_filename' : relaxed_filename,
            'atom_ind' : int(vac_i), 'Z' : int(vac_Z), 'vac_pos' : vac_pos.tolist()}
        if len(set(bulk_supercell.get_atomic_numbers())) > 1:
            properties["defects"][label]["dmu"] = [1, vac_Z]

    print("returning properties", properties)
    return properties