Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/source/tutorials/python/phonons.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
" temp_min=0.0,\n",
" temp_max=1000.0,\n",
" minimize=False,\n",
" force_consts_to_hdf5=True,\n",
" hdf5=True,\n",
" plot_to_file=True,\n",
" symmetrize=False,\n",
" write_full=True,\n",
Expand Down Expand Up @@ -249,7 +249,7 @@
" temp_min=0.0,\n",
" temp_max=1000.0,\n",
" minimize=True,\n",
" force_consts_to_hdf5=True,\n",
" hdf5=True,\n",
" plot_to_file=True,\n",
" symmetrize=False,\n",
" write_full=True,\n",
Expand Down Expand Up @@ -317,7 +317,7 @@
" temp_min=0.0,\n",
" temp_max=1000.0,\n",
" minimize=True,\n",
" force_consts_to_hdf5=True,\n",
" hdf5=True,\n",
" plot_to_file=True,\n",
" symmetrize=False,\n",
" write_full=True,\n",
Expand Down Expand Up @@ -399,7 +399,7 @@
" temp_min=0.0,\n",
" temp_max=1000.0,\n",
" minimize=True,\n",
" force_consts_to_hdf5=True,\n",
" hdf5=True,\n",
" plot_to_file=True,\n",
" symmetrize=False,\n",
" write_full=True,\n",
Expand Down Expand Up @@ -440,7 +440,7 @@
" temp_min=0.0,\n",
" temp_max=1000.0,\n",
" minimize=True,\n",
" force_consts_to_hdf5=True,\n",
" hdf5=True,\n",
" plot_to_file=True,\n",
" symmetrize=False,\n",
" write_full=True,\n",
Expand Down
79 changes: 56 additions & 23 deletions janus_core/calculations/phonons.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from collections.abc import Sequence
from typing import Any, get_args
from warnings import warn

from ase import Atoms
from numpy import ndarray
Expand Down Expand Up @@ -108,7 +109,9 @@ class Phonons(BaseCalculation):
temp_step
Temperature step for thermal properties calculations, in K. Default is 50.0.
force_consts_to_hdf5
Whether to write force constants in hdf format or not. Default is True.
Deprecated. Please use `hdf5`.
hdf5
Whether to write force constants and bands in hdf5 or not. Default is True.
plot_to_file
Whether to plot various graphs as band stuctures, dos/pdos in svg.
Default is False.
Expand Down Expand Up @@ -159,7 +162,8 @@ def __init__(
temp_min: float = 0.0,
temp_max: float = 1000.0,
temp_step: float = 50.0,
force_consts_to_hdf5: bool = True,
force_consts_to_hdf5: None = None,
hdf5: bool = True,
plot_to_file: bool = False,
write_results: bool = True,
write_full: bool = True,
Expand Down Expand Up @@ -238,7 +242,9 @@ def __init__(
temp_step
Temperature step for thermal calculations, in K. Default is 50.0.
force_consts_to_hdf5
Whether to write force constants in hdf format or not. Default is True.
Deprecated. Please use `hdf5`.
hdf5
Whether to write force constants and bands in hdf5 or not. Default is True.
plot_to_file
Whether to plot various graphs as band stuctures, dos/pdos in svg.
Default is False.
Expand Down Expand Up @@ -278,11 +284,27 @@ def __init__(
self.temp_max = temp_max
self.temp_step = temp_step
self.force_consts_to_hdf5 = force_consts_to_hdf5
self.hdf5 = hdf5
self.plot_to_file = plot_to_file
self.write_results = write_results
self.write_full = write_full
self.enable_progress_bar = enable_progress_bar

# Handle deprecation
if force_consts_to_hdf5:
if hdf5:
raise ValueError(
"""`force_consts_to_hdf5`: has replaced `hdf5`.
Please only use `hdf5`"""
)
self.hdf5 = force_consts_to_hdf5
warn(
"""`force_consts_to_hdf5` has been deprecated.
Please use `hdf5`.""",
FutureWarning,
stacklevel=2,
)

# Ensure supercell is a valid list
self.supercell = [supercell] * 3 if isinstance(supercell, int) else supercell
if len(self.supercell) not in [3, 9]:
Expand Down Expand Up @@ -340,11 +362,12 @@ def __init__(
# Output files
self.phonopy_file = self._build_filename("phonopy.yml")
self.force_consts_file = self._build_filename("force_constants.hdf5")
if self.qpoint_file:
self.bands_file = self._build_filename("bands.yml.xz")
else:
self.bands_file = self._build_filename("auto_bands.yml.xz")
self.bands_plot_file = self._build_filename("bands.svg")

filename = "bands" + (".hdf5" if hdf5 else ".yml")
if not self.qpoint_file:
filename = f"auto_{filename}"
self.bands_file = self._build_filename(filename)

self.dos_file = self._build_filename("dos.dat")
self.dos_plot_file = self._build_filename("dos.svg")
self.bands_dos_plot_file = self._build_filename("bs-dos.svg")
Expand Down Expand Up @@ -430,9 +453,7 @@ def output_files(self) -> None:
return {
"log": self.log_kwargs["filename"] if self.logger else None,
"params": self.phonopy_file if self.write_results else None,
"force_constants": (
self.force_consts_file if self.force_consts_to_hdf5 else None
),
"force_constants": (self.force_consts_file if self.hdf5 else None),
"bands": (
self.bands_file
if self.write_results and "bands" in self.calcs
Expand Down Expand Up @@ -552,7 +573,7 @@ def write_force_constants(
self,
*,
phonopy_file: PathLike | None = None,
force_consts_to_hdf5: bool | None = None,
hdf5: bool | None = None,
force_consts_file: PathLike | None = None,
) -> None:
"""
Expand All @@ -563,11 +584,11 @@ def write_force_constants(
phonopy_file
Name of yaml file to save params of phonopy and optionally force constants.
Default is inferred from `file_prefix`.
force_consts_to_hdf5
hdf5
Whether to save the force constants separately to an hdf5 file. Default is
self.force_consts_to_hdf5.
self.hdf5.
force_consts_file
Name of hdf5 file to save force constants. Unused if `force_consts_to_hdf5`
Name of hdf5 file to save force constants. Unused if `hdf5`
is False. Default is inferred from `file_prefix`.
"""
if "phonon" not in self.results:
Expand All @@ -576,8 +597,8 @@ def write_force_constants(
"Please run `calc_force_constants` first"
)

if force_consts_to_hdf5 is None:
force_consts_to_hdf5 = self.force_consts_to_hdf5
if hdf5 is None:
hdf5 = self.hdf5

if phonopy_file:
self.phonopy_file = phonopy_file
Expand All @@ -586,11 +607,11 @@ def write_force_constants(

phonon = self.results["phonon"]

save_force_consts = not force_consts_to_hdf5
save_force_consts = not hdf5
build_file_dir(self.phonopy_file)
phonon.save(self.phonopy_file, settings={"force_constants": save_force_consts})

if force_consts_to_hdf5:
if hdf5:
build_file_dir(self.force_consts_file)
write_force_constants_to_hdf5(
phonon.force_constants, filename=self.force_consts_file
Expand Down Expand Up @@ -621,6 +642,7 @@ def calc_bands(self, write_bands: bool | None = None, **kwargs) -> None:
def write_bands(
self,
*,
hdf5: bool | None = None,
bands_file: PathLike | None = None,
save_plots: bool | None = None,
plot_file: PathLike | None = None,
Expand All @@ -630,6 +652,9 @@ def write_bands(

Parameters
----------
hdf5
Whether to save the bands in an hdf5 file. Default is
self.hdf5.
bands_file
Name of yaml file to save band structure. Default is inferred from
`file_prefix`.
Expand All @@ -645,11 +670,15 @@ def write_bands(
"Please run `calc_force_constants` first"
)

if hdf5 is None:
hdf5 = self.hdf5

if save_plots is None:
save_plots = self.plot_to_file

if bands_file:
self.bands_file = bands_file

if plot_file:
self.bands_plot_file = plot_file

Expand Down Expand Up @@ -682,10 +711,14 @@ def write_bands(
)

build_file_dir(self.bands_file)
self.results["phonon"].write_yaml_band_structure(
filename=self.bands_file,
compression="lzma",
)
if hdf5:
self.results["phonon"].write_hdf5_band_structure(
filename=self.bands_file,
)
else:
self.results["phonon"].write_yaml_band_structure(
filename=self.bands_file,
)

bplt = self.results["phonon"].plot_band_structure()
if save_plots:
Expand Down
20 changes: 16 additions & 4 deletions janus_core/cli/phonons.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
Summary,
Tracker,
)
from janus_core.cli.utils import yaml_converter_callback
from janus_core.cli.utils import deprecated_option, yaml_converter_callback

app = Typer()

Expand Down Expand Up @@ -110,11 +110,20 @@ def phonons(
),
] = 0.1,
minimize_kwargs: MinimizeKwargs = None,
hdf5: Annotated[
force_consts_to_hdf5: Annotated[
bool,
Option(
help="Whether to save force constants in hdf5.",
rich_help_panel="Calculation",
callback=deprecated_option,
hidden=True,
),
] = True,
hdf5: Annotated[
bool,
Option(
help="Whether to save force constants and bands in hdf5.",
rich_help_panel="Calculation",
),
] = True,
plot_to_file: Annotated[
Expand Down Expand Up @@ -228,8 +237,11 @@ def phonons(
Default is 0.1.
minimize_kwargs
Other keyword arguments to pass to geometry optimizer. Default is {}.
force_consts_to_hdf5
Deprecated. Please use `hdf5`.
hdf5
Whether to save force constants in hdf5 format. Default is True.
Whether to save force constants and bands in hdf5 format.
Default is True.
plot_to_file
Whether to plot. Default is False.
write_full
Expand Down Expand Up @@ -391,7 +403,7 @@ def phonons(
"temp_min": temp_min,
"temp_max": temp_max,
"temp_step": temp_step,
"force_consts_to_hdf5": hdf5,
"hdf5": hdf5,
"plot_to_file": plot_to_file,
"write_results": True,
"write_full": write_full,
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dependencies = [
"click<9,>=8.2.1",
"codecarbon<4.0.0,>=3.0.4",
"numpy<3.0.0,>=1.26.4",
"phonopy<3.0.0,>=2.23.1",
"phonopy<3.0.0,>=2.39.0",
"pymatgen>=2025.1.24",
"pyyaml<7.0.0,>=6.0.1",
"rich<14.0.0,>=13.9.1",
Expand Down
15 changes: 9 additions & 6 deletions tests/test_phonons_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def test_phonons(tmp_path):

has_eigenvectors = False
has_velocity = False
with lzma.open(bands_path, mode="rt") as file:
with open(bands_path) as file:
for line in file:
if "eigenvector" in line:
has_eigenvectors = True
Expand Down Expand Up @@ -109,7 +109,7 @@ def test_phonons(tmp_path):
def test_bands_simple(tmp_path):
"""Test calculating force constants and reduced bands information."""
file_prefix = tmp_path / "NaCl"
autoband_results = tmp_path / "NaCl-auto_bands.yml.xz"
autoband_results = tmp_path / "NaCl-auto_bands.yml"
summary_path = tmp_path / "NaCl-phonons-summary.yml"

result = runner.invoke(
Expand Down Expand Up @@ -153,6 +153,7 @@ def test_hdf5(tmp_path):
file_prefix = tmp_path / "test" / "NaCl"
phonon_results = tmp_path / "test" / "NaCl-phonopy.yml"
hdf5_results = tmp_path / "test" / "NaCl-force_constants.hdf5"
bands_results = tmp_path / "test" / "NaCl-auto_bands.hdf5"
summary_path = tmp_path / "test" / "NaCl-phonons-summary.yml"
log_path = tmp_path / "test" / "NaCl-phonons-log.yml"

Expand All @@ -164,6 +165,7 @@ def test_hdf5(tmp_path):
DATA_PATH / "NaCl.cif",
"--arch",
"mace_mp",
"--bands",
"--file-prefix",
file_prefix,
"--hdf5",
Expand All @@ -172,6 +174,7 @@ def test_hdf5(tmp_path):
assert result.exit_code == 0
assert phonon_results.exists()
assert hdf5_results.exists()
assert bands_results.exists()

# Read phonons summary file
with open(summary_path, encoding="utf8") as file:
Expand All @@ -180,7 +183,7 @@ def test_hdf5(tmp_path):
output_files = {
"params": phonon_results,
"force_constants": hdf5_results,
"bands": None,
"bands": bands_results,
"bands_plot": None,
"dos": None,
"dos_plot": None,
Expand Down Expand Up @@ -289,10 +292,10 @@ def test_plot(tmp_path):
"""Test for plotting routines."""
file_prefix = tmp_path / "NaCl"
phonon_results = tmp_path / "NaCl-phonopy.yml"
bands_path = tmp_path / "NaCl-auto_bands.yml.xz"
bands_path = tmp_path / "NaCl-auto_bands.yml"
pdos_results = tmp_path / "NaCl-pdos.dat"
dos_results = tmp_path / "NaCl-dos.dat"
autoband_results = tmp_path / "NaCl-auto_bands.yml.xz"
autoband_results = tmp_path / "NaCl-auto_bands.yml"
summary_path = tmp_path / "NaCl-phonons-summary.yml"
log_path = tmp_path / "NaCl-phonons-log.yml"
svgs = [
Expand Down Expand Up @@ -630,7 +633,7 @@ def test_paths(tmp_path):
"""Test passing qpoint file."""
file_prefix = tmp_path / "NaCl"
qpoint_file = DATA_PATH / "paths.yml"
band_results = tmp_path / "NaCl-bands.yml.xz"
band_results = tmp_path / "NaCl-bands.yml"

result = runner.invoke(
app,
Expand Down
Loading