-
Notifications
You must be signed in to change notification settings - Fork 41
Adding cleavage benchmarks #404
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
vue1999
wants to merge
30
commits into
ddmms:main
Choose a base branch
from
vue1999:cleavage_benchmark
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
7011b8d
Adding cleavage benchmarks
vue1999 aa13732
Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py
vue1999 2de40cd
Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py
vue1999 b7bf3f5
Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py
vue1999 22a2d68
Update ml_peg/calcs/surfaces/cleavage_energy/calc_cleavage_energy.py
vue1999 c0b5256
Update ml_peg/analysis/surfaces/cleavage_energy/metrics.yml
vue1999 acc02ef
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 9727b82
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 c988422
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 44a633f
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 51e3400
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 152e174
Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py
vue1999 fcaa3f8
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 d955056
Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py
vue1999 f2bb3ca
Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py
vue1999 179592e
Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py
vue1999 7025768
Update ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py
vue1999 7e8ddaa
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 a3c85b0
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 0eee54f
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 a8abb46
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 5dc9eb0
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 8f9cc86
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 20f76be
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 b106bd0
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 43ff312
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 708a4cc
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 3c2230f
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 28da106
Update ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_ener…
vue1999 96daa54
Update docs/source/user_guide/benchmarks/surfaces.rst
vue1999 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
225 changes: 225 additions & 0 deletions
225
ml_peg/analysis/surfaces/cleavage_energy/analyse_cleavage_energy.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| """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_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 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 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 | ||
| def cleavage_energies() -> dict[str, 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, dict[str, list]] | ||
| Dictionary of model names to ``{"ref": [...], "pred": [...]}`` in meV/A^2. | ||
| """ | ||
| results = {mlip: {"ref": [], "pred": []} for mlip in MODELS} | ||
| ref_stored = False | ||
| stored_ref = [] | ||
|
|
||
| for model_name in MODELS: | ||
| model_dir = CALC_PATH / model_name | ||
| if not model_dir.exists(): | ||
| continue | ||
|
|
||
| model_pred = [] | ||
| model_ref = [] | ||
|
|
||
| for xyz_file in sorted(model_dir.glob("*.xyz"), key=lambda p: int(p.stem)): | ||
| slab = read(xyz_file) | ||
|
|
||
| pred_ce = ( | ||
| compute_cleavage_energy( | ||
| slab.info["slab_energy"], | ||
| slab.info["bulk_energy"], | ||
| slab.info["thickness_ratio"], | ||
| slab.info["area_slab"], | ||
| ) | ||
| * EV_TO_MEV | ||
| ) | ||
| 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 | ||
|
|
||
| @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]: | ||
| """ | ||
| 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: | ||
| 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 | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| @build_table( | ||
| filename=OUT_PATH / "cleavage_energy_metrics_table.json", | ||
| metric_tooltips=DEFAULT_TOOLTIPS, | ||
| thresholds=DEFAULT_THRESHOLDS, | ||
vue1999 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| weights=DEFAULT_WEIGHTS, | ||
| ) | ||
| def metrics(cleavage_mae: dict[str, float]) -> dict[str, dict]: | ||
| """ | ||
| Get all cleavage energy metrics. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| cleavage_mae | ||
| Mean absolute errors for all models. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, dict] | ||
| Metric names and values for all models. | ||
| """ | ||
| return {"MAE": cleavage_mae} | ||
|
|
||
|
|
||
| def test_cleavage_energy( | ||
| metrics: dict[str, dict], | ||
| cleavage_density: dict[str, dict], | ||
| ) -> None: | ||
| """ | ||
| Run cleavage energy analysis. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| metrics | ||
| All cleavage energy metrics. | ||
| cleavage_density | ||
| Density-scatter inputs for all models (drives saved plots). | ||
| """ | ||
vue1999 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| metrics: | ||
| MAE: | ||
| good: 0.0 | ||
| bad: 10.0 | ||
| unit: meV/A^2 | ||
| tooltip: Mean Absolute Error of cleavage energies | ||
| level_of_theory: PBE |
95 changes: 95 additions & 0 deletions
95
ml_peg/app/surfaces/cleavage_energy/app_cleavage_energy.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| """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.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 | ||
|
|
||
| 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: | ||
| """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: | ||
| """ | ||
| Get cleavage energy benchmark app layout and callback registration. | ||
|
|
||
| Returns | ||
| ------- | ||
| CleavageEnergyApp | ||
| Benchmark layout and callback registration. | ||
| """ | ||
|
|
||
| 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(id=f"{BENCHMARK_NAME}-figure-placeholder"), | ||
| Div(id=f"{BENCHMARK_NAME}-struct-placeholder"), | ||
| ], | ||
| ) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| full_app = Dash( | ||
| __name__, | ||
| assets_folder=DATA_PATH.parent.parent, | ||
| ) | ||
|
|
||
| cleavage_energy_app = get_app() | ||
| full_app.layout = cleavage_energy_app.layout | ||
| cleavage_energy_app.register_callbacks() | ||
|
|
||
| full_app.run(port=8056, debug=True) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.