File: test_shared_calculator_neb.py

package info (click to toggle)
python-ase 3.21.1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 13,936 kB
  • sloc: python: 122,428; xml: 946; makefile: 111; javascript: 47
file content (120 lines) | stat: -rw-r--r-- 4,702 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""
This is testing NEB in general, though at the moment focusing on the shared
calculator implementation that is replacing
the SingleCalculatorNEB class.
Intending to be a *true* unittest, by testing small things
"""

from pytest import warns, raises

from ase import Atoms
from ase import neb
from ase.calculators.emt import EMT
from ase.calculators.singlepoint import SinglePointCalculator


def test_get_neb_method():
    neb_dummy = neb.NEB([])

    assert isinstance(neb.get_neb_method(neb_dummy, "eb"), neb.EB)
    assert isinstance(neb.get_neb_method(neb_dummy, "aseneb"), neb.ASENEB)
    assert isinstance(neb.get_neb_method(neb_dummy, "improvedtangent"),
                      neb.ImprovedTangent)

    with raises(ValueError, match=r".*some_random_string.*"):
        _ = neb.get_neb_method(neb_dummy, "some_random_string")


class TestNEB(object):
    @classmethod
    def setup_class(cls):
        cls.h_atom = Atoms("H", positions=[[0., 0., 0.]], cell=[10., 10., 10.])
        cls.h2_molecule = Atoms("H2", positions=[[0., 0., 0.], [0., 1., 0.]])
        cls.images_dummy = [cls.h_atom.copy(), cls.h_atom.copy(),
                            cls.h_atom.copy()]

    def test_deprecations(self):
        # future warning on deprecated class
        with warns(FutureWarning, match=r".*Please use.*"):
            deprecated_neb = neb.SingleCalculatorNEB(self.images_dummy)
        assert deprecated_neb.allow_shared_calculator

        neb_dummy = neb.NEB(self.images_dummy)
        with warns(FutureWarning, match=r".*Please use.*idpp_interpolate.*"):
            neb_dummy.idpp_interpolate(steps=1)

    def test_neb_default(self):
        # default should be allow_shared_calculator=False
        neb_dummy = neb.NEB(self.images_dummy)
        assert not neb_dummy.allow_shared_calculator

    def test_raising_parallel_errors(self):
        # error is calculators are shared in parallel run
        with raises(RuntimeError, match=r".*Cannot use shared calculators.*"):
            _ = neb.NEB(self.images_dummy, allow_shared_calculator=True,
                        parallel=True)

    def test_no_shared_calc(self):
        images_shared_calc = [self.h_atom.copy(), self.h_atom.copy(),
                              self.h_atom.copy()]

        shared_calc = EMT()
        for at in images_shared_calc:
            at.calc = shared_calc

        neb_not_allow = neb.NEB(images_shared_calc,
                                allow_shared_calculator=False)

        # error if calculators are shared but not allowed to be
        with raises(ValueError, match=r".*NEB images share the same.*"):
            neb_not_allow.get_forces()

        # raise if calc cannot be shared
        with raises(RuntimeError, match=r".*Cannot set shared calculator.*"):
            neb_not_allow.set_calculators(EMT())

        # same calculators
        new_calculators = [EMT() for _ in range(neb_not_allow.nimages)]
        neb_not_allow.set_calculators(new_calculators)
        for i in range(neb_not_allow.nimages):
            assert new_calculators[i] == neb_not_allow.images[i].calc

        # just for the intermediate images
        neb_not_allow.set_calculators(new_calculators[1:-1])
        for i in range(1, neb_not_allow.nimages - 1):
            assert new_calculators[i] == neb_not_allow.images[i].calc

        # nimages-1 calculator is not allowed
        with raises(RuntimeError, match=r".*does not fit to len.*"):
            neb_not_allow.set_calculators(new_calculators[:-1])

    def test_init_checks(self):
        mismatch_len = [self.h_atom.copy(), self.h2_molecule.copy()]
        with raises(ValueError, match=r".*different numbers of atoms.*"):
            _ = neb.NEB(mismatch_len)

        mismatch_pbc = [self.h_atom.copy(), self.h_atom.copy()]
        mismatch_pbc[-1].set_pbc(True)
        with raises(ValueError, match=r".*different boundary conditions.*"):
            _ = neb.NEB(mismatch_pbc)

        mismatch_numbers = [
            self.h_atom.copy(),
            Atoms("C", positions=[[0., 0., 0.]], cell=[10., 10., 10.])]
        with raises(ValueError, match=r".*atoms in different orders.*"):
            _ = neb.NEB(mismatch_numbers)

        mismatch_cell = [self.h_atom.copy(), self.h_atom.copy()]
        mismatch_cell[-1].set_cell(mismatch_cell[-1].get_cell() + 0.00001)
        with raises(NotImplementedError, match=r".*Variable cell.*"):
            _ = neb.NEB(mismatch_cell)

    def test_freeze_method(self):
        at = self.h_atom.copy()
        at.calc = EMT()
        at.get_forces()
        results = dict(**at.calc.results)

        neb.NEB.freeze_results_on_image(at, **results)

        assert isinstance(at.calc, SinglePointCalculator)