def test_chain_operators(seed):
    from ase.ga.startgenerator import StartGenerator
    from ase.ga.cutandsplicepairing import CutAndSplicePairing
    from ase.ga.standardmutations import StrainMutation
    from ase.ga.utilities import (closest_distances_generator, atoms_too_close,
                                  CellBounds)
    import numpy as np
    from ase import Atoms

    # set up the random number generator
    rng = np.random.RandomState(seed)

    slab = Atoms('', cell=(0, 16, 16), pbc=[True, False, False])
    blocks = ['C'] * 8
    n_top = 8

    use_tags = False
    num_vcv = 1
    box_volume = 8. * n_top

    blmin = closest_distances_generator(atom_numbers=[6],
                                        ratio_of_covalent_radii=0.6)

    cellbounds = CellBounds(
        bounds={
            'phi': [0.1 * 180., 0.9 * 180.],
            'chi': [0.1 * 180., 0.9 * 180.],
            'psi': [0.1 * 180., 0.9 * 180.],
            'a': [1, 6]
        })

    box_to_place_in = [[None, 6., 6.], [None, [0., 4., 0.], [0., 0., 4.]]]

    sg = StartGenerator(slab,
                        blocks,
                        blmin,
                        box_volume=box_volume,
                        splits=None,
                        box_to_place_in=box_to_place_in,
                        number_of_variable_cell_vectors=num_vcv,
                        cellbounds=cellbounds,
                        test_too_far=True,
                        test_dist_to_slab=False,
                        rng=rng)

    parents = []
    for i in range(2):
        a = None
        while a is None:
            a = sg.get_new_candidate()

        a.info['confid'] = i
        parents.append(a)

        assert len(a) == n_top
        assert len(np.unique(a.get_tags())) == 8
        assert np.allclose(a.get_pbc(), slab.get_pbc())

        p = a.get_positions()
        assert np.min(p[:, 1:]) > 6.
        assert np.max(p[:, 1:]) < 6. + 4.
        assert not atoms_too_close(a, blmin, use_tags=use_tags)

        c = a.get_cell()
        assert np.allclose(c[1:], slab.get_cell()[1:])
        assert cellbounds.is_within_bounds(c)

        v = a.get_volume() * (4. / 16.)**2
        assert abs(v - box_volume) < 1e-5

    # Test cut-and-splice pairing and strain mutation
    pairing = CutAndSplicePairing(slab,
                                  n_top,
                                  blmin,
                                  number_of_variable_cell_vectors=num_vcv,
                                  p1=1.,
                                  p2=0.,
                                  minfrac=0.15,
                                  cellbounds=cellbounds,
                                  use_tags=use_tags,
                                  rng=rng)

    strainmut = StrainMutation(blmin,
                               cellbounds=cellbounds,
                               number_of_variable_cell_vectors=num_vcv,
                               use_tags=use_tags,
                               rng=rng)
    strainmut.update_scaling_volume(parents)

    for operator in [pairing, strainmut]:
        child = None
        while child is None:
            child, desc = operator.get_new_individual(parents)

        assert not atoms_too_close(child, blmin, use_tags=use_tags)
        cell = child.get_cell()
        assert cellbounds.is_within_bounds(cell)
        assert np.allclose(cell[1:], slab.get_cell()[1:])
blmin = closest_distances_generator(atom_numbers_to_optimize, 1.0)
cellbounds = CellBounds(bounds={'phi': [30, 150], 'chi': [30, 150],
                                'psi': [30, 150]})

# Note the "use_tags" keyword argument being used
# to signal that we want to preserve molecular identity
# via the tags
pairing = CutAndSplicePairing(slab, n_top, blmin, p1=1., p2=0.,
                              minfrac=0.15, cellbounds=cellbounds,
                              number_of_variable_cell_vectors=3,
                              use_tags=True)

rattlemut = RattleMutation(blmin, n_top, rattle_prop=0.3, rattle_strength=0.5,
                           use_tags=True)

strainmut = StrainMutation(blmin, stddev=0.7, cellbounds=cellbounds,
                           use_tags=True)

rotmut = RotationalMutation(blmin, fraction=0.3, min_angle=0.5 * np.pi)

rattlerotmut = RattleRotationalMutation(rattlemut, rotmut)

blmin_soft = closest_distances_generator(atom_numbers_to_optimize, 0.8)
softmut = SoftMutation(blmin_soft, bounds=[2., 5.], use_tags=True)

operators = OperationSelector([5, 1, 1, 1, 1, 1], [pairing, rattlemut,
                                                   strainmut, rotmut, rattlerotmut, softmut])

# Relaxing the initial candidates
while da.get_number_of_unrelaxed_candidates() > 0:
    a = da.get_an_unrelaxed_candidate()
    relax(a)
Example #3
0
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)
Example #4
0
def test_film_operators(seed):
    from ase.ga.startgenerator import StartGenerator
    from ase.ga.cutandsplicepairing import CutAndSplicePairing
    from ase.ga.standardmutations import StrainMutation
    from ase.ga.utilities import (closest_distances_generator, atoms_too_close,
                                  CellBounds)
    import numpy as np
    from ase import Atoms
    from ase.build import molecule

    # set up the random number generator
    rng = np.random.RandomState(seed)

    slab = Atoms('', cell=(0, 0, 15), pbc=[True, True, False])

    cation, anion = 'Mg', molecule('OH')
    d_oh = anion.get_distance(0, 1)
    blocks = [(cation, 4), (anion, 8)]
    n_top = 4 + 8 * len(anion)

    use_tags = True
    num_vcv = 2
    box_volume = 8. * n_top

    blmin = closest_distances_generator(atom_numbers=[1, 8, 12],
                                        ratio_of_covalent_radii=0.6)

    cellbounds = CellBounds(
        bounds={
            'phi': [0.1 * 180., 0.9 * 180.],
            'chi': [0.1 * 180., 0.9 * 180.],
            'psi': [0.1 * 180., 0.9 * 180.],
            'a': [2, 8],
            'b': [2, 8]
        })

    box_to_place_in = [[None, None, 3.], [None, None, [0., 0., 5.]]]

    sg = StartGenerator(slab,
                        blocks,
                        blmin,
                        box_volume=box_volume,
                        splits={(2, 1): 1},
                        box_to_place_in=box_to_place_in,
                        number_of_variable_cell_vectors=num_vcv,
                        cellbounds=cellbounds,
                        test_too_far=True,
                        test_dist_to_slab=False,
                        rng=rng)

    parents = []
    for i in range(2):
        a = None
        while a is None:
            a = sg.get_new_candidate()

        a.info['confid'] = i
        parents.append(a)

        assert len(a) == n_top
        assert len(np.unique(a.get_tags())) == 4 + 8
        assert np.allclose(a.get_pbc(), slab.get_pbc())

        p = a.get_positions()
        assert np.min(p[:, 2]) > 3. - 0.5 * d_oh
        assert np.max(p[:, 2]) < 3. + 5. + 0.5 * d_oh
        assert not atoms_too_close(a, blmin, use_tags=use_tags)

        c = a.get_cell()
        assert np.allclose(c[2], slab.get_cell()[2])
        assert cellbounds.is_within_bounds(c)

        v = a.get_volume() * 5. / 15.
        assert abs(v - box_volume) < 1e-5

    # Test cut-and-splice pairing and strain mutation
    pairing = CutAndSplicePairing(slab,
                                  n_top,
                                  blmin,
                                  number_of_variable_cell_vectors=num_vcv,
                                  p1=1.,
                                  p2=0.,
                                  minfrac=0.15,
                                  cellbounds=cellbounds,
                                  use_tags=use_tags,
                                  rng=rng)

    strainmut = StrainMutation(blmin,
                               cellbounds=cellbounds,
                               number_of_variable_cell_vectors=num_vcv,
                               use_tags=use_tags,
                               rng=rng)
    strainmut.update_scaling_volume(parents)

    for operator in [pairing, strainmut]:
        child = None
        while child is None:
            child, desc = operator.get_new_individual(parents)

        assert not atoms_too_close(child, blmin, use_tags=use_tags)
        cell = child.get_cell()
        assert cellbounds.is_within_bounds(cell)
        assert np.allclose(cell[2], slab.get_cell()[2])
Example #5
0
# contributing to at least 15% of the child's scaled coordinates
pairing = CutAndSplicePairing(slab,
                              n_top,
                              blmin,
                              p1=1.,
                              p2=0.,
                              minfrac=0.15,
                              number_of_variable_cell_vectors=3,
                              cellbounds=cellbounds,
                              use_tags=False)

# Define a strain mutation with a typical standard deviation of 0.7
# for the strain matrix elements (drawn from a normal distribution)
strainmut = StrainMutation(blmin,
                           stddev=0.7,
                           cellbounds=cellbounds,
                           number_of_variable_cell_vectors=3,
                           use_tags=False)

# Define a soft mutation; we need to provide a dictionary with
# (typically rather short) minimal interatomic distances which
# is used to determine when to stop displacing the atoms along
# the chosen mode. The minimal and maximal single-atom displacement
# distances (in Angstrom) for a valid mutation are provided via
# the 'bounds' keyword argument.
blmin_soft = closest_distances_generator(atom_numbers_to_optimize, 0.1)
softmut = SoftMutation(blmin_soft, bounds=[2., 5.], use_tags=False)
# By default, the operator will update a "used_modes.json" file
# after every mutation, listing which modes have been used so far
# for each structure in the database. The mode indices start at 3
# as the three lowest frequency modes are translational modes.