Source code for kmcpy.cli.init

"""CLI utilities to scaffold a kMCpy Configuration YAML template."""

from __future__ import annotations

import argparse
from pathlib import Path
from textwrap import dedent
from typing import Sequence


DEFAULT_TEMPLATE_FILENAME = "input_template.yaml"


[docs] def build_template() -> str: """Return a commented YAML template for ``Configuration``.""" return dedent( """\ # kMCpy input template (modern Configuration format) # # Usage: # 1) Fill the required file paths below. # 2) Adjust optional settings as needed. # 3) Run: run_kmc --input input_template.yaml # # API usage: # from kmcpy.simulator.config import Configuration # config = Configuration.from_file("input_template.yaml") kmc: type: default default: # ----- Required loader inputs ----- # Path to crystal structure (CIF/structure file) structure_file: "path/to/structure.cif" # Path to migration event library JSON event_file: "path/to/event.json" # Path to serialized model JSON model_file: "path/to/model.json" # ----- Optional loader inputs ----- # Optional serialized initial simulation state file initial_state_file: null # Optional direct initial occupations list (used if state file is null) initial_occupations: null # ----- System fields ----- # Supercell replication factors [a, b, c] supercell_shape: [1, 1, 1] # Dimensionality of transport (1, 2, or 3) dimension: 3 # Mobile ion specie label mobile_ion_specie: "Li" # Mobile ion charge in |e| mobile_ion_charge: 1.0 # Characteristic hop distance (Angstrom) elementary_hop_distance: 1.0 # Optional model selector for hand-written payloads. Files written # by model.to(...) infer this from model_file. model_type: "composite_lce" # Site mapping. One allowed species means fixed; multiple means active. site_mapping: Li: [Li, X] # Convert structure to primitive cell before simulation convert_to_primitive_cell: false # ----- Runtime fields ----- # Temperature in Kelvin temperature: 300.0 # Attempt frequency (Hz) attempt_frequency: 10000000000000.0 # Number of equilibration passes equilibration_passes: 1000 # Number of production KMC passes kmc_passes: 10000 # Optional RNG seed (null for nondeterministic) random_seed: null # Simulation label used in outputs name: "DefaultSimulation" # ----- Optional property sampling controls ----- # Global property sampling event-step interval (null = default once per pass) property_sampling_interval: null # Global property sampling time interval in seconds (null = disabled) property_sampling_time_interval: null # Built-in property toggles (defaults to enabled for all fields) # Supported keys: msd, jump_diffusivity, tracer_diffusivity, # conductivity, havens_ratio, correlation_factor # Output units: # time: s # msd: Angstrom^2 # jump_diffusivity, tracer_diffusivity: cm^2/s # conductivity: mS/cm # havens_ratio, correlation_factor: dimensionless builtin_property_enabled: {} # Optional custom callback definitions resolved by import path. # Example: # property_callbacks: # - callable: "myproject.kmc_props:calc_occupation" # name: "occupied_fraction" # interval: 100 # time_interval: null # store: true # max_records: null # enabled: true property_callbacks: [] """ )
[docs] def write_template(output: str | Path, force: bool = False) -> Path: """Write the template to ``output`` and return the output path.""" output_path = Path(output).expanduser() output_path.parent.mkdir(parents=True, exist_ok=True) if output_path.exists() and not force: raise FileExistsError( f"Refusing to overwrite existing file: {output_path}. " "Use --force to overwrite." ) output_path.write_text(build_template(), encoding="utf-8") return output_path
[docs] def build_parser() -> argparse.ArgumentParser: """Build parser for the standalone ``kmcpy-init`` style command.""" parser = argparse.ArgumentParser( description="Generate a commented kMCpy YAML input template." ) parser.add_argument( "-o", "--output", default=DEFAULT_TEMPLATE_FILENAME, help=f"Output YAML path (default: {DEFAULT_TEMPLATE_FILENAME})", ) parser.add_argument( "-f", "--force", action="store_true", help="Overwrite output file if it already exists.", ) return parser
[docs] def main(argv: Sequence[str] | None = None) -> int: """Entry point for generating template files.""" parser = build_parser() args = parser.parse_args(argv) output_path = write_template(args.output, force=args.force) print(f"Template written to: {output_path}") print(f"Next step: run_kmc --input {output_path}") return 0
if __name__ == "__main__": raise SystemExit(main())