Skip to content

Commit

Permalink
Dielectric, Piezoelectric, Magnetism, Bonds, and Phase Diagrams (#420)
Browse files Browse the repository at this point in the history
* Emmet bump

* Update dielectric, piezoelectric, magnetism

* task_id to material_id in clients

* Fix collection names

* Remove sub doc fields from client tests

* Ignore some endpoints in tests temp

* Temp xfail on endpoints

* Bump emmet

* Add bonds endpoint

* Bump emmet

* Phase diagram endpoint added to thermo

* Temp xfail on thermo pd client method

* Linting

* Alter materials and thermo collection names

* Fix tests

* Linting

* Fix robocrys test

* Update robocrys test

* Update database names

* Fix missing fstrings

* Remove stray print

* Temp xfail on find structure test
  • Loading branch information
munrojm committed Nov 10, 2021
1 parent fcb94a4 commit 113557a
Show file tree
Hide file tree
Showing 34 changed files with 559 additions and 254 deletions.
73 changes: 56 additions & 17 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@
debug = default_settings.DEBUG

materials_store_json = os.environ.get("MATERIALS_STORE", "materials_store.json")
bonds_store_json = os.environ.get("BONDS_STORE", "bonds_store.json")
formula_autocomplete_store_json = os.environ.get(
"FORMULA_AUTOCOMPLETE_STORE", "formula_autocomplete_store.json"
)
task_store_json = os.environ.get("TASK_STORE", "task_store.json")
thermo_store_json = os.environ.get("THERMO_STORE", "thermo_store.json")
dielectric_piezo_store_json = os.environ.get(
"DIELECTRIC_PIEZO_STORE", "dielectric_piezo_store.json"
phase_diagram_store_json = os.environ.get(
"PHASE_DIAGRAM_STORE", "phase_diagram_store.json"
)
dielectric_store_json = os.environ.get("DIELECTRIC_STORE", "dielectric_store.json")
piezoelectric_store_json = os.environ.get(
"PIEZOELECTRIC_STORE", "piezoelectric_store.json"
)
magnetism_store_json = os.environ.get("MAGNETISM_STORE", "magnetism_store.json")
phonon_bs_store_json = os.environ.get("PHONON_BS_STORE", "phonon_bs_store.json")
Expand Down Expand Up @@ -75,7 +80,14 @@
uri=f"mongodb+srv://{db_uri}",
database=f"mp_core_{db_suffix}",
key="material_id",
collection_name=f"materials.core_{db_version}",
collection_name="materials",
)

bonds_store = MongoURIStore(
uri=f"mongodb+srv://{db_uri}",
database=f"mp_core_{db_suffix}",
key="material_id",
collection_name="bonds",
)

formula_autocomplete_store = MongoURIStore(
Expand All @@ -96,20 +108,34 @@
uri=f"mongodb+srv://{db_uri}",
database=f"mp_core_{db_suffix}",
key="material_id",
collection_name=f"thermo_{db_version}",
collection_name="thermo",
)

dielectric_piezo_store = MongoURIStore(
phase_diagram_store = MongoURIStore(
uri=f"mongodb+srv://{db_uri}",
database=f"mp_core_{db_suffix}",
key="task_id",
key="chemsys",
collection_name="phase_diagram",
)

dielectric_store = MongoURIStore(
uri=f"mongodb+srv://{db_uri}",
database=f"mp_core_{db_suffix}",
key="material_id",
collection_name="dielectric",
)

piezoelectric_store = MongoURIStore(
uri=f"mongodb+srv://{db_uri}",
database=f"mp_core_{db_suffix}",
key="material_id",
collection_name="piezoelectric",
)

magnetism_store = MongoURIStore(
uri=f"mongodb+srv://{db_uri}",
database=f"mp_core_{db_suffix}",
key="task_id",
key="material_id",
collection_name="magnetism",
)

Expand Down Expand Up @@ -308,10 +334,13 @@

else:
materials_store = loadfn(materials_store_json)
bonds_store = loadfn(bonds_store_json)
formula_autocomplete_store = loadfn(formula_autocomplete_store_json)
task_store = loadfn(task_store_json)
thermo_store = loadfn(thermo_store_json)
dielectric_piezo_store = loadfn(dielectric_piezo_store_json)
phase_diagram_store = loadfn(phase_diagram_store_json)
dielectric_store = loadfn(dielectric_store_json)
piezoelectric_store = loadfn(piezoelectric_store_json)
magnetism_store = loadfn(magnetism_store_json)
phonon_bs_store = loadfn(phonon_bs_store_json)
eos_store = loadfn(eos_store_json)
Expand Down Expand Up @@ -362,7 +391,10 @@
}
)

# resources.update({"find_structure": find_structure_resource(materials_store)})
# Bonds
from mp_api.routes.bonds.resources import bonds_resource

resources.update({"bonds": [bonds_resource(bonds_store)]})

# Tasks
from mp_api.routes.tasks.resources import (
Expand All @@ -382,25 +414,32 @@
)

# Thermo
from mp_api.routes.thermo.resources import thermo_resource
from mp_api.routes.thermo.resources import phase_diagram_resource, thermo_resource

resources.update({"thermo": [thermo_resource(thermo_store)]})
resources.update(
{
"thermo": [
phase_diagram_resource(phase_diagram_store),
thermo_resource(thermo_store),
]
}
)

# Dielectric
from mp_api.routes.dielectric.resources import dielectric_resource

resources.update({"dielectric": [dielectric_resource(dielectric_piezo_store)]})
resources.update({"dielectric": [dielectric_resource(dielectric_store)]})

# Piezoelectric
from mp_api.routes.piezo.resources import piezo_resource

resources.update({"piezoelectric": [piezo_resource(piezoelectric_store)]})

# Magnetism
from mp_api.routes.magnetism.resources import magnetism_resource

resources.update({"magnetism": [magnetism_resource(magnetism_store)]})

# Piezoelectric
from mp_api.routes.piezo.resources import piezo_resource

resources.update({"piezoelectric": [piezo_resource(dielectric_piezo_store)]})

# Phonon
from mp_api.routes.phonon.resources import phonon_bsdos_resource

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ typing-extensions==3.10.0.2
maggma==0.31.0
requests==2.26.0
monty==2021.8.17
emmet-core==0.15.11
emmet-core==0.15.7
ratelimit==2.2.1
mpcontribs-client>=3.14.3
Empty file.
105 changes: 105 additions & 0 deletions src/mp_api/routes/bonds/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from typing import List, Optional, Tuple
from collections import defaultdict

from mp_api.core.client import BaseRester
from emmet.core.bonds import BondingDoc


class BondsRester(BaseRester[BondingDoc]):

suffix = "bonds"
document_model = BondingDoc # type: ignore
primary_key = "material_id"

def search_bonds_docs(
self,
max_bond_length: Optional[Tuple[float, float]] = None,
min_bond_length: Optional[Tuple[float, float]] = None,
mean_bond_length: Optional[Tuple[float, float]] = None,
coordination_envs: Optional[List[str]] = None,
coordination_envs_anonymous: Optional[List[str]] = None,
sort_field: Optional[str] = None,
ascending: Optional[bool] = None,
num_chunks: Optional[int] = None,
chunk_size: int = 1000,
all_fields: bool = True,
fields: Optional[List[str]] = None,
):
"""
Query dielectric docs using a variety of search criteria.
Arguments:
max_bond_length (Tuple[float,float]): Minimum and maximum value for the maximum bond length
in the structure to consider.
min_bond_length (Tuple[float,float]): Minimum and maximum value for the minimum bond length
in the structure to consider.
mean_bond_length (Tuple[float,float]): Minimum and maximum value for the mean bond length
in the structure to consider.
coordination_envs (List[str]): List of coordination environments to consider (e.g. ['Mo-S(6)', 'S-Mo(3)']).
coordination_envs_anonymous (List[str]): List of anonymous coordination environments to consider
(e.g. ['A-B(6)', 'A-B(3)']).
sort_field (str): Field used to sort results.
ascending (bool): Whether sorting should be in ascending order.
num_chunks (int): Maximum number of chunks of data to yield. None will yield all possible.
chunk_size (int): Number of data entries per chunk.
all_fields (bool): Whether to return all fields in the document. Defaults to True.
fields (List[str]): List of fields in DielectricDoc to return data for.
Default is material_id and last_updated if all_fields is False.
Returns:
([BondingDoc]) List of bonding documents.
"""

query_params = defaultdict(dict) # type: dict

if max_bond_length:
query_params.update(
{
"max_bond_length_min": max_bond_length[0],
"max_bond_length_max": max_bond_length[1],
}
)

if min_bond_length:
query_params.update(
{
"min_bond_length_min": min_bond_length[0],
"min_bond_length_max": min_bond_length[1],
}
)

if mean_bond_length:
query_params.update(
{
"mean_bond_length_min": mean_bond_length[0],
"mean_bond_length_max": mean_bond_length[1],
}
)

if coordination_envs is not None:
query_params.update({"coordination_envs": ",".join(coordination_envs)})

if coordination_envs_anonymous is not None:
query_params.update(
{"coordination_envs_anonymous": ",".join(coordination_envs_anonymous)}
)

if sort_field:
query_params.update({"sort_field": sort_field})

if ascending is not None:
query_params.update({"ascending": ascending})

query_params = {
entry: query_params[entry]
for entry in query_params
if query_params[entry] is not None
}

return super().search(
num_chunks=num_chunks,
chunk_size=chunk_size,
all_fields=all_fields,
fields=fields,
**query_params
)
102 changes: 102 additions & 0 deletions src/mp_api/routes/bonds/query_operators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from typing import Optional
from fastapi import Query
from maggma.api.query_operator import QueryOperator
from maggma.api.utils import STORE_PARAMS

from collections import defaultdict


class BondLengthQuery(QueryOperator):
"""
Method to generate a query on bond length data.
"""

def query(
self,
max_bond_length_max: Optional[float] = Query(
None,
description="Maximum value for the maximum bond length in the structure.",
),
max_bond_length_min: Optional[float] = Query(
None,
description="Minimum value for the maximum bond length in the structure.",
),
min_bond_length_max: Optional[float] = Query(
None,
description="Maximum value for the minimum bond length in the structure.",
),
min_bond_length_min: Optional[float] = Query(
None,
description="Minimum value for the minimum bond length in the structure.",
),
mean_bond_length_max: Optional[float] = Query(
None,
description="Maximum value for the mean bond length in the structure.",
),
mean_bond_length_min: Optional[float] = Query(
None,
description="Minimum value for the mean bond length in the structure.",
),
) -> STORE_PARAMS:

crit = defaultdict(dict) # type: dict

d = {
"bond_length_stats.max": [max_bond_length_min, max_bond_length_max],
"bond_length_stats.min": [min_bond_length_min, min_bond_length_max],
"bond_length_stats.mean": [mean_bond_length_min, mean_bond_length_max],
}

for entry in d:
if d[entry][0] is not None:
crit[entry]["$gte"] = d[entry][0]

if d[entry][1] is not None:
crit[entry]["$lte"] = d[entry][1]

return {"criteria": crit}

def ensure_indexes(self): # pragma: no cover
keys = [
"bond_length_stats.max",
"bond_length_stats.min",
"bond_length_stats.mean",
]
return [(key, False) for key in keys]


class CoordinationEnvsQuery(QueryOperator):
"""
Method to generate a query on coordination environment data.
"""

def query(
self,
coordination_envs: Optional[str] = Query(
None,
description="Query by coordination environments in the material composition as a comma-separated list\
(e.g. 'Mo-S(6),S-Mo(3)')",
),
coordination_envs_anonymous: Optional[str] = Query(
None,
description="Query by anonymous coordination environments in the material composition as a comma-separated\
list (e.g. 'A-B(6),A-B(3)')",
),
) -> STORE_PARAMS:

crit = {} # type: dict

if coordination_envs:
env_list = [env.strip() for env in coordination_envs.split(",")]
crit["coordination_envs"] = {"$all": [str(env) for env in env_list]}

if coordination_envs_anonymous:
env_list = [env.strip() for env in coordination_envs_anonymous.split(",")]
crit["coordination_envs_anonymous"] = {
"$all": [str(env) for env in env_list]
}

return {"criteria": crit}

def ensure_indexes(self): # pragma: no cover
return [("coordination_envs", False), ("coordination_envs_anonymous", False)]
26 changes: 26 additions & 0 deletions src/mp_api/routes/bonds/resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from maggma.api.resource import ReadOnlyResource
from emmet.core.bonds import BondingDoc

from maggma.api.query_operator import PaginationQuery, SortQuery, SparseFieldsQuery

from mp_api.routes.bonds.query_operators import BondLengthQuery, CoordinationEnvsQuery


def bonds_resource(bonds_store):
resource = ReadOnlyResource(
bonds_store,
BondingDoc,
query_operators=[
BondLengthQuery(),
CoordinationEnvsQuery(),
SortQuery(),
PaginationQuery(),
SparseFieldsQuery(
BondingDoc, default_fields=["material_id", "last_updated"],
),
],
tags=["Bonds"],
disable_validation=True,
)

return resource
Loading

0 comments on commit 113557a

Please sign in to comment.