170 lines
5.1 KiB
Python
170 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Structure file format converter using pymatgen.
|
|
|
|
This script converts between different structure file formats supported by pymatgen.
|
|
Supports automatic format detection and batch conversion.
|
|
|
|
Usage:
|
|
python structure_converter.py input_file output_file
|
|
python structure_converter.py input_file --format cif
|
|
python structure_converter.py *.cif --output-dir ./converted --format poscar
|
|
|
|
Examples:
|
|
python structure_converter.py POSCAR structure.cif
|
|
python structure_converter.py structure.cif --format json
|
|
python structure_converter.py *.vasp --output-dir ./cif_files --format cif
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
try:
|
|
from pymatgen.core import Structure
|
|
except ImportError:
|
|
print("Error: pymatgen is not installed. Install with: pip install pymatgen")
|
|
sys.exit(1)
|
|
|
|
|
|
def convert_structure(input_path: Path, output_path: Path = None, output_format: str = None) -> bool:
|
|
"""
|
|
Convert a structure file to a different format.
|
|
|
|
Args:
|
|
input_path: Path to input structure file
|
|
output_path: Path to output file (optional if output_format is specified)
|
|
output_format: Target format (e.g., 'cif', 'poscar', 'json', 'yaml')
|
|
|
|
Returns:
|
|
True if conversion succeeded, False otherwise
|
|
"""
|
|
try:
|
|
# Read structure with automatic format detection
|
|
struct = Structure.from_file(str(input_path))
|
|
print(f"✓ Read structure: {struct.composition.reduced_formula} from {input_path}")
|
|
|
|
# Determine output path
|
|
if output_path is None and output_format:
|
|
output_path = input_path.with_suffix(f".{output_format}")
|
|
elif output_path is None:
|
|
print("Error: Must specify either output_path or output_format")
|
|
return False
|
|
|
|
# Write structure
|
|
struct.to(filename=str(output_path))
|
|
print(f"✓ Wrote structure to {output_path}")
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
print(f"✗ Error converting {input_path}: {e}")
|
|
return False
|
|
|
|
|
|
def batch_convert(input_files: List[Path], output_dir: Path, output_format: str) -> None:
|
|
"""
|
|
Convert multiple structure files to a common format.
|
|
|
|
Args:
|
|
input_files: List of input structure files
|
|
output_dir: Directory for output files
|
|
output_format: Target format for all files
|
|
"""
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
success_count = 0
|
|
for input_file in input_files:
|
|
output_file = output_dir / f"{input_file.stem}.{output_format}"
|
|
if convert_structure(input_file, output_file):
|
|
success_count += 1
|
|
|
|
print(f"\n{'='*60}")
|
|
print(f"Conversion complete: {success_count}/{len(input_files)} files converted successfully")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Convert structure files between different formats using pymatgen",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Supported formats:
|
|
Input: CIF, POSCAR, CONTCAR, XYZ, PDB, JSON, YAML, and many more
|
|
Output: CIF, POSCAR, XYZ, PDB, JSON, YAML, XSF, and many more
|
|
|
|
Examples:
|
|
%(prog)s POSCAR structure.cif
|
|
%(prog)s structure.cif --format json
|
|
%(prog)s *.cif --output-dir ./poscar_files --format poscar
|
|
"""
|
|
)
|
|
|
|
parser.add_argument(
|
|
"input",
|
|
nargs="+",
|
|
help="Input structure file(s). Supports wildcards for batch conversion."
|
|
)
|
|
|
|
parser.add_argument(
|
|
"output",
|
|
nargs="?",
|
|
help="Output structure file (ignored if --output-dir is used)"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--format", "-f",
|
|
help="Output format (e.g., cif, poscar, json, yaml, xyz)"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--output-dir", "-o",
|
|
type=Path,
|
|
help="Output directory for batch conversion"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Expand wildcards and convert to Path objects
|
|
input_files = []
|
|
for pattern in args.input:
|
|
matches = list(Path.cwd().glob(pattern))
|
|
if matches:
|
|
input_files.extend(matches)
|
|
else:
|
|
input_files.append(Path(pattern))
|
|
|
|
# Filter to files only
|
|
input_files = [f for f in input_files if f.is_file()]
|
|
|
|
if not input_files:
|
|
print("Error: No input files found")
|
|
sys.exit(1)
|
|
|
|
# Batch conversion mode
|
|
if args.output_dir or len(input_files) > 1:
|
|
if not args.format:
|
|
print("Error: --format is required for batch conversion")
|
|
sys.exit(1)
|
|
|
|
output_dir = args.output_dir or Path("./converted")
|
|
batch_convert(input_files, output_dir, args.format)
|
|
|
|
# Single file conversion
|
|
elif len(input_files) == 1:
|
|
input_file = input_files[0]
|
|
|
|
if args.output:
|
|
output_file = Path(args.output)
|
|
convert_structure(input_file, output_file)
|
|
elif args.format:
|
|
convert_structure(input_file, output_format=args.format)
|
|
else:
|
|
print("Error: Must specify output file or --format")
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|