File: test_fixedline_fixedplane.py

package info (click to toggle)
python-ase 3.26.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 15,484 kB
  • sloc: python: 148,112; xml: 2,728; makefile: 110; javascript: 47
file content (139 lines) | stat: -rw-r--r-- 4,001 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# fmt: off
import numpy as np
import pytest

from ase.build import molecule
from ase.calculators.emt import EMT
from ase.constraints import FixedLine, FixedPlane
from ase.optimize import BFGS


@pytest.fixture(params=[FixedLine, FixedPlane])
def fixture_test_class(request):
    return request.param


@pytest.mark.parametrize(
    'indices', [
        0,
        [0],
        [0, 1],
        np.array([0, 1], dtype=np.int64),
    ]
)
def test_valid_inputs_indices(fixture_test_class, indices):
    _ = fixture_test_class(indices, [1, 0, 0])


@pytest.mark.parametrize(
    'indices', [
        [0, 1, 1],
        [[0, 1], [0, 1]],
    ]
)
def test_invalid_inputs_indices(fixture_test_class, indices):
    with pytest.raises(ValueError) as _:
        _ = fixture_test_class(indices, [1, 0, 0])


@pytest.mark.parametrize('direction', [[0, 0, 1], (0, 0, 1)])
def test_valid_inputs_direction(fixture_test_class, direction):
    _ = fixture_test_class(0, direction)


@pytest.mark.parametrize('direction', [[0, 1], None, "42"])
def test_invalid_inputs_direction(fixture_test_class, direction):
    with pytest.raises(Exception) as _:
        _ = FixedLine(0, direction)


def _check_simple_constraints(constraints, indices):
    mol = molecule("butadiene")
    mol.set_constraint(constraints)

    assert len(mol.constraints) == 1
    assert isinstance(constraints.dir, np.ndarray)
    assert (np.asarray([1, 0, 0]) == constraints.dir).all()

    mol.calc = EMT()

    cold_positions = mol[indices].positions.copy()
    opt = BFGS(mol)
    opt.run(steps=5)
    cnew_positions = mol[indices].positions.copy()

    return cold_positions, cnew_positions


@pytest.mark.parametrize('indices', [0, [0], [0, 1]])
def test_repr_fixedline(fixture_test_class, indices):
    repr(FixedLine(indices, [1, 0, 0])) == (
        "<FixedLine: "
        "{'indices': " + str(indices) + ", 'direction': [1. 0. 0.]}>"
    )


@pytest.mark.parametrize(
    'indices,expected', [
        (0, 2),
        ([0], 2),
        ([0, 1], 4),
    ]
)
def test_removed_dof_fixedline(indices, expected):
    mol = molecule("butadiene")  # `get_removed_dof` requires an `Atoms` object
    constraints = FixedLine(indices, direction=[1, 0, 0])
    assert constraints.get_removed_dof(atoms=mol) == expected


@pytest.mark.optimize()
@pytest.mark.parametrize('indices', [[0], [0, 1]])
def test_constrained_optimization_fixedline(indices):
    """
    A single int is not tested as that changes the call from Atoms.positions
    to Atom.position
    """
    constraints = FixedLine(indices, [1, 0, 0])

    cold_positions, cnew_positions = _check_simple_constraints(
        constraints, indices
    )
    assert np.max(np.abs(cnew_positions[:, 1:] - cold_positions[:, 1:])) < 1e-8
    assert np.max(np.abs(cnew_positions[:, 0] - cold_positions[:, 0])) > 1e-8


@pytest.mark.parametrize('indices', [0, [0], [0, 1]])
def test_repr_fixedplane(fixture_test_class, indices):
    repr(FixedPlane(indices, [1, 0, 0])) == (
        "<FixedPlane: "
        "{'indices': " + str(indices) + ", 'direction': [1. 0. 0.]}>"
    )


@pytest.mark.parametrize(
    'indices,expected', [
        (0, 1),
        ([0], 1),
        ([0, 1], 2),
    ]
)
def test_removed_dof_fixedplane(indices, expected):
    mol = molecule("butadiene")  # `get_removed_dof` requires an `Atoms` object
    constraints = FixedPlane(indices, direction=[1, 0, 0])
    assert constraints.get_removed_dof(atoms=mol) == expected


@pytest.mark.optimize()
@pytest.mark.parametrize('indices', [[0], [0, 1]])
def test_constrained_optimization_fixedplane(indices):
    """
    A single int is not tested as that changes the call from Atoms.positions
    to Atom.position
    """
    constraints = FixedPlane(indices, [1, 0, 0])

    cold_positions, cnew_positions = _check_simple_constraints(
        constraints, indices
    )
    assert np.max(np.abs(cnew_positions[:, 1:] - cold_positions[:, 1:])) > 1e-8
    assert np.max(np.abs(cnew_positions[:, 0] - cold_positions[:, 0])) < 1e-8