From 23c1d4117c95f6fbaec5093d48a96c8eba6a2f76 Mon Sep 17 00:00:00 2001 From: Shyam D Date: Wed, 10 Mar 2021 08:03:55 -0800 Subject: [PATCH 1/6] add Kspacing to validation --- emmet-core/emmet/core/settings.py | 5 +++ emmet-core/emmet/core/vasp/validation.py | 40 +++++++++++++++++------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/emmet-core/emmet/core/settings.py b/emmet-core/emmet/core/settings.py index b02660bb71..59094c4071 100644 --- a/emmet-core/emmet/core/settings.py +++ b/emmet-core/emmet/core/settings.py @@ -54,6 +54,11 @@ class EmmetSettings(BaseSettings): description="Relative tolerance for kpt density to still be a valid task document", ) + VASP_KSPACING_TOLERANCE: float = Field( + 0.05, + description="Relative tolerance for kspacing to still be a valid task document", + ) + VASP_DEFAULT_INPUT_SETS: Dict[str, PyObject] = Field( { "GGA Structure Optimization": "pymatgen.io.vasp.sets.MPRelaxSet", diff --git a/emmet-core/emmet/core/vasp/validation.py b/emmet-core/emmet/core/vasp/validation.py index d63e0ed4d5..eb91da8016 100644 --- a/emmet-core/emmet/core/vasp/validation.py +++ b/emmet-core/emmet/core/vasp/validation.py @@ -14,6 +14,7 @@ class DeprecationMessage(DocEnum): MANUAL = "M", "manual deprecation" KPTS = "C001", "Too few KPoints" + KSPACING = "C002", "KSpacing not high enough" ENCUT = "C002", "ENCUT too low" FORCES = "C003", "Forces too large" CONVERGENCE = "E001", "Calculation did not converge" @@ -53,6 +54,7 @@ def from_task_doc( cls, task_doc: TaskDocument, kpts_tolerance: float = SETTINGS.VASP_KPTS_TOLERANCE, + kspacing_tolerance: float = SETTINGS.VASP_KSPACING_TOLERANCE, input_sets: Dict[str, PyObject] = SETTINGS.VASP_DEFAULT_INPUT_SETS, LDAU_fields: List[str] = SETTINGS.VASP_CHECKED_LDAU_FIELDS, max_allowed_scf_gradient: float = SETTINGS.VASP_MAX_SCF_GRADIENT, @@ -62,9 +64,11 @@ def from_task_doc( Args: task_doc: the task document to process - input_sets (dict): a dictionary of task_types -> pymatgen input set for validation - kpts_tolerance (float): the tolerance to allow kpts to lag behind the input set settings - LDAU_fields (list(String)): LDAU fields to check for consistency + kpts_tolerance: the tolerance to allow kpts to lag behind the input set settings + kspacing_tolerance: the tolerance to allow kspacing to lag behind the input set settings + input_sets: a dictionary of task_types -> pymatgen input set for validation + LDAU_fields: LDAU fields to check for consistency + max_allowed_scf_gradient: maximum uphill gradient allowed for SCF steps after the initial equillibriation periuod """ structure = task_doc.output.structure @@ -78,15 +82,27 @@ def from_task_doc( valid_input_set = input_sets[task_type](structure) # Checking K-Points - valid_num_kpts = valid_input_set.kpoints.num_kpts or np.prod( - valid_input_set.kpoints.kpts[0] - ) - num_kpts = inputs.get("kpoints", {}).get("nkpoints", 0) or np.prod( - inputs.get("kpoints", {}).get("kpoints", [1, 1, 1]) - ) - data["kpts_ratio"] = num_kpts / valid_num_kpts - if data["kpts_ratio"] < kpts_tolerance: - reasons.append(DeprecationMessage.KPTS) + # Calculations that use KSPACING will not have a .kpoints attr + if valid_input_set.kpoints is not None: + valid_num_kpts = valid_input_set.kpoints.num_kpts or np.prod( + valid_input_set.kpoints.kpts[0] + ) + num_kpts = inputs.get("kpoints", {}).get("nkpoints", 0) or np.prod( + inputs.get("kpoints", {}).get("kpoints", [1, 1, 1]) + ) + data["kpts_ratio"] = num_kpts / valid_num_kpts + if data["kpts_ratio"] < kpts_tolerance: + reasons.append(DeprecationMessage.KPTS) + + else: + valid_kspacing = valid_input_set.incar.get("KSPACING", 0) + if inputs.get("incar", {}).get("KSPACING"): + data["kspacing_delta"] = ( + inputs["incar"].get("KSPACING") - valid_kspacing + ) + # larger KSPACING means fewer k-points + if data["kspacing_delta"] > kspacing_tolerance: + reasons.append(DeprecationMessage.KSPACING) # Checking ENCUT encut = inputs.get("incar", {}).get("ENCUT") From d15c7c0784f55edf4f3519acf7de0ebd6eeb0976 Mon Sep 17 00:00:00 2001 From: Shyam D Date: Wed, 10 Mar 2021 08:25:57 -0800 Subject: [PATCH 2/6] remove old metadata --- emmet-builders/emmet/builders/vasp/task_validator.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/emmet-builders/emmet/builders/vasp/task_validator.py b/emmet-builders/emmet/builders/vasp/task_validator.py index a2ab69b6c7..4effb32b2b 100644 --- a/emmet-builders/emmet/builders/vasp/task_validator.py +++ b/emmet-builders/emmet/builders/vasp/task_validator.py @@ -11,10 +11,6 @@ from emmet.core.vasp.validation import DeprecationMessage, ValidationDoc from emmet.builders.settings import EmmetBuildSettings -__author__ = "Shyam Dwaraknath" -__email__ = "shyamd@lbl.gov" - - class TaskValidator(MapBuilder): def __init__( self, From 15e5c28e4d4a1b3a0b98a76ff87e64c3767be6da Mon Sep 17 00:00:00 2001 From: Shyam D Date: Wed, 10 Mar 2021 08:36:38 -0800 Subject: [PATCH 3/6] ensure settings can be serialized --- tests/emmet-core/test_settings.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/emmet-core/test_settings.py b/tests/emmet-core/test_settings.py index ad105938be..fd851a8c69 100644 --- a/tests/emmet-core/test_settings.py +++ b/tests/emmet-core/test_settings.py @@ -4,6 +4,8 @@ from random import random from emmet.core.settings import EmmetSettings +from monty.serialization import loadfn, dumpfn +from monty.tempfile import ScratchDir def test_default_config_path(tmp_path: PosixPath): @@ -40,3 +42,14 @@ def test_from_url(): test_config = EmmetSettings() assert test_config.ANGLE_TOL == 1.0 + + +def test_seriallization(): + + test_config = EmmetSettings() + + with ScratchDir("."): + dumpfn(test_config, "test.json") + reload_config = loadfn("test.json") + + assert isinstance(reload_config, EmmetSettings) From ee07aaf3395c10f3d98f8a45a623e9b75b9a3dd8 Mon Sep 17 00:00:00 2001 From: Shyam D Date: Wed, 10 Mar 2021 08:36:48 -0800 Subject: [PATCH 4/6] hotpatch monty serialization --- emmet-core/emmet/core/settings.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/emmet-core/emmet/core/settings.py b/emmet-core/emmet/core/settings.py index 59094c4071..de69ac661a 100644 --- a/emmet-core/emmet/core/settings.py +++ b/emmet-core/emmet/core/settings.py @@ -3,7 +3,7 @@ """ import importlib import json -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Union, TypeVar, Type import requests from pydantic import BaseSettings, Field, root_validator, validator @@ -12,6 +12,9 @@ DEFAULT_CONFIG_FILE_PATH = str(Path.home().joinpath(".emmet.json")) +S = TypeVar("S", bound="EmmetSettings") + + class EmmetSettings(BaseSettings): """ Settings for the emmet- packages @@ -99,3 +102,25 @@ def load_default_settings(cls, values): new_values.update(values) return new_values + + @classmethod + def autoload(cls: Type[S], settings: Union[None, dict, Type[S]]) -> S: + if settings is None: + return cls() + elif isinstance(settings, dict): + return cls(settings) + return settings + + def as_dict(self): + """ + HotPatch to enable serializing EmmetSettings via Monty + """ + return self.dict(exclude_unset=True, exclude_defaults=True) + + @classmethod + def from_dict(cls: Type[S], settings: Dict) -> S: + """ + HotPatch to enable serializing EmmetSettings via Monty + """ + return cls(**settings) + From 0bb5b8dce4e408da0c286d7620c4bef810ae0df8 Mon Sep 17 00:00:00 2001 From: Shyam D Date: Wed, 10 Mar 2021 08:45:44 -0800 Subject: [PATCH 5/6] use autoload in builders --- emmet-builders/emmet/builders/vasp/materials.py | 2 +- emmet-builders/emmet/builders/vasp/task_validator.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/emmet-builders/emmet/builders/vasp/materials.py b/emmet-builders/emmet/builders/vasp/materials.py index 400687800d..fe6f10608b 100644 --- a/emmet-builders/emmet/builders/vasp/materials.py +++ b/emmet-builders/emmet/builders/vasp/materials.py @@ -62,7 +62,7 @@ def __init__( self.materials = materials self.task_validation = task_validation self.query = query if query else {} - self.settings = settings or SETTINGS + self.settings = EmmetBuildSettings.autoload(settings) self.kwargs = kwargs sources = [tasks] diff --git a/emmet-builders/emmet/builders/vasp/task_validator.py b/emmet-builders/emmet/builders/vasp/task_validator.py index 4effb32b2b..7fbad01e22 100644 --- a/emmet-builders/emmet/builders/vasp/task_validator.py +++ b/emmet-builders/emmet/builders/vasp/task_validator.py @@ -11,6 +11,7 @@ from emmet.core.vasp.validation import DeprecationMessage, ValidationDoc from emmet.builders.settings import EmmetBuildSettings + class TaskValidator(MapBuilder): def __init__( self, @@ -28,7 +29,7 @@ def __init__( """ self.tasks = tasks self.task_validation = task_validation - self.settings = settings or SETTINGS + self.settings = EmmetBuildSettings.autoload(settings) self.kwargs = kwargs super().__init__( @@ -55,6 +56,7 @@ def unary_function(self, item): validation_doc = ValidationDoc.from_task_doc( task_doc=task_doc, kpts_tolerance=self.settings.VASP_KPTS_TOLERANCE, + kspacing_tolerance=self.settings.VASP_KSPACING_TOLERANCE, input_sets=self.settings.VASP_DEFAULT_INPUT_SETS, LDAU_fields=self.settings.VASP_CHECKED_LDAU_FIELDS, max_allowed_scf_gradient=self.settings.VASP_MAX_SCF_GRADIENT, From f51232af41963f19f7df756b9bae201a7e0fadf5 Mon Sep 17 00:00:00 2001 From: Shyam D Date: Wed, 10 Mar 2021 08:52:23 -0800 Subject: [PATCH 6/6] linting fixes --- emmet-core/emmet/core/settings.py | 7 +++---- emmet-core/emmet/core/vasp/validation.py | 3 ++- tests/emmet-core/test_settings.py | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/emmet-core/emmet/core/settings.py b/emmet-core/emmet/core/settings.py index de69ac661a..23fd23b494 100644 --- a/emmet-core/emmet/core/settings.py +++ b/emmet-core/emmet/core/settings.py @@ -3,7 +3,7 @@ """ import importlib import json -from typing import Dict, List, Optional, Union, TypeVar, Type +from typing import Dict, List, Optional, Type, TypeVar, Union import requests from pydantic import BaseSettings, Field, root_validator, validator @@ -104,11 +104,11 @@ def load_default_settings(cls, values): return new_values @classmethod - def autoload(cls: Type[S], settings: Union[None, dict, Type[S]]) -> S: + def autoload(cls: Type[S], settings: Union[None, dict, S]) -> S: if settings is None: return cls() elif isinstance(settings, dict): - return cls(settings) + return cls(**settings) return settings def as_dict(self): @@ -123,4 +123,3 @@ def from_dict(cls: Type[S], settings: Dict) -> S: HotPatch to enable serializing EmmetSettings via Monty """ return cls(**settings) - diff --git a/emmet-core/emmet/core/vasp/validation.py b/emmet-core/emmet/core/vasp/validation.py index eb91da8016..bf8bf2d8f1 100644 --- a/emmet-core/emmet/core/vasp/validation.py +++ b/emmet-core/emmet/core/vasp/validation.py @@ -68,7 +68,8 @@ def from_task_doc( kspacing_tolerance: the tolerance to allow kspacing to lag behind the input set settings input_sets: a dictionary of task_types -> pymatgen input set for validation LDAU_fields: LDAU fields to check for consistency - max_allowed_scf_gradient: maximum uphill gradient allowed for SCF steps after the initial equillibriation periuod + max_allowed_scf_gradient: maximum uphill gradient allowed for SCF steps after the + initial equillibriation period """ structure = task_doc.output.structure diff --git a/tests/emmet-core/test_settings.py b/tests/emmet-core/test_settings.py index fd851a8c69..c98c8aeaca 100644 --- a/tests/emmet-core/test_settings.py +++ b/tests/emmet-core/test_settings.py @@ -3,10 +3,11 @@ from pathlib import PosixPath from random import random -from emmet.core.settings import EmmetSettings -from monty.serialization import loadfn, dumpfn +from monty.serialization import dumpfn, loadfn from monty.tempfile import ScratchDir +from emmet.core.settings import EmmetSettings + def test_default_config_path(tmp_path: PosixPath): """Make sure the default config path works"""