From ac2da2f5c240f80ec47cd077c80933f1cae5faa8 Mon Sep 17 00:00:00 2001 From: Thang Pham Date: Tue, 26 May 2026 11:19:04 -0500 Subject: [PATCH] Add YAML-based gRASPA isotherm batch setup script Add a Python script and YAML config for setting up gRASPA isotherm simulations with many temperature/pressure combinations, avoiding tedious CLI flag repetition. Supports pressure unit conversion (bar, kPa, atm, Pa). --- pyproject.toml | 3 +- scripts/graspa/isotherm_config.yaml | 42 ++++++++++++++++++ scripts/graspa/setup_isotherms.py | 66 +++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 scripts/graspa/isotherm_config.yaml create mode 100644 scripts/graspa/setup_isotherms.py diff --git a/pyproject.toml b/pyproject.toml index 0455557..eacd84d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,8 @@ rdkit = ["rdkit"] mlip = ["mace-torch"] plot = ["matplotlib>=3.5"] pacmof2 = ["pacmof2"] -all = ["rdkit", "mace-torch", "matplotlib>=3.5", "pacmof2"] +graspa = ["pyyaml>=6.0"] +all = ["rdkit", "mace-torch", "matplotlib>=3.5", "pacmof2", "pyyaml>=6.0"] dev = ["pytest>=7.0", "ruff>=0.4"] [project.scripts] diff --git a/scripts/graspa/isotherm_config.yaml b/scripts/graspa/isotherm_config.yaml new file mode 100644 index 0000000..86e86b4 --- /dev/null +++ b/scripts/graspa/isotherm_config.yaml @@ -0,0 +1,42 @@ +# gRASPA isotherm simulation config +# Usage: python setup_isotherms.py isotherm_config.yaml + +cif_dir: ./cifs +outdir: ./batch_results + +adsorbates: [CO2, N2] + +temperatures: [283, 293, 313, 333] + +pressures: + - 0.001 + - 0.005 + - 0.01 + - 0.02 + - 0.03 + - 0.04 + - 0.05 + - 0.10 + - 0.15 + - 0.20 + - 0.25 + - 0.30 + - 0.35 + - 0.40 + - 0.45 + - 0.50 + - 0.55 + - 0.60 + - 0.65 + - 0.70 + - 0.75 + - 0.80 + - 0.85 + - 0.90 + - 0.95 + - 1.0 + +pressure_unit: bar # bar, kPa, atm, or Pa + +cutoff: 12.8 +cycles: 1000 diff --git a/scripts/graspa/setup_isotherms.py b/scripts/graspa/setup_isotherms.py new file mode 100644 index 0000000..4167833 --- /dev/null +++ b/scripts/graspa/setup_isotherms.py @@ -0,0 +1,66 @@ +"""Set up gRASPA isotherm simulations from a YAML config file. + +Usage: + python setup_isotherms.py + python setup_isotherms.py # defaults to isotherm_config.yaml +""" + +import sys +from pathlib import Path + +import yaml + +from matkit.graspa import setup_batch + +PRESSURE_TO_PA = { + "pa": 1.0, + "bar": 1e5, + "kpa": 1e3, + "atm": 101325.0, +} + + +def main(): + if len(sys.argv) > 1: + config_path = Path(sys.argv[1]) + else: + config_path = Path(__file__).parent / "isotherm_config.yaml" + + with open(config_path) as f: + cfg = yaml.safe_load(f) + + pressure_unit = cfg.get("pressure_unit", "Pa").lower() + if pressure_unit not in PRESSURE_TO_PA: + raise ValueError( + f"Unknown pressure_unit '{cfg['pressure_unit']}'. " + f"Supported: {list(PRESSURE_TO_PA.keys())}" + ) + factor = PRESSURE_TO_PA[pressure_unit] + pressures_pa = [p * factor for p in cfg["pressures"]] + + adsorbates = [{"MoleculeName": name} for name in cfg["adsorbates"]] + + print(f"Config: {config_path}") + print(f"CIF dir: {cfg['cif_dir']}") + print(f"Adsorbates: {cfg['adsorbates']}") + print(f"Temperatures: {cfg['temperatures']}") + print(f"Pressures: {len(pressures_pa)} points " + f"({cfg['pressures'][0]}-{cfg['pressures'][-1]} " + f"{cfg.get('pressure_unit', 'Pa')})") + + manifest = setup_batch( + cif_dir=cfg["cif_dir"], + outpath=cfg["outdir"], + adsorbates=adsorbates, + temperatures=cfg["temperatures"], + pressures=pressures_pa, + cutoff=cfg.get("cutoff", 12.8), + n_cycle=cfg.get("cycles", 1000), + ) + + print(f"\nSet up {len(manifest)} simulations in {cfg['outdir']}") + print(f"Manifest: {cfg['outdir']}/simulations.jsonl") + + +if __name__ == "__main__": + main()