Pseudopotential Selection in VASP#

Choosing the right pseudopotential (POTCAR) is critical for accurate VASP calculations. This tutorial covers:

  • Types of VASP pseudopotentials and naming conventions

  • When to use each variant

  • How to specify custom setups in the calculator

  • ENMAX/ENCUT considerations

POTCAR Variants#

VASP uses PAW (Projector Augmented Wave) pseudopotentials. For each element, multiple versions are available:

Suffix

Meaning

Description

(none)

Standard

Default, computationally efficient

_pv

p-valence

Includes semi-core p states

_sv

Semi-core valence

Includes more core states

_d

d-electrons

Includes d states for main group

_h

Hard

Higher cutoff, more accurate

_s

Soft

Lower cutoff, faster

_GW

GW-ready

For GW calculations

Example 1: Transition Metals (Fe)#

For 3d transition metals, the standard POTCAR freezes 3s3p electrons. This can cause errors in:

  • Magnetic properties

  • Oxide compounds

  • High-pressure calculations

Recommendation: Use _pv for transition metal oxides and magnetic systems.

from ase.build import bulk

from vasp import Vasp

# Create BCC Fe
fe = bulk('Fe', 'bcc', a=2.87)
fe.set_initial_magnetic_moments([2.5])
# Standard Fe POTCAR (8 valence electrons: 3d6 4s2)
# Freezes 3s and 3p core electrons

calc_standard = Vasp(
    label='results/fe_standard',
    atoms=fe.copy(),
    xc='PBE',
    encut=400,
    kpts=(12, 12, 12),
    ispin=2,
    # No setups = use default Fe POTCAR
)

print("Standard Fe: 8 valence electrons (3d6 4s2)")
print("ENCUT = 400 eV is sufficient")
Standard Fe: 8 valence electrons (3d6 4s2)
ENCUT = 400 eV is sufficient
# Fe_pv POTCAR (14 valence electrons: 3p6 3d6 4s2)
# Includes 3p semi-core states

calc_pv = Vasp(
    label='results/fe_pv',
    atoms=fe.copy(),
    xc='PBE',
    encut=450,  # Higher cutoff needed for _pv
    kpts=(12, 12, 12),
    ispin=2,
    setups={'Fe': 'pv'},  # Use Fe_pv POTCAR
)

print("Fe_pv: 14 valence electrons (3p6 3d6 4s2)")
print("ENCUT = 450 eV recommended")
print("More accurate for oxides and magnetic systems")
Fe_pv: 14 valence electrons (3p6 3d6 4s2)
ENCUT = 450 eV recommended
More accurate for oxides and magnetic systems

Example 2: Perovskite Oxides (SrTiO₃)#

For perovskites (ABO₃), recommended setups:

  • A-site (Sr, Ba, Ca): Use _sv or _pv

  • B-site (Ti, Zr, Fe): Use _pv

  • O: Standard is usually fine

from ase import Atoms

# Create cubic SrTiO3
a = 3.905  # Lattice constant in Å

srtio3 = Atoms(
    'SrTiO3',
    positions=[
        (0.0, 0.0, 0.0),      # Sr at corner
        (a/2, a/2, a/2),      # Ti at body center
        (a/2, a/2, 0.0),      # O at face centers
        (a/2, 0.0, a/2),
        (0.0, a/2, a/2),
    ],
    cell=[a, a, a],
    pbc=True,
)

print(f"SrTiO3 unit cell: {len(srtio3)} atoms")
print(f"Lattice constant: {a} Å")
SrTiO3 unit cell: 5 atoms
Lattice constant: 3.905 Å
# Recommended setups for perovskites
setups = {
    'Sr': 'sv',  # Include 4s4p semi-core (10 valence e-)
    'Ti': 'pv',  # Include 3p semi-core (10 valence e-)
    'O': '',     # Standard O is fine (6 valence e-)
}

calc = Vasp(
    label='results/srtio3',
    atoms=srtio3,
    xc='PBE',
    encut=520,  # Higher cutoff for _sv/_pv
    kpts=(6, 6, 6),
    setups=setups,
)

print("Setups:")
for elem, setup in setups.items():
    variant = f"_{setup}" if setup else " (standard)"
    print(f"  {elem}: {elem}{variant}")
Setups:
  Sr: Sr_sv
  Ti: Ti_pv
  O: O (standard)

Example 3: Battery Materials (LiFePO₄)#

For Li-ion battery cathodes:

  • Li: Use _sv (CRITICAL - treats 1s as valence)

  • Transition metals: Use _pv

  • P, O: Standard is fine

Why Li_sv is important#

POTCAR

Valence e⁻

Core

Notes

Li

1

1s²

May underestimate Li binding

Li_sv

3

none

Accurate for intercalation voltages

# Battery material setups
battery_setups = {
    'Li': 'sv',  # CRITICAL: Include 1s electrons (3 valence e-)
    'Fe': 'pv',  # Include 3p semi-core (14 valence e-)
    'P': '',     # Standard is fine (5 valence e-)
    'O': '',     # Standard is fine (6 valence e-)
}

print("Recommended setups for LiFePO4:")
for elem, setup in battery_setups.items():
    variant = f"_{setup}" if setup else " (standard)"
    print(f"  {elem}: {elem}{variant}")

print("\nNote: Li_sv requires ENCUT ≥ 650 eV due to high ENMAX (499 eV)")
Recommended setups for LiFePO4:
  Li: Li_sv
  Fe: Fe_pv
  P: P (standard)
  O: O (standard)

Note: Li_sv requires ENCUT ≥ 650 eV due to high ENMAX (499 eV)

ENCUT Recommendations#

Each POTCAR has an ENMAX value (recommended minimum plane-wave cutoff).

Rule of thumb: ENCUT 1.3 × max(ENMAX)

Typical ENMAX values (eV)#

Element

Standard

_pv

_sv

Notes

Li

140

-

499

Use _sv for batteries

Na

102

265

646

Use _pv minimum

K

117

117

249

Standard already has 3s3p

Ca

267

267

267

All variants similar

Ti

178

222

275

Use _pv for oxides

Fe

268

293

391

Use _pv for oxides

O

400

-

-

Standard is fine

Sr

-

-

229

Use _sv for perovskites

# ENCUT calculation helper
def recommend_encut(elements_enmax: dict, factor: float = 1.3) -> int:
    """Calculate recommended ENCUT from element ENMAX values."""
    max_enmax = max(elements_enmax.values())
    encut = int(factor * max_enmax / 10) * 10  # Round to nearest 10
    return encut

# Example: Fe2O3 with Fe_pv
fe2o3_enmax = {'Fe_pv': 293, 'O': 400}
print(f"Fe2O3 (Fe_pv): max ENMAX = {max(fe2o3_enmax.values())} eV")
print(f"Recommended ENCUT = {recommend_encut(fe2o3_enmax)} eV")

print()

# Example: LiFePO4 with Li_sv, Fe_pv
lifepo4_enmax = {'Li_sv': 499, 'Fe_pv': 293, 'P': 255, 'O': 400}
print(f"LiFePO4 (Li_sv, Fe_pv): max ENMAX = {max(lifepo4_enmax.values())} eV")
print(f"Recommended ENCUT = {recommend_encut(lifepo4_enmax)} eV")
Fe2O3 (Fe_pv): max ENMAX = 400 eV
Recommended ENCUT = 520 eV

LiFePO4 (Li_sv, Fe_pv): max ENMAX = 499 eV
Recommended ENCUT = 640 eV

Material-Specific Recommendations#

Perovskite Oxides (ABO₃)#

perovskite_setups = {
    # A-site
    'Sr': 'sv', 'Ba': 'sv', 'Ca': 'pv', 'La': '', 'Pb': 'd',
    # B-site
    'Ti': 'pv', 'Zr': 'sv', 'Fe': 'pv', 'Mn': 'pv', 'Nb': 'pv',
    # Oxygen
    'O': '',
}

print("Perovskite oxide setups:")
print("  A-site: Sr_sv, Ba_sv, Ca_pv, La (std), Pb_d")
print("  B-site: Ti_pv, Zr_sv, Fe_pv, Mn_pv, Nb_pv")
print("  O: standard")
print("  ENCUT: 520 eV")
Perovskite oxide setups:
  A-site: Sr_sv, Ba_sv, Ca_pv, La (std), Pb_d
  B-site: Ti_pv, Zr_sv, Fe_pv, Mn_pv, Nb_pv
  O: standard
  ENCUT: 520 eV

Battery Cathode Materials#

battery_setups = {
    # Alkali
    'Li': 'sv', 'Na': 'pv',
    # Transition metals
    'Fe': 'pv', 'Mn': 'pv', 'Co': '', 'Ni': '',
    # Anions
    'O': '', 'P': '', 'S': '',
}

print("Battery cathode setups:")
print("  Alkali: Li_sv (critical!), Na_pv")
print("  TM: Fe_pv, Mn_pv, Co (std), Ni (std)")
print("  Anions: O, P, S (all standard)")
print("  ENCUT: 520 eV (650 eV with Li_sv)")
Battery cathode setups:
  Alkali: Li_sv (critical!), Na_pv
  TM: Fe_pv, Mn_pv, Co (std), Ni (std)
  Anions: O, P, S (all standard)
  ENCUT: 520 eV (650 eV with Li_sv)

Semiconductors#

# Standard potentials usually sufficient for semiconductors
semiconductor_setups = {
    'Si': '',   # Standard
    'Ge': 'd',  # Include d for better band structure
    'Ga': 'd',  # Include d
    'As': '',   # Standard
    'N': '',    # Standard
}

print("Semiconductor setups:")
print("  Group IV: Si (std), Ge_d")
print("  III-V: Ga_d, As (std), N (std)")
print("  ENCUT: 400-520 eV")
Semiconductor setups:
  Group IV: Si (std), Ge_d
  III-V: Ga_d, As (std), N (std)
  ENCUT: 400-520 eV

Summary: Quick Reference#

When to use _pv#

  • 3d transition metals in oxides

  • Magnetic systems

  • High-pressure calculations

When to use _sv#

  • Alkali metals (Li, Na, K) in batteries

  • Alkaline earth metals (Ca, Sr, Ba) in perovskites

  • When highest accuracy is needed

General guidelines#

  1. Check VASP wiki for specific recommendations

  2. Test convergence with ENCUT for your system

  3. Compare variants for critical properties

  4. Document your choices for reproducibility

# Complete example with all parameters
from ase import Atoms
from ase.build import bulk

from vasp import Vasp

# Example: Fe2O3 (hematite) - create manually since ASE doesn't have corundum
# Using a simplified rhombohedral cell
a = 5.035  # Lattice parameter in Å
c = 13.747

# Create Fe2O3 with hexagonal setting (simplified 2 formula units)
fe2o3 = Atoms(
    symbols=['Fe', 'Fe', 'Fe', 'Fe', 'O', 'O', 'O', 'O', 'O', 'O'],
    scaled_positions=[
        (0.0, 0.0, 0.355),    # Fe
        (0.0, 0.0, 0.145),    # Fe
        (0.0, 0.0, 0.645),    # Fe
        (0.0, 0.0, 0.855),    # Fe
        (0.306, 0.0, 0.25),   # O
        (0.0, 0.306, 0.25),   # O
        (0.694, 0.694, 0.25), # O
        (0.694, 0.0, 0.75),   # O
        (0.0, 0.694, 0.75),   # O
        (0.306, 0.306, 0.75), # O
    ],
    cell=[(a, 0, 0),
          (-a/2, a*0.866, 0),
          (0, 0, c)],
    pbc=True,
)

calc = Vasp(
    label='results/fe2o3',
    atoms=fe2o3,
    xc='PBE',
    setups={
        'Fe': 'pv',  # Include 3p semi-core
        'O': '',     # Standard oxygen
    },
    encut=520,       # 1.3 × max(ENMAX)
    kpts=(4, 4, 2),
    ispin=2,         # Spin-polarized for Fe
    lorbit=11,       # Project onto atoms
)

print("Fe2O3 (hematite) calculation configured with:")
print(f"  Atoms: {len(fe2o3)} ({fe2o3.get_chemical_formula()})")
print(f"  setups = {calc.parameters.get('setups', {})}")
print(f"  encut = {calc.parameters.get('encut')} eV")
Fe2O3 (hematite) calculation configured with:
  Atoms: 10 (Fe4O6)
  setups = {'Fe': 'pv', 'O': ''}
  encut = 520 eV

References#