def test_get_entry_energy(self): # Test warning message. comp = Composition('MnO3') with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") energy = InterfacialReactivity._get_entry_energy(self.pd, comp) self.assertTrue(len(w) == 1) self.assertTrue( "The reactant MnO3 has no matching entry with" " negative formation energy, instead convex " "hull energy for this composition will be used" " for reaction energy calculation." in str(w[-1].message)) test1 = np.isclose(energy, -30, atol=1e-03) self.assertTrue( test1, '_get_entry_energy: energy for {} is wrong!'.format( comp.reduced_formula)) # Test normal functionality comp = Composition('MnO2') test2 = np.isclose(InterfacialReactivity._get_entry_energy( self.pd, comp), -30, atol=1e-03) self.assertTrue( test2, '_get_entry_energy: energy for {} is wrong!'.format( comp.reduced_formula))
def test_get_chempot_correction(self): # test data from fig. 6 in ref: # Prediction of A2BX4 metal-chalcogenide compounds via # first-principles thermodynamics, PHYSICAL REVIEW B 86, 014109 (2012) # test pressure effect. actual = InterfacialReactivity.get_chempot_correction("O", 298.15, 100e5) expect = 0.05916 self.assertTrue( np.isclose(actual, expect, atol=1e-2), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect, actual), ) # test temperature effect. actual_2 = InterfacialReactivity.get_chempot_correction("O", 1000, 1e5) expect_2 = -0.82352 self.assertTrue( np.isclose(actual_2, expect_2, atol=1e-2), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect_2, actual_2), ) actual_3 = InterfacialReactivity.get_chempot_correction("O", 500, 1e5) expect_3 = -0.223 self.assertTrue( np.isclose(actual_3, expect_3, atol=1e-2), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect_3, actual_3), ) # test mixed effect. actual_4 = InterfacialReactivity.get_chempot_correction("O", 1000, 1e-25) expect_4 = -3.800 self.assertTrue( np.isclose(actual_4, expect_4, atol=1e-2), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect_4, actual_4), ) actual_5 = InterfacialReactivity.get_chempot_correction("O", 1250, 1e-25) expect_5 = -4.86 self.assertTrue( np.isclose(actual_5, expect_5, atol=1e-2), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect_5, actual_5), ) actual_6 = InterfacialReactivity.get_chempot_correction("O", 1500, 1e-25) expect_6 = -5.928 self.assertTrue( np.isclose(actual_6, expect_6, atol=1e-2), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect_6, actual_6), ) actual_7 = InterfacialReactivity.get_chempot_correction("O", 1000, 1e-15) expect_7 = -2.808 self.assertTrue( np.isclose(actual_7, expect_7, atol=1e-2), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect_7, actual_7), ) # test non-gas phase. actual_8 = InterfacialReactivity.get_chempot_correction("Li", 1000, 1e15) expect_8 = 0 self.assertTrue( np.isclose(actual_8, expect_8, atol=1e-5), "get_chempot_correction gets error, {0} expected but gets {1}".format(expect_8, actual_8), )
def test_convert(self): test_array = [(0.5, 1, 3), (0.4, 2, 3), (0, 1, 9), (1, 2, 7)] result = [InterfacialReactivity._convert(x, f1, f2) for x, f1, f2 in test_array] answer = [0.75, 0.5, 0, 1] self.assertTrue(np.allclose(result, answer), '_convert: conversion gets error! {0} expected,' ' but gets {1}'.format(answer, result))
def test_reverse_convert(self): test_array = [(0.5, 1, 3), (0.4, 2, 3), (0, 1, 9), (1, 2, 7)] result = [InterfacialReactivity._reverse_convert(x, f1, f2) for x, f1, f2 in test_array] answer = [0.25, 0.3076923, 0, 1] self.assertTrue(np.allclose(result, answer), '_convert: conversion gets error! {0} expected,' ' but gets {1}'.format(answer, result))
def react_interface(r1, r2, pd, num_entries, grand_pd=None): """ Calculate thermodynamically predicted reactions at the interface between two materials. Args: r1 (Composition): first reactant r2 (Composition): second reactant pd (PhaseDiagram): pymatgen phase diagram object num_entries (int): total number of entries in system, used in building reaction vector grand_pd (GrandPotentialPhaseDiagram): pymatgen grand pot. phase diagram object Returns: [ComputedReaction]: List of computed reacitons """ if grand_pd: interface = InterfacialReactivity( r1, r2, grand_pd, norm=True, include_no_mixing_energy=False, pd_non_grand=pd, use_hull_energy=True, ) else: interface = InterfacialReactivity( r1, r2, pd, norm=False, include_no_mixing_energy=False, pd_non_grand=None, use_hull_energy=True, ) entries = pd.all_entries rxns = { get_computed_rxn(rxn, entries, num_entries) for _, _, _, rxn, _ in interface.get_kinks() } return rxns
def test_convert(self): test_array = [(0.5, 1, 3), (0.4, 2, 3), (0, 1, 9), (1, 2, 7)] result = [ InterfacialReactivity._convert(x, f1, f2) for x, f1, f2 in test_array ] answer = [0.75, 0.5, 0, 1] self.assertTrue( np.allclose(result, answer), f"_convert: conversion gets error! {answer} expected, but gets {result}", )
def test_get_entry_energy(self): # Test warning message. comp = Composition('MnO3') with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") energy = InterfacialReactivity._get_entry_energy(self.pd, comp) self.assertTrue(len(w) == 1) self.assertTrue("The reactant MnO3 has no matching entry with" " negative formation energy, instead convex " "hull energy for this composition will be used" " for reaction energy calculation." in str(w[-1].message)) test1 = np.isclose(energy, -30, atol=1e-03) self.assertTrue(test1, '_get_entry_energy: energy for {} is wrong!'.format( comp.reduced_formula)) # Test normal functionality comp = Composition('MnO2') test2 = np.isclose(InterfacialReactivity._get_entry_energy(self.pd, comp), -30, atol=1e-03) self.assertTrue(test2, '_get_entry_energy: energy for {} is wrong!'.format( comp.reduced_formula))
def setUp(self): self.entries = [ComputedEntry(Composition('Li'), 0), ComputedEntry(Composition('Mn'), 0), ComputedEntry(Composition('O2'), 0), ComputedEntry(Composition('MnO2'), -10), ComputedEntry(Composition('Mn2O4'), -60), ComputedEntry(Composition('MnO3'), 20), ComputedEntry(Composition('Li2O'), -10), ComputedEntry(Composition('Li2O2'), -8), ComputedEntry(Composition('LiMnO2'), -30) ] self.pd = PhaseDiagram(self.entries) chempots = {'Li': -3} self.gpd = GrandPotentialPhaseDiagram(self.entries, chempots) self.ir = [] self.ir.append( InterfacialReactivity(Composition('O2'), Composition('Mn'), self.pd, norm=0, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('MnO2'), Composition('Mn'), self.gpd, norm=0, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Mn'), Composition('O2'), self.gpd, norm=1, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Li2O'), Composition('Mn'), self.gpd, norm=0, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Mn'), Composition('O2'), self.gpd, norm=1, include_no_mixing_energy=0, pd_non_grand=self.pd, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Mn'), Composition('Li2O'), self.gpd, norm=1, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Li2O2'), Composition('Li'), self.pd, norm=0, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=True)) self.ir.append( InterfacialReactivity(Composition('Li2O2'), Composition('Li'), self.pd, norm=0, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Li2O2'), Composition('MnO2'), self.gpd, norm=0, include_no_mixing_energy=0, pd_non_grand=self.pd, use_hull_energy=True)) self.ir.append( InterfacialReactivity(Composition('Li2O2'), Composition('MnO2'), self.gpd, norm=0, include_no_mixing_energy=0, pd_non_grand=self.pd, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('O2'), Composition('Mn'), self.pd, norm=1, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Li2O2'), Composition('Li2O2'), self.gpd, norm=1, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False)) self.ir.append( InterfacialReactivity(Composition('Li2O2'), Composition('Li2O2'), self.pd, norm=1, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False)) with self.assertRaises(Exception) as context1: self.ir.append( InterfacialReactivity(Composition('Li2O2'), Composition('Li'), self.pd, norm=1, include_no_mixing_energy=1, pd_non_grand=None)) self.assertTrue( 'Please provide grand phase diagram ' 'to compute no_mixing_energy!' == str(context1.exception)) with self.assertRaises(Exception) as context2: self.ir.append( InterfacialReactivity(Composition('O2'), Composition('Mn'), self.gpd, norm=0, include_no_mixing_energy=1, pd_non_grand=None)) self.assertTrue( 'Please provide non-grand phase diagram ' 'to compute no_mixing_energy!' == str(context2.exception))
def setUp(self): self.entries = [ ComputedEntry(Composition("Li"), 0), ComputedEntry(Composition("Mn"), 0), ComputedEntry(Composition("O2"), 0), ComputedEntry(Composition("MnO2"), -10), ComputedEntry(Composition("Mn2O4"), -60), ComputedEntry(Composition("MnO3"), 20), ComputedEntry(Composition("Li2O"), -10), ComputedEntry(Composition("Li2O2"), -8), ComputedEntry(Composition("LiMnO2"), -30), ] self.pd = PhaseDiagram(self.entries) chempots = {"Li": -3} self.gpd = GrandPotentialPhaseDiagram(self.entries, chempots) self.ir = [] # ir[0] self.ir.append( InterfacialReactivity( Composition("O2"), Composition("Mn"), self.pd, norm=0, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False, ) ) # ir[1] self.ir.append( InterfacialReactivity( Composition("MnO2"), Composition("Mn"), self.gpd, norm=0, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False, ) ) # ir[2] self.ir.append( InterfacialReactivity( Composition("Mn"), Composition("O2"), self.gpd, norm=1, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False, ) ) # ir[3] self.ir.append( InterfacialReactivity( Composition("Li2O"), Composition("Mn"), self.gpd, norm=0, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False, ) ) # ir[4] self.ir.append( InterfacialReactivity( Composition("Mn"), Composition("O2"), self.gpd, norm=1, include_no_mixing_energy=0, pd_non_grand=self.pd, use_hull_energy=False, ) ) # ir[5] self.ir.append( InterfacialReactivity( Composition("Mn"), Composition("Li2O"), self.gpd, norm=1, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False, ) ) # ir[6] self.ir.append( InterfacialReactivity( Composition("Li2O2"), Composition("Li"), self.pd, norm=0, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=True, ) ) # ir[7] self.ir.append( InterfacialReactivity( Composition("Li2O2"), Composition("Li"), self.pd, norm=0, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False, ) ) # ir[8] self.ir.append( InterfacialReactivity( Composition("Li2O2"), Composition("MnO2"), self.gpd, norm=0, include_no_mixing_energy=0, pd_non_grand=self.pd, use_hull_energy=True, ) ) # ir[9] self.ir.append( InterfacialReactivity( Composition("Li2O2"), Composition("MnO2"), self.gpd, norm=0, include_no_mixing_energy=0, pd_non_grand=self.pd, use_hull_energy=False, ) ) # ir[10] self.ir.append( InterfacialReactivity( Composition("O2"), Composition("Mn"), self.pd, norm=1, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False, ) ) # ir[11] self.ir.append( InterfacialReactivity( Composition("Li2O2"), Composition("Li2O2"), self.gpd, norm=1, include_no_mixing_energy=1, pd_non_grand=self.pd, use_hull_energy=False, ) ) # ir[12] self.ir.append( InterfacialReactivity( Composition("Li2O2"), Composition("Li2O2"), self.pd, norm=1, include_no_mixing_energy=0, pd_non_grand=None, use_hull_energy=False, ) ) with self.assertRaises(Exception) as context1: self.ir.append( InterfacialReactivity( Composition("Li2O2"), Composition("Li"), self.pd, norm=1, include_no_mixing_energy=1, pd_non_grand=None, ) ) self.assertTrue("Please provide grand phase diagram to compute no_mixing_energy!" == str(context1.exception)) with self.assertRaises(Exception) as context2: self.ir.append( InterfacialReactivity( Composition("O2"), Composition("Mn"), self.gpd, norm=0, include_no_mixing_energy=1, pd_non_grand=None, ) ) self.assertTrue( "Please provide non-grand phase diagram to compute no_mixing_energy!" == str(context2.exception) )
def setUp(self): self.entries = [ ComputedEntry(Composition("Li"), 0), ComputedEntry(Composition("Mn"), 0), ComputedEntry(Composition("O2"), 0), ComputedEntry(Composition("MnO2"), -10), ComputedEntry(Composition("Mn2O4"), -60), ComputedEntry(Composition("MnO3"), 20), ComputedEntry(Composition("Li2O"), -10), ComputedEntry(Composition("Li2O2"), -8), ComputedEntry(Composition("LiMnO2"), -30), ] self.pd = PhaseDiagram(self.entries) chempots = {Element("Li"): -3} self.gpd = GrandPotentialPhaseDiagram(self.entries, chempots) ir_0 = InterfacialReactivity( c1=Composition("O2"), c2=Composition("Mn"), pd=self.pd, norm=False, use_hull_energy=False, ) ir_1 = GrandPotentialInterfacialReactivity( c1=Composition("MnO2"), c2=Composition("Mn"), grand_pd=self.gpd, pd_non_grand=self.pd, norm=False, include_no_mixing_energy=True, use_hull_energy=False, ) ir_2 = GrandPotentialInterfacialReactivity( c1=Composition("Mn"), c2=Composition("O2"), grand_pd=self.gpd, pd_non_grand=self.pd, norm=True, include_no_mixing_energy=True, use_hull_energy=False, ) ir_3 = GrandPotentialInterfacialReactivity( c1=Composition("Li2O"), c2=Composition("Mn"), grand_pd=self.gpd, norm=False, include_no_mixing_energy=True, pd_non_grand=self.pd, use_hull_energy=False, ) ir_4 = GrandPotentialInterfacialReactivity( c1=Composition("Mn"), c2=Composition("O2"), grand_pd=self.gpd, norm=True, include_no_mixing_energy=False, pd_non_grand=self.pd, use_hull_energy=False, ) ir_5 = GrandPotentialInterfacialReactivity( c1=Composition("Mn"), c2=Composition("Li2O"), grand_pd=self.gpd, pd_non_grand=self.pd, norm=True, include_no_mixing_energy=True, use_hull_energy=False, ) ir_6 = InterfacialReactivity( c1=Composition("Li2O2"), c2=Composition("Li"), pd=self.pd, norm=False, use_hull_energy=True, ) ir_7 = InterfacialReactivity( c1=Composition("Li2O2"), c2=Composition("Li"), pd=self.pd, norm=False, use_hull_energy=False, ) ir_8 = GrandPotentialInterfacialReactivity( c1=Composition("Li2O2"), c2=Composition("MnO2"), grand_pd=self.gpd, pd_non_grand=self.pd, norm=False, include_no_mixing_energy=False, use_hull_energy=True, ) ir_9 = GrandPotentialInterfacialReactivity( c1=Composition("Li2O2"), c2=Composition("MnO2"), grand_pd=self.gpd, pd_non_grand=self.pd, norm=False, include_no_mixing_energy=False, use_hull_energy=False, ) ir_10 = InterfacialReactivity( Composition("O2"), Composition("Mn"), pd=self.pd, norm=True, use_hull_energy=False, ) ir_11 = GrandPotentialInterfacialReactivity( Composition("Li2O2"), Composition("Li2O2"), grand_pd=self.gpd, norm=True, include_no_mixing_energy=True, pd_non_grand=self.pd, use_hull_energy=False, ) ir_12 = InterfacialReactivity( Composition("Li2O2"), Composition("Li2O2"), pd=self.pd, norm=True, use_hull_energy=False, ) with self.assertRaises(Exception) as context1: ir_13 = InterfacialReactivity(Composition("Li2O2"), Composition("Li"), pd=self.gpd, norm=True) self.assertTrue( "Please use the GrandPotentialInterfacialReactivity " "class for interfacial reactions with open elements!" == str( context1.exception)) with self.assertRaises(Exception) as context2: ir_14 = GrandPotentialInterfacialReactivity( Composition("O2"), Composition("Mn"), grand_pd=self.gpd, pd_non_grand=None, norm=False, include_no_mixing_energy=True, ) self.assertTrue( "Please provide non-grand phase diagram to compute no_mixing_energy!" == str(context2.exception)) self.ir = [ ir_0, ir_1, ir_2, ir_3, ir_4, ir_5, ir_6, ir_7, ir_8, ir_9, ir_10, ir_11, ir_12 ]
def test_get_chempot_correction(self): # test data from fig. 6 in ref: # Prediction of A2BX4 metal-chalcogenide compounds via # first-principles thermodynamics, PHYSICAL REVIEW B 86, 014109 (2012) # test pressure effect. actual = InterfacialReactivity.get_chempot_correction("O", 298.15, 100E5) expect = 0.05916 self.assertTrue(np.isclose(actual, expect, atol=1E-2), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect, actual)) # test temperature effect. actual_2 = InterfacialReactivity.get_chempot_correction("O", 1000, 1E5) expect_2 = -0.82352 self.assertTrue(np.isclose(actual_2, expect_2, atol=1E-2), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect_2, actual_2)) actual_3 = InterfacialReactivity.get_chempot_correction("O", 500, 1E5) expect_3 = -0.223 self.assertTrue(np.isclose(actual_3, expect_3, atol=1E-2), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect_3, actual_3)) # test mixed effect. actual_4 = InterfacialReactivity.get_chempot_correction("O", 1000, 1E-25) expect_4 = -3.800 self.assertTrue(np.isclose(actual_4, expect_4, atol=1E-2), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect_4, actual_4)) actual_5 = InterfacialReactivity.get_chempot_correction("O", 1250, 1E-25) expect_5 = -4.86 self.assertTrue(np.isclose(actual_5, expect_5, atol=1E-2), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect_5, actual_5)) actual_6 = InterfacialReactivity.get_chempot_correction("O", 1500, 1E-25) expect_6 = -5.928 self.assertTrue(np.isclose(actual_6, expect_6, atol=1E-2), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect_6, actual_6)) actual_7 = InterfacialReactivity.get_chempot_correction("O", 1000, 1E-15) expect_7 = -2.808 self.assertTrue(np.isclose(actual_7, expect_7, atol=1E-2), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect_7, actual_7)) # test non-gas phase. actual_8 = InterfacialReactivity.get_chempot_correction("Li", 1000, 1E15) expect_8 = 0 self.assertTrue(np.isclose(actual_8, expect_8, atol=1E-5), "get_chempot_correction gets " "error, {0} expected but gets {1}".format(expect_8, actual_8))
entries = mpr.get_entries_in_chemsys(elements) # Build a phase diagram using these entries. pd = PhaseDiagram(entries) # For an open system, include the grand potential phase diagram. if grand: # Get the chemical potential of the pure subtance. mu = pd.get_transition_chempots(Element(open_el))[0] # Set the chemical potential in the elemental reservoir. chempots = {open_el: relative_mu + mu} # Build the grand potential phase diagram gpd = GrandPotentialPhaseDiagram(entries, chempots) # Create InterfacialReactivity object. interface = InterfacialReactivity(comp1, comp2, gpd, norm=True, include_no_mixing_energy=True, pd_non_grand=pd, use_hull_energy=False) else: interface = InterfacialReactivity(comp1, comp2, pd, norm=True, include_no_mixing_energy=False, pd_non_grand=None, use_hull_energy=False) plt = interface.plot()