Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:30:10 +08:00
commit f0bd18fb4e
824 changed files with 331919 additions and 0 deletions

View File

@@ -0,0 +1,233 @@
#!/usr/bin/env python3
"""
Phase diagram generator using Materials Project data.
This script generates phase diagrams for chemical systems using data from the
Materials Project database via pymatgen's MPRester.
Usage:
python phase_diagram_generator.py chemical_system [options]
Examples:
python phase_diagram_generator.py Li-Fe-O
python phase_diagram_generator.py Li-Fe-O --output li_fe_o_pd.png
python phase_diagram_generator.py Fe-O --show
python phase_diagram_generator.py Li-Fe-O --analyze "LiFeO2"
"""
import argparse
import os
import sys
from pathlib import Path
try:
from pymatgen.core import Composition
from pymatgen.analysis.phase_diagram import PhaseDiagram, PDPlotter
except ImportError:
print("Error: pymatgen is not installed. Install with: pip install pymatgen")
sys.exit(1)
try:
from mp_api.client import MPRester
except ImportError:
print("Error: mp-api is not installed. Install with: pip install mp-api")
sys.exit(1)
def get_api_key() -> str:
"""Get Materials Project API key from environment."""
api_key = os.environ.get("MP_API_KEY")
if not api_key:
print("Error: MP_API_KEY environment variable not set.")
print("Get your API key from https://next-gen.materialsproject.org/")
print("Then set it with: export MP_API_KEY='your_key_here'")
sys.exit(1)
return api_key
def generate_phase_diagram(chemsys: str, args):
"""
Generate and analyze phase diagram for a chemical system.
Args:
chemsys: Chemical system (e.g., "Li-Fe-O")
args: Command line arguments
"""
api_key = get_api_key()
print(f"\n{'='*60}")
print(f"PHASE DIAGRAM: {chemsys}")
print(f"{'='*60}\n")
# Get entries from Materials Project
print("Fetching data from Materials Project...")
with MPRester(api_key) as mpr:
entries = mpr.get_entries_in_chemsys(chemsys)
print(f"✓ Retrieved {len(entries)} entries")
if len(entries) == 0:
print(f"Error: No entries found for chemical system {chemsys}")
sys.exit(1)
# Build phase diagram
print("Building phase diagram...")
pd = PhaseDiagram(entries)
# Get stable entries
stable_entries = pd.stable_entries
print(f"✓ Phase diagram constructed with {len(stable_entries)} stable phases")
# Print stable phases
print("\n--- STABLE PHASES ---")
for entry in stable_entries:
formula = entry.composition.reduced_formula
energy = entry.energy_per_atom
print(f" {formula:<20} E = {energy:.4f} eV/atom")
# Analyze specific composition if requested
if args.analyze:
print(f"\n--- STABILITY ANALYSIS: {args.analyze} ---")
try:
comp = Composition(args.analyze)
# Find closest entry
closest_entry = None
min_distance = float('inf')
for entry in entries:
if entry.composition.reduced_formula == comp.reduced_formula:
closest_entry = entry
break
if closest_entry:
# Calculate energy above hull
e_above_hull = pd.get_e_above_hull(closest_entry)
print(f"Energy above hull: {e_above_hull:.4f} eV/atom")
if e_above_hull < 0.001:
print(f"Status: STABLE (on convex hull)")
elif e_above_hull < 0.05:
print(f"Status: METASTABLE (nearly stable)")
else:
print(f"Status: UNSTABLE")
# Get decomposition
decomp = pd.get_decomposition(comp)
print(f"\nDecomposes to:")
for entry, fraction in decomp.items():
formula = entry.composition.reduced_formula
print(f" {fraction:.3f} × {formula}")
# Get reaction energy
rxn_energy = pd.get_equilibrium_reaction_energy(closest_entry)
print(f"\nDecomposition energy: {rxn_energy:.4f} eV/atom")
else:
print(f"No entry found for composition {args.analyze}")
print("Checking stability of hypothetical composition...")
# Analyze hypothetical composition
decomp = pd.get_decomposition(comp)
print(f"\nWould decompose to:")
for entry, fraction in decomp.items():
formula = entry.composition.reduced_formula
print(f" {fraction:.3f} × {formula}")
except Exception as e:
print(f"Error analyzing composition: {e}")
# Get chemical potentials
if args.chemical_potentials:
print("\n--- CHEMICAL POTENTIALS ---")
print("(at stability regions)")
try:
chempots = pd.get_all_chempots()
for element, potentials in chempots.items():
print(f"\n{element}:")
for potential in potentials[:5]: # Show first 5
print(f" {potential:.4f} eV")
except Exception as e:
print(f"Could not calculate chemical potentials: {e}")
# Plot phase diagram
print("\n--- GENERATING PLOT ---")
plotter = PDPlotter(pd, show_unstable=args.show_unstable)
if args.output:
output_path = Path(args.output)
plotter.write_image(str(output_path), image_format=output_path.suffix[1:])
print(f"✓ Phase diagram saved to {output_path}")
if args.show:
print("Opening interactive plot...")
plotter.show()
print(f"\n{'='*60}\n")
def main():
parser = argparse.ArgumentParser(
description="Generate phase diagrams using Materials Project data",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Requirements:
- Materials Project API key (set MP_API_KEY environment variable)
- mp-api package: pip install mp-api
Examples:
%(prog)s Li-Fe-O
%(prog)s Li-Fe-O --output li_fe_o_phase_diagram.png
%(prog)s Fe-O --show --analyze "Fe2O3"
%(prog)s Li-Fe-O --analyze "LiFeO2" --show-unstable
"""
)
parser.add_argument(
"chemsys",
help="Chemical system (e.g., Li-Fe-O, Fe-O)"
)
parser.add_argument(
"--output", "-o",
help="Output file for phase diagram plot (PNG, PDF, SVG)"
)
parser.add_argument(
"--show", "-s",
action="store_true",
help="Show interactive plot"
)
parser.add_argument(
"--analyze", "-a",
help="Analyze stability of specific composition (e.g., LiFeO2)"
)
parser.add_argument(
"--show-unstable",
action="store_true",
help="Include unstable phases in plot"
)
parser.add_argument(
"--chemical-potentials",
action="store_true",
help="Calculate chemical potentials"
)
args = parser.parse_args()
# Validate chemical system format
elements = args.chemsys.split("-")
if len(elements) < 2:
print("Error: Chemical system must contain at least 2 elements")
print("Example: Li-Fe-O")
sys.exit(1)
# Generate phase diagram
generate_phase_diagram(args.chemsys, args)
if __name__ == "__main__":
main()