From 2cac7646ee730ed3beee0d7524fc6da4677b5a40 Mon Sep 17 00:00:00 2001 From: JaGeo Date: Fri, 24 Jan 2025 13:33:56 +0100 Subject: [PATCH 1/2] add script to generate lobster basis information --- ...basis_functions_pbeVaspFit2015_lobster.txt | 103 +++++++++++++++ dev_scripts/get_lobster_basis_from_potcars.py | 120 ++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 dev_scripts/all_basis_functions_pbeVaspFit2015_lobster.txt create mode 100644 dev_scripts/get_lobster_basis_from_potcars.py diff --git a/dev_scripts/all_basis_functions_pbeVaspFit2015_lobster.txt b/dev_scripts/all_basis_functions_pbeVaspFit2015_lobster.txt new file mode 100644 index 00000000000..cf81c3af13e --- /dev/null +++ b/dev_scripts/all_basis_functions_pbeVaspFit2015_lobster.txt @@ -0,0 +1,103 @@ +1 H 1s +2 He 1s +3 Li 1s 2s 2p +4 Be 1s 2s 2p +5 B 1s 2s 2p +6 C 1s 2s 2p +7 N 1s 2s 2p +8 O 1s 2s 2p +9 F 1s 2s 2p +10 Ne 1s 2s 2p +11 Na 1s 2s 2p 3s 3p +12 Mg 1s 2s 2p 3s 3p +13 Al 1s 2s 2p 3s 3p +14 Si 1s 2s 2p 3s 3p +15 P 1s 2s 2p 3s 3p +16 S 1s 2s 2p 3s 3p +17 Cl 1s 2s 2p 3s 3p +18 Ar 1s 2s 2p 3s 3p +19 K 1s 2s 2p 3s 3p 4s 4p +20 Ca 1s 2s 2p 3s 3p 4s 4p +21 Sc 1s 2s 2p 3s 3p 3d 4s 4p +22 Ti 1s 2s 2p 3s 3p 3d 4s 4p +23 V 1s 2s 2p 3s 3p 3d 4s 4p +24 Cr 1s 2s 2p 3s 3p 3d 4s 4p +25 Mn 1s 2s 2p 3s 3p 3d 4s 4p +26 Fe 1s 2s 2p 3s 3p 3d 4s 4p +27 Co 1s 2s 2p 3s 3p 3d 4s 4p +28 Ni 1s 2s 2p 3s 3p 3d 4s 4p +29 Cu 1s 2s 2p 3s 3p 3d 4s 4p +30 Zn 1s 2s 2p 3s 3p 3d 4s 4p +31 Ga 1s 2s 2p 3s 3p 3d 4s 4p +32 Ge 1s 2s 2p 3s 3p 3d 4s 4p +33 As 1s 2s 2p 3s 3p 3d 4s 4p +34 Se 1s 2s 2p 3s 3p 3d 4s 4p +35 Br 1s 2s 2p 3s 3p 3d 4s 4p +36 Kr 1s 2s 2p 3s 3p 3d 4s 4p +37 Rb 1s 2s 2p 3s 3p 3d 4s 4p 5s 5p +38 Sr 1s 2s 2p 3s 3p 3d 4s 4p 5s 5p +39 Y 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +40 Zr 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +41 Nb 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +42 Mo 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +43 Tc 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +44 Ru 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +45 Rh 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +46 Pd 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +47 Ag 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +48 Cd 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +49 In 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +50 Sn 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +51 Sb 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +52 Te 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +53 I 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +54 Xe 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p +55 Cs 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p 6s 6p +56 Ba 1s 2s 2p 3s 3p 3d 4s 4p 4d 5s 5p 6s 6p +57 La 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +58 Ce 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +59 Pr 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +60 Nd 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +61 Pm 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +62 Sm 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +63 Eu 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +64 Gd 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +65 Tb 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +66 Dy 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +67 Ho 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +68 Er 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +69 Tm 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +70 Yb 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +71 Lu 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +72 Hf 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +73 Ta 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +74 W 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +75 Re 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s +76 Os 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +77 Ir 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +78 Pt 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +79 Au 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +80 Hg 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +81 Tl 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +82 Pb 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +83 Bi 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +84 Po 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +85 At 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +86 Rn 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p +87 Fr 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p 7s 7p +88 Ra 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 6s 6p 7s 7p +89 Ac 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +90 Th 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +91 Pa 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +92 U 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +93 Np 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +94 Pu 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +95 Am 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +96 Cm 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s 7p +97 Bk 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s +98 Cf 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 7s +99 Es 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 7s +100 Fm 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 7s +101 Md 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 7s +102 No 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 7s +103 Lr 1s 2s 2p 3s 3p 3d 4s 4p 4d 4f 5s 5p 5d 5f 6s 6p 6d 7s diff --git a/dev_scripts/get_lobster_basis_from_potcars.py b/dev_scripts/get_lobster_basis_from_potcars.py new file mode 100644 index 00000000000..99ce3ec68be --- /dev/null +++ b/dev_scripts/get_lobster_basis_from_potcars.py @@ -0,0 +1,120 @@ +"""Script to generate potential basis functions for the LOBSTER input files. """ + + +from monty.io import zopen +from pymatgen.core import SETTINGS +from pymatgen.io.vasp.inputs import Potcar +from pathlib import Path +import yaml +import os + +def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | None = None, occupation_cutoff: float = 0.01) -> str: + """ + Extracts the valence configuration from a POTCAR file. + + Args: + filename (str): Path to the POTCAR file. + available_basis_functions (list[str] | None): List of available basis functions. + occupation_cutoff (float): Cutoff below which the orbital is considered to be empty. + + Returns: + str: A string of basis functions. + """ + nextline = False + ready = False + counter = 0 + orbitals: list[list[int]] = [] + occupations: list[float] = [] + linenumber = 0 + + with zopen(filename, 'rt') as f: + for line in f: + if linenumber == 1: + valence = float(line.split()[0]) + if not ready: + if not nextline: + if "Atomic configuration" in line: + nextline = True + else: + number_atomic_orbitals = int(line.split()[0]) + ready = True + else: + if counter <= number_atomic_orbitals: + if counter != 0: + orbitals.append([int(line.split()[0]), int(line.split()[1])]) + occupations.append(float(line.split()[4])) + counter += 1 + else: + break + linenumber += 1 + + # Reverse the lists for processing + rev_orb = list(reversed(orbitals)) + + rev_occ = list(reversed(occupations)) + basis: list[list[int]] = [] + + valence_checker = valence + for orbital in range(len(rev_orb)): + if not abs(valence_checker - 0.0) < 0.01: + if abs(rev_occ[orbital] - 0.0) >= occupation_cutoff: + valence_checker -= rev_occ[orbital] + basis.append(rev_orb[orbital]) + + basis = list(reversed(basis)) + + # Convert orbital numbers to strings + basis_result: list[str] = [] + for orbital in basis: + match orbital[1]: + case 0: + basis_result.append(f"{orbital[0]}s") + case 1: + basis_result.append(f"{orbital[0]}p") + case 2: + basis_result.append(f"{orbital[0]}d") + case 3: + basis_result.append(f"{orbital[0]}f") + + if available_basis_functions is not None: + basis_string = " ".join(e for e in sorted(set(basis_result)) if e in available_basis_functions) + else: + basis_string = " ".join(sorted(set(basis_result))) + + return basis_string + +# Set occupation cutoff +occupation_cutoff = 0.2 # if set to 0, also empty basis functions will be included + +# Path to the POTCAR directory +source_potcar = Path(SETTINGS["PMG_VASP_PSP_DIR"]) / "POT_GGA_PAW_PBE_54" + +# Get all POTCAR subfolders, excluding GW potcars +potcar_names: list[str] = [o for o in os.listdir(source_potcar)] + +# Read in all available basis functions +available_basis_functions: dict[str, list[str]] = {} +with zopen("all_basis_functions_pbeVaspFit2015_lobster.txt") as f: + data = f.read().split("\n") + +for datum in data: + datum_raw = datum.split(" ") + if len(datum_raw) > 2: + available_basis_functions[datum_raw[1]] = datum_raw[2:] + +basis_dict: dict[str, dict[str, str]] = {'BASIS': {}} +for potcar in potcar_names: + potential_type = potcar.split('.')[1] + element = potential_type.split('_')[0] + + if element in available_basis_functions: + potcar_object = Potcar.from_file(source_potcar / potcar) + basis_dict['BASIS'][potcar_object.spec[0]['symbol']] = get_valence( + filename=source_potcar / potcar, + available_basis_functions=available_basis_functions[element], + occupation_cutoff=occupation_cutoff + ) + +# Save the basis dictionary to a YAML file +with open('BASIS_PBE_54.yaml', 'w') as outfile: + yaml.dump(basis_dict, outfile, default_flow_style=False) From 108e6cde947f9bfa434f9a32eaa13f1ebf0dda3f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:41:05 +0000 Subject: [PATCH 2/2] pre-commit auto-fixes --- dev_scripts/get_lobster_basis_from_potcars.py | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/dev_scripts/get_lobster_basis_from_potcars.py b/dev_scripts/get_lobster_basis_from_potcars.py index 99ce3ec68be..a39b0bc6150 100644 --- a/dev_scripts/get_lobster_basis_from_potcars.py +++ b/dev_scripts/get_lobster_basis_from_potcars.py @@ -1,14 +1,20 @@ -"""Script to generate potential basis functions for the LOBSTER input files. """ +"""Script to generate potential basis functions for the LOBSTER input files.""" +from __future__ import annotations +import os +from pathlib import Path + +import yaml from monty.io import zopen + from pymatgen.core import SETTINGS from pymatgen.io.vasp.inputs import Potcar -from pathlib import Path -import yaml -import os -def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | None = None, occupation_cutoff: float = 0.01) -> str: + +def get_valence( + filename: str = "POTCAR", available_basis_functions: list[str] | None = None, occupation_cutoff: float = 0.01 +) -> str: """ Extracts the valence configuration from a POTCAR file. @@ -27,7 +33,7 @@ def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | occupations: list[float] = [] linenumber = 0 - with zopen(filename, 'rt') as f: + with zopen(filename, "rt") as f: for line in f: if linenumber == 1: valence = float(line.split()[0]) @@ -38,14 +44,13 @@ def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | else: number_atomic_orbitals = int(line.split()[0]) ready = True + elif counter <= number_atomic_orbitals: + if counter != 0: + orbitals.append([int(line.split()[0]), int(line.split()[1])]) + occupations.append(float(line.split()[4])) + counter += 1 else: - if counter <= number_atomic_orbitals: - if counter != 0: - orbitals.append([int(line.split()[0]), int(line.split()[1])]) - occupations.append(float(line.split()[4])) - counter += 1 - else: - break + break linenumber += 1 # Reverse the lists for processing @@ -56,12 +61,11 @@ def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | valence_checker = valence for orbital in range(len(rev_orb)): - if not abs(valence_checker - 0.0) < 0.01: - if abs(rev_occ[orbital] - 0.0) >= occupation_cutoff: - valence_checker -= rev_occ[orbital] - basis.append(rev_orb[orbital]) + if not abs(valence_checker - 0.0) < 0.01 and abs(rev_occ[orbital] - 0.0) >= occupation_cutoff: + valence_checker -= rev_occ[orbital] + basis.append(rev_orb[orbital]) - basis = list(reversed(basis)) + basis.reverse() # Convert orbital numbers to strings basis_result: list[str] = [] @@ -83,6 +87,7 @@ def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | return basis_string + # Set occupation cutoff occupation_cutoff = 0.2 # if set to 0, also empty basis functions will be included @@ -90,7 +95,7 @@ def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | source_potcar = Path(SETTINGS["PMG_VASP_PSP_DIR"]) / "POT_GGA_PAW_PBE_54" # Get all POTCAR subfolders, excluding GW potcars -potcar_names: list[str] = [o for o in os.listdir(source_potcar)] +potcar_names: list[str] = list(os.listdir(source_potcar)) # Read in all available basis functions available_basis_functions: dict[str, list[str]] = {} @@ -102,19 +107,19 @@ def get_valence(filename: str = "POTCAR", available_basis_functions: list[str] | if len(datum_raw) > 2: available_basis_functions[datum_raw[1]] = datum_raw[2:] -basis_dict: dict[str, dict[str, str]] = {'BASIS': {}} +basis_dict: dict[str, dict[str, str]] = {"BASIS": {}} for potcar in potcar_names: - potential_type = potcar.split('.')[1] - element = potential_type.split('_')[0] + potential_type = potcar.split(".")[1] + element = potential_type.split("_")[0] if element in available_basis_functions: potcar_object = Potcar.from_file(source_potcar / potcar) - basis_dict['BASIS'][potcar_object.spec[0]['symbol']] = get_valence( + basis_dict["BASIS"][potcar_object.spec[0]["symbol"]] = get_valence( filename=source_potcar / potcar, available_basis_functions=available_basis_functions[element], - occupation_cutoff=occupation_cutoff + occupation_cutoff=occupation_cutoff, ) # Save the basis dictionary to a YAML file -with open('BASIS_PBE_54.yaml', 'w') as outfile: +with open("BASIS_PBE_54.yaml", "w") as outfile: yaml.dump(basis_dict, outfile, default_flow_style=False)