Exemplo n.º 1
0
class NanoscaleStabilityTest(PymatgenTest):
    def setUp(self):

        # Load all entries
        La_hcp_entry_dict = get_entry_dict(
            os.path.join(get_path(""), "La_hcp_entries.txt"))
        La_fcc_entry_dict = get_entry_dict(
            os.path.join(get_path(""), "La_fcc_entries.txt"))
        with open(os.path.join(get_path(""),
                               'ucell_entries.txt')) as ucell_entries:
            ucell_entries = json.loads(ucell_entries.read())
        La_hcp_ucell_entry = ComputedStructureEntry.from_dict(
            ucell_entries["La_hcp"])
        La_fcc_ucell_entry = ComputedStructureEntry.from_dict(
            ucell_entries["La_fcc"])

        # Set up the NanoscaleStabilityClass
        self.La_hcp_analyzer = SurfaceEnergyPlotter(La_hcp_entry_dict,
                                                    La_hcp_ucell_entry)
        self.La_fcc_analyzer = SurfaceEnergyPlotter(La_fcc_entry_dict,
                                                    La_fcc_ucell_entry)
        self.nanoscale_stability = NanoscaleStability(
            [self.La_fcc_analyzer, self.La_hcp_analyzer])

    def test_stability_at_r(self):

        # Check that we have a different polymorph that is
        # stable below or above the equilibrium particle size
        r = self.nanoscale_stability.solve_equilibrium_point(
            self.La_hcp_analyzer, self.La_fcc_analyzer) * 10

        # hcp phase of La particle should be the stable
        # polymorph above the equilibrium radius
        hcp_wulff = self.La_hcp_analyzer.wulff_from_chempot()
        bulk = self.La_hcp_analyzer.ucell_entry
        ghcp, rhcp = self.nanoscale_stability.wulff_gform_and_r(
            hcp_wulff, bulk, r + 10, from_sphere_area=True)
        fcc_wulff = self.La_fcc_analyzer.wulff_from_chempot()
        bulk = self.La_fcc_analyzer.ucell_entry
        gfcc, rfcc = self.nanoscale_stability.wulff_gform_and_r(
            fcc_wulff, bulk, r + 10, from_sphere_area=True)
        self.assertGreater(gfcc, ghcp)

        # fcc phase of La particle should be the stable
        # polymorph below the equilibrium radius
        hcp_wulff = self.La_hcp_analyzer.wulff_from_chempot()
        bulk = self.La_hcp_analyzer.ucell_entry
        ghcp, rhcp = self.nanoscale_stability.wulff_gform_and_r(
            hcp_wulff, bulk, r - 10, from_sphere_area=True)
        fcc_wulff = self.La_fcc_analyzer.wulff_from_chempot()
        bulk = self.La_fcc_analyzer.ucell_entry
        gfcc, rfcc = self.nanoscale_stability.wulff_gform_and_r(
            fcc_wulff, bulk, r - 10, from_sphere_area=True)
        self.assertLess(gfcc, ghcp)
Exemplo n.º 2
0
class NanoscaleStabilityTest(PymatgenTest):

    def setUp(self):

        # Load all entries
        La_hcp_entry_dict = get_entry_dict(os.path.join(get_path(""),
                                                        "La_hcp_entries.txt"))
        La_fcc_entry_dict = get_entry_dict(os.path.join(get_path(""),
                                                        "La_fcc_entries.txt"))
        with open(os.path.join(get_path(""), 'ucell_entries.txt')) as ucell_entries:
            ucell_entries = json.loads(ucell_entries.read())
        La_hcp_ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["La_hcp"])
        La_fcc_ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["La_fcc"])

        # Set up the NanoscaleStabilityClass
        self.La_hcp_analyzer = SurfaceEnergyPlotter(La_hcp_entry_dict,
                                                    La_hcp_ucell_entry)
        self.La_fcc_analyzer = SurfaceEnergyPlotter(La_fcc_entry_dict,
                                                    La_fcc_ucell_entry)
        self.nanoscale_stability = NanoscaleStability([self.La_fcc_analyzer,
                                                       self.La_hcp_analyzer])

    def test_stability_at_r(self):

        # Check that we have a different polymorph that is
        # stable below or above the equilibrium particle size
        r = self.nanoscale_stability.solve_equilibrium_point(self.La_hcp_analyzer,
                                                             self.La_fcc_analyzer)*10

        # hcp phase of La particle should be the stable
        # polymorph above the equilibrium radius
        hcp_wulff = self.La_hcp_analyzer.wulff_from_chempot()
        bulk = self.La_hcp_analyzer.ucell_entry
        ghcp, rhcp = self.nanoscale_stability.wulff_gform_and_r(hcp_wulff, bulk, r+10,
                                                                from_sphere_area=True)
        fcc_wulff = self.La_fcc_analyzer.wulff_from_chempot()
        bulk = self.La_fcc_analyzer.ucell_entry
        gfcc, rfcc = self.nanoscale_stability.wulff_gform_and_r(fcc_wulff, bulk, r+10,
                                                                from_sphere_area=True)
        self.assertGreater(gfcc, ghcp)

        # fcc phase of La particle should be the stable
        # polymorph below the equilibrium radius
        hcp_wulff = self.La_hcp_analyzer.wulff_from_chempot()
        bulk = self.La_hcp_analyzer.ucell_entry
        ghcp, rhcp = self.nanoscale_stability.wulff_gform_and_r(hcp_wulff, bulk, r-10,
                                                                from_sphere_area=True)
        fcc_wulff = self.La_fcc_analyzer.wulff_from_chempot()
        bulk = self.La_fcc_analyzer.ucell_entry
        gfcc, rfcc = self.nanoscale_stability.wulff_gform_and_r(fcc_wulff, bulk, r-10,
                                                                from_sphere_area=True)
        self.assertLess(gfcc, ghcp)
Exemplo n.º 3
0
class SurfaceEnergyPlotterTest(PymatgenTest):

    def setUp(self):

        entry_dict = get_entry_dict(os.path.join(get_path(""),
                                                 "Cu_entries.txt"))
        self.Cu_entry_dict = entry_dict
        with open(os.path.join(get_path(""), 'ucell_entries.txt')) as ucell_entries:
            ucell_entries = json.loads(ucell_entries.read())

        self.Cu_ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Cu"])
        self.Cu_analyzer = SurfaceEnergyPlotter(entry_dict, self.Cu_ucell_entry)

        self.metals_O_entry_dict = load_O_adsorption()
        ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Pt"])
        self.Pt_analyzer = SurfaceEnergyPlotter(self.metals_O_entry_dict["Pt"],
                                                ucell_entry)
        ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Ni"])
        self.Ni_analyzer = SurfaceEnergyPlotter(self.metals_O_entry_dict["Ni"],
                                                ucell_entry)
        ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Rh"])
        self.Rh_analyzer = SurfaceEnergyPlotter(self.metals_O_entry_dict["Rh"],
                                                ucell_entry)
        self.Oads_analyzer_dict = {"Pt": self.Pt_analyzer,
                                   "Ni": self.Ni_analyzer,
                                   "Rh": self.Rh_analyzer}

    def test_get_stable_entry_at_u(self):

        for el in self.Oads_analyzer_dict.keys():
            plotter = self.Oads_analyzer_dict[el]
            for hkl in plotter.all_slab_entries.keys():
                # Test that the surface energy is clean for specific range of chempot
                entry1, gamma1 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): -7})
                entry2, gamma2 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): -6})
                self.assertEqual(gamma1, gamma2)
                self.assertEqual(entry1.label, entry2.label)

                # Now test that for a high chempot, adsorption
                # occurs and gamma is not equal to clean gamma
                entry3, gamma3 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): -1})
                self.assertNotEqual(entry3.label, entry2.label)
                self.assertNotEqual(gamma3, gamma2)

                # For any chempot greater than -6, surface energy should vary
                # but the configuration should remain the same
                entry4, gamma4 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): 0})
                self.assertEqual(entry3.label, entry4.label)
                self.assertNotEqual(gamma3, gamma4)

    def test_wulff_from_chempot(self):

        # Test if it generates a Wulff shape, test if
        # all the facets for Cu wulff shape are inside.
        Cu_wulff = self.Cu_analyzer.wulff_from_chempot()
        area_frac_dict = Cu_wulff.area_fraction_dict
        facets_hkl = [(1, 1, 1), (3, 3, 1), (3, 1, 0), (1, 0, 0),
                      (3, 1, 1), (2, 1, 0), (2, 2, 1)]
        for hkl in area_frac_dict.keys():
            if hkl in facets_hkl:
                self.assertNotEqual(area_frac_dict[hkl], 0)
            else:
                self.assertEqual(area_frac_dict[hkl], 0)

        for el in self.Oads_analyzer_dict.keys():
            # Test WulffShape for adsorbed surfaces
            analyzer = self.Oads_analyzer_dict[el]
            # chempot = analyzer.max_adsorption_chempot_range(0)
            wulff = analyzer.wulff_from_chempot(delu_default=-6)
            se = wulff.weighted_surface_energy

        # Test if a different Wulff shape is generated
        # for Ni when adsorption comes into play
        wulff_neg7 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-7)
        wulff_neg6 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-6)
        self.assertEqual(wulff_neg7.weighted_surface_energy,
                         wulff_neg6.weighted_surface_energy)
        wulff_neg55 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-5.5)
        self.assertNotEqual(wulff_neg55.weighted_surface_energy,
                            wulff_neg6.weighted_surface_energy)
        wulff_neg525 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-5.25)
        self.assertNotEqual(wulff_neg55.weighted_surface_energy,
                            wulff_neg525.weighted_surface_energy)

    def test_color_palette_dict(self):

        for el in self.metals_O_entry_dict.keys():
            analyzer = self.Oads_analyzer_dict[el]
            color_dict = analyzer.color_palette_dict()
            for hkl in self.metals_O_entry_dict[el].keys():
                for clean in self.metals_O_entry_dict[el][hkl].keys():
                    color = color_dict[clean]
                    for ads in self.metals_O_entry_dict[el][hkl][clean]:
                        color = color_dict[ads]

    def test_get_surface_equilibrium(self):
        # For clean stoichiometric system, the two equations should
        # be parallel because the surface energy is a constant. Then
        # get_surface_equilibrium should return None
        clean111_entry = list(self.Cu_entry_dict[(1, 1, 1)].keys())[0]
        clean100_entry = list(self.Cu_entry_dict[(1, 0, 0)].keys())[0]
        soln = self.Cu_analyzer.get_surface_equilibrium([clean111_entry,
                                                         clean100_entry])
        self.assertFalse(soln)

        # For adsorbed system, we should find one intercept
        Pt_entries = self.metals_O_entry_dict["Pt"]
        clean = list(Pt_entries[(1, 1, 1)].keys())[0]
        ads = Pt_entries[(1, 1, 1)][clean][0]
        Pt_analyzer = self.Oads_analyzer_dict["Pt"]
        soln = Pt_analyzer.get_surface_equilibrium([clean, ads])

        self.assertNotEqual(list(soln.values())[0], list(soln.values())[1])

        # Check if the number of parameters for adsorption are correct
        self.assertEqual((Symbol("delu_O"), Symbol("gamma")), tuple(soln.keys()))
        # Adsorbed systems have a b2=(-1*Nads) / (Nsurfs * Aads)
        se = ads.surface_energy(Pt_analyzer.ucell_entry, Pt_analyzer.ref_entries)
        self.assertAlmostEqual(se.as_coefficients_dict()[Symbol("delu_O")],
                               -1 / (2 * ads.surface_area))

    def test_stable_u_range_dict(self):
        for el in self.Oads_analyzer_dict.keys():
            analyzer = self.Oads_analyzer_dict[el]

        stable_u_range = analyzer.stable_u_range_dict([-1, 0], Symbol("delu_O"),
                                                      no_doped=False)
        all_u = []
        for entry in stable_u_range.keys():
            all_u.extend(stable_u_range[entry])
        self.assertGreater(len(all_u), 1)

    def test_entry_dict_from_list(self):

        # Plug in a list of entries to see if it works
        all_Pt_slab_entries = []
        Pt_entries = self.Pt_analyzer.all_slab_entries
        for hkl in Pt_entries.keys():
            for clean in Pt_entries[hkl].keys():
                all_Pt_slab_entries.append(clean)
                all_Pt_slab_entries.extend(Pt_entries[hkl][clean])

        a = SurfaceEnergyPlotter(all_Pt_slab_entries,
                                 self.Pt_analyzer.ucell_entry)
        self.assertEqual(type(a).__name__, "SurfaceEnergyPlotter")
Exemplo n.º 4
0
class SurfaceEnergyPlotterTest(PymatgenTest):

    def setUp(self):

        entry_dict = get_entry_dict(os.path.join(get_path(""),
                                                 "Cu_entries.txt"))
        self.Cu_entry_dict = entry_dict
        with open(os.path.join(get_path(""), 'ucell_entries.txt')) as ucell_entries:
            ucell_entries = json.loads(ucell_entries.read())

        self.Cu_ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Cu"])
        self.Cu_analyzer = SurfaceEnergyPlotter(entry_dict, self.Cu_ucell_entry)

        self.metals_O_entry_dict = load_O_adsorption()
        ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Pt"])
        self.Pt_analyzer = SurfaceEnergyPlotter(self.metals_O_entry_dict["Pt"],
                                                ucell_entry)
        ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Ni"])
        self.Ni_analyzer = SurfaceEnergyPlotter(self.metals_O_entry_dict["Ni"],
                                                ucell_entry)
        ucell_entry = ComputedStructureEntry.from_dict(ucell_entries["Rh"])
        self.Rh_analyzer = SurfaceEnergyPlotter(self.metals_O_entry_dict["Rh"],
                                                ucell_entry)
        self.Oads_analyzer_dict = {"Pt": self.Pt_analyzer,
                                   "Ni": self.Ni_analyzer,
                                   "Rh": self.Rh_analyzer}

    def test_get_stable_entry_at_u(self):

        for el in self.Oads_analyzer_dict.keys():
            plotter = self.Oads_analyzer_dict[el]
            for hkl in plotter.all_slab_entries.keys():
                # Test that the surface energy is clean for specific range of chempot
                entry1, gamma1 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): -7})
                entry2, gamma2 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): -6})
                self.assertEqual(gamma1, gamma2)
                self.assertEqual(entry1.label, entry2.label)

                # Now test that for a high chempot, adsorption
                # occurs and gamma is not equal to clean gamma
                entry3, gamma3 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): -1})
                self.assertNotEqual(entry3.label, entry2.label)
                self.assertNotEqual(gamma3, gamma2)

                # For any chempot greater than -6, surface energy should vary
                # but the configuration should remain the same
                entry4, gamma4 = \
                    plotter.get_stable_entry_at_u(hkl, delu_dict={Symbol("delu_O"): 0})
                self.assertEqual(entry3.label, entry4.label)
                self.assertNotEqual(gamma3, gamma4)

    def test_wulff_from_chempot(self):

        # Test if it generates a Wulff shape, test if
        # all the facets for Cu wulff shape are inside.
        Cu_wulff = self.Cu_analyzer.wulff_from_chempot()
        area_frac_dict = Cu_wulff.area_fraction_dict
        facets_hkl = [(1,1,1), (3,3,1), (3,1,0), (1,0,0),
                      (3,1,1), (2,1,0), (2,2,1)]
        for hkl in area_frac_dict.keys():
            if hkl in facets_hkl:
                self.assertNotEqual(area_frac_dict[hkl], 0)
            else:
                self.assertEqual(area_frac_dict[hkl], 0)

        for el in self.Oads_analyzer_dict.keys():
            # Test WulffShape for adsorbed surfaces
            analyzer = self.Oads_analyzer_dict[el]
            # chempot = analyzer.max_adsorption_chempot_range(0)
            wulff = analyzer.wulff_from_chempot(delu_default=-6)
            se = wulff.weighted_surface_energy

        # Test if a different Wulff shape is generated
        # for Ni when adsorption comes into play
        wulff_neg7 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-7)
        wulff_neg6 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-6)
        self.assertEqual(wulff_neg7.weighted_surface_energy,
                         wulff_neg6.weighted_surface_energy)
        wulff_neg55 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-5.5)
        self.assertNotEqual(wulff_neg55.weighted_surface_energy,
                            wulff_neg6.weighted_surface_energy)
        wulff_neg525 = self.Oads_analyzer_dict["Ni"].wulff_from_chempot(delu_default=-5.25)
        self.assertNotEqual(wulff_neg55.weighted_surface_energy,
                            wulff_neg525.weighted_surface_energy)

    def test_color_palette_dict(self):

        for el in self.metals_O_entry_dict.keys():
            analyzer = self.Oads_analyzer_dict[el]
            color_dict = analyzer.color_palette_dict()
            for hkl in self.metals_O_entry_dict[el].keys():
                for clean in self.metals_O_entry_dict[el][hkl].keys():
                    color = color_dict[clean]
                    for ads in self.metals_O_entry_dict[el][hkl][clean]:
                        color = color_dict[ads]

    def test_get_surface_equilibrium(self):
        # For clean stoichiometric system, the two equations should
        # be parallel because the surface energy is a constant. Then
        # get_surface_equilibrium should return None
        clean111_entry = list(self.Cu_entry_dict[(1, 1, 1)].keys())[0]
        clean100_entry = list(self.Cu_entry_dict[(1, 0, 0)].keys())[0]
        soln = self.Cu_analyzer.get_surface_equilibrium([clean111_entry,
                                                         clean100_entry])
        self.assertFalse(soln)

        # For adsorbed system, we should find one intercept
        Pt_entries = self.metals_O_entry_dict["Pt"]
        clean = list(Pt_entries[(1, 1, 1)].keys())[0]
        ads = Pt_entries[(1, 1, 1)][clean][0]
        Pt_analyzer = self.Oads_analyzer_dict["Pt"]
        soln = Pt_analyzer.get_surface_equilibrium([clean, ads])

        self.assertNotEqual(list(soln.values())[0], list(soln.values())[1])

        # Check if the number of parameters for adsorption are correct
        self.assertEqual((Symbol("delu_O"), Symbol("gamma")), tuple(soln.keys()))
        # Adsorbed systems have a b2=(-1*Nads) / (Nsurfs * Aads)
        se = ads.surface_energy(Pt_analyzer.ucell_entry, Pt_analyzer.ref_entries)
        self.assertAlmostEqual(se.as_coefficients_dict()[Symbol("delu_O")],
                               -1 / (2 * ads.surface_area))

    def test_stable_u_range_dict(self):
        for el in self.Oads_analyzer_dict.keys():
            analyzer = self.Oads_analyzer_dict[el]

        stable_u_range = analyzer.stable_u_range_dict([-1,0], Symbol("delu_O"),
                                                      no_doped=False)
        all_u = []
        for entry in stable_u_range.keys():
            all_u.extend(stable_u_range[entry])
        self.assertGreater(len(all_u), 1)

    def test_entry_dict_from_list(self):

        # Plug in a list of entries to see if it works
        all_Pt_slab_entries = []
        Pt_entries = self.Pt_analyzer.all_slab_entries
        for hkl in Pt_entries.keys():
            for clean in Pt_entries[hkl].keys():
                all_Pt_slab_entries.append(clean)
                all_Pt_slab_entries.extend(Pt_entries[hkl][clean])

        a = SurfaceEnergyPlotter(all_Pt_slab_entries,
                                 self.Pt_analyzer.ucell_entry)
        self.assertEqual(type(a).__name__, "SurfaceEnergyPlotter")