Ejemplo n.º 1
0
def split_comp(compstr):
    """
    Splits a string containing the composition of a perovskite solid solution into its components
    Chemical composition: (am_1, am_2)(tm_1, tm_2)Ox
    :param compstr: composition as a string
    :return:        am_1, am_2, tm_1, tm_2;
    each of these output variables contains the species and the stoichiometries
    i.e. ("Fe", 0.6)
    """

    am_1, am_2, tm_1, tm_2 = None, None, None, None

    compstr_spl = [''.join(g) for _, g in groupby(str(compstr), str.isalpha)]

    for l in range(len(compstr_spl)):
        try:
            if ptable.Element(compstr_spl[l]).is_alkaline or ptable.Element(
                compstr_spl[l]).is_alkali or ptable.Element(compstr_spl[l]).is_rare_earth_metal:
                if am_1 is None:
                    am_1 = [compstr_spl[l], float(compstr_spl[l + 1])]
                elif am_2 is None:
                    am_2 = [compstr_spl[l], float(compstr_spl[l + 1])]
            if ptable.Element(compstr_spl[l]).is_transition_metal and not (
                ptable.Element(compstr_spl[l]).is_rare_earth_metal):
                if tm_1 is None:
                    tm_1 = [compstr_spl[l], float(compstr_spl[l + 1])]
                elif tm_2 is None:
                    tm_2 = [compstr_spl[l], float(compstr_spl[l + 1])]
        # stoichiometries raise ValueErrors in pymatgen .is_alkaline etc., ignore these errors and skip that entry
        except ValueError:
            pass

    return am_1, am_2, tm_1, tm_2
Ejemplo n.º 2
0
def generateElementdict():
    # Dictionary with Elements and their properties
    # Delete preprocessed data when changing featperEle
    elementdict = {}
    for i in range(1, 100):  # 100 Elements in Dict
        commonoxidationstate = peri.Element.from_Z(i).common_oxidation_states
        orbitals = peri.Element.from_Z(i).full_electronic_structure
        sandp_count = 0
        dandf_count = 0
        ionizationenergy = 0
        valence = 0

        if len(commonoxidationstate) == 0:
            commonoxidationstate = 0
        else:
            commonoxidationstate = peri.Element.from_Z(
                i).common_oxidation_states[0]

        for j in range(len(orbitals)):
            for k in range(len(orbitals[j])):
                if orbitals[j][k] == "s" or orbitals[j][k] == "p":
                    sandp_count += orbitals[j][2]  # count in third position
                if orbitals[j][k] == "d" or orbitals[j][k] == "f":
                    dandf_count += orbitals[j][2]

        if i == 1:
            ionizationenergy = 13.6
        else:
            ionizationenergy = ((i - 1) ^ 2) * 13.6

        """
        if i == 4 or i == 12 or i == 20:
            valence = 2
            print("alkaine earth set to 2 valence e-")
        else: 
            valence = peri.Element.from_Z(i).valence
            print("Element: ", i, "Valence: ", valence, type(valence))
        """  # transition metals not working

        elementdict[i] = [
            peri.Element.from_Z(i),  # name
            peri.Element.from_Z(i).number,  # atomic number
            mg.Element(peri.Element.from_Z(i)).group,  # group
            peri.Element(peri.Element.from_Z(i)).row  # row
            #   peri.Element.from_Z(i).X,  # Pauling electronegativity (none equals zero)
            #   peri.Element.from_Z(i).number,  # atomic number
            #   commonoxidationstate,  # common oxidation state if non set to zero
            #   peri.Element.from_Z(i).average_ionic_radius,  # average ionic radius
            #   mg.Element(peri.Element.from_Z(i)).atomic_mass,  # avarage mass
            #   sandp_count,  # count of e- in s and p orbitals
            #   dandf_count,  # couunt of e- in d and f orbitals
            #   ionizationenergy,  # ionizationenergy in eV
        ]
        # peri.Element.from_Z(i).valence]  # number of valence electrons
    # print("Element and feat.:", elementdict)
    return elementdict
Ejemplo n.º 3
0
    def atom_block(self, structure):
        '''
        Create block of atoms.
        '''

        outStr = 'AtomicCoordinatesFormat Fractional\n'
        outStr += 'LatticeConstant 1.0 Ang\n'

        uniqueSpeciesList = list(set(self.get_species(self.structure)))
        nAtoms = len(self.structure.as_dict()['sites'])
        nSpecies = len(uniqueSpeciesList)

        outStr += 'NumberOfAtoms ' + str(nAtoms) + '\n'
        outStr += 'NumberOfSpecies ' + str(nSpecies) + '\n'
        outStr += '\n'

        a = self.structure.as_dict()['lattice']['a']
        b = self.structure.as_dict()['lattice']['b']
        c = self.structure.as_dict()['lattice']['c']

        alpha = self.structure.as_dict()['lattice']['alpha']
        beta = self.structure.as_dict()['lattice']['beta']
        gamma = self.structure.as_dict()['lattice']['gamma']

        outStr += '%block LatticeParameters\n'
        outStr += str(a) + ' ' + str(b) + ' ' + str(c) + ' ' + str(
            alpha) + ' ' + str(beta) + ' ' + str(gamma) + '\n'
        outStr += '%endblock LatticeParameters\n'
        outStr += '\n'

        outStr += '%block ChemicalSpeciesLabel\n'

        for index, uniqueSpec in enumerate(uniqueSpeciesList):
            ele = pmg_pt.Element(uniqueSpec)
            outStr += str(index + 1) + ' ' + str(
                ele.number) + ' ' + uniqueSpec + '\n'

        outStr += '%endblock ChemicalSpeciesLabel\n'
        outStr += '\n'

        outStr += '%block AtomicCoordinatesAndAtomicSpecies\n'

        for site in self.structure.as_dict()['sites']:
            a_a = str(site['abc'][0])
            a_b = str(site['abc'][1])
            a_c = str(site['abc'][2])
            specNum = str(
                1 + uniqueSpeciesList.index(site['species'][0]['element']))

            outStr += a_a + ' ' + a_b + ' ' + a_c + ' ' + specNum + '\n'

        outStr += '%endblock AtomicCoordinatesAndAtomicSpecies\n'

        return outStr
def get_shell_v_electrons(element):
    """get valence electrons for an element in the structure"""
    # s1 - f14 is notated as shell_v_electons
    # get shell_v_electons for corresponding element
    if element == 'H':
        return ['s1']
    elif element == 'He':
        return ['s2']
    else:
        valence_electrons = periodic_table.Element(element).electronic_structure[5:].replace('</sup>.', ' ').replace(
            '</sup>', ' ').split()
        shell_v_electrons_ls = []
        for i in range(len(valence_electrons)):
            valence_electrons[i] = valence_electrons[i].split('<sup>')
            # take the letter of the shell + the correspoinding number of valence e-, ignore principle quantum number
            shell_electron = valence_electrons[i][0][1] + valence_electrons[i][1]
            shell_v_electrons_ls.append(shell_electron)
        return shell_v_electrons_ls
def aligner(nodefile, adsfile, zdist=2.5, write_format='xyz'):

    shift_vec = np.array([0.0, 0.0, zdist])
    z = np.array([0.0, 0.0, 1.0])

    node = read(nodefile, format=nodefile.split('.')[-1])
    adsorbate = read(adsfile, format=adsfile.split('.')[-1])

    # align node metal at (0,0,0) with COM vector along negative z-axis
    metal_coords = np.array([
        a.position for a in node if periodic_table.Element(a.symbol).is_metal
    ])
    node.positions -= metal_coords[0]
    align_vec = np.average(metal_coords, axis=0)
    rotM = M(align_vec, z)
    node.positions = dot(rotM, node.positions.T).T

    # center adsorbate at (0,0,0) and maximize the minimum distance between the atoms not expected to interact strongly with the metal
    ads_interaction_coords = np.array(
        [a.position for a in adsorbate if a.symbol == 'X'])
    adsorbate.positions -= np.average(ads_interaction_coords, axis=0)
    ads_noninteraction_coords = np.array(
        [a.position for a in adsorbate if a.symbol != 'X'])
    rotM = maximize_minimum_distance(ads_noninteraction_coords, node.positions,
                                     zdist)
    adsorbate.positions = dot(rotM, adsorbate.positions.T).T + shift_vec

    # combine node and adsorbate atoms
    all_atoms = Atoms()
    for a in node:
        all_atoms.append(Atom(a.symbol, a.position))
    for a in adsorbate:
        all_atoms.append(Atom(a.symbol, a.position))

    # write all coordinates
    write_name = nodefile.split('.')[0] + '_' + adsfile.split(
        '.')[0] + '.' + write_format
    write(write_name, all_atoms, format=write_format)

    return all_atoms
    df[key] = orb_data[key]

df.sort_values(by="Atomic no", inplace=True)
df.reset_index(inplace=True, drop=True)
df = df.iloc[0:103]

# stuff that we need to instantiate Element to get: row, group, block valence

rows = []
groups = []
valences = []
blocks = []
electronic_structure = []
for row in df.iterrows():
    sym = row[1]['Symbol']
    el = pt.Element(sym)
    rows.append(el.row)
    groups.append(el.group)
    blocks.append(el.block)
    electronic_structure.append(el.electronic_structure)
    try:
        v = el.valence[1]
    except ValueError:  #ambiguous valence
        v = np.nan
    valences.append(v)

df['Row'] = rows
df['Group'] = groups
df['Valence'] = valences
df['Block'] = blocks
df['Electronic Structure'] = electronic_structure
def find_clusters(G,
                  unit_cell,
                  coordination_shells=5,
                  niter=5,
                  mode='single_node',
                  outside_cycle_elements=('H', 'O')):

    metals = [
        n for n in G
        if periodic_table.Element(G.nodes[n]['element_symbol']).is_metal
    ]
    unique_shells = []
    clusters = []

    outside_cycle_elements = set(
        list(outside_cycle_elements) +
        [G.nodes[n]['element_symbol'] for n in metals])

    for m in metals:

        start = m

        start_shell = list(neighborhood(G, start, cutoff=coordination_shells))
        full_shell = list(
            set([
                n for n in start_shell if periodic_table.Element(
                    G.nodes[n]['element_symbol']).is_metal
            ]))

        for i in range(niter):

            metals = [
                n for n in full_shell if periodic_table.Element(
                    G.nodes[n]['element_symbol']).is_metal
            ]
            full_shell = set(
                flatten([
                    list(neighborhood(G, n, cutoff=coordination_shells))
                    for n in metals
                ]))

        first_shell = flatten([list(G.neighbors(m)) for m in metals])
        full_shell = sorted(list(full_shell) + first_shell)

        if full_shell not in unique_shells:

            unique_shells.append(full_shell)
            SG = G.subgraph(full_shell)
            cycles = flatten(list(nx.cycle_basis(SG)))
            cluster = SG.subgraph([
                n for n in SG.nodes()
                if (n in cycles or n in first_shell
                    or SG.nodes[n]['element_symbol'] in outside_cycle_elements)
            ])

            if len(cluster.nodes()) == 1:

                single_atom = list(cluster.nodes())[0]
                cluster = SG.subgraph(
                    list(SG.neighbors(single_atom)) + [single_atom])

            fcoords = [data['fcoord'] for n, data in cluster.nodes(data=True)]
            anchor = fcoords[0]

            for node in cluster:

                fcoord = cluster.nodes[node]['fcoord']
                dist, sym = PBC3DF_sym(anchor, fcoord)
                cluster.nodes[node]['ccoord'] = dot(unit_cell, fcoord + sym)

            clusters.append(cluster)

            if mode == 'single_node':
                break

        else:
            continue

    return clusters
Ejemplo n.º 8
0
def find_active(mat_comp):
    """
    Finds the more redox-active species in a perovskite solid solution
    Args:
    sample_no:
    An integer sample number or a string as identifier that occurs
    in the input file name.
    mat_comp:
    The materials composition data, as to be generated by self.sample_data
    Returns:
    act_spec:
    more redox active species
    act:
    stoichiometry of the more redox active species
    """

    # calculate charge of the A site metals
    charge_sum = 0

    for i in range(2):
        if mat_comp[i]:
            if ptable.Element(mat_comp[i][0]).is_alkali:
                charge_sum += mat_comp[i][1]
            elif ptable.Element(mat_comp[i][0]).is_alkaline:
                charge_sum += 2 * mat_comp[i][1]
            elif (ptable.Element(mat_comp[i][0]).is_lanthanoid or (
                    mat_comp[i][0] == "Bi")) and mat_comp[i][0] != "Ce":
                charge_sum += 3 * mat_comp[i][1]
            elif mat_comp[i][0] == "Ce":
                charge_sum += 4 * mat_compp[i][1]
            else:
                raise ValueError("Charge of A site species unknown.")

    red_order = None
    # charge on B sites 4+
    # experimentally well-established order of A2+B4+O3 perovskite reducibility: Ti - Mn - Fe - Co - Cu
    if round((6 - charge_sum), 2) == 4:
        red_order = ["Ti", "Mn", "Fe", "Co", "Cu"]

    # charge on B sites 3+
    # order of binary oxide reducibility according to Materials Project (A2O3 -> AO + O2)
    if round((6 - charge_sum), 2) == 3:
        red_order = ["Sc", "Ti", "V", "Cr", "Fe", "Mn", "Cu", "Co", "Ni", "Ag"] # changed Ni<->Ag order according to DFT results

    # charge on B sites 5+
    # order of binary oxide reducibility according to Materials Project (A2O3 -> AO + O2)
    if round((6 - charge_sum), 2) == 5:
        red_order = ["Ta", "Nb", "W", "Mo", "V", "Cr"]

    act_a = None
    if red_order:
        for i in range(len(red_order)):
            if mat_comp[2][0] == red_order[i]:
                more_reducible = red_order[i + 1:-1]
                if mat_comp[3] is not None and (mat_comp[3][0] in more_reducible):
                    act_a = mat_comp[3]
                else:
                    act_a = mat_comp[2]
    if act_a is None:
        raise ValueError("B species reducibility unknown, preferred reduction of species not predicted")

    # correct bug for the most reducible species
    if act_a[0] == red_order[-2] and (red_order[-1] in str(mat_comp)):
        act_a[0] = red_order[-1]
        act_a[1] = 1-act_a[1]

    return act_a[0], act_a[1]
Ejemplo n.º 9
0
    def are_soluble(self, pair):
        """
        Predict whether a pair of compounds are soluble with one another.

        Args:
            pair_info: a tuple containing containing two compounds
                denoted by their filenames
        Returns:
            The pair of compounds, if they are soluble.
            Otherwise, Nonetype is returned.
        """

        reference_directory = self.ref_dir

        cmpd_A, cmpd_B = pair[0], pair[1]
        struc_A = Structure.from_file('%s/%s' % (reference_directory, cmpd_A))
        formula_A = struc_A.composition.reduced_formula
        struc_B = Structure.from_file('%s/%s' % (reference_directory, cmpd_B))
        formula_B = struc_B.composition.reduced_formula

        if formula_A != formula_B:
            if self.matcher.fit(struc_A, struc_B):
                solubility = True
                comp_A = Composition(formula_A)
                comp_B = Composition(formula_B)
                probable_oxis_A = comp_A.oxi_state_guesses()
                probable_oxis_B = comp_B.oxi_state_guesses()
                if len(
                        probable_oxis_A
                ) == 0:  ## This occurs for metals, in which case we'll just use atomic radii
                    oxi_dict_A = {}
                    for elem in [str(f) for f in comp_A.elements]:
                        oxi_dict_A[elem] = 0.0
                else:  ## Take most probable list of oxidation states
                    oxi_dict_A = probable_oxis_A[0]
                if len(probable_oxis_B) == 0:
                    oxi_dict_B = {}
                    for elem in [str(f) for f in comp_B.elements]:
                        oxi_dict_B[elem] = 0.0
                else:
                    oxi_dict_B = probable_oxis_B[0]
                try:
                    struc_B = self.matcher.get_s2_like_s1(struc_A, struc_B)
                except ValueError:  ## Sometimes order matters
                    struc_A = self.matcher.get_s2_like_s1(struc_B, struc_A)
                index = 0
                for (site_A, site_B) in zip(struc_A, struc_B):
                    elem_A = ''.join([
                        char for char in str(site_A.species_string)
                        if char.isalpha()
                    ])
                    elem_B = ''.join([
                        char for char in str(site_B.species_string)
                        if char.isalpha()
                    ])
                    if solubility == True:
                        site_A_oxi = oxi_dict_A[elem_A]
                        site_B_oxi = oxi_dict_B[elem_B]
                        if site_A_oxi.is_integer():
                            if site_A_oxi == 0:
                                possible_rA = [
                                    pt.Element(elem_A).atomic_radius
                                ]
                            else:
                                possible_rA = [
                                    pt.Element(elem_A).ionic_radii[site_A_oxi]
                                ]
                        else:
                            possible_rA = []
                            possible_rA.append(
                                pt.Element(elem_A).ionic_radii[int(
                                    np.floor(site_A_oxi))])
                            possible_rA.append(
                                pt.Element(elem_A).ionic_radii[int(
                                    np.ceil(site_A_oxi))])
                        if site_B_oxi.is_integer():
                            if site_B_oxi == 0:
                                possible_rB = [
                                    pt.Element(elem_B).atomic_radius
                                ]
                            else:
                                possible_rB = [
                                    pt.Element(elem_B).ionic_radii[site_B_oxi]
                                ]
                        else:
                            possible_rB = []
                            possible_rB.append(
                                pt.Element(elem_B).ionic_radii[int(
                                    np.floor(site_B_oxi))])
                            possible_rB.append(
                                pt.Element(elem_B).ionic_radii[int(
                                    np.ceil(site_B_oxi))])
                        possible_diffs = []
                        for rA in possible_rA:
                            for rB in possible_rB:
                                possible_diffs.append(
                                    abs(float(rA) - float(rB)) /
                                    max([float(rA), float(rB)]))
                        if min(possible_diffs) > 0.15:
                            solubility = False

                if solubility == True:
                    return [cmpd_A, cmpd_B]
Ejemplo n.º 10
0
    def structure_array(self, crystal):
        '''
        Populates the label list with cartesian coordinates and bond radii,
        then organizes that information into an array for computation

        Args:
            crystal:  A pymatgen structure
            R_max: the maximum distances for the get all neighbors function

        Returns:
            an array where the first three colums are the x, y, and z
            coordinates and the last two columns correspond to the
            atomic and metallic radii
                '''
        def get_metals():
            metals = []
            for m in dir(Element)[:102]:
                ele = Element[m]
                if ele.is_transition_metal or ele.is_post_transition_metal \
                        or ele.is_alkali or ele.is_alkaline:
                    metals.append(m)
            return metals

        def get_radii(ele):
            if ele.value in get_metals():
                return ele.metallic_radius
            else:
                return ele.atomic_radius

        # create label list
        self.create_label_list(crystal)

        elements_dict = self.label_list

        # get all neighbors out to R_max
        neighbor = crystal.get_all_neighbors(r=self.R_max,
                                             include_index=True,
                                             include_image=True)
        # loop over all neighbors to each atom
        for i, _ in enumerate(neighbor):  # origin atom
            for j, _ in enumerate(neighbor[i]):  # neighbors
                element = neighbor[i][j][0].species_string
                # call element object for atomic and metallic radii
                ele = per.Element(neighbor[i][j][0].specie)
                # input the cartesian coords, atomic radii, and metallic
                # radii information into the label list
                elements_dict[element][0].append(neighbor[i][j][0].coords)
                elements_dict[element][1].append(get_radii(ele))

        self.label_list = elements_dict

        #  structure label list into array
        for i, element in enumerate(elements_dict):
            # first loop populate the array with the first element
            if i == 0:
                coord_array = np.array(elements_dict[element][0])
                radius_array = np.array(elements_dict[element][1])[:,
                                                                   np.newaxis]

            else:  # stack the array with succeeding elements
                coord_array = np.vstack(
                    (coord_array, np.array(elements_dict[element][0])))
                radius_array = np.vstack(
                    (radius_array,
                     np.array(elements_dict[element][1])[:, np.newaxis]))

        # When an empty array is passed or the indeces do not match
        # an exception is raised and the class will return a DDF of
        # 0 values
        try:
            self.struc_array = np.hstack((coord_array, radius_array))
        except ValueError:
            self.struc_array = np.array([0, 0, 0, 0])[np.newaxis, :]