Skip to content

Commit

Permalink
Deprecation data added to PropertyDoc (#247)
Browse files Browse the repository at this point in the history
* Deprecated data added to property doc

* kwargs added to relevant model class methods

* Deprecated added to builders

* Fix tests for deprecated data
  • Loading branch information
Jason Munro authored Aug 19, 2021
1 parent eedcf9c commit 380cfc3
Show file tree
Hide file tree
Showing 18 changed files with 116 additions and 195 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def process_item(self, mat):
# Default summary data
d = dict(
material_id=mat[self.materials.key],
deprecated=mat["deprecated"],
task_id=mat["other"]["task_id"],
structure=structure,
band_gap=mat["other"]["band_gap"],
Expand Down Expand Up @@ -205,6 +206,7 @@ def process_item(self, mat):
dos=dos,
is_gap_direct=d["is_gap_direct"],
is_metal=d["is_metal"],
deprecated=d["deprecated"],
**bs,
)
doc = self._bsdos_checks(doc, dos[mat["dos"]["task_id"]], structures)
Expand Down Expand Up @@ -316,6 +318,7 @@ def _update_materials_doc(self, mat_id):
"structure",
"inputs",
"task_types",
"deprecated",
self.materials.last_updated_field,
],
criteria={self.materials.key: mat_id},
Expand Down
5 changes: 3 additions & 2 deletions emmet-builders/emmet/builders/materials/oxidation_states.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ def __init__(
super().__init__(
source=materials,
target=oxidation_states,
projection=["structure"],
projection=["structure", "deprecated"],
**kwargs,
)

def unary_function(self, item):
structure = Structure.from_dict(item["structure"])
mpid = item["material_id"]
deprecated = item["deprecated"]

oxi_doc = OxidationStateDoc.from_structure(
structure=structure, material_id=mpid
structure=structure, material_id=mpid, deprecated=deprecated
)
doc = jsanitize(oxi_doc.dict(), allow_bson=True)

Expand Down
4 changes: 3 additions & 1 deletion emmet-builders/emmet/builders/materials/robocrys.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,19 @@ def __init__(
source=oxidation_states,
target=robocrys,
query=query,
projection=["material_id", "structure"],
projection=["material_id", "structure", "deprecated"],
**kwargs
)

def unary_function(self, item):
structure = Structure.from_dict(item["structure"])
mpid = item["material_id"]
deprecated = item["deprecated"]

doc = RobocrystallogapherDoc.from_structure(
structure=structure,
material_id=mpid,
deprecated=deprecated,
fields=[],
)

Expand Down
5 changes: 4 additions & 1 deletion emmet-builders/emmet/builders/materials/substrates.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,14 @@ def get_items(self):
)
mat = self.materials.query_one(
criteria={self.materials.key: mpid},
properties=["structure", "material_id", "last_updated"],
properties=["structure", "deprecated", "material_id", "last_updated"],
)

yield {
"structure": mat["structure"],
"material_id": mat[self.materials.key],
"elastic_tensor": e_tensor,
"deprecated": mat["deprecated"],
"last_updated": max(
mat.get("last_updated"), e_tensor.get("last_updated")
),
Expand All @@ -111,6 +112,7 @@ def process_item(self, item):
elastic_tensor = (
ElasticTensor.from_voigt(elastic_tensor) if elastic_tensor else None
)
deprecated = item["deprecated"]

self.logger.debug("Calculating substrates for {}".format(item["task_id"]))

Expand All @@ -121,6 +123,7 @@ def process_item(self, item):
material_id=mpid,
structure=film,
elastic_tensor=elastic_tensor,
deprecated=deprecated,
last_updated=item["last_updated"],
)

Expand Down
6 changes: 4 additions & 2 deletions emmet-builders/emmet/builders/vasp/thermo.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def process_item(self, item: List[Dict]):
self.logger.debug(f"{len(pd_entries)} remain in {chemsys} after filtering")

try:
docs = ThermoDoc.from_entries(pd_entries)
docs = ThermoDoc.from_entries(pd_entries, deprecated=False)
for doc in docs:
doc.entries = material_entries[doc.material_id]
doc.entry_types = list(material_entries[doc.material_id].keys())
Expand Down Expand Up @@ -228,7 +228,9 @@ def get_entries(self, chemsys: str) -> List[Dict]:
new_q["chemsys"] = {"$in": list(query_chemsys)}
new_q["deprecated"] = False
materials_docs = list(
self.materials.query(criteria=new_q, properties=["material_id", "entries"])
self.materials.query(
criteria=new_q, properties=["material_id", "entries", "deprecated"]
)
)

# Get Oxidation state data for each material
Expand Down
63 changes: 15 additions & 48 deletions emmet-core/emmet/core/electronic_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,25 +46,19 @@ class ElectronicStructureSummary(ElectronicStructureBaseData):

is_metal: bool = Field(..., description="Whether the material is a metal.")

magnetic_ordering: Union[str, Ordering] = Field(
..., description="Magnetic ordering of the calculation."
)
magnetic_ordering: Union[str, Ordering] = Field(..., description="Magnetic ordering of the calculation.")


class BandStructureSummaryData(ElectronicStructureSummary):
nbands: float = Field(..., description="Number of bands.")

equivalent_labels: Dict = Field(
..., description="Equivalent k-point labels in other k-path conventions."
)
equivalent_labels: Dict = Field(..., description="Equivalent k-point labels in other k-path conventions.")

direct_gap: float = Field(..., description="Direct gap energy in eV.")


class DosSummaryData(ElectronicStructureBaseData):
spin_polarization: float = Field(
None, description="Spin polarization at the fermi level."
)
spin_polarization: float = Field(None, description="Spin polarization at the fermi level.")


class BandstructureData(BaseModel):
Expand All @@ -85,9 +79,7 @@ class BandstructureData(BaseModel):


class DosData(BaseModel):
total: Dict[Union[Spin, str], DosSummaryData] = Field(
None, description="Total DOS summary data."
)
total: Dict[Union[Spin, str], DosSummaryData] = Field(None, description="Total DOS summary data.")

elemental: Dict[
Element,
Expand All @@ -108,9 +100,7 @@ class DosData(BaseModel):
description="Band structure summary data using the Latimer-Munro path convention.",
)

magnetic_ordering: Union[str, Ordering] = Field(
None, description="Magnetic ordering of the calculation."
)
magnetic_ordering: Union[str, Ordering] = Field(None, description="Magnetic ordering of the calculation.")


T = TypeVar("T", bound="ElectronicStructureDoc")
Expand All @@ -121,11 +111,9 @@ class ElectronicStructureDoc(PropertyDoc, ElectronicStructureSummary):
Definition for a core Electronic Structure Document
"""

property_name = "electronc_structure"
property_name = "electronic_structure"

bandstructure: BandstructureData = Field(
None, description="Band structure data for the material."
)
bandstructure: BandstructureData = Field(None, description="Band structure data for the material.")

dos: DosData = Field(None, description="Density of states data for the material.")

Expand All @@ -145,6 +133,7 @@ def from_bsdos( # type: ignore[override]
setyawan_curtarolo: Dict[MPID, BandStructureSymmLine] = None,
hinuma: Dict[MPID, BandStructureSymmLine] = None,
latimer_munro: Dict[MPID, BandStructureSymmLine] = None,
**kwargs
) -> T:
"""
Builds a electronic structure document using band structure and density of states data.
Expand Down Expand Up @@ -276,13 +265,9 @@ def from_bsdos( # type: ignore[override]
bs_task, bs = list(bs_input.items())[0]

if structures is not None and structures[bs_task]:
bs_mag_ordering = CollinearMagneticStructureAnalyzer(
structures[bs_task]
).ordering
bs_mag_ordering = CollinearMagneticStructureAnalyzer(structures[bs_task]).ordering
else:
bs_mag_ordering = CollinearMagneticStructureAnalyzer(
bs.structure
).ordering
bs_mag_ordering = CollinearMagneticStructureAnalyzer(bs.structure).ordering

gap_dict = bs.get_band_gap()
is_metal = bs.is_metal()
Expand Down Expand Up @@ -313,26 +298,11 @@ def from_bsdos( # type: ignore[override]
equivalent_labels = hskp.equiv_labels

if bs_type == "latimer_munro":
gen_labels = set(
[
label
for label in equivalent_labels["latimer_munro"][
"setyawan_curtarolo"
]
]
)
kpath_labels = set(
[
kpoint.label
for kpoint in bs.kpoints
if kpoint.label is not None
]
)
gen_labels = set([label for label in equivalent_labels["latimer_munro"]["setyawan_curtarolo"]])
kpath_labels = set([kpoint.label for kpoint in bs.kpoints if kpoint.label is not None])

if not gen_labels.issubset(kpath_labels):
new_structure = SpacegroupAnalyzer(
bs.structure
).get_primitive_standard_structure(
new_structure = SpacegroupAnalyzer(bs.structure).get_primitive_standard_structure(
international_monoclinic=False
)

Expand Down Expand Up @@ -364,11 +334,7 @@ def from_bsdos( # type: ignore[override]

# Obtain summary data

bs_gap = (
bs_entry.setyawan_curtarolo.band_gap
if bs_entry.setyawan_curtarolo is not None
else None
)
bs_gap = bs_entry.setyawan_curtarolo.band_gap if bs_entry.setyawan_curtarolo is not None else None
dos_cbm, dos_vbm = dos_obj.get_cbm_vbm()
dos_gap = max(dos_cbm - dos_vbm, 0.0)

Expand Down Expand Up @@ -411,4 +377,5 @@ def from_bsdos( # type: ignore[override]
magnetic_ordering=summary_magnetic_ordering,
bandstructure=bs_entry,
dos=dos_entry,
**kwargs
)
28 changes: 15 additions & 13 deletions emmet-core/emmet/core/material_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
from __future__ import annotations

from datetime import datetime
from typing import Sequence, Type, TypeVar
from typing import Sequence, Type, TypeVar, Union, List

from pydantic import Field
from pymatgen.core import Structure

from emmet.core.material import PropertyOrigin
from emmet.core.mpid import MPID
from emmet.core.structure import StructureMetadata
from emmet.core.vasp.validation import DeprecationMessage

S = TypeVar("S", bound="PropertyDoc")

Expand All @@ -28,27 +29,28 @@ class PropertyDoc(StructureMetadata):
"This comes in the form of an MPID or int",
)

deprecated: bool = Field(
...,
description="Whether this property document is deprecated.",
)

reasons: List[Union[DeprecationMessage, str]] = Field(
None, description="List of deprecation tags detailing why this document isn't valid"
)

last_updated: datetime = Field(
description="Timestamp for the most recent calculation update for this property",
default_factory=datetime.utcnow,
)

origins: Sequence[PropertyOrigin] = Field(
[], description="Dictionary for tracking the provenance of properties"
)
origins: Sequence[PropertyOrigin] = Field([], description="Dictionary for tracking the provenance of properties")

warnings: Sequence[str] = Field(
[], description="Any warnings related to this property"
)
warnings: Sequence[str] = Field([], description="Any warnings related to this property")

@classmethod
def from_structure( # type: ignore[override]
cls: Type[S], structure: Structure, material_id: MPID, **kwargs
) -> S:
def from_structure(cls: Type[S], structure: Structure, material_id: MPID, **kwargs) -> S: # type: ignore[override]
"""
Builds a materials document using the minimal amount of information
"""

return super().from_structure( # type: ignore
structure=structure, material_id=material_id, **kwargs
)
return super().from_structure(structure=structure, material_id=material_id, **kwargs) # type: ignore
37 changes: 9 additions & 28 deletions emmet-core/emmet/core/oxidation_states.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,9 @@ class OxidationStateDoc(PropertyDoc):

property_name = "oxidation"

possible_species: List[str] = Field(
description="Possible charged species in this material"
)
possible_valences: List[float] = Field(
description="List of valences for each site in this material"
)
average_oxidation_states: Dict[str, float] = Field(
description="Average oxidation states for each unique species"
)
possible_species: List[str] = Field(description="Possible charged species in this material")
possible_valences: List[float] = Field(description="List of valences for each site in this material")
average_oxidation_states: Dict[str, float] = Field(description="Average oxidation states for each unique species")
method: str = Field(description="Method used to compute oxidation states")

@classmethod
Expand All @@ -36,8 +30,7 @@ def from_structure(cls, structure: Structure, material_id: MPID, **kwargs): # t
bva = BVAnalyzer()
valences = bva.get_valences(structure)
possible_species = {
str(Specie(structure[idx].specie, oxidation_state=valence))
for idx, valence in enumerate(valences)
str(Specie(structure[idx].specie, oxidation_state=valence)) for idx, valence in enumerate(valences)
}

structure.add_oxidation_state_by_site(valences)
Expand All @@ -51,10 +44,7 @@ def from_structure(cls, structure: Structure, material_id: MPID, **kwargs): # t
for site in structure:
site_oxidation_list[site.specie.element].append(site.specie.oxi_state)

oxi_state_dict = {
str(el): np.mean(oxi_states)
for el, oxi_states in site_oxidation_list.items()
}
oxi_state_dict = {str(el): np.mean(oxi_states) for el, oxi_states in site_oxidation_list.items()}

d = {
"possible_species": list(possible_species),
Expand All @@ -67,15 +57,10 @@ def from_structure(cls, structure: Structure, material_id: MPID, **kwargs): # t
logging.error("BVAnalyzer failed with: {}".format(e))

try:
first_oxi_state_guess = structure.composition.oxi_state_guesses(
max_sites=-50
)[0]
valences = [
first_oxi_state_guess[site.species_string] for site in structure
]
first_oxi_state_guess = structure.composition.oxi_state_guesses(max_sites=-50)[0]
valences = [first_oxi_state_guess[site.species_string] for site in structure]
possible_species = {
str(Specie(el, oxidation_state=valence))
for el, valence in first_oxi_state_guess.items()
str(Specie(el, oxidation_state=valence)) for el, valence in first_oxi_state_guess.items()
}

structure.add_oxidation_state_by_site(valences)
Expand All @@ -92,9 +77,5 @@ def from_structure(cls, structure: Structure, material_id: MPID, **kwargs): # t
raise e

return super().from_structure(
structure=structure,
material_id=material_id,
include_structure=True,
**d,
**kwargs
structure=structure, material_id=material_id, include_structure=True, **d, **kwargs
)
Loading

0 comments on commit 380cfc3

Please sign in to comment.