Exemplo n.º 1
0
 def chemical_spaces_and_subspaces(self):
     """
     Args:
         
     Returns:
         list of unique chemical spaces (tuple)
     """
     compounds = self.compounds
     return list(set([tuple(CompAnalyzer(c).els) for c in compounds]))
Exemplo n.º 2
0
 def A_for_decomp_solver(self, compound, competing_compounds):
     """
     Args:
         compound (str) - the compound (str) to analyze
         competing_compounds (list) - list of compounds (str) that may participate in the decomposition reaction for the input compound
     
     Returns:
         matrix (2D array) of elemental amounts (float) used for implementing molar conservation during decomposition solution
     """
     chemical_space = tuple(CompAnalyzer(compound).els)
     atoms_per_fu = [
         CompAnalyzer(c).num_atoms_in_formula() for c in competing_compounds
     ]
     A = self.amts_matrix(competing_compounds, chemical_space)
     for row in range(len(competing_compounds)):
         for col in range(len(chemical_space)):
             A[row, col] *= atoms_per_fu[row]
     return A.T
Exemplo n.º 3
0
    def __init__(self, hull_data, chemical_space):
        """
        Args:
            hull_data (dict) - dictionary generated in GetHullInputData().hull_data
            chemical_space (str) - chemical space to analyze in 'el1_el2_...' (alphabetized) format
        
        Returns:
            grabs only the relevant sub-dict from hull_data
            changes chemical space to tuple (el1, el2, ...)
        """
        hull_data = hull_data[chemical_space]

        # below is unnecessary except for this one case where I dont want to regenerate a hullin.json
        keys_to_remove = [
            k for k in hull_data if CompAnalyzer(k).num_els_in_formula == 1
        ]
        hull_data = {
            k: hull_data[k]
            for k in hull_data if k not in keys_to_remove
        }
        #        keys_to_remove = [k for k in keys_to_remove
        #                                  if ('1' in k) or
        #                                     ('2' in k) or
        #                                     ('3' in k) or
        #                                     ('4' in k) or
        #                                     ('5' in k) or
        #                                     ('6' in k) or
        #                                     ('7' in k) or
        #                                     ('8' in k) or
        #                                     ('9' in k) or
        #                                     ('0' in k)]
        #        self.hull_data = {k : tmp_hull_data[k] for k in tmp_hull_data if k not in keys_to_remove}
        els = chemical_space.split('_')
        for el in els:
            hull_data[el] = {
                'E': 0,
                'amts': {
                    els[i]: CompAnalyzer(el).fractional_amt_of_el(els[i])
                    for i in range(len(els))
                }
            }
        self.hull_data = hull_data
        #print(self.hull_data)
        self.chemical_space = tuple(els)
Exemplo n.º 4
0
 def decomp_energy(self, compound):
     """
     Args:
         compound (str) - the compound (str) to analyze
     
     Returns:
         decomposition energy (float)
     """
     hull_data = self.hull_data
     decomp_products = self.decomp_products(compound)
     if isinstance(decomp_products, float):
         return np.nan
     decomp_enthalpy = 0
     for k in decomp_products:
         decomp_enthalpy += decomp_products[k]['amt'] * decomp_products[k][
             'E'] * CompAnalyzer(k).num_atoms_in_formula()
     return (hull_data[compound]['E'] *
             CompAnalyzer(compound).num_atoms_in_formula() - decomp_enthalpy
             ) / CompAnalyzer(compound).num_atoms_in_formula()
Exemplo n.º 5
0
def _kJmol_eVat(E, formula):
    """
    Args:
        E (float) - energy in kJ/mol
        formula (str)
        
    Returns:
        E (float) in eV/atom
    """
    natoms = CompAnalyzer(formula).num_atoms_in_formula()
    return E / natoms / 96.485
Exemplo n.º 6
0
 def A(self):
     input_data = self.input_data
     relevant_els = self._relevant_els
     sorted_formulas = self._sorted_formulas
     A = np.zeros((len(relevant_els), len(input_data)))
     for row in range(len(relevant_els)):
         el = relevant_els[row]
         for col in range(len(input_data)):
             formula = sorted_formulas[col]
             A[row, col] = CompAnalyzer(formula).amt_of_el(el)
     return A
Exemplo n.º 7
0
def cmpd_to_pt(cmpd, els):
    """
    Args:
        cmpd (str) - chemical formula
        els (list) - ordered list of elements (str) in triangle (right, top, left)
    
    Returns:
        (x, y) for compound
    """
    tri = [CompAnalyzer(cmpd).fractional_amt_of_el(el) for el in els]
    return triangle_to_square(tri)
Exemplo n.º 8
0
def _eVat_kJmol(E, formula):
    """
    Args:
        E (float) - energy in eV/atom
        formula (str)
        
    Returns:
        E (float) in kJ/mol
    """
    natoms = CompAnalyzer(formula).num_atoms_in_formula()
    return E * natoms * 96.485
Exemplo n.º 9
0
 def __init__(self, compound_to_energy, formation_energy_key):
     """
     Args:
         compound_to_energy (dict) - {formula (str) : {formation_energy_key (str) : formation energy (float)}}
         formation_energy_key (str) - key within compound_to_energy to use for formation energy
     
     Returns:
         dictionary of {formula (str) : formation energy (float)}
     """
     self.compound_to_energy = {k : compound_to_energy[k][formation_energy_key] 
                                 for k in compound_to_energy
                                 if CompAnalyzer(k).num_els_in_formula > 1}
Exemplo n.º 10
0
 def A(self):
     input_data = self.input_data
     relevant_els = self._relevant_els
     sorted_formulas = self._sorted_formulas
     formulas = [f for f in sorted_formulas if f not in self.excluded]
     A = np.zeros((len(relevant_els), len(formulas)))
     for row in range(len(relevant_els)):
         el = relevant_els[row]
         for col in range(len(formulas)):
             formula = formulas[col]
             A[row, col] = CompAnalyzer(formula).amt_of_el(el)
     return A
Exemplo n.º 11
0
 def Es_for_decomp_solver(self, compound, competing_compounds):
     """
     Args:
         compound (str) - the compound (str) to analyze
         competing_compounds (list) - list of compounds (str) that may participate in the decomposition reaction for the input compound
     
     Returns:
         array of formation energies per formula unit (float) used for minimization problem during decomposition solution
     """     
     atoms_per_fu = [CompAnalyzer(c).num_atoms_in_formula() for c in competing_compounds]        
     Es_per_atom = self.formation_energy_array(competing_compounds)    
     return [Es_per_atom[i]*atoms_per_fu[i] for i in range(len(competing_compounds))] 
Exemplo n.º 12
0
 def hull_data(self, fjson=False, remake=False):
     """
     Args:
         fjson (str) - file name to write hull data to
         remake (bool) - if True, write json; if False, read json
         
     Returns:
         dict of {chemical space (str) : {formula (str) : {'E' : formation energy (float),
                                                           'amts' : {el (str) : fractional amt of el in formula (float) for el in space}} 
                                         for all relevant formulas including elements}
             elements are automatically given formation energy = 0
             chemical space is now in 'el1_el2_...' format to be jsonable
     """
     if not fjson:
         fjson = 'hull_input_data.json'
     if (remake == True) or not os.path.exists(fjson):
         hull_data = {}
         hull_spaces = self.hull_spaces()
         compounds = self.compounds
         compound_to_energy = self.compound_to_energy
         for space in hull_spaces:
             for el in space:
                 compound_to_energy[el] = 0
             relevant_compounds = [
                 c for c in compounds
                 if set(CompAnalyzer(c).els).issubset(set(space))
             ] + list(space)
             hull_data['_'.join(list(space))] = {
                 c: {
                     'E': compound_to_energy[c],
                     'amts': {
                         el: CompAnalyzer(c).fractional_amt_of_el(el=el)
                         for el in space
                     }
                 }
                 for c in relevant_compounds
             }
         return write_json(hull_data, fjson)
     else:
         return read_json(fjson)
Exemplo n.º 13
0
 def competing_compounds(self, compound):
     """
     Args:
         compound (str) - the compound (str) to analyze
     
     Returns:
         list of compounds (str) that may participate in the decomposition reaction for the input compound
     """
     compounds = self.sorted_compounds
     if compound in self.unstable_compounds:
         compounds = self.stable_compounds
     competing_compounds = [c for c in compounds if c != compound if set(CompAnalyzer(c).els).issubset(CompAnalyzer(compound).els)]
     return competing_compounds
Exemplo n.º 14
0
    def hull_output_data(self):
        """
        Args:
            compound (str) - formula to get data for
            
        Returns:
            hull_output_data but only for single compound
        """

        gppd = self._gppd
        entries = gppd.all_entries
        stable_entries = list(gppd.stable_entries)
        el_refs = list(gppd.el_refs.values())
        data = {}
        for e in entries + el_refs:
            print(e)
            stability = True if ((e in stable_entries) or
                                 (e in el_refs)) else False
            original_cmpd = CompAnalyzer(e.original_comp.formula).std_formula()
            print(original_cmpd)
            cmpd = CompAnalyzer(e.composition.formula).std_formula()
            print(cmpd)
            if CompAnalyzer(cmpd).num_els_in_formula == 1:
                phid = None
                decomp = None
                rxn = None
            else:
                phid = gppd.get_equilibrium_reaction_energy(
                    e) if stability else gppd.get_e_above_hull(e)
                decomp = gppd.get_decomposition(e.composition)
                rxn = _convert_decomp_to_rxn(decomp)
            data[original_cmpd] = {
                'stability': stability,
                'phid': phid,
                'rxn': rxn,
                'entry': e.as_dict()
            }

        return data
Exemplo n.º 15
0
 def b(self):
     input_data = self.input_data
     relevant_els = self._relevant_els
     b = np.zeros((len(relevant_els)))
     sorted_formulas = self._sorted_formulas
     for i in range(len(relevant_els)):
         el = relevant_els[i]
         amt = 0
         for formula in sorted_formulas:
             amt += input_data[formula]['amt'] * CompAnalyzer(
                 formula).amt_of_el(el)
         b[i] = amt
     return b
 def A(self):
     r, p = self.reactants, self.products
     balance_els = self.balance_els
     A = np.zeros(shape=(len(r) + len(p), len(balance_els) + len(p)))
     A = A.T
     for i in range(len(balance_els)):
         count = 0
         for j in range(len(r) + len(p)):
             count += 1
             if count <= len(r):
                 sign = 1
                 cmpd = r[j]
             else:
                 sign = -1
                 cmpd = p[j - len(r)]
             A[i, j] = sign * CompAnalyzer(cmpd).amt_of_el(balance_els[i])
     line = [0 for i in range(len(r))]
     for j in range(len(p)):
         line.append(
             np.sum(
                 [CompAnalyzer(p[j]).amt_of_el(el) for el in balance_els]))
     A[-1] = line
     return np.array(A)
Exemplo n.º 17
0
 def test_hull_analysis_against_MP(self):
     """
     Uses an MP query of the Al-Ca-Mg-O-Si space
     Compares my decomp energies to theirs
         Changes mine to 0 for stable compounds to force agreement with theirs
     """        
     d = read_json(os.path.join(test_data_dir, 'MP_Ca-Mg-Al-Si-O.json'))
     data_for_hulls = {CompAnalyzer(d[k]['pretty_formula']).std_formula() : {'E' : d[k]['formation_energy_per_atom']} for k in d if d[k]['is_min_ID'] == True}
     obj = GetHullInputData(data_for_hulls, 'E')
     fjson = os.path.join(test_data_dir, '_'.join(['hulls', 'Ca-Mg-Al-Si-O.json']))
     hull_data = obj.hull_data(fjson, True)
     for chemical_space in hull_data:
         obj = AnalyzeHull(hull_data, chemical_space)
         hull_results = obj.hull_output_data
     for ID in d:
         if d[ID]['is_min_ID'] == 1:
             cmpd = CompAnalyzer(d[ID]['pretty_formula']).std_formula()
             Ed_MP = d[ID]['e_above_hull']
             Ed_me = hull_results[cmpd]['Ed']
             # MP shows all stables as Hd = 0
             if Ed_me < 0:
                 Ed_me = 0
             self.assertAlmostEqual(Ed_me, Ed_MP, places=3)
Exemplo n.º 18
0
    def feed(self):
        """
        Returns:
            {formula (str) : # moles in feed (float)}
        """
        interface = self.interface
        n_species = interface.count('|') + 1

        items = interface.split('|')

        return {
            CompAnalyzer(item.split('_')[1]).std_formula():
            float(item.split('_')[0])
            for item in items
        }
Exemplo n.º 19
0
def get_label(cmpd, els):
    """
    Args:
        cmpd (str) - chemical formula
        els (list) - ordered list of elements (str) as you want them to appear in label
    
    Returns:
        neatly formatted chemical formula label
    """
    label = r'$'
    for el in els:
        amt = CompAnalyzer(cmpd).amt_of_el(el)
        if amt == 0:
            continue
        label += el
        if amt == 1:
            continue
        label += '_{%s}' % amt
    label += '$'
    return label
Exemplo n.º 20
0
    def rxn(self):
        order = self.el_order_for_rxns
        T = self.temp
        species = self.species
        rxn = r''
        reactants = [s for s in species if species[s]['side'] == 'left']
        products = [s for s in species if species[s]['side'] == 'right']
        if not order:
            order = [CompAnalyzer(c).els for c in reactants + products]
            order = [j for i in order for j in i]
            order = sorted(list(set(order)))
        count = 0
        for r in reactants:
            amt = species[r]['amt']
            if amt == 0:
                continue
            if amt != 1:
                rxn += str(np.round(amt, 2))
            rxn += get_label(r, order)
            count += 1
            if count < len(reactants):
                rxn += '+'
        rxn += ' --> '
        count = 0
        for p in products:
            amt = species[p]['amt']
            if amt == 0:
                continue
            if amt != 1:
                rxn += str(np.round(amt, 2))
            rxn += get_label(p, order)
            count += 1
            if count < len(products):
                rxn += '+'
        rxn += r''

        rxn = rxn.replace('$', '').replace('{', '').replace('}', '').replace(
            '_', '').replace('+', ' + ')
        return rxn
Exemplo n.º 21
0
def make_data(remake=False):
    fjson = '_data_for_RxnEngr.json'
    if not remake and os.path.exists(fjson):
        return read_json(fjson)
    data_file = '/Users/chrisbartel/Dropbox/postdoc/projects/synthesis/paperdb/data/mp/MP_stability.json'
    data = read_json(data_file)

    my_els = ['Li', 'Co', 'Ba', 'Ti', 'Y', 'Ba', 'Cu', 'C', 'O']

    cmpds = sorted(list(data['0'].keys()))
    relevant_cmpds = [
        c for c in cmpds
        if set(CompAnalyzer(c).els).issubset(set(sorted(my_els)))
    ]

    d = {T: {} for T in data}
    for c in relevant_cmpds:
        for T in d:
            if c in data[T]:
                d[T][c] = data[T][c]

    return write_json(d, fjson)
Exemplo n.º 22
0
    def decomp_solution(self, compound):
        """
        Args:
            compound (str) - the compound (str) to analyze
        
        Returns:
            scipy.optimize.minimize result 
                for finding the linear combination of competing compounds that minimizes the competing formation energy
        """
        competing_compounds = self.competing_compounds(compound)
        A = self.A_for_decomp_solver(compound, competing_compounds)
        b = self.b_for_decomp_solver(compound, competing_compounds)
        Es = self.Es_for_decomp_solver(compound, competing_compounds)
        n0 = [0.01 for c in competing_compounds]
        max_bound = CompAnalyzer(compound).num_atoms_in_formula()
        bounds = [(0, max_bound) for c in competing_compounds]

        def competing_formation_energy(nj):
            nj = np.array(nj)
            return np.dot(nj, Es)

        constraints = [{'type': 'eq', 'fun': lambda x: np.dot(A, x) - b}]
        tol, maxiter, disp = 1e-4, 1000, False
        for tol in [1e-4, 1e-3, 5e-3, 1e-2]:
            solution = minimize(competing_formation_energy,
                                n0,
                                method='SLSQP',
                                bounds=bounds,
                                constraints=constraints,
                                tol=tol,
                                options={
                                    'maxiter': maxiter,
                                    'disp': disp
                                })
            if solution.success:
                return solution
        return solution
Exemplo n.º 23
0
 def test_fractional_amts(self):
     formula = 'O2 Ti O'
     answer = [3 / 4, 1 / 4]
     self.assertEqual(CompAnalyzer(formula).fractional_amts, answer)
 def all_els(self):
     r, p = self.reactants, self.products
     els = [CompAnalyzer(c).els for c in r + p]
     els = [j for i in els for j in i]
     return sorted(list(set(els)))
Exemplo n.º 25
0
 def test_frac_amt_of_el_when_el_is_there(self):
     formula = 'Al2O3'
     el = 'Al'
     answer = 0.4
     self.assertEqual(
         CompAnalyzer(formula).fractional_amt_of_el(el=el), answer)
Exemplo n.º 26
0
    def _label_pts(self,
                   el_order_for_label,
                   pt_label_size=16,
                   label_unstable=False,
                   specify_labels={},
                   only_certain_labels=[],
                   skip_certain_labels=[]):
        """
        Args:
            el_order_for_label (list) - ordered list of elements for labels
            pt_label_size (int) - font size for cmpd labels
            label_unstable (bool) - whether or not to label unstable points
            specify_labels (dict) - specific positions for certain compounds
                                    {cmpd : {'xpos' : ,
                                             'ypos' : ,
                                             'xalign' : ,
                                             'yalign' : }}
            only_certain_labels (list) - enforce only these compounds are labeled
            skip_certain_labels (list) - skip these labels
        
        Returns:
            labels the compounds
        """
        input_data = self.input_data
        stable_cmpds = [
            c for c in input_data if input_data[c]['stability']
            if len(CompAnalyzer(c).els) > 1
        ]
        unstable_cmpds = [
            c for c in input_data if not input_data[c]['stability']
        ]
        if label_unstable:
            cmpds_to_label = stable_cmpds + unstable_cmpds
        else:
            cmpds_to_label = stable_cmpds
        if len(only_certain_labels) > 0:
            cmpds_to_label = only_certain_labels
        cmpds_to_label = [
            c for c in cmpds_to_label if c not in skip_certain_labels
        ]
        count = 0
        for cmpd in cmpds_to_label:
            pt = cmpd_to_pt(cmpd, self.els)
            tri = [
                CompAnalyzer(cmpd).fractional_amt_of_el(el) for el in self.els
            ]
            label = get_label(cmpd, el_order_for_label)
            if cmpd in specify_labels:
                xpos, xalign, ypos, yalign = [
                    specify_labels[cmpd][k]
                    for k in ['xpos', 'xalign', 'ypos', 'yalign']
                ]
            elif tri[1] in (0, 1):
                xpos = pt[0]
                xalign = 'center'
                ypos = -0.02
                yalign = 'top'

            elif tri[0] in (0, 1):
                xpos = pt[0] - 0.02
                xalign = 'right'
                ypos = pt[1]
                yalign = 'center'

            elif tri[2] in (0, 1):
                xpos = pt[0] + 0.02
                xalign = 'left'
                ypos = pt[1]
                yalign = 'center'
            else:
                if count % 2:
                    x_sign = 1
                    y_sign = -1
                    xalign = 'left'
                    yalign = 'top'
                else:
                    x_sign, y_sign, xalign, yalign = -1, 1, 'right', 'bottom'
                xpos = pt[0] + x_sign * 0.01
                ypos = pt[1] + y_sign * 0.01
                count += 1
            if cmpd in stable_cmpds:
                color = params()['stable']['c']
            else:
                color = params()['unstable']['c']
            ax = plt.text(xpos,
                          ypos,
                          label,
                          horizontalalignment=xalign,
                          verticalalignment=yalign,
                          fontsize=pt_label_size,
                          color=color,
                          zorder=100)
Exemplo n.º 27
0
 def _entries(self):
     d = self.compound_to_total_energy_per_atom
     return [
         PDEntry(c, d[c] * CompAnalyzer(c).num_atoms_in_formula())
         for c in d
     ]
Exemplo n.º 28
0
 def _relevant_els(self):
     cmpds = self.input_data.keys()
     els = [CompAnalyzer(c).els for c in cmpds]
     return sorted(list(set([j for i in els for j in i])))
Exemplo n.º 29
0
 def _eV_to_kJ(formula, eV_at):
     return 96.485 * eV_at * CompAnalyzer(formula).num_atoms_in_formula()
Exemplo n.º 30
0
 def test_amt_of_el_when_el_is_there(self):
     formula = 'Al2O3'
     el = 'Al'
     answer = 2
     self.assertEqual(CompAnalyzer(formula).amt_of_el(el=el), answer)