Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions calphy/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
Field,
ValidationError,
model_validator,
field_validator,
conlist,
PrivateAttr,
)
Expand Down Expand Up @@ -180,6 +181,22 @@ class MeltingTemperature(BaseModel, title="Input options for melting temperature
step: Annotated[int, Field(default=200, ge=20)]
attempts: Annotated[int, Field(default=5, ge=1)]

class MaterialsProject(BaseModel, title='Input options for materials project'):
api_key: Annotated[str, Field(default="", exclude=True)]
conventional: Annotated[bool, Field(default=True)]
target_natoms: Annotated[int, Field(default=1500, description='The structure parsed from materials project would be repeated to approximately this value')]

@field_validator("api_key", mode="after")
def resolve_api_key(cls, v: str) -> str:
if not v:
return v
value = os.getenv(v)
if not value:
raise ValueError(
f"Environment variable '{v}' not found or empty. "
f"Set it before running, e.g.:\n export {v}='your_api_key_here'"
)
return value

class Calculation(BaseModel, title="Main input class"):
monte_carlo: Optional[MonteCarlo] = MonteCarlo()
Expand All @@ -191,6 +208,8 @@ class Calculation(BaseModel, title="Main input class"):
tolerance: Optional[Tolerance] = Tolerance()
uhlenbeck_ford_model: Optional[UFMP] = UFMP()
melting_temperature: Optional[MeltingTemperature] = MeltingTemperature()
materials_project: Optional[MaterialsProject] = MaterialsProject()

element: Annotated[List[str], BeforeValidator(to_list), Field(default=[])]
n_elements: Annotated[int, Field(default=0)]
mass: Annotated[List[float], BeforeValidator(to_list), Field(default=[])]
Expand Down Expand Up @@ -496,6 +515,44 @@ def _validate_all(self) -> "Input":
self._original_lattice = self.lattice.lower()
write_structure_file = True

elif self.lattice.split('-')[0] == 'mp':
#confirm here that API key exists
if not self.materials_project.api_key:
raise ValueError('could not find API KEY, pls set it.')
#now we need to fetch the structure
try:
from mp_api.client import MPRester
except ImportError:
raise ImportError('Could not import mp_api, make sure you install mp_api package!')
#now all good
rest = {
"use_document_model": False,
"include_user_agent": True,
"api_key": self.materials_project.api_key,
}
with MPRester(**rest) as mpr:
docs = mpr.materials.summary.search(material_ids=[self.lattice])

structures = []
for doc in docs:
struct = doc['structure']
if self.materials_project.conventional:
aseatoms = struct.to_conventional().to_ase_atoms()
else:
aseatoms = struct.to_primitive().to_ase_atoms()
structures.append(aseatoms)
structure = structures[0]

if np.prod(self.repeat) == 1:
x = int(np.ceil((self.materials_project.target_natoms/len(structure))**(1/3)))
structure = structure.repeat(x)
else:
structure = structure.repeat(self.repeat)

self._natoms = len(structure)
self._original_lattice = self.lattice.lower()
write_structure_file = True

else:
# this is a file
if not os.path.exists(self.lattice):
Expand Down
32 changes: 32 additions & 0 deletions examples/example_01/input-mp.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
calculations:
- element: Fe
lattice: mp-13
mass: 55.845
md:
barostat_damping: 0.1
equilibration_control: nose_hoover
thermostat_damping: 0.1
timestep: 0.001
mode: fe
n_equilibration_steps: 10000
n_iterations: 1
n_switching_steps: 25000
pair_coeff: '* * ../potentials/Fe.eam'
pair_style: eam
pressure: 0.0
queue:
commands:
- conda activate calphy
cores: 4
scheduler: local
reference_phase: solid
repeat:
- 5
- 5
- 5
temperature: 100.0
tolerance:
pressure: 1
materials_project:
api_key: MP_API_KEY

Loading