SSCHA code was updated.

This commit is contained in:
Atsushi Togo 2020-08-26 12:55:17 +09:00
parent d37fe70e6b
commit 3801539196
4 changed files with 188 additions and 31 deletions

View File

@ -36,8 +36,8 @@
Formulae implemented are based on these papers:
Bianco et al. https://doi.org/10.1103/PhysRevB.96.014111
Aseginolaza et al. https://doi.org/10.1103/PhysRevB.100.214307
Ref. 1: Bianco et al. https://doi.org/10.1103/PhysRevB.96.014111
Ref. 2: Aseginolaza et al. https://doi.org/10.1103/PhysRevB.100.214307
"""
@ -48,7 +48,52 @@ from phono3py.phonon.func import mode_length
class SupercellPhonon(object):
def __init__(self, supercell, force_constants, factor=VaspToTHz):
"""Supercell phonon class
Dynamical matrix is created for supercell atoms and solved in real.
All phonons at commensurate points are folded to those at Gamma point.
Phonon eigenvectors are represented in real type.
Attributes
----------
eigenvalues : ndarray
Phonon eigenvalues of supercell dynamical matrix.
shape=(3 * num_satom, ), dtype='double', order='C'
eigenvectors : ndarray
Phonon eigenvectors of supercell dynamical matrix.
shape=(3 * num_satom, 3 * num_satom), dtype='double', order='C'
frequencies : ndarray
Phonon frequencies of supercell dynamical matrix. Frequency conversion
factor to THz is multiplied.
shape=(3 * num_satom, ), dtype='double', order='C'
dynamical_matrix : ndarray
Numerical matrix corresponding to supercell dynamical matrix given
at Gamma point. Therefore no phase factor is multiplied, i.e.,
force constants weighted by atomic masses, 1/sqrt(M_a, M_b).
shape=(3 * num_satom, 3 * num_satom), dtype='double', order='C'
supercell : PhonopyAtoms or its derived class
Supercell.
"""
def __init__(self,
supercell,
force_constants,
frequency_factor_to_THz=VaspToTHz):
"""
Parameters
----------
supercell : PhonopyAtoms
Supercell.
force_constants : array_like
Second order force constants.
shape=(num_satom, num_satom, 3, 3), dtype='double', order='C'
frequency_factor_to_THz : float
Frequency conversion factor to THz.
"""
self._supercell = supercell
_fc2 = np.swapaxes(force_constants, 1, 2)
_fc2 = _fc2.reshape(-1, np.prod(_fc2.shape[-2:]))
@ -56,7 +101,8 @@ class SupercellPhonon(object):
dynmat = np.array(_fc2 / np.sqrt(np.outer(masses, masses)),
dtype='double', order='C')
eigvals, eigvecs = np.linalg.eigh(dynmat)
freqs = np.sqrt(np.abs(eigvals)) * np.sign(eigvals) * factor
freqs = np.sqrt(np.abs(eigvals)) * np.sign(eigvals)
freqs *= frequency_factor_to_THz
self._eigenvalues = np.array(eigvals, dtype='double', order='C')
self._eigenvectors = np.array(eigvecs, dtype='double', order='C')
self._frequencies = np.array(freqs, dtype='double', order='C')
@ -84,11 +130,30 @@ class SupercellPhonon(object):
class DispCorrMatrix(object):
"""Calculate gamma matrix"""
"""Calculate Upsilon matrix
Attributes
----------
upsilon_matrix : ndarray
Displacement-displacement correlation matrix at temperature.
Physical unit is [1/Angstrom^2].
shape=(3 * num_satom, 3 * num_satom), dtype='double', order='C'
"""
def __init__(self, supercell_phonon):
"""
Parameters
----------
supercell_phonon : SupercellPhonon
Supercell phonon object. Phonons at Gamma point, where
eigenvectors are not complex type but real type.
"""
self._supercell_phonon = supercell_phonon
self._gamma_matrix = None
self._upsilon_matrix = None
def run(self, T):
freqs = self._supercell_phonon.frequencies
@ -96,11 +161,13 @@ class DispCorrMatrix(object):
a = mode_length(freqs, T)
masses = np.repeat(self._supercell_phonon.supercell.masses, 3)
gamma = np.dot(eigvecs, np.dot(np.diag(1.0 / a ** 2), eigvecs.T))
self._gamma_matrix = gamma * np.sqrt(np.outer(masses, masses))
self._upsilon_matrix = np.array(
gamma * np.sqrt(np.outer(masses, masses)),
dtype='double', order='C')
@property
def gamma_matrix(self):
return self._gamma_matrix
def upsilon_matrix(self):
return self._upsilon_matrix
class DispCorrMatrixMesh(object):
@ -121,7 +188,7 @@ class DispCorrMatrixMesh(object):
def commensurate_points(self):
return self._d2f.commensurate_points
def create_gamma_matrix(self, frequencies, eigenvectors, T):
def create_upsilon_matrix(self, frequencies, eigenvectors, T):
"""
Parameters
@ -142,5 +209,68 @@ class DispCorrMatrixMesh(object):
self._d2f.run()
@property
def gamma_matrix(self):
def upsilon_matrix(self):
return self._d2f.force_constants
class ThirdOrderFC(object):
r"""SSCHA third order force constants
Eq. 45a in Ref.1 (See top docstring of this file)
\Phi_{abc} = - \sum_{pq} \Upsilon_{ap} \Upsilon_{bq}
\left< u^p u^q \mathfrak{f}_c \right>_{tilde{\rho}_{\mathfrak{R},\Phi}}
\mathfrak{f}_i = f_i - \left[
\left< f_i \right>_{\tilde{\rho}_{\mathfrak{R},\Phi}}
- \sum_j \Phi_{ij}u^j \right]
Attributes
----------
displacements : ndarray
shape=(3 * num_satoms, snap_shots), dtype='double', order='C'
forces : ndarray
shape=(3 * num_satoms, snap_shots), dtype='double', order='C'
fc3 : ndarray
shape=(num_satom, num_satom, num_satom, 3, 3, 3)
"""
def __init__(self, displacements, forces, upsilon_matrix):
"""
Parameters
----------
upsilon_matrix : ndarray
Displacement-displacement correlation matrix at a temperature
point.
shape=(3 * num_satom, 3 * num_satom), dtype='double', order='C'
displacements : ndarray
shape=(snap_shots, num_satom, 3), dtype='double', order='C'
forces : ndarray
shape=(snap_shots, num_satom, 3), dtype='double', order='C'
"""
self._upsilon_matrix = upsilon_matrix
assert (displacements.shape == forces.shape)
shape = displacements.shape
self._displacements = np.array(displacements.reshape(-1, shape[0]),
dtype='double', order='C')
self._forces = np.array(forces.reshape(-1, shape[0]),
dtype='double', order='C')
@property
def displacements(self):
return self._displacements
@property
def displacements(self):
return self._forces
@property
def fc3(self):
return self._fc3
def run(self):
pass

View File

@ -1,5 +1,6 @@
import os
import pytest
import phonopy
import phono3py
current_dir = os.path.dirname(os.path.abspath(__file__))
@ -18,3 +19,10 @@ def si_pbesol():
def si_pbesol_111():
yaml_filename = os.path.join(current_dir, "phono3py_params_Si111.yaml")
return phono3py.load(yaml_filename, log_level=1)
@pytest.fixture(scope='session')
def si_pbesol_iterha_111():
yaml_filename = os.path.join(current_dir,
"phonopy_params-Si111-iterha.yaml.xz")
return phonopy.load(yaml_filename, log_level=1, produce_fc=False)

Binary file not shown.

View File

@ -1,15 +1,16 @@
import pytest
import numpy as np
from phono3py.sscha.sscha import (
DispCorrMatrix, DispCorrMatrixMesh, SupercellPhonon)
DispCorrMatrix, DispCorrMatrixMesh, SupercellPhonon, ThirdOrderFC)
from phonopy.phonon.qpoints import QpointsPhonon
si_pbesol_gamma0_0 = [[3.849187e+02, 0, 0],
[0, 3.849187e+02, 0],
[0, 0, 3.849187e+02]]
si_pbesol_gamma1_34 = [[1.886404, -1.549705, -1.126055],
[-1.549705, 1.886404, -1.126055],
[-1.126055, -1.126055, -0.006187]]
si_pbesol_upsilon0_0 = [[3.849187e+02, 0, 0],
[0, 3.849187e+02, 0],
[0, 0, 3.849187e+02]]
si_pbesol_upsilon1_34 = [[1.886404, -1.549705, -1.126055],
[-1.549705, 1.886404, -1.126055],
[-1.126055, -1.126055, -0.006187]]
si_pbesol_111_freqs = [
0.00000, 0.00000, 0.00000, 4.02839, 4.02839, 4.02839,
4.02839, 4.02839, 4.02839, 12.13724, 12.13724, 12.13724,
@ -23,7 +24,7 @@ def get_supercell_phonon(ph3):
fc2 = ph3.dynamical_matrix.force_constants
supercell = ph3.phonon_supercell
factor = ph3.unit_conversion_factor
return SupercellPhonon(supercell, fc2, factor=factor)
return SupercellPhonon(supercell, fc2, frequency_factor_to_THz=factor)
def test_SupercellPhonon(si_pbesol_111):
@ -32,30 +33,48 @@ def test_SupercellPhonon(si_pbesol_111):
si_pbesol_111_freqs, sph.frequencies, atol=1e-4)
def test_gamma_matrix_mesh(si_pbesol):
def test_upsilon_matrix_mesh(si_pbesol):
si_pbesol.mesh_numbers = [9, 9, 9]
si_pbesol.init_phph_interaction()
dynmat = si_pbesol.dynamical_matrix
gmat = DispCorrMatrixMesh(dynmat.primitive, dynmat.supercell)
qpoints_phonon = QpointsPhonon(gmat.commensurate_points,
upmat = DispCorrMatrixMesh(dynmat.primitive, dynmat.supercell)
qpoints_phonon = QpointsPhonon(upmat.commensurate_points,
dynmat,
with_eigenvectors=True)
freqs = qpoints_phonon.frequencies
eigvecs = qpoints_phonon.eigenvectors
gmat.create_gamma_matrix(freqs, eigvecs, 300.0)
gmat.run()
upmat.create_upsilon_matrix(freqs, eigvecs, 300.0)
upmat.run()
np.testing.assert_allclose(
si_pbesol_gamma0_0, gmat.gamma_matrix[0, 0], atol=1e-4)
si_pbesol_upsilon0_0, upmat.upsilon_matrix[0, 0], atol=1e-4)
np.testing.assert_allclose(
si_pbesol_gamma1_34, gmat.gamma_matrix[1, 34], atol=1e-4)
si_pbesol_upsilon1_34, upmat.upsilon_matrix[1, 34], atol=1e-4)
def test_gamma_matrix(si_pbesol):
def test_upsilon_matrix(si_pbesol):
supercell_phonon = get_supercell_phonon(si_pbesol)
gmat = DispCorrMatrix(supercell_phonon)
gmat.run(300.0)
upmat = DispCorrMatrix(supercell_phonon)
upmat.run(300.0)
np.testing.assert_allclose(
si_pbesol_gamma0_0, gmat.gamma_matrix[0:3, 0:3], atol=1e-4)
si_pbesol_upsilon0_0, upmat.upsilon_matrix[0:3, 0:3], atol=1e-4)
np.testing.assert_allclose(
si_pbesol_gamma1_34, gmat.gamma_matrix[1 * 3: 2 * 3, 34 * 3: 35 * 3],
si_pbesol_upsilon1_34, upmat.upsilon_matrix[1 * 3: 2 * 3, 34 * 3: 35 * 3],
atol=1e-4)
def test_fc3(si_pbesol_iterha_111):
try:
import alm
except ModuleNotFoundError:
pytest.skip("Skip this test because ALM module was not found.")
ph = si_pbesol_iterha_111
ph.produce_force_constants(calculate_full_force_constants=True,
fc_calculator='alm')
supercell_phonon = SupercellPhonon(
ph.supercell, ph.force_constants,
frequency_factor_to_THz=ph.unit_conversion_factor)
upmat = DispCorrMatrix(supercell_phonon)
upmat.run(300.0)
ThirdOrderFC(ph.displacements, ph.forces, upmat.upsilon_matrix)