mirror of https://github.com/phonopy/phono3py.git
484 lines
15 KiB
Python
484 lines
15 KiB
Python
"""Phono3py kaccum command line script."""
|
|
|
|
import argparse
|
|
import sys
|
|
from typing import Optional
|
|
|
|
import h5py
|
|
import numpy as np
|
|
from phonopy.cui.collect_cell_info import collect_cell_info
|
|
from phonopy.structure.atoms import PhonopyAtoms
|
|
from phonopy.structure.symmetry import Symmetry
|
|
|
|
from phono3py.interface.phono3py_yaml import Phono3pyYaml
|
|
from phono3py.other.kaccum import GammaDOSsmearing, get_mfp, run_mfp_dos, run_prop_dos
|
|
from phono3py.phonon.grid import BZGrid, get_ir_grid_points
|
|
|
|
epsilon = 1.0e-8
|
|
|
|
|
|
def _show_tensor(kdos, temperatures, sampling_points, args):
|
|
"""Show 2nd rank tensors."""
|
|
for i, kdos_t in enumerate(kdos):
|
|
if not args.gv:
|
|
print("# %d K" % temperatures[i])
|
|
|
|
for f, k in zip(sampling_points[i], kdos_t): # show kappa_xx
|
|
if args.average:
|
|
print(("%13.5f " * 3) % (f, k[0][:3].sum() / 3, k[1][:3].sum() / 3))
|
|
elif args.trace:
|
|
print(("%13.5f " * 3) % (f, k[0][:3].sum(), k[1][:3].sum()))
|
|
else:
|
|
print(("%f " * 13) % ((f,) + tuple(k[0]) + tuple(k[1])))
|
|
|
|
print("")
|
|
print("")
|
|
|
|
|
|
def _show_scalar(gdos, temperatures, sampling_points, args):
|
|
"""Show scalar values."""
|
|
if args.pqj or args.gruneisen or args.gv_norm:
|
|
for f, g in zip(sampling_points, gdos[0]):
|
|
print("%f %e %e" % (f, g[0], g[1]))
|
|
else:
|
|
for i, gdos_t in enumerate(gdos):
|
|
print("# %d K" % temperatures[i])
|
|
for f, g in zip(sampling_points[i], gdos_t):
|
|
print("%f %f %f" % (f, g[0], g[1]))
|
|
print("")
|
|
print("")
|
|
|
|
|
|
def _set_T_target(temperatures, mode_prop, T_target, mean_freepath=None):
|
|
"""Extract property at specified temperature."""
|
|
for i, t in enumerate(temperatures):
|
|
if np.abs(t - T_target) < epsilon:
|
|
temperatures = temperatures[i : i + 1]
|
|
mode_prop = mode_prop[i : i + 1, :, :]
|
|
if mean_freepath is not None:
|
|
mean_freepath = mean_freepath[i : i + 1]
|
|
return temperatures, mode_prop, mean_freepath
|
|
else:
|
|
return temperatures, mode_prop
|
|
|
|
|
|
def _get_ir_grid_info(
|
|
bz_grid: BZGrid,
|
|
weights: np.ndarray,
|
|
qpoints: Optional[np.ndarray] = None,
|
|
ir_grid_points: Optional[np.ndarray] = None,
|
|
) -> tuple[np.ndarray, np.ndarray]:
|
|
"""Return ir-grid point information.
|
|
|
|
Parameters
|
|
----------
|
|
bz_grid : BZGrid
|
|
BZ grid information.
|
|
weights : ndarray
|
|
Weights of ir-grid points stored in kappa-xxx.hdf5. This is used to check
|
|
agreement between generated ir-grid points and those underlying in hdf5.
|
|
qpoints : ndarray
|
|
Ir-grid q-point coordinates stored in kappa-xxx.hdf5. This is used to check
|
|
agreement between generated ir-grid points and q-points coordinates in hdf5.
|
|
|
|
Returns
|
|
-------
|
|
ir_grid_points : ndarray
|
|
Ir-grid point indices in BZ-grid.
|
|
shape=(ir_grid_points, ), dtype='int64'
|
|
ir_grid_map : ndarray
|
|
Mapping table to ir-grid point indices in GR-grid.
|
|
|
|
"""
|
|
(ir_grid_points_ref, weights_ref, ir_grid_map) = get_ir_grid_points(bz_grid)
|
|
ir_grid_points_ref = bz_grid.grg2bzg[ir_grid_points_ref]
|
|
_assert_grid_in_hdf5(
|
|
weights, qpoints, ir_grid_points, weights_ref, ir_grid_points_ref, bz_grid
|
|
)
|
|
|
|
return ir_grid_points_ref, ir_grid_map
|
|
|
|
|
|
def _assert_grid_in_hdf5(
|
|
weights,
|
|
qpoints,
|
|
ir_grid_points,
|
|
weights_for_check,
|
|
ir_grid_points_ref,
|
|
bz_grid: BZGrid,
|
|
):
|
|
try:
|
|
np.testing.assert_equal(weights, weights_for_check)
|
|
except AssertionError:
|
|
print("*******************************")
|
|
print("** Might forget --pa option? **")
|
|
print("*******************************")
|
|
raise
|
|
|
|
if ir_grid_points is not None:
|
|
np.testing.assert_equal(ir_grid_points, ir_grid_points_ref)
|
|
if qpoints is not None:
|
|
addresses = bz_grid.addresses[ir_grid_points_ref]
|
|
D_diag = bz_grid.D_diag.astype("double")
|
|
qpoints_for_check = np.dot(addresses / D_diag, bz_grid.Q.T)
|
|
diff_q = qpoints - qpoints_for_check
|
|
diff_q -= np.rint(diff_q)
|
|
np.testing.assert_allclose(diff_q, 0, atol=1e-5)
|
|
|
|
|
|
def _get_mode_property(args, f_kappa):
|
|
"""Read property data from hdf5 file object."""
|
|
if args.pqj:
|
|
mode_prop = f_kappa["ave_pp"][:].reshape((1,) + f_kappa["ave_pp"].shape)
|
|
elif args.cv:
|
|
mode_prop = f_kappa["heat_capacity"][:]
|
|
elif args.tau:
|
|
g = f_kappa["gamma"][:]
|
|
g = np.where(g > 0, g, -1)
|
|
mode_prop = np.where(g > 0, 1.0 / (2 * 2 * np.pi * g), 0)
|
|
elif args.gv_norm:
|
|
mode_prop = np.sqrt((f_kappa["group_velocity"][:, :, :] ** 2).sum(axis=2))
|
|
mode_prop = mode_prop.reshape((1,) + mode_prop.shape)
|
|
elif args.gamma:
|
|
mode_prop = f_kappa["gamma"][:]
|
|
elif args.gruneisen:
|
|
mode_prop = f_kappa["gruneisen"][:].reshape((1,) + f_kappa["gruneisen"].shape)
|
|
mode_prop **= 2
|
|
elif args.dos:
|
|
mode_prop = np.ones(
|
|
(1,) + f_kappa["frequency"].shape, dtype="double", order="C"
|
|
)
|
|
else:
|
|
raise RuntimeError("No property target is specified.")
|
|
return mode_prop
|
|
|
|
|
|
def _get_parser():
|
|
"""Return args of ArgumentParser."""
|
|
parser = argparse.ArgumentParser(description="Show unit cell volume")
|
|
parser.add_argument(
|
|
"--gv", action="store_true", help="Calculate for gv_x_gv (tensor)"
|
|
)
|
|
parser.add_argument("--pqj", action="store_true", help="Calculate for Pqj (scalar)")
|
|
parser.add_argument("--cv", action="store_true", help="Calculate for Cv (scalar)")
|
|
parser.add_argument(
|
|
"--tau", action="store_true", help="Calculate for lifetimes (scalar)"
|
|
)
|
|
parser.add_argument(
|
|
"--dos", action="store_true", help="Calculate for phonon DOS (scalar)"
|
|
)
|
|
parser.add_argument(
|
|
"--gamma", action="store_true", help="Calculate for Gamma (scalar)"
|
|
)
|
|
parser.add_argument(
|
|
"--gruneisen",
|
|
action="store_true",
|
|
help="Calculate for mode-Gruneisen parameters squared (scalar)",
|
|
)
|
|
parser.add_argument(
|
|
"--gv-norm", action="store_true", help="Calculate for |g_v| (scalar)"
|
|
)
|
|
parser.add_argument(
|
|
"--mfp", action="store_true", help="Mean free path is used instead of frequency"
|
|
)
|
|
parser.add_argument(
|
|
"--temperature",
|
|
type=float,
|
|
dest="temperature",
|
|
help="Temperature to output data at",
|
|
)
|
|
parser.add_argument(
|
|
"--nsp",
|
|
"--num-sampling-points",
|
|
type=int,
|
|
dest="num_sampling_points",
|
|
default=100,
|
|
help="Number of sampling points in frequency or MFP axis",
|
|
)
|
|
parser.add_argument(
|
|
"--average",
|
|
action="store_true",
|
|
help=(
|
|
"Output the traces of the tensors divided by 3 "
|
|
"rather than the unique elements"
|
|
),
|
|
)
|
|
parser.add_argument(
|
|
"--trace",
|
|
action="store_true",
|
|
help=("Output the traces of the tensors rather than the unique elements"),
|
|
)
|
|
parser.add_argument(
|
|
"--smearing",
|
|
action="store_true",
|
|
help="Use smearing method (only for scalar density)",
|
|
)
|
|
parser.add_argument(
|
|
"--no-gridsym",
|
|
dest="no_gridsym",
|
|
action="store_true",
|
|
help="Grid symmetry is unused for phonon-xxx.hdf5 inputs.",
|
|
)
|
|
parser.add_argument("filenames", nargs="*")
|
|
args = parser.parse_args()
|
|
return args
|
|
|
|
|
|
def _read_files(args: argparse.Namespace) -> tuple[h5py.File, PhonopyAtoms | None]:
|
|
primitive = None
|
|
cell_info = collect_cell_info(
|
|
supercell_matrix=np.eye(3, dtype=int),
|
|
phonopy_yaml_cls=Phono3pyYaml,
|
|
load_phonopy_yaml=True,
|
|
)
|
|
cell_filename = cell_info.optional_structure_info[0]
|
|
print(f'# Crystal structure was read from "{cell_filename}".')
|
|
cell = cell_info.unitcell
|
|
phpy_yaml = cell_info.phonopy_yaml
|
|
if phpy_yaml is not None:
|
|
primitive = phpy_yaml.primitive
|
|
if primitive is None:
|
|
primitive = cell
|
|
f_kappa = h5py.File(args.filenames[0], "r")
|
|
return f_kappa, primitive
|
|
|
|
|
|
def _collect_data(
|
|
f_kappa: h5py.File, primitive: PhonopyAtoms, args: argparse.Namespace
|
|
) -> tuple[
|
|
Optional[np.ndarray],
|
|
Optional[np.ndarray],
|
|
np.ndarray,
|
|
BZGrid,
|
|
np.ndarray,
|
|
np.ndarray,
|
|
]:
|
|
# bz_grid
|
|
if "grid_matrix" in f_kappa:
|
|
mesh = np.array(f_kappa["grid_matrix"][:], dtype="int64")
|
|
else:
|
|
mesh = np.array(f_kappa["mesh"][:], dtype="int64")
|
|
primitive_symmetry = Symmetry(primitive)
|
|
bz_grid = BZGrid(
|
|
mesh,
|
|
lattice=primitive.cell,
|
|
symmetry_dataset=primitive_symmetry.dataset,
|
|
store_dense_gp_map=True,
|
|
)
|
|
|
|
# temperatures
|
|
if "temperature" in f_kappa:
|
|
temperatures = f_kappa["temperature"][:]
|
|
else:
|
|
temperatures = np.zeros(1, dtype="double")
|
|
|
|
# frequencies, ir_weights
|
|
if "weight" in f_kappa:
|
|
# This is to read "kappa-xxx.hdf5".
|
|
# ir_grid_points_BZ in BZ-grid index will be transformed to GR-grid index.
|
|
print("# Read frequency, weight, qpoint, and optionally grid_point.")
|
|
frequencies = f_kappa["frequency"][:]
|
|
ir_weights = f_kappa["weight"][:]
|
|
if "grid_point" in f_kappa:
|
|
ir_grid_points_BZ = f_kappa["grid_point"][:]
|
|
else:
|
|
ir_grid_points_BZ = None
|
|
qpoints = f_kappa["qpoint"][:]
|
|
elif "ir_grid_weights" in f_kappa and not args.no_gridsym:
|
|
# This is to read "phonon-xxx.hdf5".
|
|
print("# Read ir_grid_weights.")
|
|
ir_weights = f_kappa["ir_grid_weights"][:]
|
|
ir_grid_points_BZ = f_kappa["ir_grid_points"][:]
|
|
qpoints = None
|
|
frequencies = np.array(f_kappa["frequency"][ir_grid_points_BZ], dtype="double")
|
|
else:
|
|
print("# Read frequency.")
|
|
frequencies = f_kappa["frequency"][:]
|
|
ir_weights = np.ones(len(frequencies), dtype="int64")
|
|
|
|
# ir_grid_points (GR-grid), ir_grid_map (GR-grid)
|
|
if args.no_gridsym or (ir_weights == 1).all():
|
|
ir_grid_points = None
|
|
ir_grid_map = None
|
|
else:
|
|
ir_grid_points, ir_grid_map = _get_ir_grid_info(
|
|
bz_grid, ir_weights, qpoints=qpoints, ir_grid_points=ir_grid_points_BZ
|
|
)
|
|
ir_grid_points = bz_grid.bzg2grg[ir_grid_points]
|
|
|
|
conditions = frequencies > 0
|
|
if np.logical_not(conditions).sum() > 3:
|
|
sys.stderr.write(
|
|
"# Imaginary frequencies are found. They are set to be zero.\n"
|
|
)
|
|
frequencies = np.where(conditions, frequencies, 0)
|
|
|
|
return ir_grid_points, ir_grid_map, ir_weights, bz_grid, frequencies, temperatures
|
|
|
|
|
|
def _run_scalar(
|
|
args: argparse.Namespace,
|
|
f_kappa: h5py.File,
|
|
temperatures: np.ndarray,
|
|
frequencies: np.ndarray,
|
|
ir_weights: np.ndarray,
|
|
ir_grid_map: Optional[np.ndarray],
|
|
ir_grid_points: Optional[np.ndarray],
|
|
bz_grid: BZGrid,
|
|
):
|
|
mode_prop = _get_mode_property(args, f_kappa)
|
|
|
|
if args.temperature is not None and not (
|
|
args.gv_norm or args.pqj or args.gruneisen or args.dos
|
|
):
|
|
temperatures, mode_prop = _set_T_target(
|
|
temperatures, mode_prop, args.temperature
|
|
)
|
|
if args.smearing:
|
|
mode_prop_dos = GammaDOSsmearing(
|
|
mode_prop,
|
|
frequencies,
|
|
ir_weights,
|
|
num_sampling_points=args.num_sampling_points,
|
|
)
|
|
sampling_points, gdos = mode_prop_dos.get_gdos()
|
|
sampling_points = np.tile(sampling_points, (len(gdos), 1))
|
|
_show_scalar(gdos[:, :, :], temperatures, sampling_points, args)
|
|
else:
|
|
for i, w in enumerate(ir_weights):
|
|
mode_prop[:, i, :] *= w
|
|
kdos, sampling_points = run_prop_dos(
|
|
frequencies,
|
|
mode_prop[:, :, :, None],
|
|
ir_grid_map,
|
|
ir_grid_points,
|
|
args.num_sampling_points,
|
|
bz_grid,
|
|
)
|
|
_show_scalar(kdos[:, :, :, 0], temperatures, sampling_points, args)
|
|
|
|
|
|
def _run_tensor(
|
|
args: argparse.Namespace,
|
|
f_kappa: h5py.File,
|
|
temperatures: np.ndarray,
|
|
frequencies: np.ndarray,
|
|
ir_grid_map: Optional[np.ndarray],
|
|
ir_grid_points: Optional[np.ndarray],
|
|
bz_grid: BZGrid,
|
|
primitive: PhonopyAtoms,
|
|
):
|
|
if args.gv:
|
|
gv_sum2 = f_kappa["gv_by_gv"][:]
|
|
# gv x gv is divied by primitive cell volume.
|
|
unit_conversion = primitive.volume
|
|
mode_prop = gv_sum2.reshape((1,) + gv_sum2.shape) / unit_conversion
|
|
else:
|
|
if "mode_kappa" in f_kappa:
|
|
mode_prop = f_kappa["mode_kappa"][:]
|
|
else:
|
|
print('No "mode_kappa" in mode_prop.')
|
|
sys.exit(1)
|
|
|
|
if args.mfp:
|
|
if "mean_free_path" in f_kappa:
|
|
mfp = f_kappa["mean_free_path"][:]
|
|
mean_freepath = np.sqrt((mfp**2).sum(axis=3))
|
|
else:
|
|
mean_freepath = get_mfp(f_kappa["gamma"][:], f_kappa["group_velocity"][:])
|
|
if args.temperature is not None:
|
|
(temperatures, mode_prop, mean_freepath) = _set_T_target(
|
|
temperatures,
|
|
mode_prop,
|
|
args.temperature,
|
|
mean_freepath=mean_freepath,
|
|
)
|
|
|
|
kdos, sampling_points = run_mfp_dos(
|
|
mean_freepath,
|
|
mode_prop,
|
|
ir_grid_map,
|
|
ir_grid_points,
|
|
args.num_sampling_points,
|
|
bz_grid,
|
|
)
|
|
_show_tensor(kdos, temperatures, sampling_points, args)
|
|
else:
|
|
if args.temperature is not None and not args.gv:
|
|
temperatures, mode_prop = _set_T_target(
|
|
temperatures, mode_prop, args.temperature
|
|
)
|
|
kdos, sampling_points = run_prop_dos(
|
|
frequencies,
|
|
mode_prop,
|
|
ir_grid_map,
|
|
ir_grid_points,
|
|
args.num_sampling_points,
|
|
bz_grid,
|
|
)
|
|
_show_tensor(kdos, temperatures, sampling_points, args)
|
|
|
|
|
|
def main():
|
|
"""Calculate kappa spectrum.
|
|
|
|
Usage
|
|
-----
|
|
If `phono3py_disp.yaml` or `phono3py.yaml` exists in current directory,
|
|
```
|
|
% phono3py-kaccum kappa-m111111.hdf5
|
|
```
|
|
|
|
Plot by gnuplot
|
|
---------------
|
|
```
|
|
% gnuplot
|
|
...
|
|
gnuplot> p "kaccum.dat" i 30 u 1:2 w l, "kaccum.dat" i 30 u 1:8 w l
|
|
```
|
|
|
|
"""
|
|
args = _get_parser()
|
|
if len(args.filenames) > 1:
|
|
raise RuntimeError(
|
|
'Use of "phono3py-kaccum CRYSTAL_STRUCTURE_FILE" is not supported.'
|
|
)
|
|
|
|
f_kappa, primitive = _read_files(args)
|
|
|
|
ir_grid_points, ir_grid_map, ir_weights, bz_grid, frequencies, temperatures = (
|
|
_collect_data(f_kappa, primitive, args)
|
|
)
|
|
|
|
# Run for scaler
|
|
if (
|
|
args.gamma
|
|
or args.gruneisen
|
|
or args.pqj
|
|
or args.cv
|
|
or args.tau
|
|
or args.gv_norm
|
|
or args.dos
|
|
):
|
|
_run_scalar(
|
|
args,
|
|
f_kappa,
|
|
temperatures,
|
|
frequencies,
|
|
ir_weights,
|
|
ir_grid_map,
|
|
ir_grid_points,
|
|
bz_grid,
|
|
)
|
|
else: # Run for tensor
|
|
_run_tensor(
|
|
args,
|
|
f_kappa,
|
|
temperatures,
|
|
frequencies,
|
|
ir_grid_map,
|
|
ir_grid_points,
|
|
bz_grid,
|
|
primitive,
|
|
)
|