From a498728379a1db4ea56b6bb77fbf40b91671951e Mon Sep 17 00:00:00 2001 From: anaik Date: Mon, 26 Jun 2023 16:09:13 +0200 Subject: [PATCH 1/3] update lobstertask schema, add bandoverlaps,grosspop and sitepotentials data --- src/atomate2/lobster/schemas.py | 65 +++++++++++++++++++++- tests/vasp/lobster/schemas/test_lobster.py | 59 ++++++++++++++++++++ 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/src/atomate2/lobster/schemas.py b/src/atomate2/lobster/schemas.py index 6ad1419034..5fedc26d36 100644 --- a/src/atomate2/lobster/schemas.py +++ b/src/atomate2/lobster/schemas.py @@ -18,6 +18,9 @@ Lobsterin, Lobsterout, MadelungEnergies, + SitePotential, + Bandoverlaps, + Grosspop, ) from atomate2 import __version__ @@ -79,19 +82,20 @@ class LobsteroutModel(BaseModel): ) has_charge: bool = Field(None, description="Bool indicating if CHARGE is present.") has_madelung: bool = Field( - None, description="Bool indicating if Madelung file is present." + None, + description="Bool indicating if Site Potentials and Madelung file is present.", ) has_projection: bool = Field( None, description="Bool indicating if projection file is present." ) has_bandoverlaps: bool = Field( - None, description="Bool indicating if BANDOVERLAPS file is presetn" + None, description="Bool indicating if BANDOVERLAPS file is present" ) has_fatbands: bool = Field( None, description="Bool indicating if Fatbands are present." ) has_grosspopulation: bool = Field( - None, description="Bool indicating if GrossPopulations file is present." + None, description="Bool indicating if GROSSPOP file is present." ) has_density_of_energies: bool = Field( None, description="Bool indicating if DensityofEnergies is present" @@ -399,6 +403,24 @@ class LobsterTaskDocument(BaseModel): description="Madelung energies dict from" " LOBSTER based on Mulliken and Loewdin charges", ) + site_potentials: dict = Field( + None, + description="Site potentials dict from" + " LOBSTER based on Mulliken and Loewdin charges", + ) + + gross_populations: dict = Field( + None, + description="Gross populations dict from" + " LOBSTER based on Mulliken and Loewdin charges with" + "each site as a key and the gross population as a value.", + ) + + band_overlaps: dict = Field( + None, + description="Band overlaps data for each k-point from" + " bandOverlaps.lobster file if it exists", + ) _schema: str = Field( __version__, @@ -454,6 +476,9 @@ def from_directory( doscar_path = dir_name / "DOSCAR.lobster.gz" structure_path = dir_name / "POSCAR.gz" madelung_energies_path = dir_name / "MadelungEnergies.lobster.gz" + site_potentials_path = dir_name / "SitePotentials.lobster.gz" + gross_populations_path = dir_name / "GROSSPOP.lobster.gz" + band_overlaps_path = dir_name / "bandOverlaps.lobster.gz" # Do automatic bonding analysis with LobsterPy condensed_bonding_analysis = None @@ -553,6 +578,37 @@ def from_directory( "Ewald_splitting": madelung_obj.ewald_splitting, } + # Read in Site Potentials + site_potentials = None + if site_potentials_path.exists(): + site_potentials_obj = SitePotential(filename=site_potentials_path) + + site_potentials = { + "Mulliken": site_potentials_obj.sitepotentials_Mulliken, + "Loewdin": site_potentials_obj.sitepotentials_Loewdin, + "Ewald_splitting": site_potentials_obj.ewald_splitting, + } + + # Read in Gross Populations + gross_populations = None + if gross_populations_path.exists(): + gross_populations_obj = Grosspop(filename=gross_populations_path) + + gross_populations = {} + for atom_index, gross_pop in enumerate( + gross_populations_obj.list_dict_grosspop + ): + gross_populations[atom_index] = gross_pop + + # Read in Band overlaps + band_overlaps = None + if band_overlaps_path.exists(): + band_overlaps_obj = Bandoverlaps(filename=band_overlaps_path) + + band_overlaps = {} + for spin, value in band_overlaps_obj.bandoverlapsdict.items(): + band_overlaps[str(spin.value)] = value + doc = cls( structure=struct, dir_name=dir_name, @@ -579,6 +635,9 @@ def from_directory( lso_dos=lso_dos, charges=charges, madelung_energies=madelung_energies, + site_potentials=site_potentials, + gross_populations=gross_populations, + band_overlaps=band_overlaps, ) doc = doc.copy(update=additional_fields) return doc diff --git a/tests/vasp/lobster/schemas/test_lobster.py b/tests/vasp/lobster/schemas/test_lobster.py index c970f17876..d61e44db7d 100644 --- a/tests/vasp/lobster/schemas/test_lobster.py +++ b/tests/vasp/lobster/schemas/test_lobster.py @@ -89,11 +89,29 @@ def test_LobsterTaskDocument(lobster_test_dir): assert isinstance(doc.coop_data, CompleteCohp) assert isinstance(doc.dos, LobsterCompleteDos) assert np.isclose(doc.madelung_energies["Mulliken"], -0.68) + assert np.allclose( + doc.site_potentials["Mulliken"], + [-1.26, -1.27, -1.26, -1.27, 1.27, 1.27, 1.26, 1.26], + rtol=1e-2, + ) + assert np.isclose(doc.site_potentials["Ewald_splitting"], 3.14) + assert len(doc.gross_populations) == 8 + assert doc.gross_populations[5]["element"] == "As" + expected_gross_popp = { + "4s": 1.38, + "4p_y": 1.18, + "4p_z": 1.18, + "4p_x": 1.18, + "total": 4.93, + } + gross_popp_here = doc.gross_populations[5]["Loewdin GP"] + assert expected_gross_popp == gross_popp_here assert np.allclose( doc.charges["Mulliken"], [0.13, 0.13, 0.13, 0.13, -0.13, -0.13, -0.13, -0.13], rtol=1e-2, ) + assert len(doc.band_overlaps["1"]) + len(doc.band_overlaps["-1"]) == 12 doc2 = LobsterTaskDocument.from_directory( dir_name=lobster_test_dir / "lobsteroutputs/mp-754354", save_cohp_plots=False @@ -104,3 +122,44 @@ def test_LobsterTaskDocument(lobster_test_dir): assert np.isclose( doc2.strongest_bonds_icohp.strongest_bonds["Ba-F"]["ICOHP"], -0.44806 ) + assert len(doc2.band_overlaps["1"]) + len(doc2.band_overlaps["-1"]) == 2 + assert np.allclose( + doc2.site_potentials["Loewdin"], + [ + -15.09, + -15.09, + -15.09, + -15.09, + -15.09, + -15.09, + -15.09, + -15.09, + 14.78, + 14.78, + 8.14, + 8.14, + 8.48, + 8.48, + 8.14, + 8.14, + 8.14, + 8.14, + 8.48, + 8.48, + 8.14, + 8.14, + ], + rtol=1e-2, + ) + assert np.isclose(doc2.site_potentials["Ewald_splitting"], 3.14) + assert len(doc2.gross_populations) == 22 + assert doc2.gross_populations[10]["element"] == "F" + expected_gross_popp = { + "2s": 1.98, + "2p_y": 1.97, + "2p_z": 1.97, + "2p_x": 1.97, + "total": 7.88, + } + gross_popp_here = doc2.gross_populations[10]["Mulliken GP"] + assert expected_gross_popp == gross_popp_here From a3450baf02515caf98449a1926763d6fe35df616 Mon Sep 17 00:00:00 2001 From: anaik Date: Mon, 26 Jun 2023 16:31:10 +0200 Subject: [PATCH 2/3] fix linting --- src/atomate2/lobster/schemas.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atomate2/lobster/schemas.py b/src/atomate2/lobster/schemas.py index 5fedc26d36..de13dff257 100644 --- a/src/atomate2/lobster/schemas.py +++ b/src/atomate2/lobster/schemas.py @@ -12,15 +12,15 @@ from pymatgen.electronic_structure.cohp import CompleteCohp from pymatgen.electronic_structure.dos import LobsterCompleteDos from pymatgen.io.lobster import ( + Bandoverlaps, Charge, Doscar, + Grosspop, Icohplist, Lobsterin, Lobsterout, MadelungEnergies, SitePotential, - Bandoverlaps, - Grosspop, ) from atomate2 import __version__ From cc01a1ec8a224c471c83f3dee1086b1f62e83fbb Mon Sep 17 00:00:00 2001 From: anaik Date: Mon, 26 Jun 2023 16:53:29 +0200 Subject: [PATCH 3/3] fix failed tests --- tests/vasp/lobster/flows/test_lobster.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/vasp/lobster/flows/test_lobster.py b/tests/vasp/lobster/flows/test_lobster.py index 31366e98b9..72e61325ad 100644 --- a/tests/vasp/lobster/flows/test_lobster.py +++ b/tests/vasp/lobster/flows/test_lobster.py @@ -96,7 +96,7 @@ def test_lobsteruniformmaker(mock_vasp, mock_lobster, clean_dir, memory_jobstore .dict() .items() ): - if key == "lso_dos": + if key == "lso_dos" or key == "band_overlaps": assert value is None else: assert value is not None @@ -170,7 +170,7 @@ def test_lobstermaker(mock_vasp, mock_lobster, clean_dir, memory_jobstore): .dict() .items() ): - if key == "lso_dos": + if key == "lso_dos" or key == "band_overlaps": assert value is None else: assert value is not None