mirror of https://github.com/phonopy/phono3py.git
Add tests for supercell_energies and forces attributes of API
This commit is contained in:
parent
eecc4b3ceb
commit
1d35ca216f
|
@ -34,6 +34,7 @@
|
|||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import copy
|
||||
from collections.abc import Sequence
|
||||
from typing import Literal, Optional, Union
|
||||
|
||||
|
@ -610,7 +611,20 @@ class Phono3py:
|
|||
|
||||
@dataset.setter
|
||||
def dataset(self, dataset):
|
||||
self._dataset = dataset
|
||||
if dataset is None:
|
||||
self._dataset = None
|
||||
elif "first_atoms" in dataset:
|
||||
self._dataset = copy.deepcopy(dataset)
|
||||
elif "displacements" in dataset:
|
||||
self._dataset = {}
|
||||
self.displacements = dataset["displacements"]
|
||||
if "forces" in dataset:
|
||||
self.forces = dataset["forces"]
|
||||
if "supercell_energies" in dataset:
|
||||
self.supercell_energies = dataset["supercell_energies"]
|
||||
else:
|
||||
raise RuntimeError("Data format of dataset is wrong.")
|
||||
|
||||
self._supercells_with_displacements = None
|
||||
self._phonon_supercells_with_displacements = None
|
||||
|
||||
|
@ -643,7 +657,21 @@ class Phono3py:
|
|||
|
||||
@phonon_dataset.setter
|
||||
def phonon_dataset(self, dataset):
|
||||
self._phonon_dataset = dataset
|
||||
if dataset is None:
|
||||
self._phonon_dataset = None
|
||||
elif "first_atoms" in dataset:
|
||||
self._phonon_dataset = copy.deepcopy(dataset)
|
||||
elif "displacements" in dataset:
|
||||
self._phonon_dataset = {}
|
||||
self.phonon_displacements = dataset["displacements"]
|
||||
if "forces" in dataset:
|
||||
self.phonon_forces = dataset["forces"]
|
||||
if "supercell_energies" in dataset:
|
||||
self.phonon_supercell_energies = dataset["supercell_energies"]
|
||||
else:
|
||||
raise RuntimeError("Data format of dataset is wrong.")
|
||||
|
||||
self._phonon_supercells_with_displacements = None
|
||||
|
||||
@property
|
||||
def band_indices(self):
|
||||
|
@ -929,7 +957,7 @@ class Phono3py:
|
|||
be the same order of phonon_supercells_with_displacements.
|
||||
|
||||
"""
|
||||
self._get_phonon_forces_energies(target="forces")
|
||||
return self._get_phonon_forces_energies(target="forces")
|
||||
|
||||
@phonon_forces.setter
|
||||
def phonon_forces(self, values):
|
||||
|
@ -948,7 +976,7 @@ class Phono3py:
|
|||
to be the same order of phonon_supercells_with_displacements.
|
||||
|
||||
"""
|
||||
self._get_phonon_forces_energies(target="supercell_energies")
|
||||
return self._get_phonon_forces_energies(target="supercell_energies")
|
||||
|
||||
@phonon_supercell_energies.setter
|
||||
def phonon_supercell_energies(self, values):
|
||||
|
@ -2261,10 +2289,15 @@ class Phono3py:
|
|||
|
||||
def _get_forces_energies(
|
||||
self, target: Literal["forces", "supercell_energies"]
|
||||
) -> np.ndarray:
|
||||
if target in self._dataset:
|
||||
) -> Optional[np.ndarray]:
|
||||
"""Return fc3 forces and supercell energies.
|
||||
|
||||
Return None if tagert data is not found rather than raising exception.
|
||||
|
||||
"""
|
||||
if target in self._dataset: # type-2
|
||||
return self._dataset[target]
|
||||
elif "first_atoms" in self._dataset:
|
||||
elif "first_atoms" in self._dataset: # type-1
|
||||
num_scells = len(self._dataset["first_atoms"])
|
||||
for disp1 in self._dataset["first_atoms"]:
|
||||
num_scells += len(disp1["second_atoms"])
|
||||
|
@ -2274,30 +2307,31 @@ class Phono3py:
|
|||
dtype="double",
|
||||
order="C",
|
||||
)
|
||||
type1_target = "forces"
|
||||
elif target == "supercell_energies":
|
||||
values = np.zeros(num_scells, dtype="double")
|
||||
type1_target = "supercell_energy"
|
||||
count = 0
|
||||
for disp1 in self._dataset["first_atoms"]:
|
||||
values[count] = disp1[target]
|
||||
values[count] = disp1[type1_target]
|
||||
count += 1
|
||||
for disp1 in self._dataset["first_atoms"]:
|
||||
for disp2 in disp1["second_atoms"]:
|
||||
values[count] = disp2[target]
|
||||
values[count] = disp2[type1_target]
|
||||
count += 1
|
||||
return values
|
||||
else:
|
||||
raise RuntimeError("FC3 displacement dataset is in wrong format.")
|
||||
return None
|
||||
|
||||
def _set_forces_energies(
|
||||
self, values, target: Literal["forces", "supercell_energies"]
|
||||
):
|
||||
if "first_atoms" in self._dataset:
|
||||
if "first_atoms" in self._dataset: # type-1
|
||||
count = 0
|
||||
for disp1 in self._dataset["first_atoms"]:
|
||||
if target == "forces":
|
||||
disp1[target] = np.array(values[count], dtype="double", order="C")
|
||||
elif target == "supercell_energies":
|
||||
disp1[target] = float(values[count])
|
||||
disp1["supercell_energy"] = float(values[count])
|
||||
count += 1
|
||||
for disp1 in self._dataset["first_atoms"]:
|
||||
for disp2 in disp1["second_atoms"]:
|
||||
|
@ -2306,22 +2340,27 @@ class Phono3py:
|
|||
values[count], dtype="double", order="C"
|
||||
)
|
||||
elif target == "supercell_energies":
|
||||
disp2[target] = float(values[count])
|
||||
disp2["supercell_energy"] = float(values[count])
|
||||
count += 1
|
||||
elif "displacements" in self._dataset or "forces" in self._dataset:
|
||||
elif "displacements" in self._dataset or "forces" in self._dataset: # type-2
|
||||
self._dataset[target] = np.array(values, dtype="double", order="C")
|
||||
else:
|
||||
raise RuntimeError("Set of FC3 displacements is not available.")
|
||||
|
||||
def _get_phonon_forces_energies(
|
||||
self, target: Literal["forces", "supercell_energies"]
|
||||
):
|
||||
) -> Optional[np.ndarray]:
|
||||
"""Return fc2 forces and supercell energies.
|
||||
|
||||
Return None if tagert data is not found rather than raising exception.
|
||||
|
||||
"""
|
||||
if self._phonon_dataset is None:
|
||||
raise RuntimeError("Dataset for fc2does not exist.")
|
||||
|
||||
if target in self._phonon_dataset:
|
||||
if target in self._phonon_dataset: # type-2
|
||||
return self._phonon_dataset[target]
|
||||
elif "first_atoms" in self._phonon_dataset:
|
||||
elif "first_atoms" in self._phonon_dataset: # type-1
|
||||
values = []
|
||||
for disp in self._phonon_dataset["first_atoms"]:
|
||||
if target == "forces":
|
||||
|
@ -2332,10 +2371,7 @@ class Phono3py:
|
|||
values.append(disp["supercell_energy"])
|
||||
if values:
|
||||
return np.array(values, dtype="double", order="C")
|
||||
else:
|
||||
None
|
||||
else:
|
||||
raise RuntimeError("FC2 displacement dataset is in wrong format.")
|
||||
return None
|
||||
|
||||
def _set_phonon_forces_energies(
|
||||
self, values, target: Literal["forces", "supercell_energies"]
|
||||
|
@ -2351,7 +2387,7 @@ class Phono3py:
|
|||
disp["supercell_energy"] = float(v)
|
||||
elif "displacements" in self._phonon_dataset:
|
||||
_values = np.array(values, dtype="double", order="C")
|
||||
natom = len(self._supercell)
|
||||
natom = len(self._phonon_supercell)
|
||||
ndisps = len(self._phonon_dataset["displacements"])
|
||||
if target == "forces" and (
|
||||
_values.ndim != 3 or _values.shape != (ndisps, natom, 3)
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
"""Tests of Phono3py API."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
|
||||
from phono3py import Phono3py
|
||||
|
||||
cwd = Path(__file__).parent
|
||||
|
@ -40,3 +44,125 @@ def test_displacements_setter_Si(si_pbesol_111_222_fd: Phono3py):
|
|||
)
|
||||
ph3.displacements = displacements
|
||||
ph3.phonon_displacements = phonon_displacements
|
||||
|
||||
|
||||
def test_type1_forces_energies_setter_Si(si_111_222_fd: Phono3py):
|
||||
"""Test type1 supercell_energies, phonon_supercell_energies attributes."""
|
||||
ph3_in = si_111_222_fd
|
||||
ref_ph_supercell_energies = [-346.85204143]
|
||||
ref_supercell_energies = [
|
||||
-43.3509760,
|
||||
-43.33608775,
|
||||
-43.35352904,
|
||||
-43.34370672,
|
||||
-43.34590849,
|
||||
-43.34540162,
|
||||
-43.34421408,
|
||||
-43.34481089,
|
||||
-43.34703607,
|
||||
-43.34241924,
|
||||
-43.34786243,
|
||||
-43.34168203,
|
||||
-43.34274245,
|
||||
-43.34703607,
|
||||
-43.34786243,
|
||||
-43.34184454,
|
||||
]
|
||||
np.testing.assert_allclose(ph3_in.supercell_energies, ref_supercell_energies)
|
||||
np.testing.assert_allclose(
|
||||
ph3_in.phonon_supercell_energies, ref_ph_supercell_energies
|
||||
)
|
||||
|
||||
ref_force00 = [-0.4109520800000000, 0.0000000100000000, 0.0000000300000000]
|
||||
ref_force_last = [0.1521426300000000, 0.0715600600000000, -0.0715600700000000]
|
||||
ref_ph_force00 = [-0.4027479600000000, 0.0000000200000000, 0.0000001000000000]
|
||||
np.testing.assert_allclose(ph3_in.forces[0, 0], ref_force00)
|
||||
np.testing.assert_allclose(ph3_in.forces[-1, -1], ref_force_last)
|
||||
np.testing.assert_allclose(ph3_in.phonon_forces[0, 0], ref_ph_force00)
|
||||
|
||||
ph3 = Phono3py(
|
||||
ph3_in.unitcell,
|
||||
supercell_matrix=ph3_in.supercell_matrix,
|
||||
phonon_supercell_matrix=ph3_in.phonon_supercell_matrix,
|
||||
primitive_matrix=ph3_in.primitive_matrix,
|
||||
)
|
||||
ph3.dataset = ph3_in.dataset
|
||||
ph3.phonon_dataset = ph3_in.phonon_dataset
|
||||
|
||||
ph3.supercell_energies = ph3_in.supercell_energies + 1
|
||||
ph3.phonon_supercell_energies = ph3_in.phonon_supercell_energies + 1
|
||||
np.testing.assert_allclose(ph3_in.supercell_energies + 1, ph3.supercell_energies)
|
||||
np.testing.assert_allclose(
|
||||
ph3_in.phonon_supercell_energies + 1, ph3.phonon_supercell_energies
|
||||
)
|
||||
|
||||
ph3.forces = ph3_in.forces + 1
|
||||
ph3.phonon_forces = ph3_in.phonon_forces + 1
|
||||
np.testing.assert_allclose(ph3_in.forces + 1, ph3.forces)
|
||||
np.testing.assert_allclose(ph3_in.phonon_forces + 1, ph3.phonon_forces)
|
||||
|
||||
|
||||
def test_type2_forces_energies_setter_Si(si_111_222_rd: Phono3py):
|
||||
"""Test type2 supercell_energies, phonon_supercell_energies attributes."""
|
||||
ph3_in = si_111_222_rd
|
||||
ref_ph_supercell_energies = [
|
||||
-346.81061270, # 1
|
||||
-346.81263617, # 2
|
||||
]
|
||||
ref_supercell_energies = [
|
||||
-43.35270268, # 1
|
||||
-43.35211687, # 2
|
||||
-43.35122776, # 3
|
||||
-43.35226673, # 4
|
||||
-43.35146358, # 5
|
||||
-43.35133209, # 6
|
||||
-43.35042212, # 7
|
||||
-43.35008442, # 8
|
||||
-43.34968796, # 9
|
||||
-43.35348999, # 10
|
||||
-43.35134937, # 11
|
||||
-43.35335251, # 12
|
||||
-43.35160892, # 13
|
||||
-43.35009115, # 14
|
||||
-43.35202797, # 15
|
||||
-43.35076370, # 16
|
||||
-43.35174477, # 17
|
||||
-43.35107001, # 18
|
||||
-43.35037949, # 19
|
||||
-43.35126123, # 20
|
||||
]
|
||||
np.testing.assert_allclose(ph3_in.supercell_energies, ref_supercell_energies)
|
||||
np.testing.assert_allclose(
|
||||
ph3_in.phonon_supercell_energies, ref_ph_supercell_energies
|
||||
)
|
||||
|
||||
ref_force00 = [0.0445647800000000, 0.1702929900000000, 0.0913398200000000]
|
||||
ref_force_last = [-0.1749668700000000, 0.0146997300000000, -0.1336066300000000]
|
||||
ref_ph_force00 = [-0.0161598900000000, -0.1161657500000000, 0.1399128100000000]
|
||||
ref_ph_force_last = [0.1049486700000000, 0.0795870900000000, 0.1062164600000000]
|
||||
|
||||
np.testing.assert_allclose(ph3_in.forces[0, 0], ref_force00)
|
||||
np.testing.assert_allclose(ph3_in.forces[-1, -1], ref_force_last)
|
||||
np.testing.assert_allclose(ph3_in.phonon_forces[0, 0], ref_ph_force00)
|
||||
np.testing.assert_allclose(ph3_in.phonon_forces[-1, -1], ref_ph_force_last)
|
||||
|
||||
ph3 = Phono3py(
|
||||
ph3_in.unitcell,
|
||||
supercell_matrix=ph3_in.supercell_matrix,
|
||||
phonon_supercell_matrix=ph3_in.phonon_supercell_matrix,
|
||||
primitive_matrix=ph3_in.primitive_matrix,
|
||||
)
|
||||
ph3.dataset = ph3_in.dataset
|
||||
ph3.phonon_dataset = ph3_in.phonon_dataset
|
||||
ph3.supercell_energies = ph3_in.supercell_energies + 1
|
||||
ph3.phonon_supercell_energies = ph3_in.phonon_supercell_energies + 1
|
||||
|
||||
np.testing.assert_allclose(ph3_in.supercell_energies + 1, ph3.supercell_energies)
|
||||
np.testing.assert_allclose(
|
||||
ph3_in.phonon_supercell_energies + 1, ph3.phonon_supercell_energies
|
||||
)
|
||||
|
||||
ph3.forces = ph3_in.forces + 1
|
||||
ph3.phonon_forces = ph3_in.phonon_forces + 1
|
||||
np.testing.assert_allclose(ph3_in.forces + 1, ph3.forces)
|
||||
np.testing.assert_allclose(ph3_in.phonon_forces + 1, ph3.phonon_forces)
|
||||
|
|
|
@ -483,6 +483,20 @@ def aln_lda(request) -> Phono3py:
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def si_111_222_fd() -> Phono3py:
|
||||
"""Return Phono3py class instance of Si-1x1x1-2x2x2 FD."""
|
||||
yaml_filename = cwd / "phono3py_params_Si-111-222-fd.yaml.xz"
|
||||
return phono3py.load(yaml_filename, produce_fc=False, log_level=1)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def si_111_222_rd() -> Phono3py:
|
||||
"""Return Phono3py class instance of Si-1x1x1-2x2x2 RD."""
|
||||
yaml_filename = cwd / "phono3py_params_Si-111-222-rd.yaml.xz"
|
||||
return phono3py.load(yaml_filename, produce_fc=False, log_level=1)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def ph_nacl() -> Phonopy:
|
||||
"""Return Phonopy class instance of NaCl 2x2x2."""
|
||||
|
@ -512,7 +526,7 @@ def ph_si() -> Phonopy:
|
|||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def si_111_222_fd() -> tarfile.TarFile:
|
||||
def si_111_222_fd_raw_data() -> tarfile.TarFile:
|
||||
"""Return Si fc3 111 fc2 222 vasp inputs.
|
||||
|
||||
tar.getnames()
|
||||
|
@ -546,7 +560,7 @@ def si_111_222_fd() -> tarfile.TarFile:
|
|||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def si_111_222_rd() -> tarfile.TarFile:
|
||||
def si_111_222_rd_raw_data() -> tarfile.TarFile:
|
||||
"""Return Si fc3 111 fc2 222 vasp inputs.
|
||||
|
||||
tar.getnames()
|
||||
|
|
Loading…
Reference in New Issue