Source code for janus_core.cli.eos

# ruff: noqa: I002, FA100
"""Set up eos commandline interface."""

# Issues with future annotations and typer
# c.f. https://github.com/maxb2/typer-config/issues/295
# from __future__ import annotations

from pathlib import Path
from typing import Annotated, Optional, get_args

from typer import Context, Option, Typer
from typer_config import use_config

from janus_core.cli.types import (
    Architecture,
    CalcKwargs,
    Device,
    LogPath,
    MinimizeKwargs,
    ModelPath,
    ReadKwargsLast,
    StructPath,
    Summary,
    WriteKwargs,
)
from janus_core.cli.utils import yaml_converter_callback

app = Typer()


[docs] @app.command() @use_config(yaml_converter_callback) def eos( # numpydoc ignore=PR02 ctx: Context, struct: StructPath, min_volume: Annotated[float, Option(help="Minimum volume scale factor.")] = 0.95, max_volume: Annotated[float, Option(help="Maximum volume scale factor.")] = 1.05, n_volumes: Annotated[int, Option(help="Number of volumes.")] = 7, eos_type: Annotated[ str, Option(help="Type of fit for equation of state.") ] = "birchmurnaghan", minimize: Annotated[ bool, Option(help="Whether to minimize initial structure before calculations.") ] = True, minimize_all: Annotated[ bool, Option(help="Whether to minimize all generated structures for calculations."), ] = False, fmax: Annotated[ float, Option(help="Maximum force for optimization convergence.") ] = 0.1, minimize_kwargs: MinimizeKwargs = None, write_structures: Annotated[ bool, Option(help="Whether to write out all genereated structures."), ] = False, write_kwargs: WriteKwargs = None, plot_to_file: Annotated[ bool, Option(help="Whether to plot equation of state."), ] = False, arch: Architecture = "mace_mp", device: Device = "cpu", model_path: ModelPath = None, read_kwargs: ReadKwargsLast = None, calc_kwargs: CalcKwargs = None, file_prefix: Annotated[ Optional[Path], Option( help=( """ Prefix for output filenames. Default is inferred from structure name, or chemical formula. """ ), ), ] = None, log: LogPath = None, tracker: Annotated[ bool, Option(help="Whether to save carbon emissions of calculation") ] = True, summary: Summary = None, ) -> None: """ Calculate equation of state and write out results. Parameters ---------- ctx : Context Typer (Click) Context. Automatically set. struct : Path Path of structure to simulate. min_volume : float Minimum volume scale factor. Default is 0.95. max_volume : float Maximum volume scale factor. Default is 1.05. n_volumes : int Number of volumes to use. Default is 7. eos_type : Optional[str] Type of fit for equation of state. Default is "birchmurnaghan". minimize : bool Whether to minimize initial structure before calculations. Default is True. minimize_all : bool Whether to optimize geometry for all generated structures. Default is False. fmax : float Set force convergence criteria for optimizer in units eV/Å. Default is 0.1. minimize_kwargs : Optional[dict[str, Any]] Other keyword arguments to pass to geometry optimizer. Default is {}. write_structures : bool True to write out all genereated structures. Default is False. write_kwargs : Optional[dict[str, Any]], Keyword arguments to pass to ase.io.write to save generated structures. Default is {}. plot_to_file : bool Whether to save plot equation of state to svg. Default is False. arch : Optional[str] MLIP architecture to use for geometry optimization. Default is "mace_mp". device : Optional[str] Device to run model on. Default is "cpu". model_path : Optional[str] Path to MLIP model. Default is `None`. read_kwargs : Optional[dict[str, Any]] Keyword arguments to pass to ase.io.read. By default, read_kwargs["index"] is -1. calc_kwargs : Optional[dict[str, Any]] Keyword arguments to pass to the selected calculator. Default is {}. file_prefix : Optional[PathLike] Prefix for output filenames. Default is inferred from structure name, or chemical formula. log : Optional[Path] Path to write logs to. Default is inferred from the name of the structure file. tracker : bool Whether to save carbon emissions of calculation in log file and summary. Default is True. summary : Optional[Path] Path to save summary of inputs, start/end time, and carbon emissions. Default is inferred from the name of the structure file. config : Optional[Path] Path to yaml configuration file to define the above options. Default is None. """ from janus_core.calculations.eos import EoS from janus_core.cli.utils import ( carbon_summary, check_config, end_summary, parse_typer_dicts, save_struct_calc, set_read_kwargs_index, start_summary, ) from janus_core.helpers.janus_types import EoSNames # Check options from configuration file are all valid check_config(ctx) [read_kwargs, calc_kwargs, minimize_kwargs, write_kwargs] = parse_typer_dicts( [read_kwargs, calc_kwargs, minimize_kwargs, write_kwargs] ) if eos_type not in get_args(EoSNames): raise ValueError(f"Fit type must be one of: {get_args(EoSNames)}") # Read only first structure by default and ensure only one image is read set_read_kwargs_index(read_kwargs) # Check fmax option not duplicated if "fmax" in minimize_kwargs: raise ValueError("'fmax' must be passed through the --fmax option") minimize_kwargs["fmax"] = fmax log_kwargs = {"filemode": "w"} if log: log_kwargs["filename"] = log # Dictionary of inputs for EoS class eos_kwargs = { "struct_path": struct, "arch": arch, "device": device, "model_path": model_path, "read_kwargs": read_kwargs, "calc_kwargs": calc_kwargs, "attach_logger": True, "log_kwargs": log_kwargs, "track_carbon": tracker, "min_volume": min_volume, "max_volume": max_volume, "n_volumes": n_volumes, "eos_type": eos_type, "minimize": minimize, "minimize_all": minimize_all, "minimize_kwargs": minimize_kwargs, "write_structures": write_structures, "write_kwargs": write_kwargs, "plot_to_file": plot_to_file, "file_prefix": file_prefix, } # Initialise EoS equation_of_state = EoS(**eos_kwargs) # Set summary and log files summary = equation_of_state._build_filename( "eos-summary.yml", filename=summary ).absolute() log = equation_of_state.log_kwargs["filename"] # Store inputs for yaml summary inputs = eos_kwargs.copy() # Add structure, MLIP information, and log to inputs save_struct_calc( inputs=inputs, struct=equation_of_state.struct, struct_path=struct, arch=arch, device=device, model_path=model_path, read_kwargs=read_kwargs, calc_kwargs=calc_kwargs, log=log, ) # Save summary information before calculations begin start_summary(command="eos", summary=summary, inputs=inputs) # Run equation of state calculations equation_of_state.run() # Save carbon summary if tracker: carbon_summary(summary=summary, log=log) # Time after calculations have finished end_summary(summary)