"""
calphy: a Python library and command line interface for automated free
energy calculations.
Copyright 2021 (c) Sarath Menon^1, Yury Lysogorskiy^2, Ralf Drautz^2
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
^2: Ruhr-University Bochum, Bochum, Germany
calphy is published and distributed under the Academic Software License v1.0 (ASL).
calphy is distributed in the hope that it will be useful for non-commercial academic research,
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
calphy API is published and distributed under the BSD 3-Clause "New" or "Revised" License
See the LICENSE FILE for more details.
More information about the program can be found in:
Menon, Sarath, Yury Lysogorskiy, Jutta Rogal, and Ralf Drautz.
“Automated Free Energy Calculation from Atomistic Simulations.” Physical Review Materials 5(10), 2021
DOI: 10.1103/PhysRevMaterials.5.103801
For more information contact:
sarath.menon@ruhr-uni-bochum.de/yury.lysogorskiy@icams.rub.de
"""
import os
import numpy as np
import shutil
import argparse as ap
import subprocess
import yaml
import time
import datetime
from calphy.input import read_inputfile
from calphy.liquid import Liquid
from calphy.solid import Solid
from calphy.alchemy import Alchemy
from calphy.routines import (
MeltingTemp,
routine_fe,
routine_ts,
routine_pscale,
routine_tscale,
routine_alchemy,
routine_composition_scaling,
)
[docs]def setup_calculation(calc):
"""
Set up a calculation
Parameters
----------
options: dict
options object
kernel: int
index of the calculation to be run
Returns
-------
job: Phase class
job class
"""
# now we need to modify the routines
if calc.mode == "melting_temperature":
simfolder = None
job = MeltingTemp(calculation=calc, simfolder=simfolder)
elif calc.mode == "alchemy" or calc.mode == "composition_scaling":
simfolder = calc.create_folders()
job = Alchemy(calculation=calc, simfolder=simfolder)
else:
simfolder = calc.create_folders()
if calc.reference_phase == "liquid":
job = Liquid(calculation=calc, simfolder=simfolder)
else:
job = Solid(calculation=calc, simfolder=simfolder)
return job
[docs]def run_calculation(job):
"""
Run calphy calculation
Parameters
----------
job: Phase class
Returns
-------
job : Phase class
"""
if job.calc.mode == "fe":
job = routine_fe(job)
elif job.calc.mode == "ts":
job = routine_ts(job)
elif job.calc.mode == "alchemy":
job = routine_alchemy(job)
elif job.calc.mode == "melting_temperature":
job.calculate_tm()
elif job.calc.mode == "tscale":
job = routine_tscale(job)
elif job.calc.mode == "pscale":
job = routine_pscale(job)
elif job.calc.mode == "composition_scaling":
job = routine_composition_scaling(job)
else:
raise ValueError(
"Mode should be either fe/ts/alchemy/melting_temperature/tscale/pscale/composition_scaling"
)
return job
[docs]def main():
arg = ap.ArgumentParser()
# argument name of input file
arg.add_argument(
"-i", "--input", required=True, type=str, help="name of the input file"
)
arg.add_argument(
"-k",
"--kernel",
required=True,
type=int,
help="kernel number of the calculation to be run.",
)
arg.add_argument(
"-s",
"--screen",
required=False,
type=bool,
help="enable logging to screen",
default=False,
)
arg.add_argument(
"--validate",
action="store_true",
default=False,
help="perform full validation during input parsing (slower, validates all calculations)",
)
# parse input
# parse arguments
args = vars(arg.parse_args())
kernel = args["kernel"]
log_to_screen = args["screen"]
validate = args["validate"]
if validate:
# Full validation mode: validate all calculations during parse
calculations = read_inputfile(args["input"], validate=True)
calc = calculations[kernel]
else:
# Fast mode: parse without validation, then validate only the one we need
# Re-read the YAML to get clean data for just the kernel we need
with open(args["input"], "r") as fin:
data = yaml.safe_load(fin)
calc_data = data["calculations"][kernel]
calc_data["kernel"] = kernel
calc_data["inputfile"] = args["input"]
# Handle pressure conversion
if "pressure" in calc_data.keys():
from calphy.input import _to_none
calc_data["pressure"] = _to_none(calc_data["pressure"])
# Now validate this single calculation
from calphy.input import Calculation
calc = Calculation(**calc_data)
# format and parse the arguments
simfolder = calc.create_folders()
if calc.mode == "melting_temperature":
os.rmdir(simfolder)
simfolder = None
job = MeltingTemp(
calculation=calc, simfolder=simfolder, log_to_screen=log_to_screen
)
elif calc.mode == "alchemy" or calc.mode == "composition_scaling":
job = Alchemy(
calculation=calc, simfolder=simfolder, log_to_screen=log_to_screen
)
os.chdir(simfolder)
else:
if calc.reference_phase == "liquid":
job = Liquid(
calculation=calc, simfolder=simfolder, log_to_screen=log_to_screen
)
else:
job = Solid(
calculation=calc, simfolder=simfolder, log_to_screen=log_to_screen
)
os.chdir(simfolder)
if job.calc.mode == "fe":
_ = routine_fe(job)
elif job.calc.mode == "ts":
_ = routine_ts(job)
elif job.calc.mode == "alchemy":
_ = routine_alchemy(job)
elif job.calc.mode == "melting_temperature":
job.calculate_tm()
elif job.calc.mode == "tscale":
_ = routine_tscale(job)
elif job.calc.mode == "pscale":
_ = routine_pscale(job)
elif job.calc.mode == "composition_scaling":
_ = routine_composition_scaling(job)
else:
raise ValueError(
"Mode should be either fe/ts/alchemy/melting_temperature/tscale/pscale/composition_scaling"
)