Tutorial 1: Getting Started

Learn the basics of py-electrostatic: loading structures, initializing the calculator, and computing energy and forces.

Prerequisites

  • py-electrostatic installed

  • BaTiO3 example files (included in repository)

Step 1: Load Structure

Load a structure with effective charges from a Quantum ESPRESSO dynamical matrix:

import cellconstructor as CC
import cellconstructor.Phonons

dyn = CC.Phonons.Phonons("BaTiO3_")
structure = dyn.structure

print(f"Atoms: {structure.N_atoms}")
print(f"Charges shape: {dyn.effective_charges.shape}")  # (nat, 3, 3)
print(f"Dielectric:\n{dyn.dielectric_tensor}")

Step 2: Initialize Calculator

import pyelectrostatic.calculator as calc

calculator = calc.ElectrostaticCalculator()
calculator.eta = 0.5        # Gaussian screening (Å)
calculator.cutoff = 5.0     # k-point cutoff
calculator.init_from_phonons(dyn)

Step 3: Compute Energy and Forces

atoms = structure.get_ase_atoms()
atoms.calc = calculator

energy = atoms.get_total_energy()
forces = atoms.get_forces()

print(f"Energy: {energy:.6f} eV")
print(f"Max force: {np.max(np.linalg.norm(forces, axis=1)):.6f} eV/Å")

Complete Example

"""
Tutorial 1: Getting Started with py-electrostatic

This example shows the basic usage of py-electrostatic:
1. Load a structure with effective charges
2. Initialize the calculator
3. Compute energy and forces
4. Displace an atom and recompute
"""

import cellconstructor as CC
import cellconstructor.Phonons
import pyelectrostatic.calculator as calc
import numpy as np
import os

# Change to the directory where this script is located
os.chdir(os.path.dirname(os.path.abspath(__file__)))

print("=" * 60)
print("Tutorial 1: Getting Started")
print("=" * 60)

# Step 1: Load the structure with effective charges
print("\n1. Loading structure from dynamical matrix...")
dyn = CC.Phonons.Phonons("BaTiO3_")

structure = dyn.structure
print(f"   Number of atoms: {structure.N_atoms}")
print(f"   Atomic species: {structure.atoms}")
print(f"   Unit cell (Å):\n{structure.unit_cell}")

# Check effective charges and dielectric tensor
print(f"\n   Effective charges shape: {dyn.effective_charges.shape}")
print(f"   Dielectric tensor:\n{dyn.dielectric_tensor}")

# Step 2: Initialize the calculator
print("\n2. Initializing calculator...")
calculator = calc.ElectrostaticCalculator()
calculator.eta = 0.5        # Gaussian screening parameter (Å)
calculator.cutoff = 5.0     # k-point cutoff

# Initialize from phonons (loads structure, charges, and dielectric)
calculator.init_from_phonons(dyn)

print(f"   eta = {calculator.eta} Å")
print(f"   cutoff = {calculator.cutoff}")
print(f"   Number of k-points: {len(calculator.kpoints)}")
print(f"   Julia acceleration: {calc.is_julia_available()}")

# Step 3: Compute energy and forces on reference structure
print("\n3. Computing energy and forces on reference structure...")
atoms = structure.get_ase_atoms()
atoms.calc = calculator

energy = atoms.get_total_energy()
forces = atoms.get_forces()

print(f"   Energy: {energy:.6f} eV")
print(f"   Max force magnitude: {np.max(np.linalg.norm(forces, axis=1)):.6f} eV/Å")

# Step 4: Displace an atom and recompute
print("\n4. Displacing first atom by 0.1 Å in x direction...")
displaced_structure = structure.copy()
displaced_structure.coords[0, 0] += 0.1  # Displace 0.1 Å in x

displaced_atoms = displaced_structure.get_ase_atoms()
displaced_atoms.calc = calculator

new_energy = displaced_atoms.get_total_energy()
new_forces = displaced_atoms.get_forces()

print(f"   New energy: {new_energy:.6f} eV")
print(f"   Energy change: {new_energy - energy:.6f} eV")
print(f"   Force on displaced atom: [{new_forces[0, 0]:.3f}, {new_forces[0, 1]:.3f}, {new_forces[0, 2]:.3f}] eV/Å")
print(f"   Max force magnitude: {np.max(np.linalg.norm(new_forces, axis=1)):.6f} eV/Å")

# Step 5: Check acoustic sum rule
print("\n5. Checking acoustic sum rule (ASR)...")
try:
    calculator.check_asr(threshold=1e-6)
    print("   ✓ Acoustic sum rule satisfied!")
except ValueError as e:
    print(f"   ✗ Acoustic sum rule violated: {e}")

print("\n" + "=" * 60)
print("Tutorial 1 complete!")
print("=" * 60)

Running

python 01_basic_energy_force.py