From 7011b8d9ff900f06eaa4b2c08392c79188df2903 Mon Sep 17 00:00:00 2001 From: vue1999 Date: Wed, 4 Mar 2026 02:44:42 +0000 Subject: [PATCH 01/30] Adding cleavage benchmarks --- .../source/user_guide/benchmarks/surfaces.rst | 53 ++++ .../analyse_cleavage_energy.py | 238 ++++++++++++++++++ .../surfaces/cleavage_energy/metrics.yml | 13 + .../cleavage_energy/app_cleavage_energy.py | 68 +++++ .../cleavage_energy/calc_cleavage_energy.py | 76 ++++++ 5 files changed, 448 insertions(+) create mode 100644 ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py create mode 100644 ml_peg/analysis/surfaces/cleavage_energy/metrics.yml create mode 100644 ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py create mode 100644 ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py diff --git a/docs/source/user_guide/benchmarks/surfaces.rst b/docs/source/user_guide/benchmarks/surfaces.rst index 780118c7c..a49e55d01 100644 --- a/docs/source/user_guide/benchmarks/surfaces.rst +++ b/docs/source/user_guide/benchmarks/surfaces.rst @@ -145,3 +145,56 @@ Reference data: * S. P. Ong, W. D. Richards, A. Jain, G. Hautier, M. Kocher, S. Cholia, D. Gunter, V. Chevrier, K. A. Persson, G. Ceder, "Python Materials Genomics (pymatgen): A Robust, Open-Source Python Library for Materials Analysis," Comput. Mater. Sci., 2013, 68, 314–319. https://doi.org/10.1016/j.commatsci.2012.10.028 * Tran et al. relaxed the slabs using spin-polarized PBE calculations performed in VASP, with a cutoff energy of 400 eV. + +Cleavage Energy +=============== + +Summary +------- + +Performance in predicting cleavage energies for 36,718 surface configurations +across a wide range of materials and Miller indices. + +Metrics +------- + +1. Cleavage energy MAE + +Accuracy of cleavage energy predictions compared to DFT reference values. + +For each surface, the cleavage energy is calculated as +``(E_slab - thickness_ratio * E_bulk) / (2 * A)``, where ``E_slab`` and +``E_bulk`` are single-point energies of the slab and the lattice-matched bulk +unit cell, ``thickness_ratio`` is the number of bulk unit cells in the slab +thickness, and ``A`` is the surface area. Results are reported in meV/A^2. +The mean absolute error is computed over all 36,718 surfaces. + +2. Cleavage energy RMSE + +Root mean squared error of cleavage energy predictions across all surfaces. + +Computational cost +------------------ + +Medium: benchmark involves only single-point calculations, but for 36,718 slab-bulk pairs. + +Data availability +----------------- + +Input data: + +* Surface configurations were obtained from the Materials Project, covering + 3,699 unique bulk materials with multiple Miller indices and terminations + per material. The original unfiltered data source is available at + Zenodo (DOI: 10.5281/zenodo.10381505). + +Reference data: + +* DFT cleavage energies calculated using PBE functional. + +Publication: + +* A. Mehdizadeh and P. Schindler, "Surface stability modeling with universal + machine learning interatomic potentials: a comprehensive cleavage energy + benchmarking study," Mach. Learn.: Sci. Technol., 2025. + https://iopscience.iop.org/article/10.1088/3050-287X/ae1408 diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py new file mode 100644 index 000000000..8c40c35ee --- /dev/null +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -0,0 +1,238 @@ +"""Analyse cleavage energy benchmark.""" + +from __future__ import annotations + +import json +from pathlib import Path + +import numpy as np +import pytest + +from ml_peg.analysis.utils.decorators import build_table, plot_parity +from ml_peg.analysis.utils.utils import load_metrics_config, mae +from ml_peg.app import APP_ROOT +from ml_peg.calcs import CALCS_ROOT +from ml_peg.models.get_models import get_model_names +from ml_peg.models.models import current_models + +MODELS = get_model_names(current_models) +CALC_PATH = CALCS_ROOT / "surfaces" / "cleavage_energy" / "outputs" +OUT_PATH = APP_ROOT / "data" / "surfaces" / "cleavage_energy" + +METRICS_CONFIG_PATH = Path(__file__).with_name("metrics.yml") +DEFAULT_THRESHOLDS, DEFAULT_TOOLTIPS, DEFAULT_WEIGHTS = load_metrics_config( + METRICS_CONFIG_PATH +) + +EV_TO_MEV = 1000.0 + + +def _load_model_results(model_name: str) -> dict | None: + """ + Load the JSON energy results for a model, or None if absent. + + Parameters + ---------- + model_name + Name of the model whose results file to load. + + Returns + ------- + dict | None + Parsed JSON results dictionary, or None if the file does not exist. + """ + result_file = CALC_PATH / f"{model_name}.json" + if not result_file.exists(): + return None + with open(result_file, encoding="utf-8") as f: + return json.load(f) + + +def system_names() -> list[str]: + """ + Get list of system identifiers from calc outputs. + + Returns + ------- + list[str] + Sorted list of unique_id values from the first model with results. + """ + for model_name in MODELS: + data = _load_model_results(model_name) + if data is not None: + return sorted(data.keys()) + return [] + + +def compute_cleavage_energy( + slab_energy: float, + bulk_energy: float, + thickness_ratio: float, + area_slab: float, +) -> float: + """ + Compute cleavage energy from slab and bulk energies. + + Parameters + ---------- + slab_energy + Total energy of the slab. + bulk_energy + Total energy of the lattice-matched bulk unit cell. + thickness_ratio + Number of bulk unit cells in the slab thickness. + area_slab + Surface area of the slab in Angstrom^2. + + Returns + ------- + float + Cleavage energy in eV/Angstrom^2. + """ + return (slab_energy - thickness_ratio * bulk_energy) / (2 * area_slab) + + +@pytest.fixture +@plot_parity( + filename=OUT_PATH / "figure_cleavage_energies.json", + title="Cleavage Energies", + x_label="Predicted cleavage energy / meV/\u00c5\u00b2", + y_label="Reference cleavage energy / meV/\u00c5\u00b2", + hoverdata={ + "System": system_names(), + }, +) +def cleavage_energies() -> dict[str, list]: + """ + Get cleavage energies for all systems in meV/A^2. + + Also saves per-system errors for the distribution plot. + + Returns + ------- + dict[str, list] + Dictionary of reference and predicted cleavage energies in meV/A^2. + """ + results = {"ref": []} | {mlip: [] for mlip in MODELS} + canonical_ids = None + + for model_name in MODELS: + data = _load_model_results(model_name) + if data is None: + continue + + if canonical_ids is None: + canonical_ids = sorted(data.keys()) + for uid in canonical_ids: + entry = data[uid] + results["ref"].append(entry["ref_cleavage_energy"] * EV_TO_MEV) + + for uid in canonical_ids: + entry = data[uid] + pred_ce = ( + compute_cleavage_energy( + entry["slab_energy"], + entry["bulk_energy"], + entry["thickness_ratio"], + entry["area_slab"], + ) + * EV_TO_MEV + ) + results[model_name].append(pred_ce) + + return results + + +@pytest.fixture +def cleavage_mae(cleavage_energies: dict[str, list]) -> dict[str, float]: + """ + Get mean absolute error for cleavage energies. + + Parameters + ---------- + cleavage_energies + Dictionary of reference and predicted cleavage energies. + + Returns + ------- + dict[str, float] + MAE for each model. + """ + results = {} + for model_name in MODELS: + if cleavage_energies[model_name]: + results[model_name] = mae( + cleavage_energies["ref"], cleavage_energies[model_name] + ) + else: + results[model_name] = None + return results + + +@pytest.fixture +def cleavage_rmse(cleavage_energies: dict[str, list]) -> dict[str, float]: + """ + Get root mean squared error for cleavage energies. + + Parameters + ---------- + cleavage_energies + Dictionary of reference and predicted cleavage energies. + + Returns + ------- + dict[str, float] + RMSE for each model. + """ + results = {} + for model_name in MODELS: + if cleavage_energies[model_name]: + ref = np.array(cleavage_energies["ref"]) + pred = np.array(cleavage_energies[model_name]) + results[model_name] = float(np.sqrt(np.mean((pred - ref) ** 2))) + else: + results[model_name] = None + return results + + +@pytest.fixture +@build_table( + filename=OUT_PATH / "cleavage_energy_metrics_table.json", + metric_tooltips=DEFAULT_TOOLTIPS, + thresholds=DEFAULT_THRESHOLDS, +) +def metrics( + cleavage_mae: dict[str, float], + cleavage_rmse: dict[str, float], +) -> dict[str, dict]: + """ + Get all cleavage energy metrics. + + Parameters + ---------- + cleavage_mae + Mean absolute errors for all models. + cleavage_rmse + Root mean squared errors for all models. + + Returns + ------- + dict[str, dict] + Metric names and values for all models. + """ + return { + "MAE": cleavage_mae, + "RMSE": cleavage_rmse, + } + + +def test_cleavage_energy(metrics: dict[str, dict]) -> None: + """ + Run cleavage energy analysis. + + Parameters + ---------- + metrics + All cleavage energy metrics. + """ + return diff --git a/ml_peg/analysis/surfaces/cleavage_energy/metrics.yml b/ml_peg/analysis/surfaces/cleavage_energy/metrics.yml new file mode 100644 index 000000000..2a94b1508 --- /dev/null +++ b/ml_peg/analysis/surfaces/cleavage_energy/metrics.yml @@ -0,0 +1,13 @@ +metrics: + MAE: + good: 0.0 + bad: 10.0 + unit: meV/A^2 + tooltip: Mean Absolute Error of cleavage energies + level_of_theory: PBE + RMSE: + good: 0.0 + bad: 10.0 + unit: meV/A^2 + tooltip: Root Mean Squared Error of cleavage energies + level_of_theory: PBE diff --git a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py new file mode 100644 index 000000000..35e4bb2f9 --- /dev/null +++ b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py @@ -0,0 +1,68 @@ +"""Run cleavage energy app.""" + +from __future__ import annotations + +from dash import Dash +from dash.html import Div + +from ml_peg.app import APP_ROOT +from ml_peg.app.base_app import BaseApp +from ml_peg.app.utils.load import read_plot +from ml_peg.models.get_models import get_model_names +from ml_peg.models.models import current_models + +MODELS = get_model_names(current_models) +BENCHMARK_NAME = "Cleavage Energy" +DOCS_URL = ( + "https://ddmms.github.io/ml-peg/user_guide/benchmarks/surfaces.html#cleavage-energy" +) +DATA_PATH = APP_ROOT / "data" / "surfaces" / "cleavage_energy" + + +class CleavageEnergyApp(BaseApp): + """Cleavage energy benchmark app layout and callbacks.""" + + def register_callbacks(self) -> None: + """No interactive callbacks needed.""" + + +def get_app() -> CleavageEnergyApp: + """ + Get cleavage energy benchmark app layout and callback registration. + + Returns + ------- + CleavageEnergyApp + Benchmark layout and callback registration. + """ + scatter = read_plot( + DATA_PATH / "figure_cleavage_energies.json", + id=f"{BENCHMARK_NAME}-figure", + ) + + return CleavageEnergyApp( + name=BENCHMARK_NAME, + description=( + "Performance in predicting cleavage energies for " + "36,718 surface configurations." + ), + docs_url=DOCS_URL, + table_path=DATA_PATH / "cleavage_energy_metrics_table.json", + extra_components=[ + Div(scatter, style={"marginTop": "20px"}), + ], + ) + + +if __name__ == "__main__": + full_app = Dash( + __name__, + assets_folder=DATA_PATH.parent.parent, + suppress_callback_exceptions=True, + ) + + cleavage_energy_app = get_app() + full_app.layout = cleavage_energy_app.layout + cleavage_energy_app.register_callbacks() + + full_app.run(port=8056, debug=True) diff --git a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py new file mode 100644 index 000000000..7b1004a0b --- /dev/null +++ b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py @@ -0,0 +1,76 @@ +"""Run calculations for cleavage energy benchmark.""" + +from __future__ import annotations + +from copy import copy +import json +from pathlib import Path +from typing import Any + +from ase.io import read +import pytest + +from ml_peg.calcs.utils.utils import download_s3_data +from ml_peg.models.get_models import load_models +from ml_peg.models.models import current_models + +MODELS = load_models(current_models) + +OUT_PATH = Path(__file__).parent / "outputs" + + +@pytest.mark.parametrize("mlip", MODELS.items()) +def test_cleavage_energy(mlip: tuple[str, Any]) -> None: + """ + Run cleavage energy benchmark calculations. + + For each surface configuration, single-point energies are computed for + the slab and the lattice-matched bulk. Results are saved as a single + JSON file per model containing only energies and system identifiers, + avoiding redundant storage of atomic coordinates. + + Parameters + ---------- + mlip + Name of model and model to get calculator. + """ + model_name, model = mlip + calc = model.get_calculator() + + data_dir = ( + download_s3_data( + key="inputs/surfaces/cleavage_energy/cleavage_energy.zip", + filename="cleavage_energy.zip", + ) + / "cleavage_energy" + ) + + results = {} + + for mpid_dir in sorted(d for d in data_dir.iterdir() if d.is_dir()): + for xyz_file in sorted(mpid_dir.glob("*.xyz")): + structs = read(xyz_file, index=":") + slab, bulk = structs[0], structs[1] + + slab.calc = copy(calc) + slab_energy = float(slab.get_potential_energy()) + + bulk.calc = copy(calc) + bulk_energy = float(bulk.get_potential_energy()) + + unique_id = slab.info["unique_id"] + results[unique_id] = { + "slab_energy": slab_energy, + "bulk_energy": bulk_energy, + "area_slab": float(slab.info["area_slab"]), + "thickness_ratio": float(slab.info["thickness_ratio"]), + "ref_cleavage_energy": float(slab.info["ref_cleavage_energy"]), + "mpid": slab.info["mpid"], + "miller": slab.info["miller"], + "term": int(slab.info["term"]), + } + + OUT_PATH.mkdir(parents=True, exist_ok=True) + output_file = OUT_PATH / f"{model_name}.json" + with open(output_file, "w", encoding="utf-8") as f: + json.dump(results, f) From aa13732da8302db45d069d99ece06044f44eb755 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:42:24 +0000 Subject: [PATCH 02/30] Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py index 7b1004a0b..e75a794f7 100644 --- a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py +++ b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py @@ -7,7 +7,8 @@ from pathlib import Path from typing import Any -from ase.io import read +from ase.io import read, write +from tqdm import tqdm import pytest from ml_peg.calcs.utils.utils import download_s3_data From 2de40cd268cb63f969faf034d87949c3dbdbc111 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:42:37 +0000 Subject: [PATCH 03/30] Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py index e75a794f7..4e0fa9590 100644 --- a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py +++ b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py @@ -46,7 +46,8 @@ def test_cleavage_energy(mlip: tuple[str, Any]) -> None: / "cleavage_energy" ) - results = {} + write_dir = OUT_PATH / model_name + write_dir.mkdir(parents=True, exist_ok=True) for mpid_dir in sorted(d for d in data_dir.iterdir() if d.is_dir()): for xyz_file in sorted(mpid_dir.glob("*.xyz")): From b7bf3f5f6f08a111c974eafd521ce85b3dc995b6 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:42:50 +0000 Subject: [PATCH 04/30] Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py index 4e0fa9590..f38d16686 100644 --- a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py +++ b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py @@ -49,7 +49,8 @@ def test_cleavage_energy(mlip: tuple[str, Any]) -> None: write_dir = OUT_PATH / model_name write_dir.mkdir(parents=True, exist_ok=True) - for mpid_dir in sorted(d for d in data_dir.iterdir() if d.is_dir()): + idx = 0 + for mpid_dir in tqdm(sorted(d for d in data_dir.iterdir() if d.is_dir())): for xyz_file in sorted(mpid_dir.glob("*.xyz")): structs = read(xyz_file, index=":") slab, bulk = structs[0], structs[1] From 22a2d687961f75ccd32adf1b15daa761e9f54392 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:43:02 +0000 Subject: [PATCH 05/30] Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../cleavage_energy/calc_cleavage_energy.py | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py index f38d16686..fa8507e1f 100644 --- a/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py +++ b/ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py @@ -61,19 +61,17 @@ def test_cleavage_energy(mlip: tuple[str, Any]) -> None: bulk.calc = copy(calc) bulk_energy = float(bulk.get_potential_energy()) - unique_id = slab.info["unique_id"] - results[unique_id] = { - "slab_energy": slab_energy, - "bulk_energy": bulk_energy, - "area_slab": float(slab.info["area_slab"]), - "thickness_ratio": float(slab.info["thickness_ratio"]), - "ref_cleavage_energy": float(slab.info["ref_cleavage_energy"]), - "mpid": slab.info["mpid"], - "miller": slab.info["miller"], - "term": int(slab.info["term"]), - } - - OUT_PATH.mkdir(parents=True, exist_ok=True) - output_file = OUT_PATH / f"{model_name}.json" - with open(output_file, "w", encoding="utf-8") as f: - json.dump(results, f) + slab.info.update( + { + "slab_energy": slab_energy, + "bulk_energy": bulk_energy, + "area_slab": float(slab.info["area_slab"]), + "thickness_ratio": float(slab.info["thickness_ratio"]), + "ref_cleavage_energy": float(slab.info["ref_cleavage_energy"]), + "mpid": slab.info["mpid"], + "miller": slab.info["miller"], + "term": int(slab.info["term"]), + } + ) + write(write_dir / f"{idx}.xyz", slab, format="extxyz") + idx += 1 From c0b5256d552248461f8e0935a4fbbee488129e23 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:43:18 +0000 Subject: [PATCH 06/30] Update ml_peg/analysis/surfaces/cleavage_energy/metrics.yml Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/analysis/surfaces/cleavage_energy/metrics.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/metrics.yml b/ml_peg/analysis/surfaces/cleavage_energy/metrics.yml index 2a94b1508..c5839cc62 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/metrics.yml +++ b/ml_peg/analysis/surfaces/cleavage_energy/metrics.yml @@ -5,9 +5,3 @@ metrics: unit: meV/A^2 tooltip: Mean Absolute Error of cleavage energies level_of_theory: PBE - RMSE: - good: 0.0 - bad: 10.0 - unit: meV/A^2 - tooltip: Root Mean Squared Error of cleavage energies - level_of_theory: PBE From acc02ef484c433d153aee5caa91d3d216d093157 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:43:39 +0000 Subject: [PATCH 07/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 8c40c35ee..5d709fff7 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -8,8 +8,12 @@ import numpy as np import pytest -from ml_peg.analysis.utils.decorators import build_table, plot_parity -from ml_peg.analysis.utils.utils import load_metrics_config, mae +from ml_peg.analysis.utils.decorators import build_table, plot_density_scatter +from ml_peg.analysis.utils.utils import ( + load_metrics_config, + mae, + write_density_trajectories, +) from ml_peg.app import APP_ROOT from ml_peg.calcs import CALCS_ROOT from ml_peg.models.get_models import get_model_names From 9727b823f982a903578e01a52cedc827928e085e Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:43:51 +0000 Subject: [PATCH 08/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../cleavage_energy/analyse_cleavage_energy.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 5d709fff7..cca79b1c6 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -97,16 +97,7 @@ def compute_cleavage_energy( @pytest.fixture -@plot_parity( - filename=OUT_PATH / "figure_cleavage_energies.json", - title="Cleavage Energies", - x_label="Predicted cleavage energy / meV/\u00c5\u00b2", - y_label="Reference cleavage energy / meV/\u00c5\u00b2", - hoverdata={ - "System": system_names(), - }, -) -def cleavage_energies() -> dict[str, list]: +def cleavage_energies() -> dict[str, dict[str, list]]: """ Get cleavage energies for all systems in meV/A^2. From c9884229e95f5e909c98389983c677954b733b9f Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:44:04 +0000 Subject: [PATCH 09/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../analyse_cleavage_energy.py | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index cca79b1c6..4e6e471ee 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -31,43 +31,6 @@ EV_TO_MEV = 1000.0 -def _load_model_results(model_name: str) -> dict | None: - """ - Load the JSON energy results for a model, or None if absent. - - Parameters - ---------- - model_name - Name of the model whose results file to load. - - Returns - ------- - dict | None - Parsed JSON results dictionary, or None if the file does not exist. - """ - result_file = CALC_PATH / f"{model_name}.json" - if not result_file.exists(): - return None - with open(result_file, encoding="utf-8") as f: - return json.load(f) - - -def system_names() -> list[str]: - """ - Get list of system identifiers from calc outputs. - - Returns - ------- - list[str] - Sorted list of unique_id values from the first model with results. - """ - for model_name in MODELS: - data = _load_model_results(model_name) - if data is not None: - return sorted(data.keys()) - return [] - - def compute_cleavage_energy( slab_energy: float, bulk_energy: float, From 44a633f5d1ee620b8fd2e93ad43943e24b1cb4ff Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:44:19 +0000 Subject: [PATCH 10/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 4e6e471ee..d1ddbb7a9 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -68,8 +68,8 @@ def cleavage_energies() -> dict[str, dict[str, list]]: Returns ------- - dict[str, list] - Dictionary of reference and predicted cleavage energies in meV/A^2. + dict[str, dict[str, list]] + Dictionary of model names to ``{"ref": [...], "pred": [...]}`` in meV/A^2. """ results = {"ref": []} | {mlip: [] for mlip in MODELS} canonical_ids = None From 51e3400c8bb7f62918850720f303ee6b34d455da Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:44:35 +0000 Subject: [PATCH 11/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index d1ddbb7a9..330e3045c 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -71,8 +71,9 @@ def cleavage_energies() -> dict[str, dict[str, list]]: dict[str, dict[str, list]] Dictionary of model names to ``{"ref": [...], "pred": [...]}`` in meV/A^2. """ - results = {"ref": []} | {mlip: [] for mlip in MODELS} - canonical_ids = None + results = {mlip: {"ref": [], "pred": []} for mlip in MODELS} + ref_stored = False + stored_ref = [] for model_name in MODELS: data = _load_model_results(model_name) From 152e174532784774ebc28e3bb8f4a282165cc8e7 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:45:06 +0000 Subject: [PATCH 12/30] Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py index 35e4bb2f9..c28fe986f 100644 --- a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py +++ b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py @@ -58,7 +58,6 @@ def get_app() -> CleavageEnergyApp: full_app = Dash( __name__, assets_folder=DATA_PATH.parent.parent, - suppress_callback_exceptions=True, ) cleavage_energy_app = get_app() From fcaa3f82ec26659f8c70466cf576e4ff04b981e8 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:45:18 +0000 Subject: [PATCH 13/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 330e3045c..e089a48ff 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -76,8 +76,8 @@ def cleavage_energies() -> dict[str, dict[str, list]]: stored_ref = [] for model_name in MODELS: - data = _load_model_results(model_name) - if data is None: + model_dir = CALC_PATH / model_name + if not model_dir.exists(): continue if canonical_ids is None: From d9550567bad80b5f09ce530c18756b398d91a3e1 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:45:31 +0000 Subject: [PATCH 14/30] Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py index c28fe986f..43a281f21 100644 --- a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py +++ b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py @@ -7,7 +7,8 @@ from ml_peg.app import APP_ROOT from ml_peg.app.base_app import BaseApp -from ml_peg.app.utils.load import read_plot +from ml_peg.app.utils.build_callbacks import plot_from_table_cell, struct_from_scatter +from ml_peg.app.utils.load import collect_traj_assets, read_density_plot_for_model from ml_peg.models.get_models import get_model_names from ml_peg.models.models import current_models From f2bb3ca1eb133caa622474885c4d11c558139c83 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:46:12 +0000 Subject: [PATCH 15/30] Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../cleavage_energy/app_cleavage_energy.py | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py index 43a281f21..70cf4722a 100644 --- a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py +++ b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py @@ -24,7 +24,37 @@ class CleavageEnergyApp(BaseApp): """Cleavage energy benchmark app layout and callbacks.""" def register_callbacks(self) -> None: - """No interactive callbacks needed.""" + """Register callbacks to app.""" + density_plots: dict[str, dict] = {} + for model in MODELS: + density_graph = read_density_plot_for_model( + filename=DATA_PATH / "figure_cleavage_energies.json", + model=model, + id=f"{BENCHMARK_NAME}-{model}-density", + ) + if density_graph is not None: + density_plots[model] = {"MAE": density_graph} + + plot_from_table_cell( + table_id=self.table_id, + plot_id=f"{BENCHMARK_NAME}-figure-placeholder", + cell_to_plot=density_plots, + ) + + struct_trajs = collect_traj_assets( + data_path=DATA_PATH, + assets_prefix="assets/surfaces/cleavage_energy", + models=MODELS, + traj_dirname="density_traj", + suffix=".extxyz", + ) + for model in struct_trajs: + struct_from_scatter( + scatter_id=f"{BENCHMARK_NAME}-{model}-density", + struct_id=f"{BENCHMARK_NAME}-struct-placeholder", + structs=struct_trajs[model], + mode="traj", + ) def get_app() -> CleavageEnergyApp: From 179592ed8c6f5d05c876bd7a455bec0799f44b81 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:46:30 +0000 Subject: [PATCH 16/30] Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py index 70cf4722a..1400cdab7 100644 --- a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py +++ b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py @@ -66,10 +66,6 @@ def get_app() -> CleavageEnergyApp: CleavageEnergyApp Benchmark layout and callback registration. """ - scatter = read_plot( - DATA_PATH / "figure_cleavage_energies.json", - id=f"{BENCHMARK_NAME}-figure", - ) return CleavageEnergyApp( name=BENCHMARK_NAME, From 7025768ebce4678b69fdd8385e47c2291e70b1ec Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:46:45 +0000 Subject: [PATCH 17/30] Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py index 1400cdab7..b705c5762 100644 --- a/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py +++ b/ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py @@ -76,7 +76,8 @@ def get_app() -> CleavageEnergyApp: docs_url=DOCS_URL, table_path=DATA_PATH / "cleavage_energy_metrics_table.json", extra_components=[ - Div(scatter, style={"marginTop": "20px"}), + Div(id=f"{BENCHMARK_NAME}-figure-placeholder"), + Div(id=f"{BENCHMARK_NAME}-struct-placeholder"), ], ) From 7e8ddaa988909710f664e99cc2cd2d35bd7bf6e8 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:47:15 +0000 Subject: [PATCH 18/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index e089a48ff..c5adb3f90 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -193,5 +193,7 @@ def test_cleavage_energy(metrics: dict[str, dict]) -> None: ---------- metrics All cleavage energy metrics. + cleavage_density + Density-scatter inputs for all models (drives saved plots). """ return From a3c85b0a3cf77b0cf55f55c0518d31cc0068b600 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:47:35 +0000 Subject: [PATCH 19/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index c5adb3f90..c4750933f 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -80,11 +80,8 @@ def cleavage_energies() -> dict[str, dict[str, list]]: if not model_dir.exists(): continue - if canonical_ids is None: - canonical_ids = sorted(data.keys()) - for uid in canonical_ids: - entry = data[uid] - results["ref"].append(entry["ref_cleavage_energy"] * EV_TO_MEV) + model_pred = [] + model_ref = [] for uid in canonical_ids: entry = data[uid] From 0eee54fa2d93d805d780c96ed3b80168490cf373 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:47:59 +0000 Subject: [PATCH 20/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index c4750933f..c10e4cf9a 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -83,8 +83,9 @@ def cleavage_energies() -> dict[str, dict[str, list]]: model_pred = [] model_ref = [] - for uid in canonical_ids: - entry = data[uid] + for xyz_file in sorted(model_dir.glob("*.xyz"), key=lambda p: int(p.stem)): + slab = read(xyz_file) + pred_ce = ( compute_cleavage_energy( entry["slab_energy"], From a8abb4627aa29f5dd659d9a4c0fce2f8089cbd2c Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:51:42 +0000 Subject: [PATCH 21/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index c10e4cf9a..3646251af 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -88,10 +88,10 @@ def cleavage_energies() -> dict[str, dict[str, list]]: pred_ce = ( compute_cleavage_energy( - entry["slab_energy"], - entry["bulk_energy"], - entry["thickness_ratio"], - entry["area_slab"], + slab.info["slab_energy"], + slab.info["bulk_energy"], + slab.info["thickness_ratio"], + slab.info["area_slab"], ) * EV_TO_MEV ) From 5dc9eb0990bc1d12404f05a78a324c1e0df22a07 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:53:34 +0000 Subject: [PATCH 22/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../cleavage_energy/analyse_cleavage_energy.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 3646251af..edf1f68f5 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -95,7 +95,17 @@ def cleavage_energies() -> dict[str, dict[str, list]]: ) * EV_TO_MEV ) - results[model_name].append(pred_ce) + model_pred.append(pred_ce) + + if not ref_stored: + model_ref.append(slab.info["ref_cleavage_energy"] * EV_TO_MEV) + + if model_pred: + results[model_name]["pred"] = model_pred + if not ref_stored: + stored_ref = model_ref + results[model_name]["ref"] = stored_ref + ref_stored = True return results From 8f9cc86eb5816d2d73ff4710c5ea6ed58e8180b5 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:54:19 +0000 Subject: [PATCH 23/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../analyse_cleavage_energy.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index edf1f68f5..811bc7f81 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -109,7 +109,55 @@ def cleavage_energies() -> dict[str, dict[str, list]]: return results +@pytest.fixture +@plot_density_scatter( + filename=OUT_PATH / "figure_cleavage_energies.json", + title="Cleavage Energies", + x_label="Predicted cleavage energy / meV/Ų", + y_label="Reference cleavage energy / meV/Ų", +) +def cleavage_density( + cleavage_energies: dict[str, dict[str, list]], +) -> dict[str, dict]: + """ + Build density scatter inputs and write density trajectories. + + Parameters + ---------- + cleavage_energies + Reference and predicted cleavage energies per model. + Returns + ------- + dict[str, dict] + Mapping of model names to density-plot payloads. + """ + label_list = [ + f.stem + for f in sorted( + (CALC_PATH / MODELS[0]).glob("*.xyz"), key=lambda p: int(p.stem) + ) + ] + + density_inputs: dict[str, dict] = {} + for model_name in MODELS: + preds = cleavage_energies[model_name]["pred"] + refs = cleavage_energies[model_name]["ref"] + density_inputs[model_name] = { + "ref": refs, + "pred": preds, + "meta": {"system_count": len([v for v in preds if v is not None])}, + } + if preds: + write_density_trajectories( + labels_list=label_list, + ref_vals=refs, + pred_vals=preds, + struct_dir=CALC_PATH / model_name, + traj_dir=OUT_PATH / model_name / "density_traj", + struct_filename_builder=lambda label: f"{label}.xyz", + ) + return density_inputs @pytest.fixture def cleavage_mae(cleavage_energies: dict[str, list]) -> dict[str, float]: """ From 20f76be644bf4cb318c7b8f7144a2c7097747a46 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:55:39 +0000 Subject: [PATCH 24/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../analyse_cleavage_energy.py | 34 +++---------------- 1 file changed, 4 insertions(+), 30 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 811bc7f81..298a9f732 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -175,36 +175,10 @@ def cleavage_mae(cleavage_energies: dict[str, list]) -> dict[str, float]: """ results = {} for model_name in MODELS: - if cleavage_energies[model_name]: - results[model_name] = mae( - cleavage_energies["ref"], cleavage_energies[model_name] - ) - else: - results[model_name] = None - return results - - -@pytest.fixture -def cleavage_rmse(cleavage_energies: dict[str, list]) -> dict[str, float]: - """ - Get root mean squared error for cleavage energies. - - Parameters - ---------- - cleavage_energies - Dictionary of reference and predicted cleavage energies. - - Returns - ------- - dict[str, float] - RMSE for each model. - """ - results = {} - for model_name in MODELS: - if cleavage_energies[model_name]: - ref = np.array(cleavage_energies["ref"]) - pred = np.array(cleavage_energies[model_name]) - results[model_name] = float(np.sqrt(np.mean((pred - ref) ** 2))) + ref_vals = cleavage_energies[model_name]["ref"] + pred_vals = cleavage_energies[model_name]["pred"] + if pred_vals: + results[model_name] = mae(ref_vals, pred_vals) else: results[model_name] = None return results From b106bd0b0b23e4b217901d96563169a7c7fc8b33 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:55:59 +0000 Subject: [PATCH 25/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 298a9f732..a785f14fd 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -189,6 +189,7 @@ def cleavage_mae(cleavage_energies: dict[str, list]) -> dict[str, float]: filename=OUT_PATH / "cleavage_energy_metrics_table.json", metric_tooltips=DEFAULT_TOOLTIPS, thresholds=DEFAULT_THRESHOLDS, + weights=DEFAULT_WEIGHTS, ) def metrics( cleavage_mae: dict[str, float], From 43ff3120d672d0c11e4acaeb10eab45d5fe7c071 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:56:30 +0000 Subject: [PATCH 26/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index a785f14fd..1fc7d6408 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -191,10 +191,7 @@ def cleavage_mae(cleavage_energies: dict[str, list]) -> dict[str, float]: thresholds=DEFAULT_THRESHOLDS, weights=DEFAULT_WEIGHTS, ) -def metrics( - cleavage_mae: dict[str, float], - cleavage_rmse: dict[str, float], -) -> dict[str, dict]: +def metrics(cleavage_mae: dict[str, float]) -> dict[str, dict]: """ Get all cleavage energy metrics. From 708a4cc4e14e8474c128187efa9e089964862e8d Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:56:59 +0000 Subject: [PATCH 27/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 1fc7d6408..b7ed4b94d 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -199,8 +199,6 @@ def metrics(cleavage_mae: dict[str, float]) -> dict[str, dict]: ---------- cleavage_mae Mean absolute errors for all models. - cleavage_rmse - Root mean squared errors for all models. Returns ------- From 3c2230f69fd1d769860e37895c4568e486df63d6 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:57:14 +0000 Subject: [PATCH 28/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index b7ed4b94d..2a0139b48 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -205,10 +205,7 @@ def metrics(cleavage_mae: dict[str, float]) -> dict[str, dict]: dict[str, dict] Metric names and values for all models. """ - return { - "MAE": cleavage_mae, - "RMSE": cleavage_rmse, - } + return {"MAE": cleavage_mae} def test_cleavage_energy(metrics: dict[str, dict]) -> None: From 28da1060cc53a33783684bb3c11cb9c156e9d6e1 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Wed, 25 Mar 2026 11:57:29 +0000 Subject: [PATCH 29/30] Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- .../surfaces/cleavage_energy/analyse_cleavage_energy.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py index 2a0139b48..af5d14b8a 100644 --- a/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py +++ b/ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py @@ -208,7 +208,10 @@ def metrics(cleavage_mae: dict[str, float]) -> dict[str, dict]: return {"MAE": cleavage_mae} -def test_cleavage_energy(metrics: dict[str, dict]) -> None: +def test_cleavage_energy( + metrics: dict[str, dict], + cleavage_density: dict[str, dict], +) -> None: """ Run cleavage energy analysis. From 96daa54255860e1a898092d8c0ba882951986be5 Mon Sep 17 00:00:00 2001 From: EszterVU <93268063+vue1999@users.noreply.github.com> Date: Sun, 29 Mar 2026 00:33:09 +0000 Subject: [PATCH 30/30] Update docs/source/user_guide/benchmarks/surfaces.rst Co-authored-by: Joseph Hart <92541539+joehart2001@users.noreply.github.com> --- docs/source/user_guide/benchmarks/surfaces.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/user_guide/benchmarks/surfaces.rst b/docs/source/user_guide/benchmarks/surfaces.rst index a49e55d01..3cbf32110 100644 --- a/docs/source/user_guide/benchmarks/surfaces.rst +++ b/docs/source/user_guide/benchmarks/surfaces.rst @@ -176,7 +176,7 @@ Root mean squared error of cleavage energy predictions across all surfaces. Computational cost ------------------ -Medium: benchmark involves only single-point calculations, but for 36,718 slab-bulk pairs. +Medium: benchmark involves only single-point calculations, but for 36,718 slab-bulk pairs. Takes roughly 5-20 minutes on GPU or a few hours on CPUs. Data availability -----------------