From e4be0283a899008708c8f7cde373ba385308eb9d Mon Sep 17 00:00:00 2001 From: Leon Wehrhan Date: Wed, 24 Jun 2026 11:52:22 +0200 Subject: [PATCH 1/5] feat: add md stability benchmark --- .../benchmarks/molecular_dynamics.rst | 37 ++++++++ .../stability/analyse_stability.py | 87 +++++++++++++++++++ .../molecular_dynamics/stability/metrics.yml | 6 ++ .../molecular_dynamics/molecular_dynamics.yml | 2 +- .../stability/app_stability.py | 50 +++++++++++ .../stability/calc_stability.py | 54 ++++++++++++ ml_peg/calcs/utils/mlipaudit.py | 16 ++++ 7 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py create mode 100644 ml_peg/analysis/molecular_dynamics/stability/metrics.yml create mode 100644 ml_peg/app/molecular_dynamics/stability/app_stability.py create mode 100644 ml_peg/calcs/molecular_dynamics/stability/calc_stability.py create mode 100644 ml_peg/calcs/utils/mlipaudit.py diff --git a/docs/source/user_guide/benchmarks/molecular_dynamics.rst b/docs/source/user_guide/benchmarks/molecular_dynamics.rst index 24f3fb3b3..9ac9eea9a 100644 --- a/docs/source/user_guide/benchmarks/molecular_dynamics.rst +++ b/docs/source/user_guide/benchmarks/molecular_dynamics.rst @@ -76,3 +76,40 @@ Reference data: * Same as input data * Experimental + + +Stability +========= + +Summary +------- + +Performance in running stable molecular dynamics across a diverse set of +systems: small molecules (containing H/C/N/O, sulfur, and halogens), peptides +in vacuum (neurotensin, PDB: 2LNF; cyclic oxytocin, PDB: 7OFG), a protein in +vacuum (PDB: 1A7M), and solvated peptides with and without counter-ions. + +Metrics +------- + +1. Success rate + +Each system is run with a short NVT molecular dynamics simulation at 300 K. The +fraction of simulations that complete without error is reported. A simulation +counts as failed if it raises an error during integration (for example, a +numerical instability). Higher is better, with 1.0 meaning every system ran to +completion. + +Computational cost +------------------ + +High: tests are likely to take many hours on GPU. Faster simulation times can be +achieved using the jax accelerated simulations in MLIP Audit directly. + +Data availability +----------------- + +Input structures: + +* MLIP Audit benchmark suite, InstaDeep. + Structures derived from PDB entries 2LNF, 7OFG, and 1A7M. diff --git a/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py b/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py new file mode 100644 index 000000000..ea793f6d2 --- /dev/null +++ b/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py @@ -0,0 +1,87 @@ +"""Analyse molecular dynamics stability benchmark.""" + +from __future__ import annotations + +from pathlib import Path + +from mlipaudit.io import load_model_output_from_disk +import pytest + +from ml_peg.analysis.utils.decorators import build_table +from ml_peg.analysis.utils.utils import build_dispersion_name_map, load_metrics_config +from ml_peg.app import APP_ROOT +from ml_peg.calcs import CALCS_ROOT +from ml_peg.calcs.utils.mlipaudit import MlPegStabilityBenchmark +from ml_peg.models import current_models +from ml_peg.models.get_models import load_models + +MODELS = load_models(current_models) +DISPERSION_NAME_MAP = build_dispersion_name_map(MODELS) + +CALC_PATH = CALCS_ROOT / "molecular_dynamics" / "stability" / "outputs" +OUT_PATH = APP_ROOT / "data" / "molecular_dynamics" / "stability" + +METRICS_CONFIG_PATH = Path(__file__).with_name("metrics.yml") +DEFAULT_THRESHOLDS, DEFAULT_TOOLTIPS, DEFAULT_WEIGHTS = load_metrics_config( + METRICS_CONFIG_PATH +) + + +@pytest.fixture +def success_rate() -> dict[str, float]: + """ + Get the fraction of MD simulations that completed without error. + + Returns + ------- + dict[str, float] + Fraction of successful simulations for each model. + """ + results = {} + for model_name in MODELS: + output_zip = CALC_PATH / model_name / MlPegStabilityBenchmark.name + if not (output_zip / "model_output.zip").exists(): + continue + model_output = load_model_output_from_disk( + CALC_PATH / model_name, MlPegStabilityBenchmark + ) + states = model_output.simulation_states + results[model_name] = sum(s is not None for s in states) / len(states) + return results + + +@pytest.fixture +@build_table( + filename=OUT_PATH / "stability_metrics_table.json", + metric_tooltips=DEFAULT_TOOLTIPS, + thresholds=DEFAULT_THRESHOLDS, + mlip_name_map=DISPERSION_NAME_MAP, +) +def metrics(success_rate: dict[str, float]) -> dict[str, dict]: + """ + Get all metrics. + + Parameters + ---------- + success_rate + Fraction of successful simulations for all models. + + Returns + ------- + dict[str, dict] + Metric names and values for all models. + """ + return { + "Success Rate": success_rate, + } + + +def test_stability(metrics: dict[str, dict]) -> None: + """ + Run stability analysis. + + Parameters + ---------- + metrics : dict[str, dict] + Stability metric results provided by fixtures. + """ diff --git a/ml_peg/analysis/molecular_dynamics/stability/metrics.yml b/ml_peg/analysis/molecular_dynamics/stability/metrics.yml new file mode 100644 index 000000000..7c9f0542c --- /dev/null +++ b/ml_peg/analysis/molecular_dynamics/stability/metrics.yml @@ -0,0 +1,6 @@ +metrics: + Success Rate: + good: 1.0 + bad: 0.0 + unit: null + tooltip: Fraction of MD simulations that completed without error. diff --git a/ml_peg/app/molecular_dynamics/molecular_dynamics.yml b/ml_peg/app/molecular_dynamics/molecular_dynamics.yml index abcdd622f..5b893e61e 100644 --- a/ml_peg/app/molecular_dynamics/molecular_dynamics.yml +++ b/ml_peg/app/molecular_dynamics/molecular_dynamics.yml @@ -1,3 +1,3 @@ title: Molecular Dynamics -description: Liquid Densities, Water Densities +description: Liquid Densities, Water Densities, Stability weight: 0 diff --git a/ml_peg/app/molecular_dynamics/stability/app_stability.py b/ml_peg/app/molecular_dynamics/stability/app_stability.py new file mode 100644 index 000000000..a90a81c58 --- /dev/null +++ b/ml_peg/app/molecular_dynamics/stability/app_stability.py @@ -0,0 +1,50 @@ +"""Run molecular dynamics stability app.""" + +from __future__ import annotations + +from dash import Dash + +from ml_peg.app import APP_ROOT +from ml_peg.app.base_app import BaseApp + +BENCHMARK_NAME = "Stability" +DOCS_URL = "https://ddmms.github.io/ml-peg/user_guide/benchmarks/molecular_dynamics.html#stability" +DATA_PATH = APP_ROOT / "data" / "molecular_dynamics" / "stability" + + +class StabilityApp(BaseApp): + """Stability benchmark app layout and callbacks.""" + + def register_callbacks(self) -> None: + """Register callbacks to app.""" + + +def get_app() -> StabilityApp: + """ + Get stability benchmark app layout and callback registration. + + Returns + ------- + StabilityApp + Benchmark layout and callback registration. + """ + return StabilityApp( + name=BENCHMARK_NAME, + framework_id="mlip_audit", + description=( + "Fraction of short molecular dynamics simulations that complete " + "without error, across small molecules, peptides and proteins in " + "vacuum and solvent." + ), + docs_url=DOCS_URL, + table_path=DATA_PATH / "stability_metrics_table.json", + extra_components=[], + ) + + +if __name__ == "__main__": + full_app = Dash(__name__, assets_folder=DATA_PATH.parent.parent) + benchmark_app = get_app() + full_app.layout = benchmark_app.layout + benchmark_app.register_callbacks() + full_app.run(port=8067, debug=True) diff --git a/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py b/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py new file mode 100644 index 000000000..5cb74dfa5 --- /dev/null +++ b/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py @@ -0,0 +1,54 @@ +""" +Run molecular dynamics stability simulations. + +Short MD runs for small molecules, peptides and proteins in vacuum and +solvent, checking how many simulations complete without error. +""" + +from __future__ import annotations + +from pathlib import Path +from typing import Any + +from mlipaudit.io import write_model_output_to_disk +import pytest + +from ml_peg.calcs.utils.mlipaudit import MlPegStabilityBenchmark +from ml_peg.calcs.utils.utils import download_s3_data +from ml_peg.models import current_models +from ml_peg.models.get_models import load_models + +MODELS = load_models(current_models) + +OUT_PATH = Path(__file__).parent / "outputs" + + +@pytest.mark.parametrize("mlip", MODELS.items()) +def test_stability(mlip: tuple[str, Any]) -> None: + """ + Benchmark molecular dynamics stability. + + Parameters + ---------- + mlip + Name of model and model object to get calculator. + """ + model_name, model = mlip + calc = model.get_calculator() + calc = model.add_d3_calculator(calc) + + data_input_dir = download_s3_data( + key="inputs/molecular_dynamics/stability/stability.zip", + filename="stability.zip", + ) + + benchmark = MlPegStabilityBenchmark( + force_field=calc, + data_input_dir=data_input_dir, + run_mode="standard", + ) + benchmark.run_model() + + write_model_output_to_disk( + "stability", benchmark.model_output, OUT_PATH / model_name + ) diff --git a/ml_peg/calcs/utils/mlipaudit.py b/ml_peg/calcs/utils/mlipaudit.py new file mode 100644 index 000000000..2772c7014 --- /dev/null +++ b/ml_peg/calcs/utils/mlipaudit.py @@ -0,0 +1,16 @@ +"""Adapters for using mlipaudit benchmarks with ml-peg's ASE calculators.""" + +from __future__ import annotations + +from mlipaudit.benchmarks.stability.stability import StabilityBenchmark + + +class MlPegStabilityBenchmark(StabilityBenchmark): + """ + StabilityBenchmark wired up for ml-peg's ASE calculators. + + ``skip_if_elements_missing`` is disabled because ASE ``Calculator`` objects + do not expose ``allowed_atomic_numbers``. + """ + + skip_if_elements_missing = False From e18361d4c8ab7bb7fce0dbc45f6843d0664822c3 Mon Sep 17 00:00:00 2001 From: Leon Wehrhan Date: Wed, 1 Jul 2026 23:39:17 +0200 Subject: [PATCH 2/5] feat: simulation progress plots per system --- .../stability/analyse_stability.py | 117 ++++++++++++++++-- ml_peg/analysis/utils/decorators.py | 14 ++- .../stability/app_stability.py | 10 +- ml_peg/app/utils/frameworks.yml | 7 ++ .../stability/calc_stability.py | 2 +- 5 files changed, 133 insertions(+), 17 deletions(-) diff --git a/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py b/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py index ea793f6d2..31cc9746a 100644 --- a/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py +++ b/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py @@ -4,14 +4,16 @@ from pathlib import Path +from ase.calculators.calculator import Calculator from mlipaudit.io import load_model_output_from_disk import pytest -from ml_peg.analysis.utils.decorators import build_table +from ml_peg.analysis.utils.decorators import build_table, plot_scatter from ml_peg.analysis.utils.utils import build_dispersion_name_map, load_metrics_config from ml_peg.app import APP_ROOT from ml_peg.calcs import CALCS_ROOT from ml_peg.calcs.utils.mlipaudit import MlPegStabilityBenchmark +from ml_peg.calcs.utils.utils import download_s3_data from ml_peg.models import current_models from ml_peg.models.get_models import load_models @@ -27,29 +29,118 @@ ) +def _fraction_completed(result) -> float: + """ + Get how far a simulation got before it became unstable. + + Parameters + ---------- + result + A ``StabilityStructureResult`` for a single structure. + + Returns + ------- + float + Fraction of the trajectory completed: 1.0 if stable, 0.0 if the + simulation did not run, otherwise the frame at which it exploded or + drifted divided by the total number of frames. + """ + if result.failed: + return 0.0 + if result.exploded_frame != -1: + return result.exploded_frame / result.num_frames + if result.drift_frame != -1: + return result.drift_frame / result.num_frames + return 1.0 + + @pytest.fixture -def success_rate() -> dict[str, float]: +def structure_results() -> dict[str, list]: """ - Get the fraction of MD simulations that completed without error. + Analyse each stored trajectory into per-structure stability results. Returns ------- - dict[str, float] - Fraction of successful simulations for each model. + dict[str, list] + List of ``StabilityStructureResult`` objects for each model. """ + data_input_dir = download_s3_data( + key="inputs/molecular_dynamics/stability/stability.zip", + filename="stability.zip", + ) + results = {} for model_name in MODELS: - output_zip = CALC_PATH / model_name / MlPegStabilityBenchmark.name - if not (output_zip / "model_output.zip").exists(): + output_dir = CALC_PATH / model_name / MlPegStabilityBenchmark.name + if not (output_dir / "model_output.zip").exists(): continue - model_output = load_model_output_from_disk( + benchmark = MlPegStabilityBenchmark( + force_field=Calculator(), + data_input_dir=data_input_dir, + run_mode="standard", + ) + benchmark.model_output = load_model_output_from_disk( CALC_PATH / model_name, MlPegStabilityBenchmark ) - states = model_output.simulation_states - results[model_name] = sum(s is not None for s in states) / len(states) + results[model_name] = benchmark.analyze().structure_results return results +@pytest.fixture +def success_rate(structure_results: dict[str, list]) -> dict[str, float]: + """ + Get the fraction of MD simulations that completed without error. + + Parameters + ---------- + structure_results + Per-structure stability results for all models. + + Returns + ------- + dict[str, float] + Fraction of successful simulations for each model. + """ + return { + model_name: sum(not r.failed for r in results) / len(results) + for model_name, results in structure_results.items() + } + + +@pytest.fixture +@plot_scatter( + title="Trajectory stability", + x_label="System", + y_label="Fraction of trajectory completed", + hovertemplate="%{x}
Completed: %{y:.2f}%{fullData.name}", + filename=str(OUT_PATH / "stability_progress.json"), +) +def progress(structure_results: dict[str, list]) -> dict[str, tuple[list, list]]: + """ + Get per-structure trajectory progress for each model. + + For every system, reports the fraction of the trajectory completed before it + exploded, drifted or failed to run. + + Parameters + ---------- + structure_results + Per-structure stability results for all models. + + Returns + ------- + dict[str, tuple[list, list]] + Structure names and completed fractions for each model. + """ + return { + model_name: ( + [r.structure_name for r in results], + [_fraction_completed(r) for r in results], + ) + for model_name, results in structure_results.items() + } + + @pytest.fixture @build_table( filename=OUT_PATH / "stability_metrics_table.json", @@ -76,7 +167,9 @@ def metrics(success_rate: dict[str, float]) -> dict[str, dict]: } -def test_stability(metrics: dict[str, dict]) -> None: +def test_stability( + metrics: dict[str, dict], progress: dict[str, tuple[list, list]] +) -> None: """ Run stability analysis. @@ -84,4 +177,6 @@ def test_stability(metrics: dict[str, dict]) -> None: ---------- metrics : dict[str, dict] Stability metric results provided by fixtures. + progress : dict[str, tuple[list, list]] + Per-structure trajectory progress provided by fixtures. """ diff --git a/ml_peg/analysis/utils/decorators.py b/ml_peg/analysis/utils/decorators.py index a0c3ebe6f..a082ab9ee 100644 --- a/ml_peg/analysis/utils/decorators.py +++ b/ml_peg/analysis/utils/decorators.py @@ -448,6 +448,7 @@ def plot_scatter( show_line: bool = False, show_markers: bool = True, hoverdata: dict | None = None, + hovertemplate: str | None = None, filename: str = "scatter.json", highlight_range: dict = None, ) -> Callable: @@ -468,6 +469,9 @@ def plot_scatter( Whether to show markers on the plot. Default is True. hoverdata Hover data dictionary. Default is `{}`. + hovertemplate + Base hovertemplate string. Overrides the default reference/prediction + template. Any ``hoverdata`` keys are appended to it. Default is `None`. filename Filename to save plot as JSON. Default is "scatter.json". highlight_range @@ -513,11 +517,15 @@ def plot_scatter_wrapper(*args, **kwargs) -> dict[str, Any]: """ results = func(*args, **kwargs) - hovertemplate = "Pred: %{x}
" + "Ref: %{y}
" + template = ( + hovertemplate + if hovertemplate is not None + else "Pred: %{x}
" + "Ref: %{y}
" + ) customdata = [] if hoverdata: for i, key in enumerate(hoverdata): - hovertemplate += f"{key}: %{{customdata[{i}]}}
" + template += f"{key}: %{{customdata[{i}]}}
" customdata = list(zip(*hoverdata.values(), strict=True)) modes = [] @@ -538,7 +546,7 @@ def plot_scatter_wrapper(*args, **kwargs) -> dict[str, Any]: name=name, mode=mode, customdata=customdata, - hovertemplate=hovertemplate, + hovertemplate=template, ) ) diff --git a/ml_peg/app/molecular_dynamics/stability/app_stability.py b/ml_peg/app/molecular_dynamics/stability/app_stability.py index a90a81c58..71c25795e 100644 --- a/ml_peg/app/molecular_dynamics/stability/app_stability.py +++ b/ml_peg/app/molecular_dynamics/stability/app_stability.py @@ -6,6 +6,7 @@ from ml_peg.app import APP_ROOT from ml_peg.app.base_app import BaseApp +from ml_peg.app.utils.load import read_plot BENCHMARK_NAME = "Stability" DOCS_URL = "https://ddmms.github.io/ml-peg/user_guide/benchmarks/molecular_dynamics.html#stability" @@ -30,7 +31,7 @@ def get_app() -> StabilityApp: """ return StabilityApp( name=BENCHMARK_NAME, - framework_id="mlip_audit", + framework_ids="mlip_audit", description=( "Fraction of short molecular dynamics simulations that complete " "without error, across small molecules, peptides and proteins in " @@ -38,7 +39,12 @@ def get_app() -> StabilityApp: ), docs_url=DOCS_URL, table_path=DATA_PATH / "stability_metrics_table.json", - extra_components=[], + extra_components=[ + read_plot( + filename=DATA_PATH / "stability_progress.json", + id=f"{BENCHMARK_NAME}-progress-figure", + ) + ], ) diff --git a/ml_peg/app/utils/frameworks.yml b/ml_peg/app/utils/frameworks.yml index 27b079925..2d0f5537c 100644 --- a/ml_peg/app/utils/frameworks.yml +++ b/ml_peg/app/utils/frameworks.yml @@ -26,3 +26,10 @@ mace-polar-1: url: "https://arxiv.org/abs/2602.19411" icon: "📄" tooltip: "Benchmark from the MACE-POLAR-1 paper (arXiv:2602.19411) - click to read" + +mlip_audit: + label: MLIP Audit + color: "#1d4ed8" + text_color: "#ffffff" + url: "https://github.com/instadeepai/mlipaudit" + logo: "https://raw.githubusercontent.com/instadeepai/mlipaudit/mlpeg-migration/InstaDeep_Logo.png" diff --git a/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py b/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py index 5cb74dfa5..a5857d391 100644 --- a/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py +++ b/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py @@ -35,7 +35,7 @@ def test_stability(mlip: tuple[str, Any]) -> None: """ model_name, model = mlip calc = model.get_calculator() - calc = model.add_d3_calculator(calc) + calc = model.get_calculator(precision="low") data_input_dir = download_s3_data( key="inputs/molecular_dynamics/stability/stability.zip", From 4f8d42cab02ef5eecc1c4012ac5abbb152aae2dd Mon Sep 17 00:00:00 2001 From: Leon Wehrhan Date: Wed, 1 Jul 2026 23:39:59 +0200 Subject: [PATCH 3/5] docs: simulation progress plots per system --- docs/source/user_guide/benchmarks/molecular_dynamics.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/user_guide/benchmarks/molecular_dynamics.rst b/docs/source/user_guide/benchmarks/molecular_dynamics.rst index 9ac9eea9a..258e8e42b 100644 --- a/docs/source/user_guide/benchmarks/molecular_dynamics.rst +++ b/docs/source/user_guide/benchmarks/molecular_dynamics.rst @@ -100,6 +100,11 @@ counts as failed if it raises an error during integration (for example, a numerical instability). Higher is better, with 1.0 meaning every system ran to completion. +A scatter plot below the table shows, for each system and model, the fraction of +the trajectory completed before it became unstable: 1.0 for a fully stable run, a +smaller value when the run exploded or hydrogens drifted, and 0.0 for systems that +failed to run at all. Individual models can be toggled via the legend. + Computational cost ------------------ From 538b9fb4bbc0b60b8508423587d368fbd0e8e256 Mon Sep 17 00:00:00 2001 From: Leon Wehrhan Date: Fri, 3 Jul 2026 14:28:22 +0200 Subject: [PATCH 4/5] Apply suggestion Co-authored-by: Elliott Kasoar <45317199+ElliottKasoar@users.noreply.github.com> --- ml_peg/calcs/molecular_dynamics/stability/calc_stability.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py b/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py index a5857d391..be9404b28 100644 --- a/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py +++ b/ml_peg/calcs/molecular_dynamics/stability/calc_stability.py @@ -34,7 +34,7 @@ def test_stability(mlip: tuple[str, Any]) -> None: Name of model and model object to get calculator. """ model_name, model = mlip - calc = model.get_calculator() + calc = model.get_calculator(precision="low") calc = model.get_calculator(precision="low") data_input_dir = download_s3_data( From 918e5493f89b55ecadf843b2b6a0f3a589c1bae6 Mon Sep 17 00:00:00 2001 From: Leon Wehrhan Date: Fri, 24 Jul 2026 00:58:34 +0200 Subject: [PATCH 5/5] feat: add element filtering --- .../stability/analyse_stability.py | 27 +++++++++++++++++-- .../stability/app_stability.py | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py b/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py index 31cc9746a..e60a40823 100644 --- a/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py +++ b/ml_peg/analysis/molecular_dynamics/stability/analyse_stability.py @@ -5,11 +5,16 @@ from pathlib import Path from ase.calculators.calculator import Calculator +from mlipaudit.benchmarks.stability.stability import STRUCTURE_NAMES, STRUCTURES from mlipaudit.io import load_model_output_from_disk import pytest from ml_peg.analysis.utils.decorators import build_table, plot_scatter -from ml_peg.analysis.utils.utils import build_dispersion_name_map, load_metrics_config +from ml_peg.analysis.utils.utils import ( + build_dispersion_name_map, + load_metrics_config, + write_struct_info, +) from ml_peg.app import APP_ROOT from ml_peg.calcs import CALCS_ROOT from ml_peg.calcs.utils.mlipaudit import MlPegStabilityBenchmark @@ -167,8 +172,24 @@ def metrics(success_rate: dict[str, float]) -> dict[str, dict]: } +@pytest.fixture +def element_info() -> None: + """Write element info for all benchmark systems, used by the app element filter.""" + data_input_dir = download_s3_data( + key="inputs/molecular_dynamics/stability/stability.zip", + filename="stability.zip", + ) + xyz_paths = [ + data_input_dir / MlPegStabilityBenchmark.name / STRUCTURES[name]["xyz"] + for name in STRUCTURE_NAMES + ] + write_struct_info(data_path=xyz_paths, out_path=OUT_PATH) + + def test_stability( - metrics: dict[str, dict], progress: dict[str, tuple[list, list]] + metrics: dict[str, dict], + progress: dict[str, tuple[list, list]], + element_info: None, ) -> None: """ Run stability analysis. @@ -179,4 +200,6 @@ def test_stability( Stability metric results provided by fixtures. progress : dict[str, tuple[list, list]] Per-structure trajectory progress provided by fixtures. + element_info : None + Element info written for the app element filter. """ diff --git a/ml_peg/app/molecular_dynamics/stability/app_stability.py b/ml_peg/app/molecular_dynamics/stability/app_stability.py index 71c25795e..fcdf6b169 100644 --- a/ml_peg/app/molecular_dynamics/stability/app_stability.py +++ b/ml_peg/app/molecular_dynamics/stability/app_stability.py @@ -11,6 +11,7 @@ BENCHMARK_NAME = "Stability" DOCS_URL = "https://ddmms.github.io/ml-peg/user_guide/benchmarks/molecular_dynamics.html#stability" DATA_PATH = APP_ROOT / "data" / "molecular_dynamics" / "stability" +INFO_PATH = DATA_PATH / "info.json" class StabilityApp(BaseApp): @@ -45,6 +46,7 @@ def get_app() -> StabilityApp: id=f"{BENCHMARK_NAME}-progress-figure", ) ], + info_path=INFO_PATH, )