From 13d82b4202818e60f128b8aaccbf0b4fefd13c49 Mon Sep 17 00:00:00 2001 From: hdsassnick Date: Sat, 9 Dec 2023 15:51:39 +0100 Subject: [PATCH 1/8] Add different energies to energies and inner-scf blocks. --- cp2k_output_tools/blocks/energies.py | 32 ++++++++++++++++++++++++---- cp2k_output_tools/blocks/scf.py | 23 +++++++++++++++----- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/cp2k_output_tools/blocks/energies.py b/cp2k_output_tools/blocks/energies.py index 49a0210..f6caec6 100644 --- a/cp2k_output_tools/blocks/energies.py +++ b/cp2k_output_tools/blocks/energies.py @@ -4,6 +4,23 @@ from .common import FLOAT, BlockMatch +MAIN_ENERGY_RE = re.compile( + rf""" +^\s*Overlap\ energy\ of\ the\ core\ charge\ distribution:\s*(?P{FLOAT})\n +\s*Self\ energy\ of\ the\ core\ charge\ distribution:\s*(?P{FLOAT})\n +\s*Core\ Hamiltonian\ energy:\s*(?P{FLOAT})\n +\s*Hartree\ energy:\s*(?P{FLOAT})\n +\s*Exchange-correlation\ energy:\s*(?P{FLOAT})\n +(\s*Electronic\ entropic\ energy:\s*(?P{FLOAT})\n)? +(\s*Fermi\ energy:\s*(?P{FLOAT})\n)? +(\s*Dispersion\ energy:\s*(?P{FLOAT})\n)? +\n +\s*Total\ energy:\s*(?P{FLOAT})\n +""", + re.VERBOSE | re.MULTILINE, +) + + FORCE_EVAL_ENERGY_RE = re.compile( rf""" ^\s*ENERGY\|\ Total\ FORCE_EVAL [^:]+:\s*(?P{FLOAT})\n @@ -13,9 +30,16 @@ def match_energies(content: str) -> Optional[BlockMatch]: + spans = [] + energies = {} + match = MAIN_ENERGY_RE.search(content) + if match: + energies = match.groupdict() + spans = match.spans(0) match = FORCE_EVAL_ENERGY_RE.search(content) - - if not match: + if match: + energies["total force_eval"] = match["value"] + spans += match.spans(0) + if len(energies) == 0: return None - - return BlockMatch({"energies": {"total force_eval": float(match["value"])}}, match.spans(0)) + return BlockMatch({"energies": {key: float(val) for key, val in energies.items() if val is not None}}, spans) diff --git a/cp2k_output_tools/blocks/scf.py b/cp2k_output_tools/blocks/scf.py index c0c3632..68f99bb 100644 --- a/cp2k_output_tools/blocks/scf.py +++ b/cp2k_output_tools/blocks/scf.py @@ -7,7 +7,7 @@ from . import UREG from .common import FLOAT, Level -from .energies import FORCE_EVAL_ENERGY_RE +from .energies import FORCE_EVAL_ENERGY_RE, MAIN_ENERGY_RE from .mulliken import MULLIKEN_POPULATION_ANALYSIS_RE from .warnings import Message, match_messages @@ -71,7 +71,7 @@ INNER_SCF_START_RE = re.compile(r"^\s+ SCF\ WAVEFUNCTION\ OPTIMIZATION", re.VERBOSE | re.MULTILINE) -INNER_SCF_END_RE = re.compile( +INNER_SCF_CONV_RE = re.compile( r"^\s+ (?P\*\*\*\ SCF\ run\ converged\ in|Leaving\ inner\ SCF\ loop\ after\ reaching) \s+ (?P\d+)\ steps", re.VERBOSE | re.MULTILINE, ) @@ -132,6 +132,15 @@ class OuterSCF(Level): class InnerSCF(Level): converged: bool nsteps: int + overlap_core_energy: Decimal + self_core_energy: Decimal + core_hamiltonian_energy: Decimal + hartree_energy: Decimal + xc_energy: Decimal + total_energy: Decimal + electronic_entropic_energy: Optional[Decimal] = None + fermi_energy: Optional[Decimal] = None + dispersion_energy: Optional[Decimal] = None @dataclass @@ -194,11 +203,15 @@ def match_scf(content: str, start: int = 0, end: int = sys.maxsize) -> Optional[ match = INNER_SCF_START_RE.search(content, start, end) if match: start = match.span()[1] - ematch = INNER_SCF_END_RE.search(content, start, end) - if ematch: + energy_match = MAIN_ENERGY_RE.search(content, start, end) + conv_match = INNER_SCF_CONV_RE.search(content, start, end) + if conv_match and energy_match: start = match.span()[1] + kwargs = {key + "_energy": float(val) for key, val in energy_match.groupdict().items() if val is not None} sublevels.append( - InnerSCF(converged="SCF run converged" in ematch["convtxt"], nsteps=int(ematch["nsteps"]), sublevels=[]) + InnerSCF( + converged="SCF run converged" in conv_match["convtxt"], nsteps=int(conv_match["nsteps"]), **kwargs, sublevels=[] + ) ) force_eval_energy: Optional[Decimal] = None From 60efdb4d34a959dca51df1d6e054579824c156e7 Mon Sep 17 00:00:00 2001 From: hdsassnick Date: Sat, 9 Dec 2023 18:58:05 +0100 Subject: [PATCH 2/8] Adjust tests and change output format for levelparser. --- cp2k_output_tools/blocks/scf.py | 4 +- tests/test_energies.py | 14 +++- tests/test_optimization.py | 128 +++++++++++++++++++++++++++++--- 3 files changed, 133 insertions(+), 13 deletions(-) diff --git a/cp2k_output_tools/blocks/scf.py b/cp2k_output_tools/blocks/scf.py index 68f99bb..eed7061 100644 --- a/cp2k_output_tools/blocks/scf.py +++ b/cp2k_output_tools/blocks/scf.py @@ -207,7 +207,9 @@ def match_scf(content: str, start: int = 0, end: int = sys.maxsize) -> Optional[ conv_match = INNER_SCF_CONV_RE.search(content, start, end) if conv_match and energy_match: start = match.span()[1] - kwargs = {key + "_energy": float(val) for key, val in energy_match.groupdict().items() if val is not None} + kwargs = { + key + "_energy": Decimal(val) * UREG.hartree for key, val in energy_match.groupdict().items() if val is not None + } sublevels.append( InnerSCF( converged="SCF run converged" in conv_match["convtxt"], nsteps=int(conv_match["nsteps"]), **kwargs, sublevels=[] diff --git a/tests/test_energies.py b/tests/test_energies.py index 799a111..a2aaa8e 100644 --- a/tests/test_energies.py +++ b/tests/test_energies.py @@ -9,4 +9,16 @@ def test_energies(): result = next(parse_iter(fhandle.read(), matchers=[match_energies])) assert result - assert result == {"energies": {"total force_eval": -251.687390311050706}} + assert result == { + "energies": { + "core_hamiltonian": 138.60026809219576, + "electronic_entropic": -1.256404e-08, + "fermi": 0.20382509931778, + "hartree": 343.3040142273272, + "overlap_core": 3.0088e-10, + "self_core": -656.5115154010256, + "total": -251.63989121633358, + "xc": -77.03265812258856, + "total force_eval": -251.687390311050706, + } + } diff --git a/tests/test_optimization.py b/tests/test_optimization.py index 1abb40a..14959d9 100644 --- a/tests/test_optimization.py +++ b/tests/test_optimization.py @@ -13,8 +13,19 @@ "num_occ_orb": 1, "num_mol_orb": 1, "num_orb_func": 10, - "nsteps": 8, "force_eval_energy": -1.16096052, + "inner_scf": { + "nsteps": 8, + "overlap_core_energy": 6.0512959e-07, + "self_core_energy": -2.82094792, + "core_hamiltonian_energy": 1.07883184, + "hartree_energy": 1.30392538, + "xc_energy": -0.72277042, + "total_energy": -1.16096052, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, { "nspin": 1, @@ -22,8 +33,19 @@ "num_occ_orb": 1, "num_mol_orb": 1, "num_orb_func": 10, - "nsteps": 4, "force_eval_energy": -1.16118019, + "inner_scf": { + "nsteps": 4, + "overlap_core_energy": 0.0000012, + "self_core_energy": -2.82094792, + "core_hamiltonian_energy": 1.08370608, + "hartree_energy": 1.30183473, + "xc_energy": -0.72577425, + "total_energy": -1.16118019, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, { "nspin": 1, @@ -31,8 +53,19 @@ "num_occ_orb": 1, "num_mol_orb": 1, "num_orb_func": 10, - "nsteps": 4, "force_eval_energy": -1.16118537, + "inner_scf": { + "nsteps": 4, + "overlap_core_energy": 1.07320985e-06, + "self_core_energy": -2.82094792, + "core_hamiltonian_energy": 1.08302262, + "hartree_energy": 1.30210002, + "xc_energy": -0.72536117, + "total_energy": -1.16118537, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, { "nspin": 1, @@ -40,8 +73,19 @@ "num_occ_orb": 1, "num_mol_orb": 1, "num_orb_func": 10, - "nsteps": 4, "force_eval_energy": -1.16118537, + "inner_scf": { + "nsteps": 4, + "overlap_core_energy": 1.07320985e-06, + "self_core_energy": -2.82094792, + "core_hamiltonian_energy": 1.08302280, + "hartree_energy": 1.30210002, + "xc_energy": -0.72536117, + "total_energy": -1.16118537, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, ], }, @@ -53,8 +97,19 @@ "num_occ_orb": 16, "num_mol_orb": 16, "num_orb_func": 55, - "nsteps": 10, "force_eval_energy": -65.98706397, + "inner_scf": { + "nsteps": 10, + "overlap_core_energy": 0.0, + "self_core_energy": -138.89582544, + "core_hamiltonian_energy": 27.22305865, + "hartree_energy": 56.70225641, + "xc_energy": -11.01655328, + "total_energy": -65.98706366, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, { "nspin": 1, @@ -62,8 +117,19 @@ "num_occ_orb": 16, "num_mol_orb": 16, "num_orb_func": 55, - "nsteps": 9, "force_eval_energy": -65.98706506, + "inner_scf": { + "nsteps": 9, + "overlap_core_energy": 0.0, + "self_core_energy": -138.89582544, + "core_hamiltonian_energy": 27.22275912, + "hartree_energy": 56.70220023, + "xc_energy": -11.01647284, + "total_energy": -65.98733894, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, { "nspin": 1, @@ -71,8 +137,19 @@ "num_occ_orb": 16, "num_mol_orb": 16, "num_orb_func": 55, - "nsteps": 5, "force_eval_energy": -65.98710767, + "inner_scf": { + "nsteps": 5, + "overlap_core_energy": 0.0, + "self_core_energy": -138.89582544, + "core_hamiltonian_energy": 27.20749466, + "hartree_energy": 56.71104696, + "xc_energy": -11.00902476, + "total_energy": -65.98630859, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, { "nspin": 1, @@ -80,8 +157,19 @@ "num_occ_orb": 16, "num_mol_orb": 16, "num_orb_func": 55, - "nsteps": 4, "force_eval_energy": -65.98710770, + "inner_scf": { + "nsteps": 4, + "overlap_core_energy": 0.0, + "self_core_energy": -138.89582544, + "core_hamiltonian_energy": 27.20670707, + "hartree_energy": 56.71083178, + "xc_energy": -11.00884866, + "total_energy": -65.98713525, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, { "nspin": 1, @@ -89,8 +177,19 @@ "num_occ_orb": 16, "num_mol_orb": 16, "num_orb_func": 55, - "nsteps": 1, "force_eval_energy": -65.98710770, + "inner_scf": { + "nsteps": 1, + "overlap_core_energy": 0.0, + "self_core_energy": -138.89582544, + "core_hamiltonian_energy": 27.20676302, + "hartree_energy": 56.71080149, + "xc_energy": -11.00884677, + "total_energy": -65.98710770, + "electronic_entropic_energy": None, + "fermi_energy": None, + "dispersion_energy": None, + }, }, ], "cell_infos": [ @@ -149,12 +248,19 @@ def test_optimization(opt_type): for step_scf, opt_ref in zip(opt_steps_scf + [result.levels[0].sublevels[1]], ref["opt"]): assert step_scf.converged assert step_scf.sublevels[0].converged + inner_scf_ref = opt_ref.pop("inner_scf") + inner_scf = step_scf.sublevels[0] + for keyw, val in inner_scf_ref.items(): + if val is None: + assert getattr(inner_scf, keyw) is None + elif isinstance(val, float): + assert abs(float(getattr(inner_scf, keyw).magnitude) - val) < 1.0e-7 + else: + assert getattr(inner_scf, keyw) == val assert abs(float(step_scf.force_eval_energy.magnitude) - opt_ref.pop("force_eval_energy")) < 1.0e-7 - assert step_scf.sublevels[0].nsteps == opt_ref.pop("nsteps") for keyw, val in opt_ref.items(): assert getattr(step_scf, keyw) == val if opt_type == "cell": - print(result.levels[0].cell_infos) assert len(result.levels[0].cell_infos) == len(ref["cell_infos"]) for info, ref_info in zip(result.levels[0].cell_infos, ref["cell_infos"]): assert abs(float(info.volume.magnitude) - ref_info.pop("volume")) < 1.0e-7 From 49b9657de66b23a3ab5a31f0105f16d0ab98d032 Mon Sep 17 00:00:00 2001 From: hdsassnick <78720500+hdsassnick@users.noreply.github.com> Date: Mon, 11 Dec 2023 06:02:17 +0100 Subject: [PATCH 3/8] Update cp2k_output_tools/blocks/energies.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tiziano Müller --- cp2k_output_tools/blocks/energies.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cp2k_output_tools/blocks/energies.py b/cp2k_output_tools/blocks/energies.py index f6caec6..cb6702c 100644 --- a/cp2k_output_tools/blocks/energies.py +++ b/cp2k_output_tools/blocks/energies.py @@ -10,10 +10,10 @@ \s*Self\ energy\ of\ the\ core\ charge\ distribution:\s*(?P{FLOAT})\n \s*Core\ Hamiltonian\ energy:\s*(?P{FLOAT})\n \s*Hartree\ energy:\s*(?P{FLOAT})\n -\s*Exchange-correlation\ energy:\s*(?P{FLOAT})\n -(\s*Electronic\ entropic\ energy:\s*(?P{FLOAT})\n)? -(\s*Fermi\ energy:\s*(?P{FLOAT})\n)? -(\s*Dispersion\ energy:\s*(?P{FLOAT})\n)? +(?:\s*Exchange-correlation\ energy:\s*(?P{FLOAT})\n)? +(?:\s*Electronic\ entropic\ energy:\s*(?P{FLOAT})\n)? +(?:\s*Fermi\ energy:\s*(?P{FLOAT})\n)? +(?:\s*Dispersion\ energy:\s*(?P{FLOAT})\n)? \n \s*Total\ energy:\s*(?P{FLOAT})\n """, From ede75000d7d13327cba935988cbcc67670cb49d2 Mon Sep 17 00:00:00 2001 From: hdsassnick <78720500+hdsassnick@users.noreply.github.com> Date: Mon, 11 Dec 2023 06:02:27 +0100 Subject: [PATCH 4/8] Update cp2k_output_tools/blocks/energies.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tiziano Müller --- cp2k_output_tools/blocks/energies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cp2k_output_tools/blocks/energies.py b/cp2k_output_tools/blocks/energies.py index cb6702c..58166cf 100644 --- a/cp2k_output_tools/blocks/energies.py +++ b/cp2k_output_tools/blocks/energies.py @@ -40,6 +40,6 @@ def match_energies(content: str) -> Optional[BlockMatch]: if match: energies["total force_eval"] = match["value"] spans += match.spans(0) - if len(energies) == 0: + if not energies: return None return BlockMatch({"energies": {key: float(val) for key, val in energies.items() if val is not None}}, spans) From a055b4973c88ab342eb3343633fdc1dd8c6b591b Mon Sep 17 00:00:00 2001 From: hdsassnick <78720500+hdsassnick@users.noreply.github.com> Date: Mon, 11 Dec 2023 06:02:51 +0100 Subject: [PATCH 5/8] Update cp2k_output_tools/blocks/energies.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tiziano Müller --- cp2k_output_tools/blocks/energies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cp2k_output_tools/blocks/energies.py b/cp2k_output_tools/blocks/energies.py index 58166cf..24dc4a9 100644 --- a/cp2k_output_tools/blocks/energies.py +++ b/cp2k_output_tools/blocks/energies.py @@ -39,7 +39,7 @@ def match_energies(content: str) -> Optional[BlockMatch]: match = FORCE_EVAL_ENERGY_RE.search(content) if match: energies["total force_eval"] = match["value"] - spans += match.spans(0) + spans += [match.spans(0)] if not energies: return None return BlockMatch({"energies": {key: float(val) for key, val in energies.items() if val is not None}}, spans) From e74b64031dc374ad4b42bd5ecce5bf98872a5ccb Mon Sep 17 00:00:00 2001 From: hdsassnick <78720500+hdsassnick@users.noreply.github.com> Date: Mon, 11 Dec 2023 06:03:20 +0100 Subject: [PATCH 6/8] Update cp2k_output_tools/blocks/energies.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tiziano Müller --- cp2k_output_tools/blocks/energies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cp2k_output_tools/blocks/energies.py b/cp2k_output_tools/blocks/energies.py index 24dc4a9..abb5960 100644 --- a/cp2k_output_tools/blocks/energies.py +++ b/cp2k_output_tools/blocks/energies.py @@ -35,7 +35,7 @@ def match_energies(content: str) -> Optional[BlockMatch]: match = MAIN_ENERGY_RE.search(content) if match: energies = match.groupdict() - spans = match.spans(0) + spans = [match.spans(0)] match = FORCE_EVAL_ENERGY_RE.search(content) if match: energies["total force_eval"] = match["value"] From 48e355467820c87fc9913ad85cbe283b0b255c16 Mon Sep 17 00:00:00 2001 From: hdsassnick Date: Mon, 11 Dec 2023 06:12:07 +0100 Subject: [PATCH 7/8] Name INNER_SCF_CONV_RE pattern back to INNER_SCF_END_RE to avoid backwards incompatibility. --- cp2k_output_tools/blocks/scf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cp2k_output_tools/blocks/scf.py b/cp2k_output_tools/blocks/scf.py index eed7061..0e07ddc 100644 --- a/cp2k_output_tools/blocks/scf.py +++ b/cp2k_output_tools/blocks/scf.py @@ -71,7 +71,7 @@ INNER_SCF_START_RE = re.compile(r"^\s+ SCF\ WAVEFUNCTION\ OPTIMIZATION", re.VERBOSE | re.MULTILINE) -INNER_SCF_CONV_RE = re.compile( +INNER_SCF_END_RE = re.compile( r"^\s+ (?P\*\*\*\ SCF\ run\ converged\ in|Leaving\ inner\ SCF\ loop\ after\ reaching) \s+ (?P\d+)\ steps", re.VERBOSE | re.MULTILINE, ) @@ -204,7 +204,7 @@ def match_scf(content: str, start: int = 0, end: int = sys.maxsize) -> Optional[ if match: start = match.span()[1] energy_match = MAIN_ENERGY_RE.search(content, start, end) - conv_match = INNER_SCF_CONV_RE.search(content, start, end) + conv_match = INNER_SCF_END_RE.search(content, start, end) if conv_match and energy_match: start = match.span()[1] kwargs = { From 3591c12cfbd8bebc986803a8b319240ca7a307ed Mon Sep 17 00:00:00 2001 From: hdsassnick Date: Mon, 11 Dec 2023 06:24:34 +0100 Subject: [PATCH 8/8] Reverse nested list for spans. --- cp2k_output_tools/blocks/energies.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cp2k_output_tools/blocks/energies.py b/cp2k_output_tools/blocks/energies.py index abb5960..58166cf 100644 --- a/cp2k_output_tools/blocks/energies.py +++ b/cp2k_output_tools/blocks/energies.py @@ -35,11 +35,11 @@ def match_energies(content: str) -> Optional[BlockMatch]: match = MAIN_ENERGY_RE.search(content) if match: energies = match.groupdict() - spans = [match.spans(0)] + spans = match.spans(0) match = FORCE_EVAL_ENERGY_RE.search(content) if match: energies["total force_eval"] = match["value"] - spans += [match.spans(0)] + spans += match.spans(0) if not energies: return None return BlockMatch({"energies": {key: float(val) for key, val in energies.items() if val is not None}}, spans)