From 708aaed1161fed121fa3a01089fb1f96a7932803 Mon Sep 17 00:00:00 2001 From: superstar54 Date: Tue, 10 Sep 2024 16:24:40 +0200 Subject: [PATCH] update ld1 --- src/ase_quantumespresso/ld1.py | 45 +++-------- src/ase_quantumespresso/parsers/dos.py | 1 - src/ase_quantumespresso/parsers/exit_code.py | 6 +- src/ase_quantumespresso/parsers/ld1.py | 80 ++++++++++++++++++++ tests/test_ld1.py | 50 ++++++++++++ tests/test_pw.py | 2 +- 6 files changed, 144 insertions(+), 40 deletions(-) create mode 100644 src/ase_quantumespresso/parsers/ld1.py create mode 100644 tests/test_ld1.py diff --git a/src/ase_quantumespresso/ld1.py b/src/ase_quantumespresso/ld1.py index 37614e7..210045c 100644 --- a/src/ase_quantumespresso/ld1.py +++ b/src/ase_quantumespresso/ld1.py @@ -1,8 +1,9 @@ from .namelist import NamelistTemplate -import re + class Ld1Template(NamelistTemplate): _label = "ld1" + outputname = "ld1.ld1o" def __init__(self): super().__init__( @@ -13,6 +14,7 @@ def __init__(self): def write_input(self, profile, directory, atoms, parameters, properties): from ase.io.espresso_namelist.keys import ld1_keys + # I removed the "test" key from ld1_keys, because it was causing the following error: # Error: reading number of pseudo wavefunctions (nwfs) ld1_keys.pop("test") @@ -22,38 +24,11 @@ def write_input(self, profile, directory, atoms, parameters, properties): super().write_input(profile, directory, atoms, parameters, properties) def read_results(self, directory): - path = directory / "ld1.ld1o" - with open(path, "r") as f: - energy_data = parse_energy_totals(f.read()) - - return {"ld1": energy_data} - - + from .parsers.ld1 import Ld1Parser -def parse_energy_totals(text): - # Pattern to find Etot and Etotps lines and capture relevant parts - etot_pattern = r"Etot\s+=\s+([-\d\.]+)\s+Ry,\s+([-\d\.]+)\s+Ha,\s+([-\d\.]+)\s+eV" - etotps_pattern = r"Etotps\s+=\s+([-\d\.]+)\s+Ry,\s+([-\d\.]+)\s+Ha,\s+([-\d\.]+)\s+eV" - - # Search for patterns and extract values - etot_match = re.search(etot_pattern, text) - etotps_match = re.search(etotps_pattern, text) - - # Structured data - energy_data = {} - - if etot_match: - energy_data['Etot'] = { - 'Ry': float(etot_match.group(1)), - 'Ha': float(etot_match.group(2)), - 'eV': float(etot_match.group(3)) - } - - if etotps_match: - energy_data['Etotps'] = { - 'Ry': float(etotps_match.group(1)), - 'Ha': float(etotps_match.group(2)), - 'eV': float(etotps_match.group(3)) - } - - return energy_data \ No newline at end of file + parser = Ld1Parser(directory, self.outputname) + exit_code = parser.parse() + results = parser.results + results["exit_code"] = exit_code + print("results", results) + return results diff --git a/src/ase_quantumespresso/parsers/dos.py b/src/ase_quantumespresso/parsers/dos.py index a2c1f23..e14117e 100644 --- a/src/ase_quantumespresso/parsers/dos.py +++ b/src/ase_quantumespresso/parsers/dos.py @@ -4,7 +4,6 @@ Modified from aiida-quantumespresso.parsers.dos.DosParser. """ -# from aiida_quantumespresso.calculations.pw import PwCalculation from aiida_quantumespresso.utils.mapping import get_logging_container from .exit_code import DosExitCodes from .base import BaseParser diff --git a/src/ase_quantumespresso/parsers/exit_code.py b/src/ase_quantumespresso/parsers/exit_code.py index 82f7e95..46fe290 100644 --- a/src/ase_quantumespresso/parsers/exit_code.py +++ b/src/ase_quantumespresso/parsers/exit_code.py @@ -120,7 +120,7 @@ class PwExitCodes: @dataclass(frozen=True) -class NamelistsCalculation: +class NamelistsExitCodes: ERROR_OUTPUT_STDOUT_MISSING: ExitCode = ExitCode( 302, "The folder did not contain the required stdout output file." ) @@ -139,14 +139,14 @@ class NamelistsCalculation: @dataclass(frozen=True) -class DosExitCodes(NamelistsCalculation): +class DosExitCodes(NamelistsExitCodes): ERROR_OUTPUT_STDOUT_MISSING: ExitCode = ExitCode( 302, "The folder did not contain the required stdout output file." ) @dataclass(frozen=True) -class ProjwfcExitCodes(NamelistsCalculation): +class ProjwfcExitCodes(NamelistsExitCodes): ERROR_NO_RETRIEVED_TEMPORARY_FOLDER: ExitCode = ExitCode( 301, "The retrieved temporary folder could not be accessed." ) diff --git a/src/ase_quantumespresso/parsers/ld1.py b/src/ase_quantumespresso/parsers/ld1.py new file mode 100644 index 0000000..2b69832 --- /dev/null +++ b/src/ase_quantumespresso/parsers/ld1.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +"""`Parser` implementation for the `ld1.x` code of Quantum ESPRESSO. + +""" + +from aiida_quantumespresso.utils.mapping import get_logging_container +from .exit_code import NamelistsExitCodes +from .base import BaseParser +import re + + +class Ld1Parser(BaseParser): + """`Parser` implementation for the `dos.x` calculation, modified from aiida-quantumespresso.""" + + success_string = "End of pseudopotential test" + + def __init__(self, directory, outputname): + """Initialize the instance of `PwParser`.""" + super().__init__(directory, output_filename=outputname) + self.outputname = outputname + self.exit_codes = NamelistsExitCodes() + + def parse(self, **kwargs): + """Parse the retrieved files of a ``DosCalculation`` into output nodes.""" + + logs = get_logging_container() + + _, parsed_stdout, logs = self.parse_stdout_from_retrieved(logs) + + base_exit_code = self.check_base_errors(logs) + if base_exit_code: + return self.exit(base_exit_code, logs) + + self.out("output_parameters", parsed_stdout) + + if "ERROR_OUTPUT_STDOUT_INCOMPLETE" in logs.error: + return self.exit(self.exit_codes.ERROR_OUTPUT_STDOUT_INCOMPLETE, logs) + + # Parse the Energy + filepath_dos = self.directory / self.outputname + try: + with open(filepath_dos, "r") as handle: + text = handle.read() + energy_data = parse_energy_totals(text) + self.out("ld1", energy_data) + except OSError: + return self.exit(self.exit_codes.ERROR_READING_DOS_FILE, logs) + + return self.exit(logs=logs) + + +def parse_energy_totals(text): + # Pattern to find Etot and Etotps lines and capture relevant parts + etot_pattern = r"Etot\s+=\s+([-\d\.]+)\s+Ry,\s+([-\d\.]+)\s+Ha,\s+([-\d\.]+)\s+eV" + etotps_pattern = ( + r"Etotps\s+=\s+([-\d\.]+)\s+Ry,\s+([-\d\.]+)\s+Ha,\s+([-\d\.]+)\s+eV" + ) + + # Search for patterns and extract values + etot_match = re.search(etot_pattern, text) + etotps_match = re.search(etotps_pattern, text) + + # Structured data + energy_data = {} + + if etot_match: + energy_data["Etot"] = { + "Ry": float(etot_match.group(1)), + "Ha": float(etot_match.group(2)), + "eV": float(etot_match.group(3)), + } + + if etotps_match: + energy_data["Etotps"] = { + "Ry": float(etotps_match.group(1)), + "Ha": float(etotps_match.group(2)), + "eV": float(etotps_match.group(3)), + } + + return energy_data diff --git a/tests/test_ld1.py b/tests/test_ld1.py new file mode 100644 index 0000000..6c7610a --- /dev/null +++ b/tests/test_ld1.py @@ -0,0 +1,50 @@ +from ase_quantumespresso.espresso import Espresso, EspressoProfile +from ase_quantumespresso.ld1 import Ld1Template + +input_data = { + "input": { + "title": "Pt", + "zed": 78.0, + "rel": 1, + "config": "[Xe] 4f13 6s1 6p0 5d9", + "iswitch": 3, + "dft": "PBE", + }, + "inputp": { + "lpaw": True, + "use_xsd": False, + "pseudotype": 3, + "file_pseudopw": "Pt.star4f.pbe-n-kjpaw_psl.1.0.0.UPF", + "author": "Test", + "lloc": -1, + "rcloc": 2.4, + "which_augfun": "PSQ", + "rmatch_augfun_nc": True, + "nlcc": True, + "new_core_ps": True, + "rcore": 1.8, + "tm": True, + }, +} +pseudo_potential_test_cards = """ +6 +6S 1 0 1.00 0.00 2.00 2.20 0.0 +6S 1 0 0.00 4.40 2.00 2.20 0.0 +6P 2 1 0.00 0.00 2.30 2.50 0.0 +6P 2 1 0.00 6.40 2.30 2.50 0.0 +5D 3 2 9.00 0.00 1.00 2.20 0.0 +5D 3 2 0.00 0.80 1.00 2.20 0.0 +""" + + +def test_base_ld1(): + profile = EspressoProfile(command="ld1.x", pseudo_dir=".") + calc = Espresso( + directory="calculatioin", + profile=profile, + template=Ld1Template(), + input_data=input_data, + pseudo_potential_test_cards=pseudo_potential_test_cards, + ) + calc.get_property("ld1") + assert calc.results["exit_code"].status == 0 diff --git a/tests/test_pw.py b/tests/test_pw.py index edda039..a17f2a9 100644 --- a/tests/test_pw.py +++ b/tests/test_pw.py @@ -4,7 +4,7 @@ def test_pw(bulk_si, pseudopotentials, pseudo_dir, pw_input_data): profile = EspressoProfile(command="pw.x", pseudo_dir=pseudo_dir) calc = Espresso( - directory="test", + directory="calculatioin", profile=profile, pseudopotentials=pseudopotentials, input_data=pw_input_data,