emmet-builders 0.78.3__py3-none-any.whl → 0.86.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. emmet/builders/abinit/phonon.py +47 -47
  2. emmet/builders/abinit/sound_velocity.py +15 -11
  3. emmet/builders/feff/xas.py +1 -2
  4. emmet/builders/materials/absorption_spectrum.py +25 -14
  5. emmet/builders/materials/alloys.py +10 -11
  6. emmet/builders/materials/chemenv.py +2 -3
  7. emmet/builders/materials/corrected_entries.py +21 -15
  8. emmet/builders/materials/dielectric.py +19 -11
  9. emmet/builders/materials/elasticity.py +44 -33
  10. emmet/builders/materials/electrodes.py +35 -28
  11. emmet/builders/materials/electronic_structure.py +17 -17
  12. emmet/builders/materials/magnetism.py +11 -4
  13. emmet/builders/materials/optimade.py +7 -3
  14. emmet/builders/materials/piezoelectric.py +24 -21
  15. emmet/builders/materials/provenance.py +16 -13
  16. emmet/builders/materials/robocrys.py +2 -3
  17. emmet/builders/materials/substrates.py +9 -8
  18. emmet/builders/materials/summary.py +3 -3
  19. emmet/builders/materials/thermo.py +17 -11
  20. emmet/builders/matscholar/missing_compositions.py +12 -8
  21. emmet/builders/mobility/migration_graph.py +5 -5
  22. emmet/builders/settings.py +21 -17
  23. emmet/builders/utils.py +101 -12
  24. emmet/builders/vasp/materials.py +40 -51
  25. emmet/builders/vasp/mp_potcar_stats.json.gz +0 -0
  26. emmet/builders/vasp/task_validator.py +25 -36
  27. emmet_builders-0.86.0.dist-info/METADATA +37 -0
  28. emmet_builders-0.86.0.dist-info/RECORD +41 -0
  29. {emmet_builders-0.78.3.dist-info → emmet_builders-0.86.0.dist-info}/WHEEL +1 -1
  30. emmet/builders/materials/ml.py +0 -87
  31. emmet/builders/molecules/atomic.py +0 -589
  32. emmet/builders/molecules/bonds.py +0 -324
  33. emmet/builders/molecules/metal_binding.py +0 -526
  34. emmet/builders/molecules/orbitals.py +0 -288
  35. emmet/builders/molecules/redox.py +0 -496
  36. emmet/builders/molecules/summary.py +0 -383
  37. emmet/builders/molecules/thermo.py +0 -500
  38. emmet/builders/molecules/vibration.py +0 -278
  39. emmet/builders/qchem/__init__.py +0 -0
  40. emmet/builders/qchem/molecules.py +0 -734
  41. emmet_builders-0.78.3.dist-info/METADATA +0 -47
  42. emmet_builders-0.78.3.dist-info/RECORD +0 -51
  43. /emmet/builders/{molecules/__init__.py → py.typed} +0 -0
  44. {emmet_builders-0.78.3.dist-info → emmet_builders-0.86.0.dist-info}/top_level.txt +0 -0
@@ -17,8 +17,9 @@ The build proceeds in the below steps:
17
17
  7. Fit the elastic tensor.
18
18
  """
19
19
 
20
+ from __future__ import annotations
21
+
20
22
  from datetime import datetime
21
- from typing import Any, Dict, Generator, List, Optional, Tuple, Union
22
23
 
23
24
  import numpy as np
24
25
  from maggma.core import Builder, Store
@@ -29,10 +30,18 @@ from pymatgen.core import Structure
29
30
  from pymatgen.core.tensors import TensorMapping
30
31
 
31
32
  from emmet.core.elasticity import ElasticityDoc
32
- from emmet.core.mpid import MPID
33
+ from emmet.core.mpid import AlphaID
33
34
  from emmet.core.utils import jsanitize
34
35
  from emmet.core.vasp.calc_types import CalcType
35
36
 
37
+ from typing import TYPE_CHECKING
38
+
39
+ if TYPE_CHECKING:
40
+ from collections.abc import Generator
41
+ from typing import Any
42
+
43
+ from emmet.core.types.typing import IdentifierType
44
+
36
45
 
37
46
  class ElasticityBuilder(Builder):
38
47
  def __init__(
@@ -40,7 +49,7 @@ class ElasticityBuilder(Builder):
40
49
  tasks: Store,
41
50
  materials: Store,
42
51
  elasticity: Store,
43
- query: Optional[Dict] = None,
52
+ query: dict | None = None,
44
53
  fitting_method: str = "finite_difference",
45
54
  **kwargs,
46
55
  ):
@@ -78,7 +87,7 @@ class ElasticityBuilder(Builder):
78
87
 
79
88
  def get_items(
80
89
  self,
81
- ) -> Generator[Tuple[str, Dict[str, str], List[Dict]], None, None]:
90
+ ) -> Generator[tuple[str, dict[str, str], list[dict]], None, None]:
82
91
  """
83
92
  Gets all items to process into elasticity docs.
84
93
 
@@ -129,8 +138,8 @@ class ElasticityBuilder(Builder):
129
138
  yield material_id, calc_types, tasks
130
139
 
131
140
  def process_item(
132
- self, item: Tuple[MPID, Dict[str, str], List[Dict]]
133
- ) -> Union[Dict, None]:
141
+ self, item: tuple[IdentifierType, dict[str, str], list[dict]]
142
+ ) -> dict | None:
134
143
  """
135
144
  Process all tasks belong to the same material into an elasticity doc.
136
145
 
@@ -191,7 +200,7 @@ class ElasticityBuilder(Builder):
191
200
 
192
201
  # convert to elasticity doc
193
202
  deforms = []
194
- stresses = []
203
+ stresses: list[Stress] = [] # TODO: mypy misfires on `Stress`
195
204
  deform_task_ids = []
196
205
  deform_dir_names = []
197
206
  for doc in final_deform:
@@ -200,7 +209,7 @@ class ElasticityBuilder(Builder):
200
209
  )
201
210
  # 0.1 to convert to GPa from kBar, and the minus sign to flip the stress
202
211
  # direction from compressive as positive (in vasp) to tensile as positive
203
- stresses.append(-0.1 * Stress(doc["output"]["stress"]))
212
+ stresses.append(-0.1 * Stress(doc["output"]["stress"])) # type: ignore[arg-type]
204
213
  deform_task_ids.append(doc["task_id"])
205
214
  deform_dir_names.append(doc["dir_name"])
206
215
 
@@ -208,10 +217,10 @@ class ElasticityBuilder(Builder):
208
217
  structure=Structure.from_dict(final_opt["output"]["structure"]),
209
218
  material_id=material_id,
210
219
  deformations=deforms,
211
- stresses=stresses,
220
+ stresses=stresses, # type: ignore[arg-type]
212
221
  deformation_task_ids=deform_task_ids,
213
222
  deformation_dir_names=deform_dir_names,
214
- equilibrium_stress=-0.1 * Stress(final_opt["output"]["stress"]),
223
+ equilibrium_stress=-0.1 * Stress(final_opt["output"]["stress"]), # type: ignore[arg-type]
215
224
  optimization_task_id=final_opt["task_id"],
216
225
  optimization_dir_name=final_opt["dir_name"],
217
226
  fitting_method="finite_difference",
@@ -220,7 +229,7 @@ class ElasticityBuilder(Builder):
220
229
 
221
230
  return elasticity_doc
222
231
 
223
- def update_targets(self, items: List[Dict]):
232
+ def update_targets(self, items: list[dict]):
224
233
  """
225
234
  Insert the new elasticity docs into the elasticity collection.
226
235
 
@@ -233,24 +242,26 @@ class ElasticityBuilder(Builder):
233
242
 
234
243
 
235
244
  def filter_opt_tasks(
236
- tasks: List[Dict],
237
- calc_types: Dict[str, str],
238
- target_calc_type: str = CalcType.GGA_Structure_Optimization,
239
- ) -> List[Dict]:
245
+ tasks: list[dict],
246
+ calc_types: dict[str, str],
247
+ target_calc_type: str | CalcType = CalcType.GGA_Structure_Optimization,
248
+ ) -> list[dict]:
240
249
  """
241
250
  Filter optimization tasks, by
242
251
  - calculation type
243
252
  """
244
- opt_tasks = [t for t in tasks if calc_types[str(t["task_id"])] == target_calc_type]
253
+ opt_tasks = [
254
+ t for t in tasks if calc_types[str(AlphaID(t["task_id"]))] == target_calc_type
255
+ ]
245
256
 
246
257
  return opt_tasks
247
258
 
248
259
 
249
260
  def filter_deform_tasks(
250
- tasks: List[Dict],
251
- calc_types: Dict[str, str],
252
- target_calc_type: str = CalcType.GGA_Deformation,
253
- ) -> List[Dict]:
261
+ tasks: list[dict],
262
+ calc_types: dict[str, str],
263
+ target_calc_type: str | CalcType = CalcType.GGA_Deformation,
264
+ ) -> list[dict]:
254
265
  """
255
266
  Filter deformation tasks, by
256
267
  - calculation type
@@ -271,8 +282,8 @@ def filter_deform_tasks(
271
282
 
272
283
 
273
284
  def filter_by_incar_settings(
274
- tasks: List[Dict], incar_settings: Optional[Dict[str, Any]] = None
275
- ) -> List[Dict]:
285
+ tasks: list[dict], incar_settings: dict[str, Any] | None = None
286
+ ) -> list[dict]:
276
287
  """
277
288
  Filter tasks by incar parameters.
278
289
  """
@@ -315,7 +326,7 @@ def filter_by_incar_settings(
315
326
  return selected
316
327
 
317
328
 
318
- def filter_opt_tasks_by_time(tasks: List[Dict], logger) -> Dict:
329
+ def filter_opt_tasks_by_time(tasks: list[dict], logger) -> dict:
319
330
  """
320
331
  Filter a set of tasks to select the latest completed one.
321
332
 
@@ -330,8 +341,8 @@ def filter_opt_tasks_by_time(tasks: List[Dict], logger) -> Dict:
330
341
 
331
342
 
332
343
  def filter_deform_tasks_by_time(
333
- tasks: List[Dict], deform_comp_tol: float = 1e-5, logger=None
334
- ) -> List[Dict]:
344
+ tasks: list[dict], deform_comp_tol: float = 1e-5, logger=None
345
+ ) -> list[dict]:
335
346
  """
336
347
  For deformation tasks with the same deformation, select the latest completed one.
337
348
 
@@ -364,7 +375,7 @@ def filter_deform_tasks_by_time(
364
375
  return selected
365
376
 
366
377
 
367
- def _filter_tasks_by_time(tasks: List[Dict], mode: str, logger) -> Dict:
378
+ def _filter_tasks_by_time(tasks: list[dict], mode: str, logger) -> dict:
368
379
  """
369
380
  Helper function to filter a set of tasks to select the latest completed one.
370
381
  """
@@ -388,11 +399,11 @@ def _filter_tasks_by_time(tasks: List[Dict], mode: str, logger) -> Dict:
388
399
 
389
400
 
390
401
  def select_final_opt_deform_tasks(
391
- opt_tasks: List[Tuple[np.ndarray, Dict]],
392
- deform_tasks: List[Tuple[np.ndarray, List[Dict]]],
402
+ opt_tasks: list[tuple[np.ndarray, dict]],
403
+ deform_tasks: list[tuple[np.ndarray, list[dict]]],
393
404
  logger,
394
405
  lattice_comp_tol: float = 1e-5,
395
- ) -> Tuple[Union[Dict, None], Union[List[Dict], None]]:
406
+ ) -> tuple[dict | None, list[dict] | None]:
396
407
  """
397
408
  Select the final opt task and deform tasks for fitting.
398
409
 
@@ -445,8 +456,8 @@ def select_final_opt_deform_tasks(
445
456
 
446
457
 
447
458
  def group_by_parent_lattice(
448
- tasks: List[Dict], mode: str, lattice_comp_tol: float = 1e-5
449
- ) -> List[Tuple[np.ndarray, List[Dict]]]:
459
+ tasks: list[dict], mode: str, lattice_comp_tol: float = 1e-5
460
+ ) -> list[tuple[np.ndarray, list[dict]]]:
450
461
  """
451
462
  Groups a set of task docs by parent lattice equivalence.
452
463
 
@@ -459,11 +470,11 @@ def group_by_parent_lattice(
459
470
  lattice_comp_tol: tolerance for comparing lattice equivalence.
460
471
 
461
472
  Returns:
462
- [(lattice, List[tasks])]: each tuple gives the common parent lattice of a
473
+ [(lattice, list[tasks])]: each tuple gives the common parent lattice of a
463
474
  list of the structures before deformation (if any), and the list tasks
464
475
  from which the structures are taken.
465
476
  """
466
- docs_by_lattice: List[Tuple[np.ndarray, List[Dict]]] = []
477
+ docs_by_lattice: list[tuple[np.ndarray, list[dict]]] = []
467
478
 
468
479
  for doc in tasks:
469
480
  sim_lattice = get(doc, "output.structure.lattice.matrix")
@@ -1,22 +1,27 @@
1
1
  import operator
2
+ from collections import defaultdict
2
3
  from datetime import datetime
3
4
  from functools import lru_cache
4
5
  from itertools import chain
5
6
  from math import ceil
6
- from typing import Any, Iterator, Dict, List, Optional
7
- from collections import defaultdict
8
7
 
9
8
  from maggma.builders import Builder
10
9
  from maggma.stores import MongoStore
11
10
  from maggma.utils import grouper
12
- from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry
11
+ from pymatgen.analysis.phase_diagram import Composition, PhaseDiagram
13
12
  from pymatgen.entries.compatibility import MaterialsProject2020Compatibility
14
- from pymatgen.analysis.phase_diagram import PhaseDiagram, Composition
13
+ from pymatgen.entries.computed_entries import ComputedEntry, ComputedStructureEntry
15
14
 
16
- from emmet.core.electrode import InsertionElectrodeDoc, ConversionElectrodeDoc
15
+ from emmet.builders.settings import EmmetBuildSettings
16
+ from emmet.core.electrode import ConversionElectrodeDoc, InsertionElectrodeDoc
17
17
  from emmet.core.structure_group import StructureGroupDoc, _get_id_lexi
18
18
  from emmet.core.utils import jsanitize
19
- from emmet.builders.settings import EmmetBuildSettings
19
+
20
+ from typing import TYPE_CHECKING
21
+
22
+ if TYPE_CHECKING:
23
+ from typing import Any
24
+ from collections.abc import Iterator
20
25
 
21
26
 
22
27
  def s_hash(el):
@@ -85,7 +90,7 @@ class StructureGroupBuilder(Builder):
85
90
  materials: MongoStore,
86
91
  sgroups: MongoStore,
87
92
  working_ion: str,
88
- query: Optional[dict] = None,
93
+ query: dict | None = None,
89
94
  ltol: float = default_build_settings.LTOL,
90
95
  stol: float = default_build_settings.STOL,
91
96
  angle_tol: float = default_build_settings.ANGLE_TOL,
@@ -115,15 +120,15 @@ class StructureGroupBuilder(Builder):
115
120
  self.check_newer = check_newer
116
121
  self.chunk_size = chunk_size
117
122
 
118
- self.query[
119
- "deprecated"
120
- ] = False # Ensure only non-deprecated materials are chosen
123
+ self.query["deprecated"] = (
124
+ False # Ensure only non-deprecated materials are chosen
125
+ )
121
126
 
122
127
  super().__init__(
123
128
  sources=[materials], targets=[sgroups], chunk_size=chunk_size, **kwargs
124
129
  )
125
130
 
126
- def prechunk(self, number_splits: int) -> Iterator[Dict]: # pragma: no cover
131
+ def prechunk(self, number_splits: int) -> Iterator[dict]: # pragma: no cover
127
132
  """
128
133
  Prechunk method to perform chunking by the key field
129
134
  """
@@ -268,7 +273,7 @@ class StructureGroupBuilder(Builder):
268
273
  else:
269
274
  yield {"chemsys": chemsys, "materials": all_mats_in_chemsys}
270
275
 
271
- def update_targets(self, items: List):
276
+ def update_targets(self, items: list):
272
277
  items = list(filter(None, chain.from_iterable(items)))
273
278
  if len(items) > 0:
274
279
  self.logger.info("Updating {} sgroups documents".format(len(items)))
@@ -319,7 +324,7 @@ class InsertionElectrodeBuilder(Builder):
319
324
  grouped_materials: MongoStore,
320
325
  thermo: MongoStore,
321
326
  insertion_electrode: MongoStore,
322
- query: Optional[Dict] = None,
327
+ query: dict | None = None,
323
328
  strip_structures: bool = False,
324
329
  **kwargs,
325
330
  ):
@@ -335,7 +340,7 @@ class InsertionElectrodeBuilder(Builder):
335
340
  **kwargs,
336
341
  )
337
342
 
338
- def prechunk(self, number_splits: int) -> Iterator[Dict]:
343
+ def prechunk(self, number_splits: int) -> Iterator[dict]:
339
344
  """
340
345
  Prechunk method to perform chunking by the key field
341
346
  """
@@ -418,7 +423,7 @@ class InsertionElectrodeBuilder(Builder):
418
423
  else:
419
424
  yield None
420
425
 
421
- def process_item(self, item) -> Dict:
426
+ def process_item(self, item) -> dict:
422
427
  """
423
428
  - Add volume information to each entry to create the insertion electrode document
424
429
  - Add the host structure
@@ -460,14 +465,14 @@ class InsertionElectrodeBuilder(Builder):
460
465
  # {"failed_reason": "unable to create InsertionElectrode document"}
461
466
  return jsanitize(ie.model_dump())
462
467
 
463
- def update_targets(self, items: List):
468
+ def update_targets(self, items: list):
464
469
  items = list(filter(None, items))
465
470
  if len(items) > 0:
466
471
  self.logger.info("Updating {} battery documents".format(len(items)))
467
472
  for struct_group_dict in items:
468
- struct_group_dict[
469
- self.grouped_materials.last_updated_field
470
- ] = datetime.utcnow()
473
+ struct_group_dict[self.grouped_materials.last_updated_field] = (
474
+ datetime.utcnow()
475
+ )
471
476
  self.insertion_electrode.update(docs=items, key=["battery_id"])
472
477
  else:
473
478
  self.logger.info("No items to update")
@@ -480,7 +485,7 @@ class ConversionElectrodeBuilder(Builder):
480
485
  conversion_electrode_store: MongoStore,
481
486
  working_ion: str,
482
487
  thermo_type: str,
483
- query: Optional[dict] = None,
488
+ query: dict | None = None,
484
489
  **kwargs,
485
490
  ):
486
491
  self.phase_diagram_store = phase_diagram_store
@@ -499,7 +504,7 @@ class ConversionElectrodeBuilder(Builder):
499
504
  **kwargs,
500
505
  )
501
506
 
502
- def prechunk(self, number_splits: int) -> Iterator[Dict]:
507
+ def prechunk(self, number_splits: int) -> Iterator[dict]:
503
508
  """
504
509
  Prechunk method to perform chunking by the key field
505
510
  """
@@ -532,7 +537,7 @@ class ConversionElectrodeBuilder(Builder):
532
537
  for phase_diagram_doc in self.phase_diagram_store.query(criteria=q):
533
538
  yield phase_diagram_doc
534
539
 
535
- def process_item(self, item) -> Dict:
540
+ def process_item(self, item) -> dict:
536
541
  """
537
542
  - For each phase diagram doc, find all possible conversion electrodes and create conversion electrode docs
538
543
  """
@@ -564,14 +569,16 @@ class ConversionElectrodeBuilder(Builder):
564
569
  # Get lowest material_id with matching composition
565
570
  material_ids = [
566
571
  (
567
- lambda x: x.data["material_id"]
568
- if x.composition.reduced_formula == v[1].reduced_formula
569
- else None
572
+ lambda x: (
573
+ x.data["material_id"] # type: ignore[attr-defined]
574
+ if x.composition.reduced_formula == v[1].reduced_formula
575
+ else None
576
+ )
570
577
  )(e)
571
578
  for e in pd.entries
572
579
  ]
573
580
  material_ids = list(filter(None, material_ids))
574
- lowest_id = min(material_ids, key=_get_id_lexi)
581
+ lowest_id = min(material_ids, key=_get_id_lexi) # type: ignore[arg-type]
575
582
  conversion_electrode_doc = (
576
583
  ConversionElectrodeDoc.from_composition_and_pd(
577
584
  comp=v[1],
@@ -597,7 +604,7 @@ class ConversionElectrodeBuilder(Builder):
597
604
  relevant_entry_data = []
598
605
  for e in pd.entries:
599
606
  if e.composition == Composition(c):
600
- relevant_entry_data.append((e.energy_per_atom, e.entry_id))
607
+ relevant_entry_data.append((e.energy_per_atom, e.entry_id)) # type: ignore[attr-defined]
601
608
  relevant_entry_data.sort(key=lambda x: x[0])
602
609
  entry_id_mapping[c] = relevant_entry_data[0][1]
603
610
 
@@ -609,7 +616,7 @@ class ConversionElectrodeBuilder(Builder):
609
616
 
610
617
  return new_docs # type: ignore
611
618
 
612
- def update_targets(self, items: List):
619
+ def update_targets(self, items: list):
613
620
  combined_items = []
614
621
  for _items in items:
615
622
  _items = list(filter(None, _items))
@@ -1,29 +1,29 @@
1
- from collections import defaultdict
2
- from math import ceil
3
1
  import itertools
4
2
  import re
3
+ from collections import defaultdict
4
+ from math import ceil
5
+
5
6
  import boto3
6
7
  import numpy as np
7
8
  from botocore.handlers import disable_signing
8
9
  from maggma.builders import Builder
9
10
  from maggma.utils import grouper
10
11
  from pymatgen.analysis.magnetism.analyzer import CollinearMagneticStructureAnalyzer
12
+ from pymatgen.analysis.structure_matcher import StructureMatcher
11
13
  from pymatgen.core import Structure
12
- from pymatgen.electronic_structure.core import Spin
13
14
  from pymatgen.electronic_structure.bandstructure import BandStructureSymmLine
15
+ from pymatgen.electronic_structure.core import Spin
14
16
  from pymatgen.electronic_structure.dos import CompleteDos
15
- from pymatgen.symmetry.bandstructure import HighSymmKpath
16
- from pymatgen.analysis.structure_matcher import StructureMatcher
17
- from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
18
17
  from pymatgen.io.vasp.sets import MPStaticSet
18
+ from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
19
+ from pymatgen.symmetry.bandstructure import HighSymmKpath
19
20
 
20
- from emmet.core.settings import EmmetSettings
21
+ from emmet.builders.utils import query_open_data
21
22
  from emmet.core.electronic_structure import ElectronicStructureDoc
23
+ from emmet.core.settings import EmmetSettings
22
24
  from emmet.core.utils import jsanitize
23
25
 
24
- from emmet.builders.utils import query_open_data
25
-
26
- SETTINGS = EmmetSettings()
26
+ SETTINGS = EmmetSettings() # type: ignore[call-arg]
27
27
 
28
28
 
29
29
  class ElectronicStructureBuilder(Builder):
@@ -297,7 +297,7 @@ class ElectronicStructureBuilder(Builder):
297
297
  Inserts electronic structure documents into the electronic_structure collection
298
298
 
299
299
  Args:
300
- items ([Dict]): A list of ElectronicStructureDoc dictionaries to update
300
+ items ([dict]): A list of ElectronicStructureDoc dictionaries to update
301
301
  """
302
302
 
303
303
  items = list(filter(None, items))
@@ -577,9 +577,9 @@ class ElectronicStructureBuilder(Builder):
577
577
 
578
578
  other_calcs.append(
579
579
  {
580
- "is_static": True
581
- if "Static" in mat["task_types"][task_id]
582
- else False,
580
+ "is_static": (
581
+ True if "Static" in mat["task_types"][task_id] else False
582
+ ),
583
583
  "task_id": task_id,
584
584
  "is_hubbard": int(is_hubbard),
585
585
  "nkpoints": int(nkpoints),
@@ -640,9 +640,9 @@ class ElectronicStructureBuilder(Builder):
640
640
  bs_obj["data"] if bs_obj is not None else None
641
641
  )
642
642
 
643
- materials_doc["bandstructure"][bs_type][
644
- "output_structure"
645
- ] = sorted_bs_data[0]["output_structure"]
643
+ materials_doc["bandstructure"][bs_type]["output_structure"] = (
644
+ sorted_bs_data[0]["output_structure"]
645
+ )
646
646
 
647
647
  materials_doc["origins"].append(
648
648
  {
@@ -1,5 +1,6 @@
1
+ from __future__ import annotations
2
+
1
3
  from math import ceil
2
- from typing import Dict, Iterator, Optional
3
4
 
4
5
  from maggma.builders import Builder
5
6
  from maggma.stores import Store
@@ -7,8 +8,14 @@ from maggma.utils import grouper
7
8
  from pymatgen.core.structure import Structure
8
9
 
9
10
  from emmet.core.magnetism import MagnetismDoc
11
+ from emmet.core.mpid import AlphaID
10
12
  from emmet.core.utils import jsanitize
11
13
 
14
+ from typing import TYPE_CHECKING
15
+
16
+ if TYPE_CHECKING:
17
+ from collections.abc import Iterator
18
+
12
19
  __author__ = "Shyam Dwaraknath <shyamd@lbl.gov>, Matthew Horton <mkhorton@lbl.gov>"
13
20
 
14
21
 
@@ -18,7 +25,7 @@ class MagneticBuilder(Builder):
18
25
  materials: Store,
19
26
  magnetism: Store,
20
27
  tasks: Store,
21
- query: Optional[Dict] = None,
28
+ query: dict | None = None,
22
29
  **kwargs,
23
30
  ):
24
31
  """
@@ -42,7 +49,7 @@ class MagneticBuilder(Builder):
42
49
 
43
50
  super().__init__(sources=[materials, tasks], targets=[magnetism], **kwargs)
44
51
 
45
- def prechunk(self, number_splits: int) -> Iterator[Dict]: # pragma: no cover
52
+ def prechunk(self, number_splits: int) -> Iterator[dict]: # pragma: no cover
46
53
  """
47
54
  Prechunk method to perform chunking by the key field
48
55
  """
@@ -131,7 +138,7 @@ class MagneticBuilder(Builder):
131
138
 
132
139
  for origin in mat_doc["origins"]:
133
140
  if origin["name"] == "structure":
134
- task_id = origin["task_id"]
141
+ task_id = str(AlphaID(origin["task_id"]))
135
142
 
136
143
  task_query = self.tasks.query_one(
137
144
  properties=["last_updated", "calcs_reversed"],
@@ -1,5 +1,4 @@
1
1
  from math import ceil
2
- from typing import Dict, Iterator, Optional
3
2
 
4
3
  from maggma.builders import Builder
5
4
  from maggma.core import Store
@@ -9,6 +8,11 @@ from pymatgen.core.structure import Structure
9
8
  from emmet.core.optimade import OptimadeMaterialsDoc
10
9
  from emmet.core.utils import jsanitize
11
10
 
11
+ from typing import TYPE_CHECKING
12
+
13
+ if TYPE_CHECKING:
14
+ from collections.abc import Iterator
15
+
12
16
 
13
17
  class OptimadeMaterialsBuilder(Builder):
14
18
  def __init__(
@@ -16,7 +20,7 @@ class OptimadeMaterialsBuilder(Builder):
16
20
  materials: Store,
17
21
  thermo: Store,
18
22
  optimade: Store,
19
- query: Optional[Dict] = None,
23
+ query: dict | None = None,
20
24
  **kwargs,
21
25
  ):
22
26
  """
@@ -42,7 +46,7 @@ class OptimadeMaterialsBuilder(Builder):
42
46
 
43
47
  super().__init__(sources=[materials, thermo], targets=optimade, **kwargs)
44
48
 
45
- def prechunk(self, number_splits: int) -> Iterator[Dict]: # pragma: no cover
49
+ def prechunk(self, number_splits: int) -> Iterator[dict]: # pragma: no cover
46
50
  """
47
51
  Prechunk method to perform chunking by the key field
48
52
  """
@@ -1,5 +1,4 @@
1
1
  from math import ceil
2
- from typing import Dict, Optional
3
2
 
4
3
  import numpy as np
5
4
  from maggma.builders import Builder
@@ -8,6 +7,7 @@ from maggma.utils import grouper
8
7
  from pymatgen.core.structure import Structure
9
8
 
10
9
  from emmet.core.polar import PiezoelectricDoc
10
+ from emmet.core.mpid import AlphaID
11
11
  from emmet.core.utils import jsanitize
12
12
 
13
13
 
@@ -17,7 +17,7 @@ class PiezoelectricBuilder(Builder):
17
17
  materials: Store,
18
18
  tasks: Store,
19
19
  piezoelectric: Store,
20
- query: Optional[Dict] = None,
20
+ query: dict | None = None,
21
21
  **kwargs,
22
22
  ):
23
23
  self.materials = materials
@@ -190,20 +190,19 @@ class PiezoelectricBuilder(Builder):
190
190
  "last_updated",
191
191
  "input.is_hubbard",
192
192
  "orig_inputs.kpoints",
193
- "orig_inputs.poscar.structure",
193
+ "orig_inputs.structure",
194
194
  "input.parameters",
195
195
  "input.structure",
196
- "output.piezo_tensor",
197
- "output.piezo_ionic_tensor",
196
+ "calcs_reversed",
198
197
  "output.bandgap",
199
198
  ],
200
- criteria={self.tasks.key: str(task_id)},
199
+ criteria={self.tasks.key: str(AlphaID(task_id))},
201
200
  )
202
201
  if task_query["output"]["bandgap"] > 0:
203
202
  try:
204
- structure = task_query["orig_inputs"]["poscar"]["structure"]
205
- except KeyError:
206
203
  structure = task_query["input"]["structure"]
204
+ except KeyError:
205
+ structure = task_query["orig_inputs"]["structure"]
207
206
 
208
207
  is_hubbard = task_query["input"]["is_hubbard"]
209
208
 
@@ -223,19 +222,23 @@ class PiezoelectricBuilder(Builder):
223
222
  lu_dt = mat_doc["last_updated"]
224
223
  task_updated = task_query["last_updated"]
225
224
 
226
- final_docs.append(
227
- {
228
- "task_id": task_id,
229
- "is_hubbard": int(is_hubbard),
230
- "nkpoints": int(nkpoints),
231
- "piezo_static": task_query["output"]["piezo_tensor"],
232
- "piezo_ionic": task_query["output"]["piezo_ionic_tensor"],
233
- "structure": structure,
234
- "updated_on": lu_dt,
235
- "task_updated": task_updated,
236
- self.materials.key: mat_doc[self.materials.key],
237
- }
238
- )
225
+ if (cr := task_query.get("calcs_reversed", [])) and (
226
+ outcar := cr[0].get("output", {}).get("outcar", {})
227
+ ):
228
+
229
+ final_docs.append(
230
+ {
231
+ "task_id": task_id,
232
+ "is_hubbard": int(is_hubbard),
233
+ "nkpoints": int(nkpoints),
234
+ "piezo_static": outcar.get("piezo_tensor"),
235
+ "piezo_ionic": outcar.get("piezo_ionic_tensor"),
236
+ "structure": structure,
237
+ "updated_on": lu_dt,
238
+ "task_updated": task_updated,
239
+ self.materials.key: mat_doc[self.materials.key],
240
+ }
241
+ )
239
242
 
240
243
  if len(final_docs) > 0:
241
244
  sorted_final_docs = sorted(