Skip to content
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

Chemsys, electrode, provenance, and robocrys changes #336

Merged
merged 9 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions emmet-api/app.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os

from emmet.api.core.api import MAPI
from emmet import MAPISettings
from emmet.api.core.settings import MAPISettings
from maggma.stores import MongoURIStore, S3Store

resources = {}
Expand Down Expand Up @@ -481,7 +481,7 @@
resources.update({"_general_store": [general_store_resource(general_store)]})

# === MAPI setup
from mp_api.core.documentation import description, tags_meta
from emmet.api.core.documentation import description, tags_meta

api = MAPI(
resources=resources, debug=debug, description=description, tags_meta=tags_meta
Expand Down
16 changes: 12 additions & 4 deletions emmet-api/emmet/api/routes/elasticity/query_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,17 @@ def query(
crit = {} # type: dict

if chemsys:
eles = chemsys.split("-")
chemsys = "-".join(sorted(eles))

crit["chemsys"] = chemsys
chemsys_list = [chemsys_val.strip() for chemsys_val in chemsys.split(",")]

query_vals = []
for chemsys_val in chemsys_list:
eles = chemsys_val.split("-")
sorted_chemsys = "-".join(sorted(eles))
query_vals.append(sorted_chemsys)

if len(query_vals) == 1:
crit["chemsys"] = query_vals[0]
else:
crit["chemsys"] = {"$in": query_vals}

return {"criteria": crit}
84 changes: 76 additions & 8 deletions emmet-api/emmet/api/routes/electrodes/query_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
from fastapi import Query
from maggma.api.query_operator import QueryOperator
from maggma.api.utils import STORE_PARAMS
from emmet.api.routes.materials.utils import formula_to_criteria
from emmet.api.routes.electrodes.utils import (
electrodes_formula_to_criteria,
electrodes_chemsys_to_criteria,
)
from pymatgen.core.periodic_table import Element

from collections import defaultdict
Expand All @@ -24,18 +27,83 @@ def query(
crit = {}

if formula:
crit.update(formula_to_criteria(formula))
crit.update(electrodes_formula_to_criteria(formula))

for key in list(crit):
if "composition_reduced" in key:
framework_entry = "framework.{}".format(key.split(".")[1])
crit[framework_entry] = crit[key]
crit.pop(key)
return {"criteria": crit}

def ensure_indexes(self): # pragma: no cover
return [
("eentries_composition_summary.all_composition_reduced", False),
("entries_composition_summary.all_formulas", False),
]


class ElectrodesChemsysQuery(QueryOperator):
"""
Factory method to generate a dependency for querying by
chemical system with wild cards.
"""

def query(
self,
chemsys: Optional[str] = Query(
None,
description="A comma delimited string list of chemical systems. \
Wildcards for unknown elements only supported for single chemsys queries",
),
) -> STORE_PARAMS:

crit = {}

if chemsys:
crit.update(electrodes_chemsys_to_criteria(chemsys))

return {"criteria": crit}

def ensure_indexes(self): # pragma: no cover
return [("composition_reduced", False)]
keys = [
"entries_composition_summary.all_chemsys",
"entries_composition_summary.all_elements",
"nelements",
]
return [(key, False) for key in keys]


class ElectrodeElementsQuery(QueryOperator):
"""
Factory method to generate a dependency for querying by electrode element data
"""

def query(
self,
elements: Optional[str] = Query(
None,
description="Query by elements in the material composition as a comma-separated list",
),
exclude_elements: Optional[str] = Query(
None,
description="Query by excluded elements in the material composition as a comma-separated list",
),
) -> STORE_PARAMS:

crit = {} # type: dict

if elements or exclude_elements:
crit["entries_composition_summary.all_elements"] = {}

if elements:
element_list = [Element(e) for e in elements.strip().split(",")]
crit["entries_composition_summary.all_elements"]["$all"] = [
str(el) for el in element_list
]

if exclude_elements:
element_list = [Element(e) for e in exclude_elements.strip().split(",")]
crit["entries_composition_summary.all_elements"]["$nin"] = [
str(el) for el in element_list
]

return {"criteria": crit}


class VoltageStepQuery(QueryOperator):
Expand Down
7 changes: 4 additions & 3 deletions emmet-api/emmet/api/routes/electrodes/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
from maggma.api.query_operator import PaginationQuery, SortQuery, SparseFieldsQuery
from emmet.api.routes.electrodes.query_operators import (
ElectrodeFormulaQuery,
ElectrodeElementsQuery,
ElectrodesChemsysQuery,
WorkingIonQuery,
)
from emmet.api.routes.materials.query_operators import ElementsQuery, ChemsysQuery


def insertion_electrodes_resource(insertion_electrodes_store):
Expand All @@ -16,9 +17,9 @@ def insertion_electrodes_resource(insertion_electrodes_store):
InsertionElectrodeDoc,
query_operators=[
ElectrodeFormulaQuery(),
ChemsysQuery(),
ElectrodesChemsysQuery(),
WorkingIonQuery(),
ElementsQuery(),
ElectrodeElementsQuery(),
NumericQuery(model=InsertionElectrodeDoc),
SortQuery(),
PaginationQuery(),
Expand Down
115 changes: 115 additions & 0 deletions emmet-api/emmet/api/routes/electrodes/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from pymatgen.core import Composition
from pymatgen.core.periodic_table import DummySpecies
from typing import Dict
from fastapi import HTTPException


def electrodes_formula_to_criteria(formula: str) -> Dict:
"""
Santizes formula into a dictionary to search with wild cards
over electrodes data

Arguments:
formula: formula with wildcards in it for unknown elements

Returns:
Mongo style search criteria for this formula
"""
dummies = "ADEGJLMQRXZ"

if "*" in formula:
# Wild card in formula
nstars = formula.count("*")

formula_dummies = formula.replace("*", "{}").format(*dummies[:nstars])

integer_formula = Composition(formula_dummies).get_integer_formula_and_factor()[
0
]
comp = Composition(integer_formula).reduced_composition
crit = dict() # type: dict
crit[
"entries_composition_summary.all_formula_anonymous"
] = comp.anonymized_formula

real_elts = [
str(e)
for e in comp.elements
if not e.as_dict().get("element", "A") in dummies
]

for el, n in comp.to_reduced_dict.items():
if el in real_elts:
crit[f"entries_composition_summary.all_composition_reduced.{el}"] = n

return crit

elif any(isinstance(el, DummySpecies) for el in Composition(formula)):
# Assume fully anonymized formula
return {
"entries_composition_summary.all_formula_anonymous": Composition(
formula
).anonymized_formula
}

else:
comp = Composition(formula)
nele = len(comp)
# Paranoia below about floating-point "equality"
crit = {}
crit["nelements"] = {"$in": [nele, nele - 1]} # type: ignore
for el, n in comp.to_reduced_dict.items():
crit[f"entries_composition_summary.all_composition_reduced.{el}"] = n

return crit


def electrodes_chemsys_to_criteria(chemsys: str) -> Dict:
"""
Santizes chemsys into a dictionary to search with wild cards
over electrodes data

Arguments:
chemsys: A comma delimited string list ofchemical systems
with wildcards in it for unknown elements

Returns:
Mongo style search criteria for this formula
"""

crit = {} # type: dict

chemsys_list = [chemsys_val.strip() for chemsys_val in chemsys.split(",")]

if "*" in chemsys:
if len(chemsys_list) > 1:
raise HTTPException(
status_code=400,
detail="Wild cards only supported for single chemsys queries.",
)
else:
eles = chemsys_list[0].split("-")
neles = len(eles)

crit["nelements"] = {"$in": [neles, neles - 1]}
crit["entries_composition_summary.all_elements"] = {
"$all": [ele for ele in eles if ele != "*"]
}

if crit["entries_composition_summary.all_elements"]["$all"] == []:
del crit["entries_composition_summary.all_elements"]

return crit
else:
query_vals = []
for chemsys_val in chemsys_list:
eles = chemsys_val.split("-")
sorted_chemsys = "-".join(sorted(eles))
query_vals.append(sorted_chemsys)

if len(query_vals) == 1:
crit["entries_composition_summary.all_chemsys"] = query_vals[0]
else:
crit["entries_composition_summary.all_chemsys"] = {"$in": query_vals}

return crit
4 changes: 3 additions & 1 deletion emmet-api/emmet/api/routes/materials/query_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ class ChemsysQuery(QueryOperator):
def query(
self,
chemsys: Optional[str] = Query(
None, description="Query by chemsys including wild cards",
None,
description="A comma delimited string list of chemical systems. \
Wildcards for unknown elements only supported for single chemsys queries",
),
) -> STORE_PARAMS:

Expand Down
40 changes: 30 additions & 10 deletions emmet-api/emmet/api/routes/materials/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pymatgen.core import Composition
from pymatgen.core.periodic_table import DummySpecies
from typing import Dict
from fastapi import HTTPException


def formula_to_criteria(formula: str) -> Dict:
Expand Down Expand Up @@ -59,24 +60,43 @@ def chemsys_to_criteria(chemsys: str) -> Dict:
Santizes chemsys into a dictionary to search with wild cards

Arguments:
formula: a chemiscal system with wildcards in it for unknown elements
chemsys: A comma delimited string list of chemical systems
with wildcards in it for unknown elements

Returns:
Mongo style search criteria for this formula
"""

crit = {} # type: dict
eles = chemsys.split("-")

if "*" in eles:
crit["nelements"] = len(eles)
crit["elements"] = {"$all": [ele for ele in eles if ele != "*"]}
chemsys_list = [chemsys_val.strip() for chemsys_val in chemsys.split(",")]

if crit["elements"]["$all"] == []:
del crit["elements"]
if "*" in chemsys:
if len(chemsys_list) > 1:
raise HTTPException(
status_code=400,
detail="Wild cards only supported for single chemsys queries.",
)
else:
eles = chemsys_list[0].split("-")

return crit
crit["nelements"] = len(eles)
crit["elements"] = {"$all": [ele for ele in eles if ele != "*"]}

if crit["elements"]["$all"] == []:
del crit["elements"]

return crit
else:
chemsys = "-".join(sorted(eles))
crit["chemsys"] = chemsys
query_vals = []
for chemsys_val in chemsys_list:
eles = chemsys_val.split("-")
sorted_chemsys = "-".join(sorted(eles))
query_vals.append(sorted_chemsys)

if len(query_vals) == 1:
crit["chemsys"] = query_vals[0]
else:
crit["chemsys"] = {"$in": query_vals}

return crit
11 changes: 8 additions & 3 deletions emmet-api/emmet/api/routes/provenance/resources.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from maggma.api.resource import ReadOnlyResource
from maggma.api.query_operator import PaginationQuery
from maggma.api.query_operator import PaginationQuery, SparseFieldsQuery
from emmet.api.routes.materials.query_operators import DeprecationQuery

from emmet.core.provenance import ProvenanceDoc
Expand All @@ -9,10 +9,15 @@ def provenance_resource(provenance_store):
resource = ReadOnlyResource(
provenance_store,
ProvenanceDoc,
query_operators=[DeprecationQuery(), PaginationQuery()],
query_operators=[
DeprecationQuery(),
PaginationQuery(),
SparseFieldsQuery(
ProvenanceDoc, default_fields=["material_id", "last_updated"]
),
],
tags=["Provenance"],
disable_validation=True,
enable_default_search=False,
)

return resource
Loading