-
Notifications
You must be signed in to change notification settings - Fork 41
Water slab dipoles #349
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
MandyHoffmann
wants to merge
23
commits into
ddmms:main
Choose a base branch
from
MandyHoffmann:water_slab_dipoles
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
Water slab dipoles #349
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
ca271d3
Added calc_water_slab_dipoles.py
1768f94
added starting structure
219b782
Small fixes and added FF model for testing.
33db252
Merged changes
8e0f1e3
Added good and bad for sigma metric
5236740
Got analysis working
5626094
Added timestamps to thermo file
fc15626
Added app file
5d75040
App can run now
09e7758
Changed length of MD in calc
1749cc8
Merge branch 'water_slab_dipoles' of https://github.com/MandyHoffmann…
5396620
Drafted histogram function (one hist for each model).
f57c088
Changed plot-hist to be more like plot_hist
2171705
It's actually calling the hist decorator now
fb1e5fe
Plots are actually visible now
8ec5103
Plot exists for mp0a now, D3 names removed
74b4616
Hist has labels now.
6c7a5e4
Coloring of histogram works now
1d28c19
Removed bug-fixing prints
73385ea
Bug fix for hist marker, remove more prints
fbc7bb7
Update ml_peg/analysis/utils/decorators.py
MandyHoffmann 3a84228
Update ml_peg/app/physicality/water_slab_dipoles/app_water_slab_dipol…
MandyHoffmann 3b9c01a
Update ml_peg/calcs/physicality/water_slab_dipoles/calc_water_slab_di…
MandyHoffmann 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -135,3 +135,36 @@ Data availability | |
| ----------------- | ||
|
|
||
| None required; diatomics are generated in ASE. | ||
|
|
||
|
|
||
| Water Slab Dipoles | ||
| ================== | ||
|
|
||
| Summary | ||
| ------- | ||
|
|
||
| Distribution of dipole of water slab, checking for width of distribution and structures with dielectric breakdown. | ||
|
|
||
|
|
||
| Metrics | ||
| ------- | ||
|
|
||
| 1. Standard Deviation of Dipole Distribution | ||
|
|
||
| For a number of samples from an MD simulation, the total dipole is calculated. Compare to a reference of a LR model trained on revPBE-D3. | ||
|
|
||
| 2. Number of structures with dielectric breakdown | ||
|
|
||
| Estimate band gap based on dipole, count structures where band gap disappears. | ||
|
|
||
|
|
||
| Computational Cost | ||
| ------------------ | ||
|
|
||
| High: Requires around 500 ps of MD of 40 A slab to get converged distribution. | ||
|
|
||
|
|
||
| Data availability | ||
| ----------------- | ||
|
|
||
| Paper in preparation, contact Isaac Parker (ijp30@cam.ac.uk). | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this still the case?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it's on arxiv now: https://arxiv.org/html/2603.04228v1 |
||
190 changes: 190 additions & 0 deletions
190
ml_peg/analysis/physicality/water_slab_dipoles/analyse_water_slab_dipoles.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,190 @@ | ||
| """Analyse water slab dipole benchmark.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from pathlib import Path | ||
|
|
||
| from ase import units | ||
| from ase.io import read | ||
| import numpy as np | ||
| import pytest | ||
| from scipy.constants import e, epsilon_0 | ||
|
|
||
| from ml_peg.analysis.utils.decorators import build_table, plot_hist | ||
| from ml_peg.analysis.utils.utils import build_d3_name_map, load_metrics_config | ||
| 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) | ||
| D3_MODEL_NAMES = build_d3_name_map(MODELS) | ||
| CALC_PATH = CALCS_ROOT / "physicality" / "water_slab_dipoles" / "outputs" | ||
| OUT_PATH = APP_ROOT / "data" / "physicality" / "water_slab_dipoles" | ||
|
|
||
| METRICS_CONFIG_PATH = Path(__file__).with_name("metrics.yml") | ||
| DEFAULT_THRESHOLDS, DEFAULT_TOOLTIPS, DEFAULT_WEIGHTS = load_metrics_config( | ||
| METRICS_CONFIG_PATH | ||
| ) | ||
|
|
||
| # Unit conversion | ||
| EV_TO_KJ_PER_MOL = units.mol / units.kJ | ||
|
|
||
| # We consider a dipole as bad if the expected band gap is <= 0 | ||
| # The expected band gap is 4.50 V - |P_z_per_unit_area| / epsilon_0 | ||
| # Hence "bad" is |P_z_per_unit_area| > 4.50 V * epsilon_0 / e * 10^(-10) | ||
| # epsilon_0 is in F/m = C/(V*m), so this gives it in e/(V*A) | ||
| DIPOLE_BAD_THRESHOLD = 4.50 * epsilon_0 / e * 10 ** (-10) | ||
|
|
||
|
|
||
| def get_dipoles() -> dict[str, np.ndarray]: | ||
| """ | ||
| Get total dipole per unit area in z direction. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, np.ndarray] | ||
| Dictionary with array of dipoles for each model. | ||
| """ | ||
| results = {} | ||
| for model_name in MODELS: | ||
| model_dir = CALC_PATH / model_name | ||
| if model_dir.exists(): | ||
| if (model_dir / "dipoles.npy").is_file(): | ||
| results[model_name] = np.load(model_dir / "dipoles.npy") | ||
| else: | ||
| atoms = read(model_dir / "slab.xyz", ":") | ||
| dipoles = np.zeros(len(atoms)) | ||
| for i, struc in enumerate(atoms): | ||
| o_index = [atom.index for atom in struc if atom.number == 8] | ||
| h_index = [atom.index for atom in struc if atom.number == 1] | ||
| dipoles[i] = ( | ||
| np.sum(struc.positions[o_index, 2]) * (-0.8476) | ||
| + np.sum(struc.positions[h_index, 2]) * 0.4238 | ||
| ) | ||
| dipoles_unit_area = dipoles / atoms[0].cell[0, 0] / atoms[0].cell[1, 1] | ||
| results[model_name] = dipoles_unit_area | ||
| np.save(model_dir / "dipoles.npy", dipoles_unit_area) | ||
| return results | ||
|
|
||
|
|
||
| def plot_distribution(model: str) -> None: | ||
| """ | ||
| Plot Dipole Distribution. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| model | ||
| Name of MLIP. | ||
| """ | ||
| bins_start = -1.5 * DIPOLE_BAD_THRESHOLD | ||
| bins_stop = 1.5 * DIPOLE_BAD_THRESHOLD | ||
| bins_size = 3 * DIPOLE_BAD_THRESHOLD / 40 | ||
| # one might want to consider reducing the bin size further... | ||
|
|
||
| @plot_hist( | ||
| filename=OUT_PATH / f"figure_{model}_dipoledistr.json", | ||
| title=f"Dipole Distribution {model}", | ||
| x_label="Total z-Dipole per unit area [e/A]", | ||
| y_label="Probability Density", | ||
| good=-DIPOLE_BAD_THRESHOLD, | ||
| bad=DIPOLE_BAD_THRESHOLD, | ||
| bins={"start": bins_start, "end": bins_stop, "size": bins_size}, | ||
| ) | ||
| def plot_distr() -> dict[str, np.ndarray]: | ||
| """ | ||
| Plot a NEB and save the structure file. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, np.ndarray] | ||
| Dictionary of array with all dipoles for each model. | ||
| """ | ||
| return {model: get_dipoles()[model]} | ||
|
|
||
| plot_distr() | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def dipole_std() -> dict[str, float]: | ||
| """ | ||
| Get standard deviation of total z dipole per unit area (in e/A). | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, float] | ||
| Dictionary of standard deviation of dipole distribution for all models. | ||
| """ | ||
| dipoles = get_dipoles() | ||
| results = {} | ||
| for model_name in MODELS: | ||
| if model_name in dipoles.keys(): | ||
| plot_distribution(model_name) | ||
| results[model_name] = np.std(dipoles[model_name]) | ||
| else: | ||
| results[model_name] = None | ||
| return results | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def n_bad() -> dict[str, float]: | ||
| """ | ||
| Get fraction of dipoles that are bad. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, float] | ||
| Dictionary of percentage of breakdown candidates for all models. | ||
| """ | ||
| dipoles = get_dipoles() | ||
|
|
||
| results = {} | ||
| for model_name in MODELS: | ||
| if model_name in dipoles.keys(): | ||
| plot_distribution(model_name) | ||
| results[model_name] = ( | ||
| np.abs(dipoles[model_name]) > DIPOLE_BAD_THRESHOLD | ||
| ).sum() / len(dipoles[model_name]) | ||
| else: | ||
| results[model_name] = None | ||
| return results | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| @build_table( | ||
| filename=OUT_PATH / "water_slab_dipoles_metrics_table.json", | ||
| metric_tooltips=DEFAULT_TOOLTIPS, | ||
| thresholds=DEFAULT_THRESHOLDS, | ||
| ) | ||
| def metrics(dipole_std: dict[str, float], n_bad: dict[str, float]) -> dict[str, dict]: | ||
| """ | ||
| Get all water slab dipoles metrics. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| dipole_std | ||
| Standard deviation of dipole distribution. | ||
| n_bad | ||
| Percentage of tested structures with dipole larger than water band gap. | ||
|
|
||
| Returns | ||
| ------- | ||
| dict[str, dict] | ||
| Metric names and values for all models. | ||
| """ | ||
| return { | ||
| "sigma": dipole_std, | ||
| "Fraction Breakdown Candidates": n_bad, | ||
| } | ||
|
|
||
|
|
||
| def test_water_slab_dipoles(metrics: dict[str, dict]) -> None: | ||
| """ | ||
| Run water slab dipoles test. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| metrics | ||
| All water slab dipole metrics. | ||
| """ | ||
| return |
13 changes: 13 additions & 0 deletions
13
ml_peg/analysis/physicality/water_slab_dipoles/metrics.yml
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,13 @@ | ||
| metrics: | ||
| sigma: | ||
| good: 0.007 | ||
| bad: 0.015 | ||
| unit: e/A | ||
| tooltip: Standard deviation of total dipole in z direction | ||
| level of theory: null | ||
| Fraction Breakdown Candidates: | ||
| good: 0 | ||
| bad: 1 | ||
| unit: null | ||
| tooltip: Fraction of structures with dipole larger than band gap | ||
| level of theory: revPBE-D3 |
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
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this hours or days of GPU time, roughly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 day, if I remember correctly, multiple for larger models