Skip to content

Commit

Permalink
Incorporate blessed tasks endpoint (#880)
Browse files Browse the repository at this point in the history
* Add blessed tasks document model

* HSE to blessed

* Rename BlessedTasks

* Initial commit of blessed calcs query

* Add blessed tasks model to MaterialsDoc

* Add blessed tasks query and resource

* Add projected fields to blessed tasks

* Disable get by key in blessed tasks

* Add post processing to blessed tasks

* Add entries query to hint scheme for materials

* Remove entry energy query

* Add entries back to hint scheme

* Revert hint scheme change

* Linting

* Fix blessed task length check

* Exclude none in blessed task model dump
  • Loading branch information
munrojm committed Nov 2, 2023
1 parent dc620e7 commit 1a77a2a
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 3 deletions.
45 changes: 45 additions & 0 deletions emmet-api/emmet/api/routes/materials/materials/query_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from pymatgen.core.composition import Composition, CompositionError
from pymatgen.core.periodic_table import Element
from pymatgen.core.structure import Structure
from emmet.core.vasp.calc_types import RunType


class FormulaQuery(QueryOperator):
Expand Down Expand Up @@ -201,6 +202,50 @@ def ensure_indexes(self): # pragma: no cover
return [("task_ids", False)]


class BlessedCalcsQuery(QueryOperator):
"""
Method to generate a query for nested blessed calculation data
"""

def query(
self,
run_type: RunType = Query(
..., description="Calculation run type of blessed task data"
),
energy_min: Optional[float] = Query(
None, description="Minimum total uncorrected DFT energy in eV/atom"
),
energy_max: Optional[float] = Query(
None, description="Maximum total uncorrected DFT energy in eV/atom"
),
) -> STORE_PARAMS:
# crit = {f"entries.{run_type}": {}} # type: dict

# if energy_min:
# crit[f"entries.{run_type}"].update({"$gte": energy_min})

# if energy_max:
# crit[f"entries.{run_type}"].update({"$lte": energy_max})

# if not crit[f"entries.{run_type}"]:
# crit[f"entries.{run_type}"].update({"$exists": True})

return {"criteria": {f"entries.{run_type}": {"$exists": True}}}

def post_process(self, docs, query):
run_type = list(query["criteria"].keys())[0].split(".")[-1]

return_data = [
{
"material_id": doc["material_id"],
"blessed_entry": doc["entries"][run_type],
}
for doc in docs
]

return return_data


class MultiMaterialIDQuery(QueryOperator):
"""
Method to generate a query for different root-level material_id values
Expand Down
37 changes: 37 additions & 0 deletions emmet-api/emmet/api/routes/materials/materials/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
FormulaAutoCompleteQuery,
MultiMaterialIDQuery,
LicenseQuery,
BlessedCalcsQuery,
)
from emmet.api.core.global_header import GlobalHeaderProcessor
from emmet.api.core.settings import MAPISettings
Expand Down Expand Up @@ -61,6 +62,42 @@ def formula_autocomplete_resource(formula_autocomplete_store):
return resource


def blessed_tasks_resource(materials_store):
resource = ReadOnlyResource(
materials_store,
MaterialsDoc,
query_operators=[
BlessedCalcsQuery(),
MultiMaterialIDQuery(),
FormulaQuery(),
ChemsysQuery(),
ElementsQuery(),
MultiTaskIDQuery(),
DeprecationQuery(),
NumericQuery(model=MaterialsDoc),
SortQuery(),
PaginationQuery(),
LicenseQuery(),
],
key_fields=[
"material_id",
"chemsys",
"formula_pretty",
"deprecated",
"entries",
],
header_processor=GlobalHeaderProcessor(),
hint_scheme=MaterialsHintScheme(),
tags=["Materials"],
sub_path="/core/blessed_tasks/",
enable_get_by_key=False,
disable_validation=True,
timeout=MAPISettings().TIMEOUT,
)

return resource


def materials_resource(materials_store):
resource = ReadOnlyResource(
materials_store,
Expand Down
2 changes: 2 additions & 0 deletions emmet-api/material_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,13 +291,15 @@
from emmet.api.routes.materials.materials.resources import (
find_structure_resource,
formula_autocomplete_resource,
blessed_tasks_resource,
materials_resource,
)

materials_resources = list()

materials_resources.extend(
[
blessed_tasks_resource(materials_store),
find_structure_resource(materials_store),
formula_autocomplete_resource(formula_autocomplete_store),
materials_resource(materials_store),
Expand Down
13 changes: 11 additions & 2 deletions emmet-core/emmet/core/vasp/material.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
""" Core definition of a Materials Document """
from typing import Dict, List, Mapping, Optional

from pydantic import Field
from pydantic import Field, BaseModel
from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer
from pymatgen.analysis.structure_matcher import StructureMatcher
from pymatgen.entries.computed_entries import ComputedStructureEntry
Expand All @@ -16,6 +16,15 @@
SETTINGS = EmmetSettings()


class BlessedCalcs(BaseModel):
GGA: Optional[ComputedStructureEntry] = None
GGA_U: Optional[ComputedStructureEntry] = Field(None, alias="GGA+U")
PBESol: Optional[ComputedStructureEntry] = None
SCAN: Optional[ComputedStructureEntry] = None
R2SCAN: Optional[ComputedStructureEntry] = None
HSE: Optional[ComputedStructureEntry] = None


class MaterialsDoc(CoreMaterialsDoc, StructureMetadata):
calc_types: Mapping[str, CalcType] = Field( # type: ignore
None,
Expand All @@ -34,7 +43,7 @@ class MaterialsDoc(CoreMaterialsDoc, StructureMetadata):
None, description="Mappingionary for tracking the provenance of properties"
)

entries: Optional[Mapping[RunType, ComputedStructureEntry]] = Field(
entries: Optional[BlessedCalcs] = Field(
None, description="Dictionary for tracking entries for VASP calculations"
)

Expand Down
2 changes: 1 addition & 1 deletion emmet-core/tests/vasp/test_materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def test_make_mat(test_tasks):
material = MaterialsDoc.from_tasks(test_tasks)
assert material.formula_pretty == "Si"
assert len(material.task_ids) == 4
assert len(material.entries) == 1
assert len(material.entries.model_dump(exclude_none=True)) == 1

bad_task_group = [
task for task in test_tasks if task.task_type != TaskType.Structure_Optimization
Expand Down

0 comments on commit 1a77a2a

Please sign in to comment.