mp-api 0.47.1__tar.gz → 0.47.2rc0__tar.gz
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.
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/PKG-INFO +1 -1
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/_display.py +41 -11
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/_external.py +2 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/mprester.py +30 -9
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/electronic_structure.py +172 -137
- mp_api-0.47.2rc0/mp_api/client/routes/materials/phonon.py +602 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_external.py +26 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_quiet.py +126 -2
- mp_api-0.47.2rc0/tests/client/materials/test_electronic_structure_messages.py +208 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_phonon.py +70 -11
- mp_api-0.47.2rc0/tests/client/materials/test_phonon_methods.py +311 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/test_mprester.py +16 -3
- mp_api-0.47.1/mp_api/client/routes/materials/phonon.py +0 -423
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/.gitignore +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/LICENSE +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/_test_utils.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/_server_utils.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/_logger.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/_types.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/_units.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/client.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/schemas.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/settings.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/contribs/utils.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/_entries.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/_oxygen_evolution.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/client.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/delta.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/exceptions.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/schemas.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/settings.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/core/utils.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/_server.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/absorption.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/alloys.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/bonds.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/chemenv.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/dielectric.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/doi.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/elasticity.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/electrodes.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/eos.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/grain_boundaries.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/magnetism.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/materials.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/oxidation_states.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/piezo.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/provenance.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/robocrys.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/similarity.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/substrates.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/summary.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/surface_properties.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/synthesis.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/tasks.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/thermo.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/materials/xas.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/molecules/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/molecules/jcesr.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/molecules/molecules.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/client/routes/molecules/summary.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/mcp/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/mcp/_schemas.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/mcp/mp_mcp.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/mcp/server.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/mcp/tools.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/mcp/utils.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/mp_api/py.typed +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/pyproject.toml +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/contribs/conftest.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/contribs/test_client.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/contribs/test_contribs_schemas.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/contribs/test_contribs_utils.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/contribs/test_side_effects.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/contribs/test_types.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_client_progress.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_delta.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_delta_versions.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_display.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_ids.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_oxygen_evolution.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_schemas.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_session_headers.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/core/test_utils.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_absorption.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_alloys.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_bonds.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_chemenv.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_dielectric.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_doi.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_elasticity.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_electrodes.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_electronic_structure.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_eos.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_grain_boundary.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_magnetism.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_materials.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_oxidation_states.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_piezo.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_provenance.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_robocrys.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_similarity.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_substrates.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_summary.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_surface_properties.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_synthesis.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_tasks.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_thermo.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/materials/test_xas.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/molecules/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/molecules/test_jcesr.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/molecules/test_molecules.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/molecules/test_summary.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/test_client.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/test_core_client.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/test_entry_progress.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/client/test_heartbeat.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/conftest.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/mcp/__init__.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/mcp/test_server.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/mcp/test_tools.py +0 -0
- {mp_api-0.47.1 → mp_api-0.47.2rc0}/tests/mcp/test_utils.py +0 -0
|
@@ -89,6 +89,10 @@ Which channel to use
|
|
|
89
89
|
unreachable, data missing, a local dataset reused): `logger.warning/info`.
|
|
90
90
|
- Diagnostics: `logger.debug`.
|
|
91
91
|
- Transient progress: `progress_bar` / `status`, interactive output only.
|
|
92
|
+
Bars and summary lines report work the caller asked for: lookups the client
|
|
93
|
+
makes on its own behalf (resolving IDs, then fetching the data) run inside a
|
|
94
|
+
`status()`, which describes the whole operation and keeps the bars inside it
|
|
95
|
+
from drawing or printing anything.
|
|
92
96
|
- Output the user explicitly asked for (`notify_db_version`): `print_notice`.
|
|
93
97
|
|
|
94
98
|
So WARNING-level log records always mean something went wrong, and
|
|
@@ -119,6 +123,7 @@ Python shows a given warning once per code location; use
|
|
|
119
123
|
|
|
120
124
|
from __future__ import annotations
|
|
121
125
|
|
|
126
|
+
import contextvars
|
|
122
127
|
import io
|
|
123
128
|
import logging
|
|
124
129
|
import threading
|
|
@@ -446,6 +451,13 @@ class ProgressHandle:
|
|
|
446
451
|
self._progress.advance(self._task_id, advance)
|
|
447
452
|
|
|
448
453
|
|
|
454
|
+
# Whether a `status()` block is running in this context. Contextvars are copied
|
|
455
|
+
# into worker threads by `_external.in_current_context`, so those inherit it.
|
|
456
|
+
_IN_OPERATION: contextvars.ContextVar[bool] = contextvars.ContextVar(
|
|
457
|
+
"mp_api_client_in_operation", default=False
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
|
|
449
461
|
def _as_int(value: float | None) -> float | None:
|
|
450
462
|
"""Show (near) whole-number counts as ints, without a trailing `.0`."""
|
|
451
463
|
if isinstance(value, float) and abs(value - round(value)) < 1e-6:
|
|
@@ -469,7 +481,9 @@ def progress_bar(
|
|
|
469
481
|
Args:
|
|
470
482
|
description (str) : label shown next to the bar
|
|
471
483
|
total (float or None) : expected number of units, None if unknown
|
|
472
|
-
enabled (bool) : if False, nothing is shown (a no-op handle is yielded)
|
|
484
|
+
enabled (bool) : if False, nothing is shown (a no-op handle is yielded).
|
|
485
|
+
Nothing is shown either inside a `status()` block, which describes
|
|
486
|
+
the whole operation itself.
|
|
473
487
|
delay (float) : seconds before the bar is shown, so quick
|
|
474
488
|
operations stay silent. Checked on each update.
|
|
475
489
|
unit (str) : unit name for the rate column
|
|
@@ -487,7 +501,7 @@ def progress_bar(
|
|
|
487
501
|
ProgressHandle
|
|
488
502
|
"""
|
|
489
503
|
console = get_console()
|
|
490
|
-
if not enabled or is_quiet():
|
|
504
|
+
if not enabled or is_quiet() or _IN_OPERATION.get():
|
|
491
505
|
yield ProgressHandle(total, summary=summary)
|
|
492
506
|
return
|
|
493
507
|
if not _is_interactive(console):
|
|
@@ -705,25 +719,41 @@ def status(message: str, *, enabled: bool = True) -> Iterator[None]:
|
|
|
705
719
|
of WARNING-level logs). If disabled (muted progress bars) or in quiet mode,
|
|
706
720
|
nothing is shown or logged.
|
|
707
721
|
|
|
722
|
+
The status describes the whole operation the caller asked for, so
|
|
723
|
+
everything inside it stays quiet:
|
|
724
|
+
|
|
725
|
+
- `progress_bar`s inside the block draw nothing, print no summary line and
|
|
726
|
+
log nothing (e.g. the lookup of a material's IDs the client makes on
|
|
727
|
+
its own behalf);
|
|
728
|
+
- a `status` nested in another one shows and logs nothing.
|
|
729
|
+
|
|
730
|
+
Work with countable progress that the caller should watch (a multi-page
|
|
731
|
+
download) needs a `progress_bar` instead of a `status`.
|
|
732
|
+
|
|
708
733
|
Args:
|
|
709
734
|
message (str) : what is happening, e.g. "Counting documents..."
|
|
710
735
|
enabled (bool) : if False, show nothing
|
|
711
736
|
"""
|
|
712
737
|
console = get_console()
|
|
713
|
-
if not enabled or is_quiet():
|
|
714
|
-
yield
|
|
715
|
-
return
|
|
716
|
-
if not (_is_interactive(console) and _can_draw_live(console)):
|
|
717
|
-
logging.getLogger(LOGGER_NAME).info(message)
|
|
738
|
+
if not enabled or is_quiet() or _IN_OPERATION.get():
|
|
718
739
|
yield
|
|
719
740
|
return
|
|
720
741
|
|
|
721
|
-
|
|
722
|
-
task_id = progress.add_task(message, total=None, status=True)
|
|
742
|
+
token = _IN_OPERATION.set(True)
|
|
723
743
|
try:
|
|
724
|
-
|
|
744
|
+
if not (_is_interactive(console) and _can_draw_live(console)):
|
|
745
|
+
logging.getLogger(LOGGER_NAME).info(message)
|
|
746
|
+
yield
|
|
747
|
+
return
|
|
748
|
+
|
|
749
|
+
progress = _STATE.acquire(console)
|
|
750
|
+
task_id = progress.add_task(message, total=None, status=True)
|
|
751
|
+
try:
|
|
752
|
+
yield
|
|
753
|
+
finally:
|
|
754
|
+
_STATE.release(task_id)
|
|
725
755
|
finally:
|
|
726
|
-
|
|
756
|
+
_IN_OPERATION.reset(token)
|
|
727
757
|
|
|
728
758
|
|
|
729
759
|
def _app_handlers(logger: logging.Logger) -> list[logging.Handler]:
|
|
@@ -154,6 +154,8 @@ def _tracked(fn: Callable[..., Any]) -> Callable[..., Any]:
|
|
|
154
154
|
|
|
155
155
|
@functools.wraps(fn)
|
|
156
156
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
157
|
+
# keep this frame out of tracebacks in IPython, Jupyter and pytest
|
|
158
|
+
__tracebackhide__ = True
|
|
157
159
|
with capturing():
|
|
158
160
|
return fn(*args, **kwargs)
|
|
159
161
|
|
|
@@ -74,6 +74,7 @@ if TYPE_CHECKING:
|
|
|
74
74
|
from typing import Any, Literal
|
|
75
75
|
|
|
76
76
|
import numpy as np
|
|
77
|
+
from emmet.core.phonon import PhononBS, PhononDOS
|
|
77
78
|
from emmet.core.tasks import CoreTaskDoc
|
|
78
79
|
from packaging.version import Version
|
|
79
80
|
from pymatgen.analysis.phase_diagram import PDEntry
|
|
@@ -1514,31 +1515,52 @@ class MPRester(_Rester):
|
|
|
1514
1515
|
load_projections=load_projections,
|
|
1515
1516
|
)
|
|
1516
1517
|
|
|
1517
|
-
def get_phonon_dos_by_material_id(
|
|
1518
|
+
def get_phonon_dos_by_material_id(
|
|
1519
|
+
self,
|
|
1520
|
+
material_id: str,
|
|
1521
|
+
phonon_method: Literal["pheasy", "dfpt"] | None = None,
|
|
1522
|
+
) -> PhononDOS | dict[str, Any]:
|
|
1518
1523
|
"""Get phonon density of states data corresponding to a material_id.
|
|
1519
1524
|
|
|
1520
1525
|
Args:
|
|
1521
1526
|
material_id (str): Materials Project material_id.
|
|
1527
|
+
phonon_method (str or None): phonon method, i.e. pheasy or dfpt. By default,
|
|
1528
|
+
the method is chosen from the material's data: pheasy if it has it,
|
|
1529
|
+
otherwise dfpt. If the pheasy calculation has no DOS, the dfpt one
|
|
1530
|
+
is used (with a warning). A method passed explicitly is never replaced.
|
|
1522
1531
|
|
|
1523
1532
|
Returns:
|
|
1524
|
-
|
|
1525
|
-
|
|
1533
|
+
dos (PhononDOS): PhononDOS object
|
|
1526
1534
|
"""
|
|
1527
1535
|
return self.materials.phonon.get_dos_from_material_id(
|
|
1528
|
-
material_id=material_id, phonon_method=
|
|
1536
|
+
material_id=material_id, phonon_method=phonon_method
|
|
1529
1537
|
)
|
|
1530
1538
|
|
|
1531
|
-
def get_phonon_bandstructure_by_material_id(
|
|
1539
|
+
def get_phonon_bandstructure_by_material_id(
|
|
1540
|
+
self,
|
|
1541
|
+
material_id: str,
|
|
1542
|
+
phonon_method: Literal["pheasy", "dfpt"] | None = None,
|
|
1543
|
+
path_type: str | BSPathType = BSPathType.setyawan_curtarolo,
|
|
1544
|
+
) -> PhononBS | dict[str, Any]:
|
|
1532
1545
|
"""Get phonon dispersion data corresponding to a material_id.
|
|
1533
1546
|
|
|
1534
1547
|
Args:
|
|
1535
1548
|
material_id (str): Materials Project material_id.
|
|
1549
|
+
phonon_method (str or None): phonon method, i.e. pheasy or dfpt. By default,
|
|
1550
|
+
the method is chosen from the material's data: pheasy if it has it,
|
|
1551
|
+
otherwise dfpt. If the pheasy calculation has no band structure,
|
|
1552
|
+
the dfpt one is used (with a warning). A method passed explicitly
|
|
1553
|
+
is never replaced.
|
|
1554
|
+
path_type (BSPathType or str): k-path selection convention for the band structure.
|
|
1555
|
+
pheasy has all conventions; dfpt only has setyawan_curtarolo.
|
|
1536
1556
|
|
|
1537
1557
|
Returns:
|
|
1538
|
-
|
|
1558
|
+
bandstructure (PhononBS): PhononBS object
|
|
1539
1559
|
"""
|
|
1540
1560
|
return self.materials.phonon.get_bandstructure_from_material_id(
|
|
1541
|
-
material_id=material_id,
|
|
1561
|
+
material_id=material_id,
|
|
1562
|
+
phonon_method=phonon_method,
|
|
1563
|
+
path_type=path_type,
|
|
1542
1564
|
)
|
|
1543
1565
|
|
|
1544
1566
|
def get_wulff_shape(self, material_id: str):
|
|
@@ -1796,8 +1818,7 @@ class MPRester(_Rester):
|
|
|
1796
1818
|
# Prevent user error
|
|
1797
1819
|
if isinstance(material_ids, str | MPID):
|
|
1798
1820
|
raise MPRestError(
|
|
1799
|
-
"Input material IDs (even a single ID) as a list: "
|
|
1800
|
-
f"`[{material_ids}]`"
|
|
1821
|
+
f"Input material IDs (even a single ID) as a list: `[{material_ids}]`"
|
|
1801
1822
|
)
|
|
1802
1823
|
|
|
1803
1824
|
entry_preference = {
|
|
@@ -16,7 +16,7 @@ from pymatgen.electronic_structure.bandstructure import (
|
|
|
16
16
|
from pymatgen.electronic_structure.core import OrbitalType, Spin
|
|
17
17
|
|
|
18
18
|
from mp_api.client.core import BaseRester, MPRestError
|
|
19
|
-
from mp_api.client.core._display import mp_deprecation
|
|
19
|
+
from mp_api.client.core._display import mp_deprecation, status
|
|
20
20
|
from mp_api.client.core.utils import validate_ids
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
@@ -284,48 +284,57 @@ class BandStructureRester(BaseESPropertyRester):
|
|
|
284
284
|
Returns:
|
|
285
285
|
bandstructure (BandStructure): BandStructure or BandStructureSymmLine object
|
|
286
286
|
"""
|
|
287
|
-
|
|
288
|
-
"
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
WHERE identifier='{str(AlphaID(task_id.split("-")[-1],padlen=8))}'
|
|
297
|
-
"""
|
|
287
|
+
with status(
|
|
288
|
+
f"Fetching the band structure for {task_id}...",
|
|
289
|
+
enabled=not self.mute_progress_bars,
|
|
290
|
+
):
|
|
291
|
+
bs_lbl, _ = self._get_delta_table(
|
|
292
|
+
"materialsproject-parsed",
|
|
293
|
+
"core/electronic-structure/bandstructures/",
|
|
294
|
+
label="bandstructure",
|
|
295
|
+
)
|
|
298
296
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
297
|
+
query = f"""
|
|
298
|
+
SELECT *
|
|
299
|
+
FROM {bs_lbl}
|
|
300
|
+
WHERE identifier='{str(AlphaID(task_id.split("-")[-1],padlen=8))}'
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
if run_type:
|
|
304
|
+
rt = RunType(run_type) if isinstance(run_type, str) else run_type
|
|
305
|
+
query += f"\nAND run_type='{rt.value}'"
|
|
306
|
+
if path_type:
|
|
307
|
+
query += f"\nAND path_convention='{path_type}'"
|
|
308
|
+
|
|
309
|
+
table = self._query_delta_single(query, label=bs_lbl)
|
|
310
|
+
if len(deser := table.to_pylist(maps_as_pydicts="strict")) > 0:
|
|
311
|
+
if load_projections:
|
|
312
|
+
proj_bs_label, _ = self._get_delta_table(
|
|
313
|
+
"materialsproject-parsed",
|
|
314
|
+
"core/electronic-structure/projected-bandstructures/",
|
|
315
|
+
label="bandstructure_projections",
|
|
316
|
+
)
|
|
317
|
+
proj_table = self._query_delta_single(
|
|
318
|
+
query.replace(bs_lbl, proj_bs_label), label=proj_bs_label
|
|
319
|
+
)
|
|
320
|
+
if (
|
|
321
|
+
len(
|
|
322
|
+
deser_proj := proj_table.to_pylist(maps_as_pydicts="strict")
|
|
323
|
+
)
|
|
324
|
+
> 0
|
|
325
|
+
):
|
|
326
|
+
deser[0]["projections"] = deser_proj[0]
|
|
327
|
+
emmet_bs = ElectronicBS(**deser[0])
|
|
328
|
+
return emmet_bs.to_pmg(
|
|
329
|
+
pmg_cls=(
|
|
330
|
+
BandStructureSymmLine if emmet_bs.labels_dict else BandStructure
|
|
331
|
+
)
|
|
315
332
|
)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
)
|
|
320
|
-
deser[0]["projections"] = deser_proj[0]
|
|
321
|
-
emmet_bs = ElectronicBS(**deser[0])
|
|
322
|
-
return emmet_bs.to_pmg(
|
|
323
|
-
pmg_cls=BandStructureSymmLine if emmet_bs.labels_dict else BandStructure
|
|
333
|
+
raise MPRestError(
|
|
334
|
+
f"No bandstructure data found for {task_id=}"
|
|
335
|
+
+ (f" and run_type={rt.value}" if run_type else "")
|
|
336
|
+
+ (f" and path_type={path_type}" if path_type else "")
|
|
324
337
|
)
|
|
325
|
-
raise MPRestError(
|
|
326
|
-
f"No bandstructure data found for {task_id=}"
|
|
327
|
-
+ (f"run_type={rt}" if run_type else "")
|
|
328
|
-
)
|
|
329
338
|
|
|
330
339
|
def get_bandstructure_from_material_id(
|
|
331
340
|
self,
|
|
@@ -349,62 +358,73 @@ class BandStructureRester(BaseESPropertyRester):
|
|
|
349
358
|
pt: BSPathType = (
|
|
350
359
|
BSPathType(path_type) if isinstance(path_type, str) else path_type
|
|
351
360
|
)
|
|
352
|
-
if line_mode
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
361
|
+
kind = f"{pt.value} band structure" if line_mode else "uniform band structure"
|
|
362
|
+
with status(
|
|
363
|
+
f"Fetching the {kind} for {material_id}...",
|
|
364
|
+
enabled=not self.mute_progress_bars,
|
|
365
|
+
):
|
|
366
|
+
if line_mode:
|
|
367
|
+
bs_doc = self.es_rester.search(
|
|
368
|
+
material_ids=material_id, fields=["bandstructure"]
|
|
359
369
|
)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
370
|
+
if not bs_doc:
|
|
371
|
+
raise MPRestError(
|
|
372
|
+
f"No electronic structure data found for material ID {material_id}."
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
if (_bs_data := bs_doc[0]["bandstructure"]) is None:
|
|
376
|
+
raise MPRestError(
|
|
377
|
+
f"No {pt.value} band structure data found for {material_id}"
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
bs_data = (
|
|
381
|
+
_bs_data.model_dump() if self.use_document_model else _bs_data # type: ignore
|
|
364
382
|
)
|
|
365
383
|
|
|
366
|
-
|
|
367
|
-
|
|
384
|
+
if bs_data.get(pt.value, None) is None:
|
|
385
|
+
available = sorted(k for k, v in bs_data.items() if v is not None)
|
|
386
|
+
raise MPRestError(
|
|
387
|
+
f"No {pt.value} band structure data found for {material_id}"
|
|
388
|
+
+ (
|
|
389
|
+
f" (available: {', '.join(available)})."
|
|
390
|
+
if available
|
|
391
|
+
else "."
|
|
392
|
+
)
|
|
393
|
+
)
|
|
394
|
+
bs_task_id = bs_data[pt.value]["task_id"]
|
|
395
|
+
|
|
396
|
+
else:
|
|
397
|
+
if not (
|
|
398
|
+
bs_doc := self.es_rester.search(
|
|
399
|
+
material_ids=material_id, fields=["dos"]
|
|
400
|
+
)
|
|
401
|
+
):
|
|
402
|
+
raise MPRestError(
|
|
403
|
+
f"No electronic structure data found for material ID {material_id}."
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
if (_bs_data := bs_doc[0]["dos"]) is None:
|
|
407
|
+
raise MPRestError(
|
|
408
|
+
f"No uniform band structure data found for {material_id}"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
bs_data = _bs_data.model_dump() if self.use_document_model else _bs_data
|
|
412
|
+
|
|
413
|
+
if bs_data.get("total", None) is None:
|
|
414
|
+
raise MPRestError(
|
|
415
|
+
f"No uniform band structure data found for {material_id}"
|
|
416
|
+
)
|
|
417
|
+
bs_task_id = bs_data["task_id"]
|
|
418
|
+
|
|
419
|
+
bs_obj = self.get_bandstructure_from_task_id(
|
|
420
|
+
bs_task_id,
|
|
421
|
+
path_type=pt if line_mode else BSPathType.unknown,
|
|
422
|
+
load_projections=load_projections,
|
|
368
423
|
)
|
|
369
424
|
|
|
370
|
-
if
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
)
|
|
374
|
-
bs_task_id = bs_data[pt.value]["task_id"]
|
|
375
|
-
|
|
376
|
-
else:
|
|
377
|
-
if not (
|
|
378
|
-
bs_doc := self.es_rester.search(
|
|
379
|
-
material_ids=material_id, fields=["dos"]
|
|
380
|
-
)
|
|
381
|
-
):
|
|
382
|
-
raise MPRestError(
|
|
383
|
-
f"No electronic structure data found for material ID {material_id}."
|
|
384
|
-
)
|
|
385
|
-
|
|
386
|
-
if (_bs_data := bs_doc[0]["dos"]) is None:
|
|
387
|
-
raise MPRestError(
|
|
388
|
-
f"No uniform band structure data found for {material_id}"
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
bs_data = _bs_data.model_dump() if self.use_document_model else _bs_data
|
|
392
|
-
|
|
393
|
-
if bs_data.get("total", None) is None:
|
|
394
|
-
raise MPRestError(
|
|
395
|
-
f"No uniform band structure data found for {material_id}"
|
|
396
|
-
)
|
|
397
|
-
bs_task_id = bs_data["task_id"]
|
|
398
|
-
|
|
399
|
-
bs_obj = self.get_bandstructure_from_task_id(
|
|
400
|
-
bs_task_id,
|
|
401
|
-
path_type=pt if line_mode else BSPathType.unknown,
|
|
402
|
-
load_projections=load_projections,
|
|
403
|
-
)
|
|
404
|
-
|
|
405
|
-
if bs_obj:
|
|
406
|
-
return bs_obj
|
|
407
|
-
raise MPRestError("No band structure object found.")
|
|
425
|
+
if bs_obj:
|
|
426
|
+
return bs_obj
|
|
427
|
+
raise MPRestError("No band structure object found.")
|
|
408
428
|
|
|
409
429
|
|
|
410
430
|
class DosRester(BaseESPropertyRester):
|
|
@@ -540,42 +560,49 @@ class DosRester(BaseESPropertyRester):
|
|
|
540
560
|
Returns:
|
|
541
561
|
pymatgen Dos
|
|
542
562
|
"""
|
|
543
|
-
|
|
544
|
-
"
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
WHERE identifier='{str(AlphaID(task_id.split("-")[-1],padlen=8))}'
|
|
553
|
-
"""
|
|
563
|
+
with status(
|
|
564
|
+
f"Fetching the density of states for {task_id}...",
|
|
565
|
+
enabled=not self.mute_progress_bars,
|
|
566
|
+
):
|
|
567
|
+
dos_lbl, _ = self._get_delta_table(
|
|
568
|
+
"materialsproject-parsed",
|
|
569
|
+
"core/electronic-structure/total-dos/",
|
|
570
|
+
label="total_dos",
|
|
571
|
+
)
|
|
554
572
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
if
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
573
|
+
query = f"""
|
|
574
|
+
SELECT *
|
|
575
|
+
FROM {dos_lbl}
|
|
576
|
+
WHERE identifier='{str(AlphaID(task_id.split("-")[-1],padlen=8))}'
|
|
577
|
+
"""
|
|
578
|
+
|
|
579
|
+
if run_type:
|
|
580
|
+
rt = RunType(run_type) if isinstance(run_type, str) else run_type
|
|
581
|
+
query += f"\nAND run_type='{rt.value}'"
|
|
582
|
+
|
|
583
|
+
table = self._query_delta_single(query, label=dos_lbl)
|
|
584
|
+
if len(deser := table.to_pylist(maps_as_pydicts="strict")) > 0:
|
|
585
|
+
if load_projections:
|
|
586
|
+
proj_dos_label, _ = self._get_delta_table(
|
|
587
|
+
"materialsproject-parsed",
|
|
588
|
+
"core/electronic-structure/projected-dos/",
|
|
589
|
+
label="dos_projections",
|
|
590
|
+
)
|
|
591
|
+
proj_table = self._query_delta_single(
|
|
592
|
+
query.replace(dos_lbl, proj_dos_label), label=proj_dos_label
|
|
593
|
+
)
|
|
594
|
+
if (
|
|
595
|
+
len(
|
|
596
|
+
deser_proj := proj_table.to_pylist(maps_as_pydicts="strict")
|
|
597
|
+
)
|
|
598
|
+
> 0
|
|
599
|
+
):
|
|
600
|
+
deser[0]["projected_densities"] = deser_proj[0]
|
|
601
|
+
return ElectronicDos(**deser[0]).to_pmg()
|
|
602
|
+
raise MPRestError(
|
|
603
|
+
f"No DOS data found for {task_id=}"
|
|
604
|
+
+ (f" and run_type={rt.value}" if run_type else "")
|
|
605
|
+
)
|
|
579
606
|
|
|
580
607
|
def get_dos_from_material_id(
|
|
581
608
|
self, material_id: str, load_projections: bool = False
|
|
@@ -590,17 +617,25 @@ class DosRester(BaseESPropertyRester):
|
|
|
590
617
|
Returns:
|
|
591
618
|
pymatgen Dos
|
|
592
619
|
"""
|
|
593
|
-
|
|
594
|
-
|
|
620
|
+
with status(
|
|
621
|
+
f"Fetching the density of states for {material_id}...",
|
|
622
|
+
enabled=not self.mute_progress_bars,
|
|
595
623
|
):
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
624
|
+
if not (
|
|
625
|
+
dos_doc := self.es_rester.search(
|
|
626
|
+
material_ids=material_id, fields=["dos"]
|
|
627
|
+
)
|
|
628
|
+
):
|
|
629
|
+
raise MPRestError(
|
|
630
|
+
f"No electronic structure data found for material ID {material_id}."
|
|
631
|
+
)
|
|
599
632
|
|
|
600
|
-
|
|
601
|
-
|
|
633
|
+
if not (dos_data := dos_doc[0].get("dos")):
|
|
634
|
+
raise MPRestError(f"No density of states data found for {material_id}")
|
|
602
635
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
636
|
+
dos_task_id = (
|
|
637
|
+
dos_data.model_dump() if self.use_document_model else dos_data
|
|
638
|
+
)["task_id"]
|
|
639
|
+
return self.get_dos_from_task_id(
|
|
640
|
+
dos_task_id, load_projections=load_projections
|
|
641
|
+
)
|