mirror of https://github.com/phonopy/phono3py.git
New --rd auto option
This commit is contained in:
parent
ae4ad6fa18
commit
1d3d085db7
|
@ -1225,11 +1225,11 @@ class Phono3py:
|
|||
|
||||
def generate_displacements(
|
||||
self,
|
||||
distance: float = 0.03,
|
||||
distance: Optional[float] = None,
|
||||
cutoff_pair_distance: Optional[float] = None,
|
||||
is_plusminus: Union[bool, str] = "auto",
|
||||
is_diagonal: bool = True,
|
||||
number_of_snapshots: Optional[int] = None,
|
||||
number_of_snapshots: Optional[Union[int, Literal["auto"]]] = None,
|
||||
random_seed: Optional[int] = None,
|
||||
max_distance: Optional[float] = None,
|
||||
):
|
||||
|
@ -1269,10 +1269,11 @@ class Phono3py:
|
|||
Parameters
|
||||
----------
|
||||
distance : float, optional
|
||||
Constant displacement Euclidean distance. Default is 0.03. For
|
||||
random direction and random distance displacements generation, this
|
||||
value is also used as `min_distance`, is used to replace generated
|
||||
random distances smaller than this value by this value.
|
||||
Constant displacement Euclidean distance. Default is None, which
|
||||
gives 0.03. For random direction and random distance displacements
|
||||
generation, this value is also used as `min_distance`, is used to
|
||||
replace generated random distances smaller than this value by this
|
||||
value.
|
||||
cutoff_pair_distance : float, optional
|
||||
This is used as a cutoff Euclidean distance to determine if each
|
||||
pair of displacements is considered to calculate fc3 or not. Default
|
||||
|
@ -1288,13 +1289,14 @@ class Phono3py:
|
|||
vectors of the supercell. With True, direction not along the basis
|
||||
vectors can be chosen when the number of the displacements may be
|
||||
reduced.
|
||||
number_of_snapshots : int or None, optional
|
||||
number_of_snapshots : int, "auto", or None, optional
|
||||
Number of snapshots of supercells with random displacements. Random
|
||||
displacements are generated displacing all atoms in random
|
||||
directions with a fixed displacement distance specified by
|
||||
'distance' parameter, i.e., all atoms in supercell are displaced
|
||||
with the same displacement distance in direct space. Default is
|
||||
None.
|
||||
displacements are generated by shifting all atoms in random
|
||||
directions by a fixed distance specified by the `distance`
|
||||
parameter. In other words, all atoms in the supercell are displaced
|
||||
by the same distance in direct space. When “auto”, the minimum
|
||||
required number of snapshots is estimated using symfc and then
|
||||
doubled. The default is None.
|
||||
random_seed : int or None, optional
|
||||
Random seed for random displacements generation. Default is None.
|
||||
max_distance : float or None, optional
|
||||
|
@ -1303,11 +1305,29 @@ class Phono3py:
|
|||
displacements generation, this value is used as `max_distance`.
|
||||
|
||||
"""
|
||||
if number_of_snapshots is not None and number_of_snapshots > 0:
|
||||
if distance is None:
|
||||
_distance = 0.03
|
||||
else:
|
||||
_distance = distance
|
||||
|
||||
if number_of_snapshots is not None and (
|
||||
number_of_snapshots == "auto" or number_of_snapshots > 0
|
||||
):
|
||||
if number_of_snapshots == "auto":
|
||||
from phonopy.interface.symfc import SymfcFCSolver
|
||||
|
||||
_number_of_snapshots = (
|
||||
SymfcFCSolver(
|
||||
self._supercell, self._symmetry
|
||||
).estimate_numbers_of_supercells(orders=[3])[3]
|
||||
* 2
|
||||
)
|
||||
else:
|
||||
_number_of_snapshots = number_of_snapshots
|
||||
self._dataset = self._generate_random_displacements(
|
||||
number_of_snapshots,
|
||||
_number_of_snapshots,
|
||||
len(self._supercell),
|
||||
distance=distance,
|
||||
distance=_distance,
|
||||
is_plusminus=is_plusminus is True,
|
||||
random_seed=random_seed,
|
||||
max_distance=max_distance,
|
||||
|
@ -1321,7 +1341,7 @@ class Phono3py:
|
|||
)
|
||||
self._dataset = direction_to_displacement(
|
||||
direction_dataset,
|
||||
distance,
|
||||
_distance,
|
||||
self._supercell,
|
||||
cutoff_distance=cutoff_pair_distance,
|
||||
)
|
||||
|
@ -1329,15 +1349,15 @@ class Phono3py:
|
|||
|
||||
if self._phonon_supercell_matrix is not None and self._phonon_dataset is None:
|
||||
self.generate_fc2_displacements(
|
||||
distance=distance, is_plusminus=is_plusminus, is_diagonal=False
|
||||
distance=_distance, is_plusminus=is_plusminus, is_diagonal=False
|
||||
)
|
||||
|
||||
def generate_fc2_displacements(
|
||||
self,
|
||||
distance: float = 0.03,
|
||||
distance: Optional[float] = None,
|
||||
is_plusminus: str = "auto",
|
||||
is_diagonal: bool = False,
|
||||
number_of_snapshots: Optional[int] = None,
|
||||
number_of_snapshots: Optional[Union[int, Literal["auto"]]] = None,
|
||||
random_seed: Optional[int] = None,
|
||||
max_distance: Optional[float] = None,
|
||||
):
|
||||
|
@ -1357,10 +1377,11 @@ class Phono3py:
|
|||
Parameters
|
||||
----------
|
||||
distance : float, optional
|
||||
Constant displacement Euclidean distance. Default is 0.03. For
|
||||
random direction and random distance displacements generation, this
|
||||
value is also used as `min_distance`, is used to replace generated
|
||||
random distances smaller than this value by this value.
|
||||
Constant displacement Euclidean distance. Default is None, which
|
||||
gives 0.03. For random direction and random distance displacements
|
||||
generation, this value is also used as `min_distance`, is used to
|
||||
replace generated random distances smaller than this value by this
|
||||
value.
|
||||
is_plusminus : True, False, or 'auto', optional
|
||||
With True, atomis are displaced in both positive and negative
|
||||
directions. With False, only one direction. With 'auto', mostly
|
||||
|
@ -1372,13 +1393,14 @@ class Phono3py:
|
|||
the supercell. With True, direction not along the basis vectors can
|
||||
be chosen when the number of the displacements may be reduced.
|
||||
Default is False.
|
||||
number_of_snapshots : int or None, optional
|
||||
number_of_snapshots : int, "auto", or None, optional
|
||||
Number of snapshots of supercells with random displacements. Random
|
||||
displacements are generated displacing all atoms in random
|
||||
directions with a fixed displacement distance specified by
|
||||
'distance' parameter, i.e., all atoms in supercell are displaced
|
||||
with the same displacement distance in direct space. Default is
|
||||
None.
|
||||
displacements are generated by shifting all atoms in random
|
||||
directions by a fixed distance specified by the `distance`
|
||||
parameter. In other words, all atoms in the supercell are displaced
|
||||
by the same distance in direct space. When “auto”, the minimum
|
||||
required number of snapshots is estimated using symfc and then
|
||||
doubled. The default is None.
|
||||
random_seed : int or None, optional
|
||||
Random seed for random displacements generation. Default is None.
|
||||
max_distance : float or None, optional
|
||||
|
@ -1387,11 +1409,30 @@ class Phono3py:
|
|||
displacements generation, this value is used as `max_distance`.
|
||||
|
||||
"""
|
||||
if number_of_snapshots is not None and number_of_snapshots > 0:
|
||||
if distance is None:
|
||||
_distance = 0.03
|
||||
else:
|
||||
_distance = distance
|
||||
|
||||
if number_of_snapshots is not None and (
|
||||
number_of_snapshots == "auto" or number_of_snapshots > 0
|
||||
):
|
||||
if number_of_snapshots == "auto":
|
||||
from phonopy.interface.symfc import SymfcFCSolver
|
||||
|
||||
_number_of_snapshots = (
|
||||
SymfcFCSolver(
|
||||
self._supercell, self._symmetry
|
||||
).estimate_numbers_of_supercells(orders=[2])[2]
|
||||
* 2
|
||||
)
|
||||
else:
|
||||
_number_of_snapshots = number_of_snapshots
|
||||
|
||||
self._phonon_dataset = self._generate_random_displacements(
|
||||
number_of_snapshots,
|
||||
_number_of_snapshots,
|
||||
len(self._phonon_supercell),
|
||||
distance=distance,
|
||||
distance=_distance,
|
||||
is_plusminus=is_plusminus is True,
|
||||
random_seed=random_seed,
|
||||
max_distance=max_distance,
|
||||
|
@ -1403,7 +1444,7 @@ class Phono3py:
|
|||
is_diagonal=is_diagonal,
|
||||
)
|
||||
self._phonon_dataset = directions_to_displacement_dataset(
|
||||
phonon_displacement_directions, distance, self._phonon_supercell
|
||||
phonon_displacement_directions, _distance, self._phonon_supercell
|
||||
)
|
||||
self._phonon_supercells_with_displacements = None
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import numpy as np
|
||||
from phonopy.interface.calculator import write_supercells_with_displacements
|
||||
from phonopy.structure.cells import print_cell
|
||||
|
||||
|
@ -83,10 +84,13 @@ def create_phono3py_supercells(
|
|||
random_seed=settings.random_seed,
|
||||
)
|
||||
|
||||
if settings.random_displacements_fc2:
|
||||
if (
|
||||
settings.random_displacements_fc2
|
||||
or settings.phonon_supercell_matrix is not None
|
||||
):
|
||||
phono3py.generate_fc2_displacements(
|
||||
distance=distance,
|
||||
is_plusminus=settings.is_plusminus_displacement,
|
||||
is_plusminus=settings.is_plusminus_displacement_fc2,
|
||||
number_of_snapshots=settings.random_displacements_fc2,
|
||||
random_seed=settings.random_seed,
|
||||
)
|
||||
|
@ -156,4 +160,21 @@ def create_phono3py_supercells(
|
|||
if log_level:
|
||||
print("Number of displacements for special fc2: %d" % num_disps)
|
||||
|
||||
if log_level:
|
||||
identity = np.eye(3, dtype=int)
|
||||
n_pure_trans = sum(
|
||||
[
|
||||
(r == identity).all()
|
||||
for r in phono3py.symmetry.symmetry_operations["rotations"]
|
||||
]
|
||||
)
|
||||
|
||||
if len(phono3py.supercell) // len(phono3py.primitive) != n_pure_trans:
|
||||
print("*" * 72)
|
||||
print(
|
||||
"Note: "
|
||||
'A better primitive cell can be chosen by using "--pa auto" option.'
|
||||
)
|
||||
print("*" * 72)
|
||||
|
||||
return phono3py
|
||||
|
|
|
@ -629,6 +629,13 @@ def get_parser(fc_symmetry=False, is_nac=False, load_phono3py_yaml=False):
|
|||
default=False,
|
||||
help="Set plus minus displacements",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pm-fc2",
|
||||
dest="is_plusminus_displacements_fc2",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Set plus minus displacements for extra fc2",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pp-unit-conversion",
|
||||
dest="pp_unit_conversion",
|
||||
|
@ -676,17 +683,15 @@ def get_parser(fc_symmetry=False, is_nac=False, load_phono3py_yaml=False):
|
|||
"--rd",
|
||||
"--random-displacements",
|
||||
dest="random_displacements",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Number of supercells with random displacements",
|
||||
help='Number of supercells with random displacements or "auto"',
|
||||
)
|
||||
parser.add_argument(
|
||||
"--rd-fc2",
|
||||
"--random-displacements-fc2",
|
||||
dest="random_displacements_fc2",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Number of phonon supercells with random displacements",
|
||||
help='Number of phonon supercells with random displacements or "auto"',
|
||||
)
|
||||
parser.add_argument(
|
||||
"--read-collision",
|
||||
|
|
|
@ -66,6 +66,7 @@ class Phono3pySettings(Settings):
|
|||
"is_kappa_star": True,
|
||||
"is_lbte": False,
|
||||
"is_N_U": False,
|
||||
"is_plusminus_displacement_fc2": "auto",
|
||||
"is_real_self_energy": False,
|
||||
"is_reducible_collision_matrix": False,
|
||||
"is_spectral_function": False,
|
||||
|
@ -214,6 +215,10 @@ class Phono3pySettings(Settings):
|
|||
"""Set is_N_U."""
|
||||
self._v["is_N_U"] = val
|
||||
|
||||
def set_is_plusminus_displacement_fc2(self, val):
|
||||
"""Set is_plusminus_displacement_fc2."""
|
||||
self._v["is_plusminus_displacement_fc2"] = val
|
||||
|
||||
def set_is_real_self_energy(self, val):
|
||||
"""Set is_real_self_energy."""
|
||||
self._v["is_real_self_energy"] = val
|
||||
|
@ -488,6 +493,10 @@ class Phono3pyConfParser(ConfParser):
|
|||
if self._args.is_N_U:
|
||||
self._confs["N_U"] = ".true."
|
||||
|
||||
if "is_plusminus_displacements_fc2" in self._args:
|
||||
if self._args.is_plusminus_displacements_fc2:
|
||||
self._confs["pm_fc2"] = ".true."
|
||||
|
||||
if "is_real_self_energy" in self._args:
|
||||
if self._args.is_real_self_energy:
|
||||
self._confs["real_self_energy"] = ".true."
|
||||
|
@ -714,7 +723,6 @@ class Phono3pyConfParser(ConfParser):
|
|||
"pinv_method",
|
||||
"pinv_solver",
|
||||
"num_points_in_batch",
|
||||
"random_displacements_fc2",
|
||||
"scattering_event_class",
|
||||
):
|
||||
self.set_parameter(conf_key, int(confs[conf_key]))
|
||||
|
@ -803,6 +811,22 @@ class Phono3pyConfParser(ConfParser):
|
|||
else:
|
||||
self.set_parameter("temperatures", vals)
|
||||
|
||||
if conf_key == "random_displacements_fc2":
|
||||
rd = confs["random_displacements_fc2"]
|
||||
if rd.lower() == "auto":
|
||||
self.set_parameter("random_displacements_fc2", "auto")
|
||||
else:
|
||||
try:
|
||||
self.set_parameter("random_displacements_fc2", int(rd))
|
||||
except ValueError:
|
||||
self.setting_error(f"{conf_key.upper()} is incorrectly set.")
|
||||
|
||||
if conf_key == "pm_fc2":
|
||||
if confs["pm_fc2"].lower() == ".false.":
|
||||
self.set_parameter("pm_fc2", False)
|
||||
elif confs["pm_fc2"].lower() == ".true.":
|
||||
self.set_parameter("pm_fc2", True)
|
||||
|
||||
def _set_settings(self):
|
||||
self.set_settings()
|
||||
params = self._parameters
|
||||
|
@ -919,6 +943,10 @@ class Phono3pyConfParser(ConfParser):
|
|||
if "N_U" in params:
|
||||
self._settings.set_is_N_U(params["N_U"])
|
||||
|
||||
# Plus minus displacement for fc2
|
||||
if "pm_fc2" in params:
|
||||
self._settings.set_is_plusminus_displacement_fc2(params["pm_fc2"])
|
||||
|
||||
# Solve reducible collision matrix but not reduced matrix
|
||||
if "reducible_collision_matrix" in params:
|
||||
self._settings.set_is_reducible_collision_matrix(
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
"""Tests of displacements.py."""
|
||||
|
||||
import itertools
|
||||
from typing import Literal, Optional, Union
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from phonopy.structure.atoms import PhonopyAtoms
|
||||
|
||||
import phono3py
|
||||
from phono3py import Phono3py
|
||||
|
@ -74,7 +79,49 @@ distances_NaCl = [
|
|||
]
|
||||
|
||||
|
||||
def test_duplicates_agno2(agno2_cell):
|
||||
@pytest.mark.parametrize(
|
||||
"is_plusminus,distance,number_of_snapshots",
|
||||
itertools.product([False, True], [None, 0.06], [8, "auto"]),
|
||||
)
|
||||
def test_random_disps_agno2(
|
||||
agno2_cell: PhonopyAtoms,
|
||||
is_plusminus: bool,
|
||||
distance: Optional[float],
|
||||
number_of_snapshots: Union[int, Literal["auto"]],
|
||||
):
|
||||
"""Test duplicated pairs of displacements."""
|
||||
ph3 = phono3py.load(unitcell=agno2_cell, supercell_matrix=[2, 1, 2])
|
||||
ph3.generate_displacements(
|
||||
number_of_snapshots=number_of_snapshots,
|
||||
distance=distance,
|
||||
is_plusminus=is_plusminus,
|
||||
)
|
||||
|
||||
ph3.generate_fc2_displacements(
|
||||
number_of_snapshots=number_of_snapshots,
|
||||
distance=distance,
|
||||
is_plusminus=is_plusminus,
|
||||
)
|
||||
|
||||
for d, n_d in zip((ph3.displacements, ph3.phonon_displacements), (92, 4)):
|
||||
if number_of_snapshots == "auto":
|
||||
assert len(d) == n_d * (is_plusminus + 1)
|
||||
else:
|
||||
assert len(d) == 8 * (is_plusminus + 1)
|
||||
|
||||
if distance is None:
|
||||
np.testing.assert_allclose(
|
||||
np.linalg.norm(d, axis=2).ravel(), 0.03, atol=1e-8
|
||||
)
|
||||
else:
|
||||
np.testing.assert_allclose(
|
||||
np.linalg.norm(d, axis=2).ravel(), 0.06, atol=1e-8
|
||||
)
|
||||
if is_plusminus:
|
||||
np.testing.assert_allclose(d[: len(d) // 2], -d[len(d) // 2 :], atol=1e-8)
|
||||
|
||||
|
||||
def test_duplicates_agno2(agno2_cell: PhonopyAtoms):
|
||||
"""Test duplicated pairs of displacements."""
|
||||
ph3 = phono3py.load(unitcell=agno2_cell, supercell_matrix=[1, 1, 1])
|
||||
ph3.generate_displacements()
|
||||
|
|
Loading…
Reference in New Issue