Quick Start Guide¶
This guide will walk you through the basic workflow for studying NH3 decomposition on a perovskite oxynitride surface.
Overview¶
A typical calculation workflow consists of:
- Build Structure - Create surface from bulk, add defects
- Place Adsorbate - Add NH3 or decomposition intermediates
- Set Up Calculation - Generate VASP inputs
- Run & Analyze - Parse results, calculate properties
Step 1: Build an Oxynitride Surface¶
Load Bulk Structure¶
from nh3sofc.structure import BulkStructure
# From CIF file
bulk = BulkStructure.from_cif("LaVO3.cif")
# Or from ASE/pymatgen
from ase.build import bulk as ase_bulk
bulk_atoms = ase_bulk('Ni', 'fcc', a=3.52)
bulk = BulkStructure(bulk_atoms)
# Check structure
print(f"Formula: {bulk.atoms.get_chemical_formula()}")
print(f"Space group: {bulk.get_spacegroup()}")
Create Surface Slab¶
from nh3sofc.structure import SurfaceBuilder
builder = SurfaceBuilder(bulk)
# Create (001) surface with 6 layers and 15 Å vacuum
surface = builder.create_surface(
miller_index=(0, 0, 1),
layers=6,
vacuum=15.0,
fix_bottom=2 # Fix bottom 2 layers
)
print(f"Slab atoms: {len(surface.atoms)}")
print(f"Cell: {surface.atoms.cell.lengths()}")
Create Oxynitride Defects¶
from nh3sofc.structure import DefectBuilder
defect_builder = DefectBuilder(surface.atoms)
# Create LaVON2-x with 10% vacancies
oxynitride = defect_builder.create_oxynitride(
nitrogen_fraction=0.67, # Replace 2/3 of O with N
vacancy_concentration=0.10 # 10% O/N vacancies
)
print(f"Composition: {oxynitride.get_chemical_formula()}")
Step 2: Place NH3 Adsorbate¶
from nh3sofc.structure import AdsorbatePlacer
placer = AdsorbatePlacer(oxynitride)
# Method 1: On-top of specific atom types
configs = placer.add_on_site(
adsorbate="NH3",
site_type="ontop", # Site type: "ontop", "bridge", or "hollow"
atom_types=["La", "V"], # Only on La or V atoms
height=2.0
)
print(f"Generated {len(configs)} configurations")
# Method 2: Random placement with collision detection
random_configs = placer.add_with_collision(
adsorbate="NH3",
n_configs=10, # Number of configurations to generate
min_distance=2.0,
height=2.0
)
# Method 3: All unique sites (using CatKit if available)
try:
all_sites = placer.add_catkit("NH3", site_type="ontop")
except ImportError:
print("CatKit not installed, using collision-aware placement")
all_sites = random_configs if random_configs else []
Step 3: Set Up VASP Calculation¶
Generate Input Files¶
from nh3sofc.calculators.vasp import VASPInputGenerator
# Select first configuration
atoms = configs[0]
# Create generator
vasp = VASPInputGenerator(
atoms,
calc_type="relax", # Options: relax, static, neb, frequency, md
work_dir="./calc/LaVON_001_NH3"
)
# Generate all input files
files = vasp.generate_all(
encut=520, # Plane-wave cutoff
kspacing=0.03, # K-point spacing
hubbard_u={"V": 3.25}, # DFT+U for V
vdw="D3BJ", # vdW correction
is_surface=True # Surface-specific settings
)
print("Generated files:")
for name, path in files.items():
print(f" {name}: {path}")
Generate PBS Script¶
from nh3sofc.jobs import create_vasp_job
pbs_file = create_vasp_job(
work_dir="./calc/LaVON_001_NH3",
nodes=2,
ppn=24,
walltime="24:00:00",
queue="normal"
)
print(f"Submit with: qsub {pbs_file}")
Step 4: Parse Results¶
After the VASP job completes:
from nh3sofc.calculators.vasp import VASPOutputParser
parser = VASPOutputParser("./calc/LaVON_001_NH3")
# Check convergence
if parser.is_converged():
energy = parser.get_energy()
forces = parser.get_forces()
final_structure = parser.get_final_structure()
print(f"Energy: {energy:.4f} eV")
print(f"Max force: {parser.get_max_force():.4f} eV/Å")
else:
print("Calculation did not converge!")
Step 5: Calculate Adsorption Energy¶
from nh3sofc.analysis import AdsorptionEnergyCalculator
calc = AdsorptionEnergyCalculator()
# Set reference energies (from your calculations)
calc.set_surface_energy(-250.0) # Clean surface energy
calc.set_gas_reference("NH3", -19.54) # Gas phase NH3
# Calculate adsorption energy
E_ads = calc.calculate(
e_total=-270.5, # NH3/surface energy
adsorbate="NH3"
)
print(f"Adsorption energy: {E_ads:.3f} eV")
Complete Workflow Example¶
Here's a complete script for studying NH3 decomposition:
from nh3sofc.structure import BulkStructure, SurfaceBuilder, DefectBuilder
from nh3sofc.structure import DecompositionBuilder
from nh3sofc.workflows import DecompositionWorkflow
# 1. Build oxynitride surface
bulk = BulkStructure.from_cif("LaVO3.cif")
surface = SurfaceBuilder(bulk).create_surface((0,0,1), layers=6, vacuum=15)
oxynitride = DefectBuilder(surface.atoms).create_oxynitride(
nitrogen_fraction=0.67,
vacancy_concentration=0.1
)
# 2. Add NH3 and optimize (assuming you have the relaxed structure)
# nh3_on_surface = ... (load from previous calculation)
# 3. Set up decomposition workflow
workflow = DecompositionWorkflow(
nh3_on_slab=nh3_on_surface,
work_dir="./decomposition",
n_configs_per_step=5,
calculator="vasp",
encut=520,
hubbard_u={"V": 3.25},
)
# 4. Generate all configurations and set up calculations
workflow.setup()
# 5. After calculations complete, analyze results
results = workflow.parse_results()
energy_profile = workflow.get_energy_profile()
workflow.print_summary()