Skip to content

Commit

Permalink
Merge phonopy PR #178 (not PR of phono3py)
Browse files Browse the repository at this point in the history
  • Loading branch information
atztogo committed Mar 5, 2022
1 parent 435669e commit 42a23c8
Show file tree
Hide file tree
Showing 6 changed files with 1,109 additions and 0 deletions.
233 changes: 233 additions & 0 deletions phono3py/phonon/velocity_operator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
"""Velocity operator of Simoncelli, Marzari, and Mauri."""
# Copyright (C) 2013 Atsushi Togo
# All rights reserved.
#
# This file is part of phonopy.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# * Neither the name of the phonopy project nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import numpy as np
from phonopy.phonon.group_velocity import GroupVelocity
from phonopy.units import VaspToTHz


class VelocityOperator(GroupVelocity):
"""Class to calculate velocity operator of phonons."""

def __init__(
self,
dynamical_matrix,
q_length=None,
symmetry=None,
frequency_factor_to_THz=VaspToTHz,
cutoff_frequency=1e-4,
):
"""Init method.
dynamical_matrix : DynamicalMatrix or DynamicalMatrixNAC
Dynamical matrix class instance.
q_length : float
This is used such as D(q + q_length) - D(q - q_length) for
calculating finite difference of dynamical matrix.
Default is None, which gives 1e-5.
symmetry : Symmetry
This is used to symmetrize group velocity at each q-points.
Default is None, which means no symmetrization.
frequency_factor_to_THz : float
Unit conversion factor to convert to THz. Default is VaspToTHz.
cutoff_frequency : float
Group velocity is set zero if phonon frequency is below this value.
"""
self._dynmat = dynamical_matrix
primitive = dynamical_matrix.primitive
self._reciprocal_lattice_inv = primitive.cell
self._reciprocal_lattice = np.linalg.inv(self._reciprocal_lattice_inv)
self._q_length = q_length
if self._q_length is None:
self._q_length = 5e-6
self._symmetry = symmetry
self._factor = frequency_factor_to_THz
self._cutoff_frequency = cutoff_frequency

self._directions = np.array(
[
[
1,
2,
3,
],
# this is a random direction, not used and left here for historical
# reasons.
[1, 0, 0], # x
[0, 1, 0], # y
[0, 0, 1],
],
dtype="double",
) # z
self._directions[0] /= np.linalg.norm(
self._directions[0]
) # normalize the random direction

self._q_points = None
self._velocity_operators = None
self._perturbation = None

def run(self, q_points, perturbation=None):
"""Velocity operators are computed at q-points.
q_points : Array-like
List of q-points such as [[0, 0, 0], [0.1, 0.2, 0.3], ...].
perturbation : Array-like
Direction in fractional coordinates of reciprocal space.
"""
self._q_points = q_points
self._perturbation = perturbation
if perturbation is None:
# Give a random direction to break symmetry
self._directions[0] = np.array([1, 0, 0]) # normalized later
else:
self._directions[0] = np.dot(self._reciprocal_lattice, perturbation)
self._directions[0] /= np.linalg.norm(self._directions[0])

gv_operator = [
self._calculate_velocity_operator_at_q(q) for q in self._q_points
]
self._velocity_operators = np.array(gv_operator, dtype="complex", order="C")

@property
def velocity_operators(self):
"""Return velocity operators."""
return self._velocity_operators

def _calculate_velocity_operator_at_q(self, q):

self._dynmat.set_dynamical_matrix(q)
dm = self._dynmat.get_dynamical_matrix()
eigvals, eigvecs = np.linalg.eigh(dm)
eigvals = eigvals.real
freqs = np.sqrt(abs(eigvals)) * np.sign(eigvals) * self._factor
nat3 = len(freqs)
gv_operator = np.zeros((nat3, nat3, 3), dtype="complex", order="C")
#
# compute the finite differences along several directions
# ddms is a list of FD derivatives of the dynamical matrix
# computed along several directions
ddms = self._get_dsqrtD_FD(np.array(q))
#
# ddms[0] cointains the FD derivative in the direction in which the velocity
# operator is diagonalized
for id_dir in range(0, 3):
gv_operator[:, :, id_dir] = (
np.matmul(eigvecs.T.conj(), np.matmul(ddms[id_dir + 1], eigvecs))
* self._factor
)
#
# enforce the velocity operator to be Hermitian
gv_operator[:, :, id_dir] = (
gv_operator[:, :, id_dir].T.conj() + gv_operator[:, :, id_dir]
) / 2.0

return gv_operator

def _get_dsqrtD_FD(self, q):
"""Compute finite difference of sqrt of dynamical matrices."""
#
ddm = []
# _q_length is a float specifying the modulus of the q-vector displacement
# used to compute the finite differences
for dqc in self._directions * self._q_length:
dq = np.dot(self._reciprocal_lattice_inv, dqc)
ddm.append(
self._delta_sqrt_dynamical_matrix(q, dq, self._dynmat)
/ self._q_length
/ 2
)
return np.array(ddm)

def _sqrt_dynamical_matrix(self, flag_gamma, dm):
# returns the sqrt of the dynamical matrix in the cartesian basis
eigvals, eigvecs = np.linalg.eigh(dm)
eigvals = eigvals.real
# will give NaN in case of negative frequencies
freqs = np.sign(eigvals) * np.sqrt(abs(eigvals))
# print('raw=',freqs)
#
# enforce eigenvalues and eigenvectors to zero for acoustic modes at Gamma point
if flag_gamma:
freqs[0] = 0.0
eigvecs[:, 0] = 0.0
freqs[1] = 0.0
eigvecs[:, 1] = 0.0
freqs[2] = 0.0
eigvecs[:, 2] = 0.0
#
if any(f < 0.0 for f in freqs):
print("ERROR: negative frequency=", freqs)
# this is a diagonal matrix containing the frequencies on the diagonal
# we take the element-wise sqrt of a diagonal matrix, in eigenmodes basis
omega_matrix = np.sqrt(np.matmul(eigvecs.T.conj(), np.matmul(dm, eigvecs)))
# now we go back to the Cartesian basis
sqrt_dm = np.matmul(eigvecs, np.matmul(omega_matrix, eigvecs.T.conj()))
#
return sqrt_dm

def _delta_sqrt_dynamical_matrix(self, q, delta_q, dynmat):
#
flag_gamma = False
if np.linalg.norm(q) < np.linalg.norm(delta_q):
flag_gamma = True

if (
(self._dynmat.is_nac())
and (self._dynmat.nac_method == "gonze")
and flag_gamma
):
dynmat.set_dynamical_matrix(
q - delta_q, q_direction=(q - delta_q) / np.linalg.norm(q - delta_q)
)
dm1 = dynmat.get_dynamical_matrix()
sqrt_dm1 = self._sqrt_dynamical_matrix(flag_gamma, dm1)
dynmat.set_dynamical_matrix(
q + delta_q, q_direction=(q + delta_q) / np.linalg.norm(q + delta_q)
)
dm2 = dynmat.get_dynamical_matrix()
sqrt_dm2 = self._sqrt_dynamical_matrix(flag_gamma, dm2)
else:
dynmat.set_dynamical_matrix(q - delta_q)
dm1 = dynmat.get_dynamical_matrix()
sqrt_dm1 = self._sqrt_dynamical_matrix(flag_gamma, dm1)
dynmat.set_dynamical_matrix(q + delta_q)
dm2 = dynmat.get_dynamical_matrix()
sqrt_dm2 = self._sqrt_dynamical_matrix(flag_gamma, dm2)
#
#
return sqrt_dm2 - sqrt_dm1
4 changes: 4 additions & 0 deletions test/BORN_NaCl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
14.400
2.43533967 0 0 0 2.43533967 0 0 0 2.43533967
1.086875 0 0 0 1.086875 0 0 0 1.086875
-1.086875 0 0 0 -1.086875 0 0 0 -1.086875
136 changes: 136 additions & 0 deletions test/FORCE_SETS_NaCl
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
64
2

1
0.0100000000000000 0.0000000000000000 0.0000000000000000
-0.0180619400 0.0000000000 0.0000000000
0.0030240400 0.0000000000 0.0000000000
-0.0000434000 0.0000000000 0.0000000000
0.0001066900 0.0000000000 0.0000000000
-0.0000434000 0.0000000000 0.0000000000
0.0001066900 0.0000000000 0.0000000000
-0.0001589900 0.0000000000 0.0000000000
0.0001344200 0.0000000000 0.0000000000
-0.0005716800 -0.0000021200 -0.0000021200
0.0003817600 0.0000002400 0.0000002400
-0.0005716800 0.0000021200 -0.0000021200
0.0003817600 -0.0000002400 0.0000002400
-0.0005716800 -0.0000021200 0.0000021200
0.0003817600 0.0000002400 -0.0000002400
-0.0005716800 0.0000021200 0.0000021200
0.0003817600 -0.0000002400 -0.0000002400
0.0004845700 0.0000000000 0.0019354900
0.0004850100 0.0000000000 -0.0019214300
-0.0000183800 0.0000000000 -0.0000178800
-0.0000173700 0.0000000000 0.0000170400
0.0004845700 0.0000000000 -0.0019354900
0.0004850100 0.0000000000 0.0019214300
-0.0000183800 0.0000000000 0.0000178800
-0.0000173700 0.0000000000 -0.0000170400
0.0004845700 0.0019354900 0.0000000000
0.0004850100 -0.0019214300 0.0000000000
0.0004845700 -0.0019354900 0.0000000000
0.0004850100 0.0019214300 0.0000000000
-0.0000183800 -0.0000178800 0.0000000000
-0.0000173700 0.0000170400 0.0000000000
-0.0000183800 0.0000178800 0.0000000000
-0.0000173700 -0.0000170400 0.0000000000
-0.0000810800 -0.0004282000 -0.0004282000
-0.0000835100 0.0004258800 0.0004258800
-0.0000810800 0.0004282000 -0.0004282000
-0.0000835100 -0.0004258800 0.0004258800
-0.0000810800 -0.0004282000 0.0004282000
-0.0000835100 0.0004258800 -0.0004258800
-0.0000810800 0.0004282000 0.0004282000
-0.0000835100 -0.0004258800 -0.0004258800
0.0050201700 0.0000000000 0.0000000000
0.0046140400 0.0000000000 0.0000000000
0.0000408300 0.0000000000 0.0000000000
0.0000373700 0.0000000000 0.0000000000
0.0000408300 0.0000000000 0.0000000000
0.0000373700 0.0000000000 0.0000000000
-0.0000105300 0.0000000000 0.0000000000
-0.0000118000 0.0000000000 0.0000000000
0.0017148800 -0.0000110200 0.0000000000
-0.0009600300 -0.0000013600 0.0000000000
0.0017148800 0.0000110200 0.0000000000
-0.0009600300 0.0000013600 0.0000000000
0.0001936100 0.0000011800 0.0000000000
-0.0002359000 0.0000000900 0.0000000000
0.0001936100 -0.0000011800 0.0000000000
-0.0002359000 -0.0000000900 0.0000000000
0.0017148800 0.0000000000 -0.0000110200
-0.0009600300 0.0000000000 -0.0000013600
0.0001936100 0.0000000000 0.0000011800
-0.0002359000 0.0000000000 0.0000000900
0.0017148800 0.0000000000 0.0000110200
-0.0009600300 0.0000000000 0.0000013600
0.0001936100 0.0000000000 -0.0000011800
-0.0002359000 0.0000000000 -0.0000000900

33
0.0100000000000000 0.0000000000000000 0.0000000000000000
-0.0000721800 -0.0004247300 -0.0004247300
-0.0000667600 0.0004272300 0.0004272300
-0.0000721800 0.0004247300 -0.0004247300
-0.0000667600 -0.0004272300 0.0004272300
-0.0000721800 -0.0004247300 0.0004247300
-0.0000667600 0.0004272300 -0.0004272300
-0.0000721800 0.0004247300 0.0004247300
-0.0000667600 -0.0004272300 -0.0004272300
0.0046345100 0.0000000000 0.0000000000
0.0050314800 0.0000000000 0.0000000000
0.0000499300 0.0000000000 0.0000000000
0.0000510900 0.0000000000 0.0000000000
0.0000499300 0.0000000000 0.0000000000
0.0000510900 0.0000000000 0.0000000000
-0.0000030400 0.0000000000 0.0000000000
0.0000012000 0.0000000000 0.0000000000
0.0017234100 0.0000077800 0.0000000000
-0.0009445700 -0.0000004700 0.0000000000
0.0017234100 -0.0000077800 0.0000000000
-0.0009445700 0.0000004700 0.0000000000
0.0002042400 0.0000019500 0.0000000000
-0.0002202400 -0.0000015500 0.0000000000
0.0002042400 -0.0000019500 0.0000000000
-0.0002202400 0.0000015500 0.0000000000
0.0017234100 0.0000000000 0.0000077800
-0.0009445700 0.0000000000 -0.0000004700
0.0002042400 0.0000000000 0.0000019500
-0.0002202400 0.0000000000 -0.0000015500
0.0017234100 0.0000000000 -0.0000077800
-0.0009445700 0.0000000000 0.0000004700
0.0002042400 0.0000000000 -0.0000019500
-0.0002202400 0.0000000000 0.0000015500
-0.0236731700 0.0000000000 0.0000000000
0.0013201600 0.0000000000 0.0000000000
-0.0005159800 0.0000000000 0.0000000000
0.0006463500 0.0000000000 0.0000000000
-0.0005159800 0.0000000000 0.0000000000
0.0006463500 0.0000000000 0.0000000000
-0.0001691500 0.0000000000 0.0000000000
0.0001742700 0.0000000000 0.0000000000
-0.0008016000 0.0000039800 0.0000039800
0.0005170500 -0.0000010700 -0.0000010700
-0.0008016000 -0.0000039800 0.0000039800
0.0005170500 0.0000010700 -0.0000010700
-0.0008016000 0.0000039800 -0.0000039800
0.0005170500 -0.0000010700 0.0000010700
-0.0008016000 -0.0000039800 -0.0000039800
0.0005170500 0.0000010700 0.0000010700
0.0013674700 0.0000000000 0.0020506700
0.0013743700 0.0000000000 -0.0020695000
-0.0000146100 0.0000000000 0.0001925900
-0.0000113300 0.0000000000 -0.0001898400
0.0013674700 0.0000000000 -0.0020506700
0.0013743700 0.0000000000 0.0020695000
-0.0000146100 0.0000000000 -0.0001925900
-0.0000113300 0.0000000000 0.0001898400
0.0013674700 0.0020506700 0.0000000000
0.0013743700 -0.0020695000 0.0000000000
0.0013674700 -0.0020506700 0.0000000000
0.0013743700 0.0020695000 0.0000000000
-0.0000146100 0.0001925900 0.0000000000
-0.0000113300 -0.0001898400 0.0000000000
-0.0000146100 -0.0001925900 0.0000000000
-0.0000113300 0.0001898400 0.0000000000
Loading

0 comments on commit 42a23c8

Please sign in to comment.