11from __future__ import annotations
22
3+ from pathlib import Path
34from typing import TYPE_CHECKING
45
56from emmet .core .symmetry import CrystalSystem
@@ -172,11 +173,11 @@ def search(
172173
173174 def find_structure (
174175 self ,
175- filename_or_structure ,
176+ filename_or_structure : str | Path | Structure ,
176177 ltol = MAPI_CLIENT_SETTINGS .LTOL ,
177178 stol = MAPI_CLIENT_SETTINGS .STOL ,
178179 angle_tol = MAPI_CLIENT_SETTINGS .ANGLE_TOL ,
179- allow_multiple_results = False ,
180+ allow_multiple_results : bool | int = False ,
180181 ) -> list [str ] | str :
181182 """Finds matching structures from the Materials Project database.
182183
@@ -186,48 +187,75 @@ def find_structure(
186187 default tolerances.
187188
188189 Args:
189- filename_or_structure: filename or Structure object
190+ filename_or_structure: filename as a str or Path, or a Structure object
190191 ltol: fractional length tolerance
191192 stol: site tolerance
192193 angle_tol: angle tolerance in degrees
193- allow_multiple_results: changes return type for either
194- a single material_id or list of material_ids
194+ allow_multiple_results (bool or int): changes return type for either
195+ a single material_id or list of material_ids.
196+ If a bool, returns either all matches (True) or one match at most (False).
197+ If an int, returns that many matches at most.
198+
195199 Returns:
196200 A matching material_id if one is found or list of results if allow_multiple_results
197201 is True
198202 Raises:
199203 MPRestError
200204 """
201- params = {"ltol" : ltol , "stol" : stol , "angle_tol" : angle_tol , "_limit" : 1 }
205+ from pymatgen .analysis .structure_matcher import (
206+ ElementComparator ,
207+ StructureMatcher ,
208+ )
202209
203- if isinstance (filename_or_structure , str ):
210+ if (
211+ isinstance (filename_or_structure , str | Path )
212+ and Path (filename_or_structure ).exists ()
213+ ):
204214 s = Structure .from_file (filename_or_structure )
205215 elif isinstance (filename_or_structure , Structure ):
206216 s = filename_or_structure
207217 else :
208218 raise MPRestError ("Provide filename or Structure object." )
209219
210- results = self ._post_resource (
211- body = s .as_dict (),
212- params = params ,
213- suburl = "find_structure" ,
214- use_document_model = False ,
215- ).get ("data" )
216-
217- if not results :
220+ mat_docs = self .search (
221+ formula = s .reduced_formula , fields = ["material_id" , "structure" ]
222+ )
223+ if not mat_docs :
218224 return []
219225
220- material_ids = validate_ids ([doc ["material_id" ] for doc in results ])
226+ if isinstance (allow_multiple_results , bool ):
227+ max_matches : int = len (mat_docs ) if allow_multiple_results else 1
228+ elif isinstance (allow_multiple_results , int ):
229+ max_matches = allow_multiple_results
230+ else :
231+ raise MPRestError (
232+ f"`allow_multiple_results` must be a bool or int, not { type (allow_multiple_results )} "
233+ )
221234
222- if len (material_ids ) > 1 : # type: ignore
223- if not allow_multiple_results :
224- raise ValueError (
225- "Multiple matches found for this combination of tolerances, but "
226- "`allow_multiple_results` set to False."
227- )
228- return material_ids # type: ignore
235+ matcher = StructureMatcher (
236+ ltol = ltol ,
237+ stol = stol ,
238+ angle_tol = angle_tol ,
239+ primitive_cell = True ,
240+ scale = True ,
241+ attempt_supercell = False ,
242+ comparator = ElementComparator (),
243+ )
229244
230- return material_ids [0 ]
245+ matches : list [str ] = []
246+ for doc in mat_docs :
247+ if matcher .fit (
248+ s ,
249+ doc .structure if self .use_document_model else Structure .from_dict (doc ["structure" ]), # type: ignore
250+ ):
251+ matches .append (doc .material_id .string if self .use_document_model else doc ["material_id" ]) # type: ignore
252+ if len (matches ) >= max_matches :
253+ break
254+
255+ if not matches :
256+ return []
257+ material_ids = validate_ids (matches )
258+ return material_ids if allow_multiple_results else material_ids [0 ]
231259
232260 def get_blessed_entries (
233261 self ,
0 commit comments