"""Module defining common jobs."""
from __future__ import annotations
from typing import TYPE_CHECKING
from jobflow import Response, job
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from atomate2 import SETTINGS
if TYPE_CHECKING:
from pymatgen.core import Structure
[docs]
@job
def structure_to_primitive(
structure: Structure, symprec: float = SETTINGS.SYMPREC
) -> Structure:
"""
Job that creates a standard primitive structure.
Parameters
----------
structure: Structure object
input structure that will be transformed
symprec: float
precision to determine symmetry
Returns
-------
.Structure
"""
sga = SpacegroupAnalyzer(structure, symprec=symprec)
return sga.get_primitive_standard_structure()
[docs]
@job
def structure_to_conventional(
structure: Structure, symprec: float = SETTINGS.SYMPREC
) -> Structure:
"""
Job hat creates a standard conventional structure.
Parameters
----------
structure: Structure object
input structure that will be transformed
symprec: float
precision to determine symmetry
Returns
-------
.Structure
"""
sga = SpacegroupAnalyzer(structure, symprec=symprec)
return sga.get_conventional_standard_structure()
[docs]
@job
def retrieve_structure_from_materials_project(
material_id_or_task_id: str,
use_task_id: bool = False,
reset_magnetic_moments: bool = False,
) -> Response[Structure]:
"""
Retrieve a Structure from Materials Project.
This job is useful for constructing a Flow that always will retrieve the most
up-to-date data at the time the Flow runs.
The retrieved Structure will change between subsequent Materials Project database
releases as old calculation tasks are removed and new, better, calculation tasks
(e.g. with more accurate lattice parameters) are added.
Using this job requires that the system where the job runs has a connection to the
outside internet. It also requires the Materials Project API key to be set
appropriately via an environment variable or otherwise. Consult the Materials
Project API documentation for more information.
Parameters
----------
material_id_or_task_id : str
The material_id or the task_id for the data record
being retrieved.
use_task_id : bool
If true, will request the Structure from the specific
calculation task in Materials Project. Structures
retrieved in this way should not change even between
new Materials Project database releases.
reset_magnetic_moments : bool
If true, will remove any magnetic moment information
or magnetic ordering on the Structure. Typically,
this will mean that the Structure will then be
initialized as ferromagnetic by any child jobs.
Returns
-------
.Response
A Response with the Structure object as the output,
and also the database version and specific task_id
corresponding to that Structure object also stored
"""
# inline import to avoid required dependency
try:
from mp_api.client import MPRester
except ImportError:
raise ImportError(
"This job requires the Materials Project API client "
"to be installed, via `pip install mp-api` or similar."
) from None
with MPRester() as mpr:
if use_task_id:
doc = mpr.tasks.get_data_by_id(material_id_or_task_id, fields=["structure"])
task_id = material_id_or_task_id
else:
doc = mpr.materials.get_data_by_id(
material_id_or_task_id, fields=["structure", "origins"]
)
origins = {prop.name: prop for prop in doc.origins}
task_id = str(origins["structure"].task_id)
database_version = mpr.get_database_version()
structure = doc.structure
if reset_magnetic_moments and "magmom" in structure.site_properties:
# Materials Project stores magnetic moments via the `magmom` site property
# and we can safely assume that here. In general, since magnetic order
# can be represented in multiple ways such as Species.spin, the
# following method would be better:
# CollinearMagneticStructureAnalyzer.get_nonmagnetic_structure()
structure.remove_site_property("magmom")
return Response(
output=structure,
stored_data={"task_id": task_id, "database_version": database_version},
)