Source code for ase2sprkkr.asr.test.test_piezoelectrictensor

from ase.units import Bohr
import numpy as np
import pytest


[docs] def zero_pad_non_pbc_strain_directions(matrix_cvv, pbc_c): return matrix_cvv * pbc_c[None] * pbc_c[None, None]
[docs] def get_strain_from_atoms(inv_cell_vc, atoms): return np.dot(inv_cell_vc, atoms.get_cell() / Bohr) - np.eye(3)
[docs] @pytest.mark.ci @pytest.mark.parametrize("nspins", [1, 2]) def test_piezoelectrictensor(asr_tmpdir_w_params, mockgpaw, mocker, test_material, nspins, get_webcontent): import numpy as np from gpaw import GPAW cell_cv = test_material.get_cell() / Bohr pbc_c = test_material.get_pbc() inv_cell_vc = np.linalg.inv(cell_cv) # dphase_c / dstrain_vv dpde_cvv = zero_pad_non_pbc_strain_directions( np.array([np.eye(3)] * 3), pbc_c, ) # ddipol_v / dstrain_vv ddipolde_vvv = zero_pad_non_pbc_strain_directions( np.array([np.eye(3)] * 3), pbc_c, ) # Also move atomic positions natoms = len(test_material) dsposde_acvv = np.zeros((natoms, 3, 3, 3), float) dsposde_acvv[:, :] = np.eye(3) dsposde_acvv *= pbc_c[None, None] * pbc_c[None, None, None] spos_ac = test_material.get_scaled_positions(wrap=True) def _get_berry_phases(self, dir=0, spin=0): strain_vv = get_strain_from_atoms(inv_cell_vc, self.atoms) phase_c = np.dot(dpde_cvv.reshape(3, -1), strain_vv.reshape(-1)) return [phase_c[dir]] def _get_scaled_positions(self): strain_vv = get_strain_from_atoms(inv_cell_vc, self.atoms) dspos_ac = np.dot(dsposde_acvv.reshape(natoms, 3, -1), strain_vv.reshape(-1)) return spos_ac + dspos_ac def _get_dipole_moment(self): strain_vv = get_strain_from_atoms(inv_cell_vc, self.atoms) dipol_v = np.dot(ddipolde_vvv.reshape(3, -1), strain_vv.reshape(-1)) return dipol_v def _get_setup_nvalence(self, element_number): return 1 def get_number_of_spins(self): return nspins mocker.patch.object(GPAW, '_get_berry_phases', new=_get_berry_phases) mocker.patch.object(GPAW, '_get_dipole_moment', new=_get_dipole_moment) mocker.patch.object(GPAW, '_get_scaled_positions', new=_get_scaled_positions) mocker.patch.object(GPAW, '_get_setup_nvalence', new=_get_setup_nvalence) mocker.patch.object(GPAW, 'get_number_of_spins', new=get_number_of_spins) from ase.io import write from asr.piezoelectrictensor import main write('structure.json', test_material) results = main() content = get_webcontent() N = np.abs(np.linalg.det(cell_cv[~pbc_c][:, ~pbc_c])) vol = test_material.get_volume() / Bohr**3 # Formula for piezoeletric tensor # (The last factor of 2 is for spins) eps_berry_analytic_vvv = np.tensordot( cell_cv, dpde_cvv, axes=([0], [0]) ) / (2 * np.pi * vol) * N * 2 eps_dipole_analytic_vvv = ddipolde_vvv / (vol * Bohr) * N Z_a = [1] * natoms eps_atomic_analytic_vvv = np.tensordot( cell_cv, np.tensordot( Z_a, dsposde_acvv, axes=([0], [0]), ), axes=([0], [0]) ) / vol * N eps_analytic_vvv = np.zeros((3, 3, 3), float) eps_analytic_vvv[pbc_c] = (eps_berry_analytic_vvv[pbc_c] + eps_atomic_analytic_vvv[pbc_c]) eps_analytic_vvv[~pbc_c] = eps_dipole_analytic_vvv[~pbc_c] eps_vvv = results['eps_vvv'] eps_clamped_vvv = results['eps_clamped_vvv'] assert eps_vvv == pytest.approx(eps_analytic_vvv) assert eps_clamped_vvv == pytest.approx(eps_analytic_vvv) assert "Piezoelectrictensor" in content, content