File: test_bulk_operators.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 (114 lines) | stat: -rw-r--r-- 4,690 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
import os
import numpy as np
import pytest
from ase import Atoms
from ase.build import bulk
from ase.ga.utilities import (closest_distances_generator, atoms_too_close,
                              CellBounds)
from ase.ga.startgenerator import StartGenerator
from ase.ga.cutandsplicepairing import CutAndSplicePairing
from ase.ga.soft_mutation import SoftMutation
from ase.ga.ofp_comparator import OFPComparator
from ase.ga.offspring_creator import CombinationMutation
from ase.ga.standardmutations import (RattleMutation, PermutationMutation,
                                      StrainMutation, RotationalMutation,
                                      RattleRotationalMutation)


@pytest.mark.slow
def test_bulk_operators(seed):
    # set up the random number generator
    rng = np.random.RandomState(seed)

    h2 = Atoms('H2', positions=[[0, 0, 0], [0, 0, 0.75]])
    blocks = [('H', 4), ('H2O', 3), (h2, 2)]  # the building blocks
    volume = 40. * sum([x[1] for x in blocks])  # cell volume in angstrom^3
    splits = {(2,): 1, (1,): 1}  # cell splitting scheme

    stoichiometry = []
    for block, count in blocks:
        if type(block) == str:
            stoichiometry += list(Atoms(block).numbers) * count
        else:
            stoichiometry += list(block.numbers) * count

    atom_numbers = list(set(stoichiometry))
    blmin = closest_distances_generator(atom_numbers=atom_numbers,
                                        ratio_of_covalent_radii=1.3)

    cellbounds = CellBounds(bounds={'phi': [30, 150], 'chi': [30, 150],
                                    'psi': [30, 150], 'a': [3, 50],
                                    'b': [3, 50], 'c': [3, 50]})

    slab = Atoms('', pbc=True)
    sg = StartGenerator(slab, blocks, blmin, box_volume=volume,
                        number_of_variable_cell_vectors=3,
                        cellbounds=cellbounds, splits=splits, rng=rng)

    # Generate 2 candidates
    a1 = sg.get_new_candidate()
    a1.info['confid'] = 1
    a2 = sg.get_new_candidate()
    a2.info['confid'] = 2

    # Define and test genetic operators
    n_top = len(a1)
    pairing = CutAndSplicePairing(slab, n_top, blmin, p1=1., p2=0., minfrac=0.15,
                                  number_of_variable_cell_vectors=3,
                                  cellbounds=cellbounds, use_tags=True, rng=rng)

    a3, desc = pairing.get_new_individual([a1, a2])
    cell = a3.get_cell()
    assert cellbounds.is_within_bounds(cell)
    assert not atoms_too_close(a3, blmin, use_tags=True)

    n_top = len(a1)
    strainmut = StrainMutation(blmin, stddev=0.7, cellbounds=cellbounds,
                               number_of_variable_cell_vectors=3,
                               use_tags=True, rng=rng)
    softmut = SoftMutation(blmin, bounds=[2., 5.], used_modes_file=None,
                           use_tags=True)  # no rng
    rotmut = RotationalMutation(blmin, fraction=0.3, min_angle=0.5 * np.pi,
                                rng=rng)
    rattlemut = RattleMutation(blmin, n_top, rattle_prop=0.3, rattle_strength=0.5,
                               use_tags=True, test_dist_to_slab=False, rng=rng)
    rattlerotmut = RattleRotationalMutation(rattlemut, rotmut)  # no rng
    permut = PermutationMutation(n_top, probability=0.33, test_dist_to_slab=False,
                                 use_tags=True, blmin=blmin, rng=rng)
    combmut = CombinationMutation(rattlemut, rotmut, verbose=True)  # no rng
    mutations = [strainmut, softmut, rotmut,
                 rattlemut, rattlerotmut, permut, combmut]

    for i, mut in enumerate(mutations):
        a = [a1, a2][i % 2]
        a3 = None
        while a3 is None:
            a3, desc = mut.get_new_individual([a])

        cell = a3.get_cell()
        assert cellbounds.is_within_bounds(cell)
        assert np.all(a3.numbers == a.numbers)
        assert not atoms_too_close(a3, blmin, use_tags=True)

    modes_file = 'modes.txt'
    softmut_with = SoftMutation(blmin, bounds=[2., 5.], use_tags=True,
                                used_modes_file=modes_file)  # no rng
    no_muts = 3
    for _ in range(no_muts):
        softmut_with.get_new_individual([a1])
    softmut_with.read_used_modes(modes_file)
    assert len(list(softmut_with.used_modes.values())[0]) == no_muts
    os.remove(modes_file)

    comparator = OFPComparator(recalculate=True)
    gold = bulk('Au') * (2, 2, 2)
    assert comparator.looks_like(gold, gold)

    # This move should not exceed the default threshold
    gc = gold.copy()
    gc[0].x += .1
    assert comparator.looks_like(gold, gc)

    # An additional step will exceed the threshold
    gc[0].x += .2
    assert not comparator.looks_like(gold, gc)