Skip to content

Aligning Polarization Branch in Berry Phase Calculations

Author: Tianyuan Zhu
Date:2025-10-15

1. Multi-valuedness of polarization and polarization branch

Polarization in a periodic crystal exhibits multi-valuedness, depending on the choice of unit cells used to define the electric dipoles. The key point is that one should focus on changes in polarization rather than absolute values, as these changes are uniquely defined and directly correspond to experimentally measurable quantities such as the switching current.

As illustrated in Fig. 1, polarization values \(\mathbf{P_1}\) and \(\mathbf{P_2}\) obtained from different choices of unit cells can even point in opposite directions. Their difference, \(\mathbf{P_q}=\mathbf{P_1}-\mathbf{P_2}\), is referred to as a polarization quanta. For a three-dimensional crystal, the polarization quanta is given by

\[ \mathbf{P}_{\mathbf{q},i} = \frac{1}{\Omega} e \mathbf{R}_i, \]

where \(\Omega\) is the cell volume, \(e\) the elementary charge, \(\mathbf{R}_i\) the lattice basis vector in the \(i\) direction.


Figure 1. Multi-valued polarization in a one-dimensional chain of alternating anions and cations. Dashed rectangles indicate unit cells with lattice parameter $a$. Extracted from Ref. [1].

To determine the spontaneous polarization of a polar structure, one should specify a nonpolar reference structure and establish a continuous polarization branch connecting the nonpolar and polar states. As shown in Fig. 2, the polarization evolves monotonically along the continuous branch; therefore, the correct polarization corresponds to \(\mathbf{P_1}\) rather than \(\mathbf{P_2}\).


Figure 2. Polarization as a function of percentage ferroelectric distortion. Extracted from Ref. [1].

2. Code for polarization branch alignment

In the absence of a priori knowledge of the polarization value for a polar structure, it is necessary to perform a series of Berry-phase calculations for a set of intermediate structures connecting a specified nonpolar reference to the target polar structure. Here, I would like to share a bash script that aligns the polarization branch using the OUTCAR and POSCAR files obtained from these calculations.

In this script, the raw polarization values are obtained by dividing the total dipole moments (ionic + electronic) by the corresponding cell volumes. The target polarization components (Pa_tmp, Pb_tmp, Pc_tmp) for the first, nonpolar reference structure are set to zero. For subsequent structures, the polarization branch is aligned such that the change in polarization between two adjacent structures remains smaller than half of the polarization quantum PQ, i.e., within the range (-PQ/2, PQ/2). Consequently, a sufficient number of intermediate structures must be included, particularly for large supercells where the polarization quanta is typically smaller than that of a unit cell.

Note that the dipole moments reported in the OUTCAR files are expressed in Cartesian coordinates (x, y, z), whereas the polarization quanta are defined along the lattice basis vectors. Therefore, the script includes a coordinate transformation between the Cartesian and lattice basis (a, b, c) representations. This step is particularly important for non-orthogonal lattices.

#!/bin/bash
# This script calculates the polarization variation from nonpolar phase to polar phase, and prints the polarization quanta
# To avoid ambiguity, it is recommended to set the lattice cell of the nonpolar phase the same as that of the polar phase
# The polarization change between two adjacent structures must be smaller than half of the polarization quanta, i.e., within (-PQ/2, PQ/2)
# This script involves transformation between Cartesian coordinates (x,y,z) and lattice basis coordinates (a,b,c)

n=5  # number of structures
const=1602.176565  # polarization unit: e/A^2 --> uC/cm^2

Pa_tmp=0; Pb_tmp=0; Pc_tmp=0
echo "P(uC/cm2)" "Pa" "Pb" "Pc" "Ptot" "PQa" "PQb" "PQc" | awk '{printf "%10s %6s %6s %6s %6s %6s %6s %6s\n",$1,$2,$3,$4,$5,$6,$7,$8}' > P.dat
for((i=1;i<=n;i++)); do
  Dix=$(grep "Ionic dipole moment" $i/OUTCAR | awk '{print $5}')  # dipole: (x,y,z)
  Diy=$(grep "Ionic dipole moment" $i/OUTCAR | awk '{print $6}')
  Diz=$(grep "Ionic dipole moment" $i/OUTCAR | awk '{print $7}')
  Dex=$(grep "Total electronic dipole moment" $i/OUTCAR | awk '{print $6}')
  Dey=$(grep "Total electronic dipole moment" $i/OUTCAR | awk '{print $7}')
  Dez=$(grep "Total electronic dipole moment" $i/OUTCAR | awk '{print $8}')
  Dx=$(echo "(-1)*($Dix+$Dex)" | bc -l)  # dipole: electrons Angst --> eA
  Dy=$(echo "(-1)*($Diy+$Dey)" | bc -l)
  Dz=$(echo "(-1)*($Diz+$Dez)" | bc -l)
  a=($(sed -n '3 p' $i/POSCAR))
  b=($(sed -n '4 p' $i/POSCAR))
  c=($(sed -n '5 p' $i/POSCAR))
  La=$(echo "sqrt(${a[0]}^2+${a[1]}^2+${a[2]}^2)" | bc -l)
  Lb=$(echo "sqrt(${b[0]}^2+${b[1]}^2+${b[2]}^2)" | bc -l)
  Lc=$(echo "sqrt(${c[0]}^2+${c[1]}^2+${c[2]}^2)" | bc -l)
  V=$(echo "${a[0]}*(${b[1]}*${c[2]}+(-1)*${b[2]}*${c[1]})+${a[1]}*(${b[2]}*${c[0]}+(-1)*${b[0]}*${c[2]})+${a[2]}*(${b[0]}*${c[1]}+(-1)*${b[1]}*${c[0]})" | bc -l)
  for((j=0;j<=2;j++)); do
    a_norm[$j]=$(echo "${a[j]}/$La" | bc -l)
    b_norm[$j]=$(echo "${b[j]}/$Lb" | bc -l)
    c_norm[$j]=$(echo "${c[j]}/$Lc" | bc -l)
  done
  determinant=$(echo "${a_norm[0]}*(${b_norm[1]}*${c_norm[2]}+(-1)*${b_norm[2]}*${c_norm[1]}) \
                     +${a_norm[1]}*(${b_norm[2]}*${c_norm[0]}+(-1)*${b_norm[0]}*${c_norm[2]}) \
                     +${a_norm[2]}*(${b_norm[0]}*${c_norm[1]}+(-1)*${b_norm[1]}*${c_norm[0]})" | bc -l)
  a_norm_inv[0]=$(echo "(${b_norm[1]}*${c_norm[2]}+(-1)*${b_norm[2]}*${c_norm[1]})/$determinant" | bc -l)
  a_norm_inv[1]=$(echo "(${c_norm[1]}*${a_norm[2]}+(-1)*${c_norm[2]}*${a_norm[1]})/$determinant" | bc -l)
  a_norm_inv[2]=$(echo "(${a_norm[1]}*${b_norm[2]}+(-1)*${a_norm[2]}*${b_norm[1]})/$determinant" | bc -l)
  b_norm_inv[0]=$(echo "(${b_norm[2]}*${c_norm[0]}+(-1)*${b_norm[0]}*${c_norm[2]})/$determinant" | bc -l)
  b_norm_inv[1]=$(echo "(${c_norm[2]}*${a_norm[0]}+(-1)*${c_norm[0]}*${a_norm[2]})/$determinant" | bc -l)
  b_norm_inv[2]=$(echo "(${a_norm[2]}*${b_norm[0]}+(-1)*${a_norm[0]}*${b_norm[2]})/$determinant" | bc -l)
  c_norm_inv[0]=$(echo "(${b_norm[0]}*${c_norm[1]}+(-1)*${b_norm[1]}*${c_norm[0]})/$determinant" | bc -l)
  c_norm_inv[1]=$(echo "(${c_norm[0]}*${a_norm[1]}+(-1)*${c_norm[1]}*${a_norm[0]})/$determinant" | bc -l)
  c_norm_inv[2]=$(echo "(${a_norm[0]}*${b_norm[1]}+(-1)*${a_norm[1]}*${b_norm[0]})/$determinant" | bc -l)
  Da=$(echo "${a_norm_inv[0]}*$Dx+${b_norm_inv[0]}*$Dy+${c_norm_inv[0]}*$Dz" | bc -l)  # dipole: (x,y,z) --> (a,b,c)
  Db=$(echo "${a_norm_inv[1]}*$Dx+${b_norm_inv[1]}*$Dy+${c_norm_inv[1]}*$Dz" | bc -l)
  Dc=$(echo "${a_norm_inv[2]}*$Dx+${b_norm_inv[2]}*$Dy+${c_norm_inv[2]}*$Dz" | bc -l)
  Pa=$(echo "$const*$Da/$V" | bc -l)  # polarization: (a,b,c)
  Pb=$(echo "$const*$Db/$V" | bc -l)
  Pc=$(echo "$const*$Dc/$V" | bc -l)
  PQa=$(echo "$const*$La/$V" | bc -l)  # polarization quanta PQ
  PQb=$(echo "$const*$Lb/$V" | bc -l)
  PQc=$(echo "$const*$Lc/$V" | bc -l)
  dPa=$(echo "$Pa+(-1)*$Pa_tmp" | bc -l)  # polarization change between two adjacent structures
  dPb=$(echo "$Pb+(-1)*$Pb_tmp" | bc -l)
  dPc=$(echo "$Pc+(-1)*$Pc_tmp" | bc -l)
  dPa=$(echo "$dPa % $PQa" | bc)  # constrain dP within (-PQ/2, PQ/2)
  if [ `echo "$dPa/$PQa > 0.5" | bc -l` -eq 1 ]; then
    dPa=$(echo "$dPa+(-1)*$PQa" | bc -l)
  elif [ `echo "$dPa/$PQa < -0.5" | bc -l` -eq 1 ]; then
    dPa=$(echo "$dPa+$PQa" | bc -l)
  fi
  dPb=$(echo "$dPb % $PQb" | bc)
  if [ `echo "$dPb/$PQb > 0.5" | bc -l` -eq 1 ]; then
    dPb=$(echo "$dPb+(-1)*$PQb" | bc -l)
  elif [ `echo "$dPb/$PQb < -0.5" | bc -l` -eq 1 ]; then
    dPb=$(echo "$dPb+$PQb" | bc -l)
  fi
  dPc=$(echo "$dPc % $PQc" | bc)
  if [ `echo "$dPc/$PQc > 0.5" | bc -l` -eq 1 ]; then
    dPc=$(echo "$dPc+(-1)*$PQc" | bc -l)
  elif [ `echo "$dPc/$PQc < -0.5" | bc -l` -eq 1 ]; then
    dPc=$(echo "$dPc+$PQc" | bc -l)
  fi
  Pa=$(echo "$dPa+$Pa_tmp" | bc -l)
  Pb=$(echo "$dPb+$Pb_tmp" | bc -l)
  Pc=$(echo "$dPc+$Pc_tmp" | bc -l)
  Pa_tmp=$Pa; Pb_tmp=$Pb; Pc_tmp=$Pc
  Px=$(echo "${a_norm[0]}*$Pa+${b_norm[0]}*$Pb+${c_norm[0]}*$Pc" | bc -l)  # polarization: (a,b,c) --> (x,y,z)
  Py=$(echo "${a_norm[1]}*$Pa+${b_norm[1]}*$Pb+${c_norm[1]}*$Pc" | bc -l)
  Pz=$(echo "${a_norm[2]}*$Pa+${b_norm[2]}*$Pb+${c_norm[2]}*$Pc" | bc -l)
  Ptot=$(echo "sqrt($Px^2+$Py^2+$Pz^2)" | bc -l)
  echo $i $Pa $Pb $Pc $Ptot $PQa $PQb $PQc| awk '{printf "%10s %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f\n",$1,$2,$3,$4,$5,$6,$7,$8}' >> P.dat
done
cat P.dat

As an example, the aligned polarization results are shown for the three polar phases of \(\mathrm{BaTiO}_3\): P4mm, Amm2, and R3m, which exhibit spontaneous polarizations along the [001], [110], and [111] directions, respectively. All polarization values are expressed in units of \(\mathrm{\mu C/cm^2}\). The components (Pa, Pb, Pc) represent the polarization projected along the lattice basis vectors (a, b, c), whereas (PQa, PQb, PQc) denote the corresponding polarization quanta along these directions. The outputs correctly reproduce the expected polarization orientations for the different polar phases. Moreover, the polarization varies monotonically along structures 1–5, where structure 1 corresponds to the nonpolar reference and structure 5 to the polar phase.

P4mm:

1
2
3
4
5
6
 P(uC/cm2)     Pa     Pb     Pc   Ptot    PQa    PQb    PQc
         1   0.00   0.00   0.00   0.00  99.33  99.33 101.82
         2   0.00   0.00   9.24   9.24  99.33  99.33 101.82
         3   0.00   0.00  18.17  18.17  99.33  99.33 101.82
         4   0.00   0.00  26.63  26.63  99.33  99.33 101.82
         5   0.00   0.00  34.60  34.60  99.33  99.33 101.82

Amm2:

1
2
3
4
5
6
 P(uC/cm2)     Pa     Pb     Pc   Ptot    PQa    PQb    PQc
         1   0.00   0.00   0.00   0.00 100.51 100.51  98.88
         2   7.29   7.29   0.00  10.34 100.51 100.51  98.88
         3  14.33  14.33   0.00  20.30 100.51 100.51  98.88
         4  20.94  20.94   0.00  29.67 100.51 100.51  98.88
         5  27.08  27.08   0.00  38.37 100.51 100.51  98.88

R3m:

1
2
3
4
5
6
 P(uC/cm2)     Pa     Pb     Pc   Ptot    PQa    PQb    PQc
         1   0.00   0.00   0.00   0.00  99.93  99.93  99.93
         2   6.09   6.09   6.09  10.58  99.93  99.93  99.93
         3  11.97  11.97  11.97  20.78  99.93  99.93  99.93
         4  17.47  17.47  17.47  30.34  99.93  99.93  99.93
         5  22.55  22.55  22.55  39.16  99.93  99.93  99.93

References

[1] Nicola A. Spaldin, A beginner’s guide to the modern theory of polarization, J. Solid State Chem. 195, 2 (2012).

[2] R. Resta, Theory of the electric polarization in crystals, Ferroelectrics, 136, 51 (1992).

[3] R. D. King-Smith and David Vanderbilt, Theory of polarization of crystalline solids, Phys. Rev. B 47, 1651 (1993).

[4] David Vanderbilt and R. D. King-Smith, Electric polarization as a bulk quantity and its relation to surface charge, Phys. Rev. B 48, 4442 (1993).

[5] R. Resta, Macroscopic polarization in crystalline dielectrics: the geometric phase approach, Rev. Mod. Phys. 66, 899 (1994).