Skip to content

Commit

Permalink
Merge pull request mantidproject#35822 from ajjackson/euphonic-1-comp…
Browse files Browse the repository at this point in the history
…atibility

Preparation for Euphonic version bump: make compatible with both 0.6 and 1.*
  • Loading branch information
gemmaguest authored Jul 28, 2023
2 parents 13f9bff + 3adfe05 commit cc8a796
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import mantid.simpleapi as s_api

from dos.load_castep import parse_castep_file
from dos.load_euphonic import euphonic_available, get_data_with_euphonic
from dos.load_euphonic import get_data_with_euphonic
from dos.load_phonon import parse_phonon_file


Expand Down Expand Up @@ -135,14 +135,6 @@ def validateInputs(self):
ions = self.getProperty("Ions").value
calc_partial = len(ions) > 0

if euphonic_filename and not euphonic_available():
issues["ForceConstantsFile"] = (
"Cannot import the Euphonic library for force constants import. "
"This will be included in a future version of Mantid. "
"Until then, it can be installed using users/AdamJackson/install_euphonic.py "
"from the Script Repository."
)

if spec_type == "IonTable" and not pdos_available:
issues["SpectrumType"] = "Cannot produce ion table when only .castep file is provided"

Expand Down Expand Up @@ -271,13 +263,9 @@ def _read_file(self):
elif castep_filename:
return self._read_data_from_file(castep_filename)
elif euphonic_filename:
if euphonic_available():
file_data, self._element_isotope = get_data_with_euphonic(
euphonic_filename, cutoff=float(self.getPropertyValue("ForceConstantsSampling")), acoustic_sum_rule=None
)
else:
raise ValueError("Could not load file using Euphonic: you may need to install this library.")

file_data, self._element_isotope = get_data_with_euphonic(
euphonic_filename, cutoff=float(self.getPropertyValue("ForceConstantsSampling")), acoustic_sum_rule=None
)
self._num_ions = file_data["num_ions"]
return file_data

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from abins.test_helpers import find_file
from mantid.simpleapi import SimulatedDensityOfStates
from systemtesting import MantidSystemTest


class SimulatedDensityOfStatesTest(MantidSystemTest):
"""Make sure normal case will run regardless of Euphonic status"""

def runTest(self):
SimulatedDensityOfStates(
CASTEPFile=find_file("Na2SiF6_CASTEP.phonon"), Function="Gaussian", SpectrumType="DOS", OutputWorkspace="Na2SiF6_DOS"
)

def validate(self):
return ("Na2SiF6_DOS", "Na2SiF6_DOS.nxs")


class SimulatedDensityOfStatesEuphonicTest(MantidSystemTest):
""" "Install Euphonic library to temporary prefix and check results"""

def runTest(self):
SimulatedDensityOfStates(
ForceConstantsFile=find_file("phonopy-Al.yaml"), Function="Gaussian", SpectrumType="DOS", OutputWorkspace="phonopy-Al_DOS"
)

def validate(self):
return ("phonopy-Al_DOS", "phonopy-Al_DOS.nxs")
63 changes: 36 additions & 27 deletions scripts/Inelastic/dos/load_euphonic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,61 @@
# NScD Oak Ridge National Laboratory, European Spallation Source,
# Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
# SPDX - License - Identifier: GPL - 3.0 +
from typing import Optional

from os import PathLike
from typing import Optional, Union

from euphonic import ForceConstants, QpointPhononModes
from euphonic.cli.utils import load_data_from_file

import numpy as np

from mantid.kernel import logger


def euphonic_available():
"""Find out if Euphonic modules can be imported, without raising an error
This allows the Simulation Interface to query the availability of these
formats without complex error-handling.
def force_constants_from_file(filename: Union[str, PathLike]) -> ForceConstants:
"""
try:
from euphonic.cli.utils import force_constants_from_file # noqa: F401
from euphonic.util import mp_grid # noqa: F401
except ImportError:
return False
return True
Read force constants file with Euphonic
Imitates a function from Euphonic versions < 1.0 for compatibility purposes
def euphonic_calculate_modes(filename: str, cutoff: float = 20.0, gamma: bool = True, acoustic_sum_rule: Optional[str] = "reciprocal"):
Args:
filename: Force constant data file (phonopy.yaml, .castep_bin or
Euphonic JSON)
"""
Read force constants file with Euphonic and sample frequencies/modes
data = load_data_from_file(filename)
if not isinstance(data, ForceConstants):
raise ValueError(f"File {filename} does not contain force constants")
return data

:param filename: Input data
:param cutoff:
Sampling density of Brillouin-zone. Specified as real-space length
cutoff in Angstrom.
:param gamma:
Shift sampling grid to include the Gamma-point.
:param acoustic_sum_rule:
Apply acoustic sum rule correction to force constants: options are
'realspace' and 'reciprocal', specifying different implementations of
the correction. If None, no correction is applied. This option is
referred to as "asr" in the Euphonic python API and command-line tools.

:returns: euphonic.QpointPhononModes
def euphonic_calculate_modes(
filename: str, cutoff: float = 20.0, gamma: bool = True, acoustic_sum_rule: Optional[str] = "reciprocal"
) -> QpointPhononModes:
"""
Read force constants file with Euphonic and sample frequencies/modes
Args:
filename:
Input data
cutoff:
Sampling density of Brillouin-zone. Specified as real-space length
cutoff in Angstrom.
gamma:
Shift sampling grid to include the Gamma-point.
acoustic_sum_rule:
Apply acoustic sum rule correction to force constants: options are
'realspace' and 'reciprocal', specifying different implementations
of the correction. If None, no correction is applied. This option
is referred to as "asr" in the Euphonic python API and command-line
tools.
"""

from math import ceil
from euphonic.cli.utils import force_constants_from_file
from euphonic.util import mp_grid

fc = force_constants_from_file(filename)

recip_lattice_lengths = np.linalg.norm(fc.crystal.reciprocal_cell().to("1/angstrom").magnitude, axis=1)
mp_sampling = [ceil(x) for x in (cutoff * recip_lattice_lengths / (2 * np.pi))]
qpts = mp_grid(mp_sampling)
Expand Down
29 changes: 10 additions & 19 deletions scripts/abins/abinsalgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -782,27 +782,18 @@ def _validate_castep_input_file(cls, filename_full_path: str) -> dict:
@classmethod
def _validate_euphonic_input_file(cls, filename_full_path: str) -> dict:
logger.information("Validate force constants file for interpolation.")
from dos.load_euphonic import euphonic_available

if euphonic_available():
try:
from euphonic.cli.utils import force_constants_from_file
from dos.load_euphonic import force_constants_from_file

force_constants_from_file(filename_full_path)
return dict(Invalid=False, Comment="")
except Exception as error:
if hasattr(error, "message"):
message = error.message
else:
message = str(error)
return dict(Invalid=True, Comment=f"Problem opening force constants file with Euphonic.: {message}")
else:
return dict(
Invalid=True,
Comment=(
"Could not import Euphonic module. " "Try running user/AdamJackson/install_euphonic.py from the Script Repository."
),
)
try:
force_constants_from_file(filename_full_path)
return dict(Invalid=False, Comment="")
except Exception as error:
if hasattr(error, "message"):
message = error.message
else:
message = str(error)
return dict(Invalid=True, Comment=f"Problem opening force constants file with Euphonic.: {message}")

@classmethod
def _validate_vasp_input_file(cls, filename_full_path: str) -> dict:
Expand Down
7 changes: 1 addition & 6 deletions scripts/abins/input/euphonicloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .abinitioloader import AbInitioLoader
from abins.parameters import sampling as sampling_parameters

from dos.load_euphonic import euphonic_available, euphonic_calculate_modes
from dos.load_euphonic import euphonic_calculate_modes


class EuphonicLoader(AbInitioLoader):
Expand Down Expand Up @@ -39,11 +39,6 @@ def read_vibrational_or_phonon_data(self):
gamma-point-only sampling.
"""
if not euphonic_available():
raise ImportError(
"Could not import Euphonic library; this is " "required to import force constants from Phonopy or .castep_bin."
)

cutoff = sampling_parameters["force_constants"]["qpt_cutoff"]
modes = euphonic_calculate_modes(filename=self._clerk.get_input_filename(), cutoff=cutoff)

Expand Down
2 changes: 0 additions & 2 deletions scripts/test/Abins/AbinsLoadPhonopyTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import abins.input
import abins.test_helpers
from abins.input import EuphonicLoader
from dos.load_euphonic import euphonic_available


class AbinsLoadPhonopyTest(unittest.TestCase, abins.input.Tester):
Expand All @@ -22,7 +21,6 @@ def tearDown(self):
abins.test_helpers.remove_output_files(list_of_names=["_LoadPhonopy"])
abins.parameters.sampling["force_constants"]["qpt_cutoff"] = self.default_cutoff

@unittest.skipUnless(euphonic_available(), "Optional dependency (euphonic) not available")
def test_non_existing_file(self):
with self.assertRaises(IOError):
bad_phonopy_reader = EuphonicLoader(input_ab_initio_filename="NonExistingFile.yaml")
Expand Down

0 comments on commit cc8a796

Please sign in to comment.