Skip to content

Commit 1a1d21a

Browse files
committed
update phonon rester to use new fields, maintain backwards compat with warnings
1 parent a82e1b9 commit 1a1d21a

2 files changed

Lines changed: 114 additions & 35 deletions

File tree

mp_api/client/routes/materials/phonon.py

Lines changed: 107 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from __future__ import annotations
22

3+
import warnings
34
from collections import defaultdict
45
from typing import TYPE_CHECKING
56

67
from emmet.core.phonon import PhononBS, PhononBSDOSDoc, PhononDOS
78

8-
from mp_api.client.core import BaseRester, MPRestError
9+
from mp_api.client.core import BaseRester, MPRestError, MPRestWarning
910
from mp_api.client.core.utils import validate_ids
1011

1112
if TYPE_CHECKING:
@@ -17,40 +18,58 @@
1718
class PhononRester(BaseRester):
1819
suffix = "materials/phonon"
1920
document_model = PhononBSDOSDoc # type: ignore
20-
primary_key = "material_id"
21+
primary_key = "identifier"
2122
delta_backed = False
2223

2324
def search(
2425
self,
25-
material_ids: str | list[str] | None = None,
26+
phonon_ids: str | list[str] | None = None,
2627
phonon_method: str | None = None,
2728
num_chunks: int | None = None,
2829
chunk_size: int = 1000,
2930
all_fields: bool = True,
3031
fields: list[str] | None = None,
32+
**kwargs,
3133
) -> list[PhononBSDOSDoc] | list[dict]:
3234
"""Query phonon docs using a variety of search criteria.
3335
3436
Arguments:
35-
material_ids (str, List[str]): A single Material ID string or list of strings
37+
phonon_ids (str, List[str]): A single Phonon Task ID string or list of strings
3638
(e.g., mp-149, [mp-149, mp-13]).
3739
phonon_method (str): phonon method to search (dfpt, phonopy, pheasy)
3840
num_chunks (int): Maximum number of chunks of data to yield. None will yield all possible.
3941
chunk_size (int): Number of data entries per chunk.
4042
all_fields (bool): Whether to return all fields in the document. Defaults to True.
4143
fields (List[str]): List of fields in PhononBSDOSDoc to return data for.
4244
Default is material_id, last_updated, and formula_pretty if all_fields is False.
45+
**kwargs : used for handling deprecated kwargs
4346
4447
Returns:
4548
([PhononBSDOSDoc], [dict]) List of phonon documents or dictionaries.
4649
"""
4750
query_params: dict = defaultdict(dict)
4851

49-
if material_ids:
50-
if isinstance(material_ids, str):
51-
material_ids = [material_ids]
52-
53-
query_params["material_ids"] = ",".join(validate_ids(material_ids))
52+
if "material_ids" in kwargs:
53+
if phonon_ids:
54+
raise MPRestError(
55+
"You have specified both `phonon_ids` and the deprecated `material_ids` tag. "
56+
"Please specify only `phonon_ids`."
57+
)
58+
phonon_ids = kwargs.pop("material_ids")
59+
warnings.warn(
60+
"`material_id` has been replaced by `identifier` in the phonon endpoint. "
61+
"Please migrate to using the newer field name and the more generic `phonon_ids` kwarg "
62+
"for searching.",
63+
stacklevel=2,
64+
category=MPRestWarning,
65+
)
66+
67+
if phonon_ids:
68+
query_params["phonon_ids"] = ",".join(
69+
validate_ids(
70+
[phonon_ids] if isinstance(phonon_ids, str) else phonon_ids
71+
)
72+
)
5473

5574
if phonon_method and phonon_method in {"dfpt", "phonopy", "pheasy"}:
5675
query_params["phonon_method"] = phonon_method
@@ -69,21 +88,21 @@ def search(
6988
**query_params,
7089
)
7190

72-
def get_bandstructure_from_material_id(
73-
self, material_id: str, phonon_method: str
91+
def get_bandstructure_from_phonon_id(
92+
self, phonon_id: str, phonon_method: str
7493
) -> PhononBS | dict[str, Any]:
75-
"""Get the phonon band structure pymatgen object associated with a given material ID and phonon method.
94+
"""Get the phonon band structure pymatgen object associated with a given phonon ID and phonon method.
7695
7796
Arguments:
78-
material_id (str): Material ID for the phonon band structure calculation
97+
phonon_id (str): Phonon ID for the phonon band structure calculation
7998
phonon_method (str): phonon method, i.e. pheasy or dfpt
8099
81100
Returns:
82101
bandstructure (PhononBS): PhononBS object
83102
"""
84103
result = self._query_open_data(
85104
bucket="materialsproject-parsed",
86-
key=f"ph-bandstructures/{phonon_method}/{material_id}.json.gz",
105+
key=f"ph-bandstructures/{phonon_method}/{phonon_id}.json.gz",
87106
)[0][0]
88107

89108
return (
@@ -92,21 +111,33 @@ def get_bandstructure_from_material_id(
92111
else result # type: ignore[return-value]
93112
)
94113

95-
def get_dos_from_material_id(
114+
def get_bandstructure_from_material_id(
96115
self, material_id: str, phonon_method: str
116+
) -> PhononBS | dict[str, Any]:
117+
"""Deprecated: use `get_bandstructure_from_phonon_id` instead."""
118+
warnings.warn(
119+
"`material_id` has been replaced by `identifier` in the phonon endpoint. "
120+
"Please migrate to using `get_bandstructure_from_phonon_id` with the `phonon_id` kwarg.",
121+
stacklevel=2,
122+
category=MPRestWarning,
123+
)
124+
return self.get_bandstructure_from_phonon_id(material_id, phonon_method)
125+
126+
def get_dos_from_phonon_id(
127+
self, phonon_id: str, phonon_method: str
97128
) -> PhononDOS | dict[str, Any]:
98-
"""Get the phonon dos pymatgen object associated with a given material ID and phonon method.
129+
"""Get the phonon dos pymatgen object associated with a given phonon ID and phonon method.
99130
100131
Arguments:
101-
material_id (str): Material ID for the phonon dos calculation
132+
phonon_id (str): Phonon ID for the phonon dos calculation
102133
phonon_method (str): phonon method, i.e. pheasy or dfpt
103134
104135
Returns:
105136
dos (PhononDOS): PhononDOS object
106137
"""
107138
result = self._query_open_data(
108139
bucket="materialsproject-parsed",
109-
key=f"ph-dos/{phonon_method}/{material_id}.json.gz",
140+
key=f"ph-dos/{phonon_method}/{phonon_id}.json.gz",
110141
)[0][0]
111142

112143
return (
@@ -115,41 +146,86 @@ def get_dos_from_material_id(
115146
else result # type: ignore[return-value]
116147
)
117148

118-
def get_forceconstants_from_material_id(
119-
self, material_id: str
120-
) -> list[list[Matrix3D]]:
121-
"""Get the force constants associated with a given material ID.
149+
def get_dos_from_material_id(
150+
self, material_id: str, phonon_method: str
151+
) -> PhononDOS | dict[str, Any]:
152+
"""Deprecated: use `get_dos_from_phonon_id` instead."""
153+
warnings.warn(
154+
"`material_id` has been replaced by `identifier` in the phonon endpoint. "
155+
"Please migrate to using `get_dos_from_phonon_id` with the `phonon_id` kwarg.",
156+
stacklevel=2,
157+
category=MPRestWarning,
158+
)
159+
return self.get_dos_from_phonon_id(material_id, phonon_method)
160+
161+
def get_forceconstants_from_phonon_id(self, phonon_id: str) -> list[list[Matrix3D]]:
162+
"""Get the force constants associated with a given phonon ID.
122163
123164
Arguments:
124-
material_id (str): Material ID for the force constants calculation
165+
phonon_id (str): Phonon ID for the force constants calculation
125166
126167
Returns:
127-
force constants (list[list[Matrix3D]]): PhononDOS object
168+
force constants (list[list[Matrix3D]]): force constants
128169
"""
129170
return self._query_open_data( # type: ignore[return-value]
130171
bucket="materialsproject-parsed",
131-
key=f"ph-force-constants/{material_id}.json.gz",
172+
key=f"ph-force-constants/{phonon_id}.json.gz",
132173
)[0][0]
133174

134-
def compute_thermo_quantities(self, material_id: str, phonon_method: str):
135-
"""Compute thermodynamical quantities for given material ID and phonon_method.
175+
def get_forceconstants_from_material_id(
176+
self, material_id: str
177+
) -> list[list[Matrix3D]]:
178+
"""Deprecated: use `get_forceconstants_from_phonon_id` instead."""
179+
warnings.warn(
180+
"`material_id` has been replaced by `identifier` in the phonon endpoint. "
181+
"Please migrate to using `get_forceconstants_from_phonon_id` with the `phonon_id` kwarg.",
182+
stacklevel=2,
183+
category=MPRestWarning,
184+
)
185+
return self.get_forceconstants_from_phonon_id(material_id)
186+
187+
def compute_thermo_quantities(
188+
self,
189+
phonon_id: str | None = None,
190+
phonon_method: str | None = None,
191+
**kwargs,
192+
):
193+
"""Compute thermodynamical quantities for given phonon ID and phonon_method.
136194
137195
Arguments:
138-
material_id (str): Material ID to calculate quantities for
196+
phonon_id (str): Phonon ID to calculate quantities for
139197
phonon_method (str): phonon method, i.e. pheasy or dfpt
198+
**kwargs : used for handling deprecated kwargs
140199
141200
Returns:
142201
quantities (dict): thermodynamical quantities
143202
"""
203+
if "material_id" in kwargs:
204+
if phonon_id:
205+
raise MPRestError(
206+
"You have specified both `phonon_id` and the deprecated `material_id` tag. "
207+
"Please specify only `phonon_id`."
208+
)
209+
phonon_id = kwargs.pop("material_id")
210+
warnings.warn(
211+
"`material_id` has been replaced by `identifier` in the phonon endpoint. "
212+
"Please migrate to using the newer field name and the more generic `phonon_id` kwarg.",
213+
stacklevel=2,
214+
category=MPRestWarning,
215+
)
216+
217+
if phonon_id is None:
218+
raise MPRestError("`phonon_id` must be specified.")
219+
144220
use_document_model = self.use_document_model
145221
self.use_document_model = False
146-
docs = self.search(material_ids=material_id, phonon_method=phonon_method)
222+
docs = self.search(phonon_ids=phonon_id, phonon_method=phonon_method)
147223
if not docs or not docs[0]:
148224
raise MPRestError("No phonon document found")
149225

150226
self.use_document_model = True
151-
docs[0]["phonon_dos"] = self.get_dos_from_material_id( # type: ignore[index]
152-
material_id, phonon_method
227+
docs[0]["phonon_dos"] = self.get_dos_from_phonon_id( # type: ignore[index]
228+
phonon_id, phonon_method
153229
)
154230
doc = PhononBSDOSDoc(**docs[0]) # type: ignore[arg-type]
155231
self.use_document_model = use_document_model

tests/client/materials/test_phonon.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
import numpy as np
44
import pytest
5-
65
from emmet.core.phonon import PhononBS, PhononDOS
76

87
from mp_api._test_utils import client_search_testing, requires_api_key
9-
108
from mp_api.client.core.exceptions import MPRestError
119
from mp_api.client.routes.materials.phonon import PhononRester
1210

@@ -23,17 +21,22 @@ def test_phonon_search():
2321
"fields",
2422
],
2523
alt_name_dict={
26-
"material_ids": "material_id",
24+
"phonon_ids": "identifier",
2725
},
2826
custom_field_tests={
27+
# test search kwarg backwards compat
2928
"material_ids": ["mp-149", "mp-13"],
30-
"material_ids": "mp-149",
29+
"phonon_ids": ["ft", "mp-13"],
30+
"phonon_ids": "mp-149",
3131
"phonon_method": "dfpt",
3232
},
3333
sub_doc_fields=[],
3434
)
3535

3636

37+
# NOTE: below funcs still query legacy jsonl s3 objects
38+
# they are key by 'mp-123' -> don't change id search strings
39+
# to Alpha version
3740
@requires_api_key
3841
@pytest.mark.parametrize("use_document_model", [True, False])
3942
def test_phonon_get_methods(use_document_model):

0 commit comments

Comments
 (0)