File: test_gpumd.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 (182 lines) | stat: -rw-r--r-- 7,254 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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# fmt: off
"""GPUMD input file parser.

Implemented:
* Input file (xyz.in)

"""
import numpy as np
import pytest

from ase import io
from ase.build import bulk
from ase.io.gpumd import load_xyz_input_gpumd


@pytest.fixture()
def gpumd_input_text():
    """This file is parsed correctly by GPUMD, since it is included
    among the examples distributed with the package, i.e.
    GPUMD/examples/ex5/xyz.in"""
    return """16 4 1.1 0 1 2
    1 1 1 6.18408 6.18408 6.18408
    0 24.6747 -9.37798 21.2733 28.085 0.0250834 -0.00953331 0.0216256 0 0
    1 29.7632 16.4709 -20.349 12.011 0.0291449 0.0156324 -0.0217974 1 1
    0 -11.3942 20.7898 -16.1723 28.085 -0.0138055 0.0189116 -0.0164401 2 0
    1 14.1056 -16.6803 15.5969 12.011 0.0110053 -0.0202905 0.0147439 3 1
    0 -6.83647 -7.06634 33.159 28.085 -0.00917232 -0.00718339 0.0314857 4 0
    1 44.7294 -12.1643 19.0095 12.011 0.0421363 -0.0134771 0.0159904 5 1
    0 -20.8261 1.14004 -38.0268 28.085 -0.0256162 -0.00106368 -0.0408793 6 0
    1 -4.53023 -50.3483 27.9666 12.011 -0.0101618 -0.0545161 0.0250959 7 1
    0 -24.0175 -12.38 -22.0283 28.085 -0.0244153 -0.0148076 -0.0246158 8 0
    1 -19.4088 19.7935 -10.8377 12.011 -0.0208416 0.0167874 -0.0143511 9 1
    0 7.39496 22.8278 17.9552 28.085 0.00529484 0.0187607 0.01603 10 0
    1 -1.24082 -7.64731 15.2911 12.011 -0.00459528 -0.0133305 0.0122104 11 1
    0 8.12018 25.4121 -10.6444 28.085 0.00603208 0.0236104 -0.0152659 12 0
    1 38.2451 -24.2186 31.0212 12.011 0.0355446 -0.0279537 0.0259785 13 1
    0 4.30332 19.9209 -9.21584 28.085 -7.06147e-05 0.0158056 -0.0138137 14 0
    1 8.91989 -1.32745 44.8546 12.011 0.00351112 -0.00690595 0.040041 15 1 """


@pytest.fixture()
def rocksalt():
    return bulk('NiO', 'rocksalt', 4.813, cubic=True)


def check_against_example_xyz(atoms):
    """Check atoms object against example structure
    (defined in gpumd_input_text)"""
    assert len(atoms) == 16
    assert set(atoms.symbols) == {'Si', 'C'}
    assert all(atoms.get_pbc())
    assert len(atoms.info) == len(atoms)
    assert len(atoms.get_velocities()) == len(atoms)

    # Check groups
    groupings = [[[i] for i in range(len(atoms))],
                 [[i for i, s in
                   enumerate(atoms.get_chemical_symbols()) if s == 'Si'],
                  [i for i, s in
                   enumerate(atoms.get_chemical_symbols()) if s == 'C']]]
    groups = [[[j for j, group in enumerate(grouping) if i in group][0]
               for grouping in groupings] for i in range(len(atoms))]
    assert all(np.array_equal(
        atoms.info[i]['groups'], np.array(groups[i])) for i in
        range(len(atoms)))


def test_read_gpumd(gpumd_input_text):
    """Test GPUMD default read."""
    with open('xyz.in', 'w') as fd:
        fd.write(gpumd_input_text)
    atoms = io.read('xyz.in', format='gpumd')
    check_against_example_xyz(atoms)


def test_read_gpumd_with_specified_species(gpumd_input_text):
    """Test GPUMD read when species are specified."""
    with open('xyz.in', 'w') as fd:
        fd.write(gpumd_input_text)

    species = ['Si', 'C']
    atoms = io.read('xyz.in', format='gpumd', species=species)
    check_against_example_xyz(atoms)


def test_read_gpumd_with_specified_masses(gpumd_input_text):
    """Test GPUMD read when isotope masses are specified."""
    with open('xyz.in', 'w') as fd:
        fd.write(gpumd_input_text)

    isotope_masses = {'Si': [28.085], 'C': [12.011]}
    atoms = io.read('xyz.in', format='gpumd',
                    isotope_masses=isotope_masses)
    check_against_example_xyz(atoms)


def test_load_gpumd_input(gpumd_input_text):
    """Load all information from a GPUMD input file."""
    with open('xyz.in', 'w') as fd:
        fd.write(gpumd_input_text)

    species_ref = ['Si', 'C']
    with open('xyz.in') as fd:
        atoms, input_parameters, species =\
            load_xyz_input_gpumd(fd, species=species_ref)
    input_parameters_ref = {'N': 16, 'M': 4, 'cutoff': 1.1,
                            'triclinic': 0, 'has_velocity': 1,
                            'num_of_groups': 2}
    assert input_parameters == input_parameters_ref
    assert species == species_ref
    check_against_example_xyz(atoms)


def test_gpumd_write_cubic(rocksalt):
    """Test write and load with triclinic cell."""
    rocksalt.write('xyz.in')

    # Ensure that we get the same structure back when reading
    readback = io.read('xyz.in')
    assert np.allclose(rocksalt.positions, readback.positions)
    assert np.allclose(rocksalt.cell, readback.cell)
    assert np.array_equal(rocksalt.numbers, readback.numbers)


def test_gpumd_write_triclinic(rocksalt):
    """Test write and load with triclinic cell."""
    rocksalt.write('xyz.in', use_triclinic=True)
    with open('xyz.in') as fd:
        readback, input_parameters, _ = load_xyz_input_gpumd(fd)
    assert input_parameters['triclinic'] == 1
    assert np.allclose(rocksalt.positions, readback.positions)
    assert np.allclose(rocksalt.cell, readback.cell)
    assert np.array_equal(rocksalt.numbers, readback.numbers)


def test_gpumd_write_with_groupings(rocksalt):
    """Test write and load with groupings."""
    groupings = [[[i for i, s in
                   enumerate(rocksalt.get_chemical_symbols()) if s == 'Ni'],
                  [i for i, s in
                   enumerate(rocksalt.get_chemical_symbols()) if s == 'O']],
                 [[i] for i in range(len(rocksalt))]]
    groups = [[[j for j, group in enumerate(grouping) if i in group][0]
               for grouping in groupings] for i in range(len(rocksalt))]
    rocksalt.write('xyz.in', groupings=groupings)
    with open('xyz.in') as fd:
        readback, input_parameters, _ = load_xyz_input_gpumd(fd)
    assert input_parameters['num_of_groups'] == 2
    assert len(readback.info) == len(rocksalt)
    assert all(np.array_equal(
        readback.info[i]['groups'], np.array(groups[i])) for i in
        range(len(rocksalt)))


def test_gpumd_write_with_velocities(rocksalt):
    """Test write and load with velocities."""
    velocities = np.array([[-0.3, 2.3, 0.7], [0.0, 0.3, 0.8],
                           [-0.6, 0.9, 0.1], [-1.7, -0.1, -0.5],
                           [-0.5, 0.0, 0.6], [-0.2, 0.1, 0.5],
                           [-0.1, 1.4, -1.9], [-1.0, -0.5, -1.2]])
    rocksalt.set_velocities(velocities)
    rocksalt.write('xyz.in')
    with open('xyz.in') as fd:
        readback, input_parameters, _ = load_xyz_input_gpumd(fd)
    assert input_parameters['has_velocity'] == 1
    assert np.allclose(readback.get_velocities(), rocksalt.get_velocities())


def test_gpumd_write_with_custom_species(rocksalt):
    """Test write and read with custom species definitions."""
    rocksalt.write('xyz.in', species=['O', 'Ni'])
    readback = io.read('xyz.in', species=['O', 'Ni'])
    assert np.allclose(rocksalt.positions, readback.positions)
    assert np.allclose(rocksalt.cell, readback.cell)
    assert np.array_equal(rocksalt.numbers, readback.numbers)


def test_gpumd_write_raises_exception_on_species_mismatch(rocksalt):
    """Test that writing raises an exception when there is a
    mismatch between species and atoms object."""
    with pytest.raises(ValueError):
        rocksalt.write('xyz.in', species=['O', 'H'])