From ffbad0501c37bf9915d576c5a9d8198a9f382102 Mon Sep 17 00:00:00 2001 From: Christina Ertural <52951132+QuantumChemist@users.noreply.github.com> Date: Thu, 3 Oct 2024 20:05:00 +0200 Subject: [PATCH] Implementation to adjust get_supercell_size to also generate orthorhombic supercells (#923) * starting with implementation to adjust get_supercell_size * adding orthorhombic supercells * add unit test * fixed the reason for the failing unit tests * adjust pymatgen version * adjust pymatgen version * fix linting * fix missing max_length in unit test * adjusted pymatgen version * add step_size to common_kwds * put max_atoms to common_kwds * adjustments to make unit tests pass * fixing ase unit test * Update test_jobs.py --------- Co-authored-by: J. George --- src/atomate2/common/flows/phonons.py | 10 +++++--- src/atomate2/common/jobs/phonons.py | 37 ++++++++++++++++++++-------- tests/forcefields/test_phonon.py | 36 ++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/atomate2/common/flows/phonons.py b/src/atomate2/common/flows/phonons.py index b8ba9a5f38..887885bdaa 100644 --- a/src/atomate2/common/flows/phonons.py +++ b/src/atomate2/common/flows/phonons.py @@ -132,7 +132,9 @@ class BasePhononMaker(Maker, ABC): symprec: float = SETTINGS.PHONON_SYMPREC displacement: float = 0.01 min_length: float | None = 20.0 + max_length: float | None = None prefer_90_degrees: bool = True + allow_orthorhombic: bool = False get_supercell_size_kwargs: dict = field(default_factory=dict) use_symmetrized_structure: Literal["primitive", "conventional"] | None = None bulk_relax_maker: ForceFieldRelaxMaker | BaseVaspMaker | BaseAimsMaker | None = None @@ -252,9 +254,11 @@ def make( # maker to ensure that cell lengths are really larger than threshold if supercell_matrix is None: supercell_job = get_supercell_size( - structure, - self.min_length, - self.prefer_90_degrees, + structure=structure, + min_length=self.min_length, + max_length=self.max_length, + prefer_90_degrees=self.prefer_90_degrees, + allow_orthorhombic=self.allow_orthorhombic, **self.get_supercell_size_kwargs, ) jobs.append(supercell_job) diff --git a/src/atomate2/common/jobs/phonons.py b/src/atomate2/common/jobs/phonons.py index 285dec17b8..e2ff6e6760 100644 --- a/src/atomate2/common/jobs/phonons.py +++ b/src/atomate2/common/jobs/phonons.py @@ -57,10 +57,15 @@ def get_total_energy_per_cell( @job def get_supercell_size( - structure: Structure, min_length: float, prefer_90_degrees: bool, **kwargs + structure: Structure, + min_length: float, + max_length: float, + prefer_90_degrees: bool, + allow_orthorhombic: bool = False, + **kwargs, ) -> list[list[float]]: """ - Determine supercell size with given min_length. + Determine supercell size with given min_length and max_length. Parameters ---------- @@ -68,36 +73,48 @@ def get_supercell_size( Input structure that will be used to determine supercell min_length: float minimum length of cell in Angstrom + max_length: float + maximum length of cell in Angstrom prefer_90_degrees: bool if True, the algorithm will try to find a cell with 90 degree angles first + allow_orthorhombic: bool + if True, orthorhombic supercells are allowed **kwargs: Additional parameters that can be set. """ kwargs.setdefault("force_diagonal", False) - common_kwds = { - "min_length": min_length, - "min_atoms": kwargs.get("min_atoms"), - "force_diagonal": kwargs["force_diagonal"], - } + common_kwds = dict( + min_length=min_length, + max_length=max_length, + min_atoms=kwargs.get("min_atoms"), + max_atoms=kwargs.get("max_atoms"), + step_size=kwargs.get("step_size", 0.1), + force_diagonal=kwargs["force_diagonal"], + ) if not prefer_90_degrees: transformation = CubicSupercellTransformation( - **common_kwds, max_atoms=kwargs.get("max_atoms"), force_90_degrees=False + **common_kwds, + force_90_degrees=False, + allow_orthorhombic=allow_orthorhombic, ) transformation.apply_transformation(structure=structure) else: try: + common_kwds.update({"max_atoms": kwargs.get("max_atoms", 1200)}) transformation = CubicSupercellTransformation( **common_kwds, - max_atoms=kwargs.get("max_atoms", 1200), force_90_degrees=True, angle_tolerance=kwargs.get("angle_tolerance", 1e-2), + allow_orthorhombic=allow_orthorhombic, ) transformation.apply_transformation(structure=structure) except AttributeError: transformation = CubicSupercellTransformation( - **common_kwds, max_atoms=kwargs.get("max_atoms"), force_90_degrees=False + **common_kwds, + force_90_degrees=False, + allow_orthorhombic=allow_orthorhombic, ) transformation.apply_transformation(structure=structure) diff --git a/tests/forcefields/test_phonon.py b/tests/forcefields/test_phonon.py index 96fe0df914..719f05cf76 100644 --- a/tests/forcefields/test_phonon.py +++ b/tests/forcefields/test_phonon.py @@ -12,7 +12,9 @@ def test_phonon_get_supercell_size(clean_dir, si_structure: Structure): - job = get_supercell_size(si_structure, min_length=18, prefer_90_degrees=True) + job = get_supercell_size( + si_structure, min_length=18, max_length=25, prefer_90_degrees=True + ) # run the flow or job and ensure that it finished running successfully responses = run_locally(job, create_folders=True, ensure_success=True) @@ -20,6 +22,38 @@ def test_phonon_get_supercell_size(clean_dir, si_structure: Structure): assert_allclose(responses[job.uuid][1].output, [[6, -2, 0], [0, 6, 0], [-3, -2, 5]]) +def test_supercell_orthorhombic(clean_dir, si_structure: Structure): + job1 = get_supercell_size( + si_structure, + min_length=5, + max_length=10, + prefer_90_degrees=False, + allow_orhtorhombic=True, + ) + + # run the flow or job and ensure that it finished running successfully + responses = run_locally(job1, create_folders=True, ensure_success=True) + + assert_allclose( + responses[job1.uuid][1].output, [[2, -1, 0], [0, 2, 0], [-1, -1, 2]] + ) + + job2 = get_supercell_size( + si_structure, + min_length=5, + max_length=10, + prefer_90_degrees=True, + allow_orhtorhombic=True, + ) + + # run the flow or job and ensure that it finished running successfully + responses = run_locally(job2, create_folders=True, ensure_success=True) + + assert_allclose( + responses[job2.uuid][1].output, [[2, -1, 0], [0, 3, 0], [-1, -1, 2]] + ) + + def test_phonon_maker_initialization_with_all_mlff( si_structure: Structure, test_dir: Path ):