Beispiel #1
0
def test_add_candidates():
    import pytest
    from ase.build import fcc111
    from ase.ga.data import PrepareDB
    from ase.ga.data import DataConnection
    from ase.ga.offspring_creator import OffspringCreator
    from ase.ga import set_raw_score

    import os

    db_file = 'gadb.db'
    if os.path.isfile(db_file):
        os.remove(db_file)

    db = PrepareDB(db_file)

    slab1 = fcc111('Ag', size=(2, 2, 2))
    db.add_unrelaxed_candidate(slab1)

    slab2 = fcc111('Cu', size=(2, 2, 2))
    set_raw_score(slab2, 4)
    db.add_relaxed_candidate(slab2)
    assert slab2.info['confid'] == 3

    db = DataConnection(db_file)
    assert db.get_number_of_unrelaxed_candidates() == 1

    slab3 = db.get_an_unrelaxed_candidate()
    old_confid = slab3.info['confid']
    slab3[0].symbol = 'Au'
    db.add_unrelaxed_candidate(slab3, 'mutated: Parent {0}'.format(old_confid))
    new_confid = slab3.info['confid']
    # confid should update when using add_unrelaxed_candidate
    assert old_confid != new_confid
    slab3[1].symbol = 'Au'
    db.add_unrelaxed_step(slab3, 'mutated: Parent {0}'.format(new_confid))
    # confid should not change when using add_unrelaxed_step
    assert slab3.info['confid'] == new_confid

    with pytest.raises(AssertionError):
        db.add_relaxed_step(slab3)
    set_raw_score(slab3, 3)
    db.add_relaxed_step(slab3)

    slab4 = OffspringCreator.initialize_individual(slab1,
                                                   fcc111('Au', size=(2, 2, 2)))
    set_raw_score(slab4, 67)
    db.add_relaxed_candidate(slab4)
    assert slab4.info['confid'] == 7

    more_slabs = []
    for m in ['Ni', 'Pd', 'Pt']:
        slab = fcc111(m, size=(2, 2, 2))
        slab = OffspringCreator.initialize_individual(slab1, slab)
        set_raw_score(slab, sum(slab.get_masses()))
        more_slabs.append(slab)
    db.add_more_relaxed_candidates(more_slabs)
    assert more_slabs[1].info['confid'] == 9

    os.remove(db_file)
Beispiel #2
0
def prepare_ga(dbfile='godb.db', splits={(2,): 1}, N=20):

    blocks = [('Pd', 4), ('OH', 8)]  # the building blocks
    volume = 50. * 4 # volume in angstrom^3

    l = [list(Atoms(block).numbers)*count for block, count in blocks]
    stoichiometry = [item for sublist in l for item in sublist]
    atom_numbers = list(set(stoichiometry))

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

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

    # create the starting population
    sg = StartGenerator(blocks, blmin, volume, cellbounds=cellbounds,
                        splits=splits)

    # create the database to store information in
    da = PrepareDB(db_file_name=dbfile, stoichiometry=stoichiometry)

    for i in range(N):
        a = sg.get_new_candidate()
        a.set_initial_magnetic_moments(magmoms=None)
        niggli_reduce(a)
        da.add_unrelaxed_candidate(a)

    return
def test_create_database():
    from ase.ga.data import PrepareDB
    from ase.ga.data import DataConnection
    import os
    import numpy as np

    db_file = 'gadb.db'
    if os.path.isfile(db_file):
        os.remove(db_file)


    from ase.build import fcc111

    atom_numbers = np.array([78, 78, 79, 79])
    slab = fcc111('Ag', size=(4, 4, 2), vacuum=10.)

    PrepareDB(db_file_name=db_file,
              simulation_cell=slab,
              stoichiometry=atom_numbers)

    assert os.path.isfile(db_file)

    dc = DataConnection(db_file)

    slab_get = dc.get_slab()
    an_get = dc.get_atom_numbers_to_optimize()

    assert len(slab) == len(slab_get)
    assert np.all(slab.numbers == slab_get.numbers)
    assert np.all(slab.get_positions() == slab_get.get_positions())
    assert np.all(an_get == atom_numbers)

    os.remove(db_file)
Beispiel #4
0
def prepare_ga(dbfile='godb.db', N=20):
    ''' This method creates a database with the desired number
    of randomly generated structures.
    '''
    blocks = [('Si', 7)]  # the building blocks
    l = [list(Atoms(block).numbers) * count for block, count in blocks]
    stoichiometry = [int(item) for sublist in l for item in sublist]
    atom_numbers = list(set(stoichiometry))

    # This dictionary will be used to check that the shortest
    # Si-Si distances are above a certain threshold 
    # (here 1.5 Angstrom):
    blmin = {(14, 14): 1.5}

    # This defines the cubic simulation cell:
    slab = Atoms('', positions=np.zeros((0, 3)), cell=[16] * 3)

    # This defines the smaller box in which the 
    # initial coordinates are allowed to vary
    density = 0.12  # in atoms per cubic Angstrom
    aspect_ratios = np.array([1.0, 1.0, 1.0])
    v = len(stoichiometry) / density
    l = np.cbrt(v / np.product(aspect_ratios))
    cell = np.identity(3) * aspect_ratios * l
    p0 = 0.5 * (np.diag(slab.get_cell() - cell))
    box = [p0, cell]

    # Seed the random number generators using the system time,
    # to ensure that no two runs produce the same results:
    np.random.seed()
    seed()

    # Generate the random structures and add them to the database:
    sg = StartGenerator(slab=slab, atom_numbers=stoichiometry,
                        closest_allowed_distances=blmin,
                        box_to_place_in=box)

    da = PrepareDB(db_file_name=dbfile,
                   simulation_cell=slab,
                   stoichiometry=stoichiometry)

    for i in range(N):
        a = sg.get_new_candidate()
        da.add_unrelaxed_candidate(a)

    return
def prepare_ga(dbfile='godb.db', N=20):
    """
    This method creates a database with the desired number
    of randomly generated structures.
    """ 
    Z = atomic_numbers['Si']
    atom_numbers = [Z] * 7

    # This dictionary will be used to check that the shortest
    # Si-Si distances are above a certain threshold 
    # (here 1.5 Angstrom):
    blmin = {(Z, Z): 1.5}  

    # This defines the cubic simulation cell. In case there
    big_cell = np.identity(3) * 16.
    slab = Atoms('', cell=big_cell)

    # This defines the smaller box in which the initial
    # coordinates are allowed to be generated
    density = 0.1  # in atoms per cubic Angstrom
    L = np.cbrt(len(atom_numbers) / density)
    small_cell = np.identity(3) * L
    p0 = 0.5 * np.diag(big_cell - small_cell)
    box = [p0, small_cell]

    # Seed the random number generators using the system time,
    # to ensure that no two runs produce the same results:
    np.random.seed()
    seed()

    # Generate the random structures and add them to the database:
    sg = StartGenerator(slab=slab, atom_numbers=atom_numbers,
                        closest_allowed_distances=blmin,
                        box_to_place_in=box)

    da = PrepareDB(db_file_name=dbfile,
                   simulation_cell=slab,
                   stoichiometry=atom_numbers)

    for i in range(N):
        a = sg.get_new_candidate()
        da.add_unrelaxed_candidate(a)

    return
def test_create_database(tmp_path):
    db_file = tmp_path / 'gadb.db'

    atom_numbers = np.array([78, 78, 79, 79])
    slab = fcc111('Ag', size=(4, 4, 2), vacuum=10.)

    PrepareDB(db_file_name=db_file,
              simulation_cell=slab,
              stoichiometry=atom_numbers)

    assert os.path.isfile(db_file)

    dc = DataConnection(db_file)

    slab_get = dc.get_slab()
    an_get = dc.get_atom_numbers_to_optimize()

    assert len(slab) == len(slab_get)
    assert np.all(slab.numbers == slab_get.numbers)
    assert np.all(slab.get_positions() == slab_get.get_positions())
    assert np.all(an_get == atom_numbers)
def test_database_logic(seed, testdir):
    from ase.ga.data import PrepareDB
    from ase.ga.data import DataConnection
    from ase.ga.startgenerator import StartGenerator
    from ase.ga.utilities import closest_distances_generator
    from ase.ga import set_raw_score
    import numpy as np
    from ase.build import fcc111
    from ase.constraints import FixAtoms

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

    slab = fcc111('Au', size=(4, 4, 2), vacuum=10.0, orthogonal=True)
    slab.set_constraint(FixAtoms(mask=slab.positions[:, 2] <= 10.))

    # define the volume in which the adsorbed cluster is optimized
    # the volume is defined by a corner position (p0)
    # and three spanning vectors (v1, v2, v3)
    pos = slab.get_positions()
    cell = slab.get_cell()
    p0 = np.array([0., 0., max(pos[:, 2]) + 2.])
    v1 = cell[0, :] * 0.8
    v2 = cell[1, :] * 0.8
    v3 = cell[2, :]
    v3[2] = 3.

    # define the closest distance between two atoms of a given species
    blmin = closest_distances_generator(atom_numbers=[47, 79],
                                        ratio_of_covalent_radii=0.7)

    # Define the composition of the atoms to optimize
    atom_numbers = 2 * [47] + 2 * [79]

    # create the starting population
    sg = StartGenerator(slab=slab,
                        blocks=atom_numbers,
                        blmin=blmin,
                        box_to_place_in=[p0, [v1, v2, v3]],
                        rng=rng)

    # generate the starting population
    starting_population = [sg.get_new_candidate() for i in range(20)]

    d = PrepareDB(db_file_name=db_file,
                  simulation_cell=slab,
                  stoichiometry=atom_numbers)

    for a in starting_population:
        d.add_unrelaxed_candidate(a)

    # and now for the actual test
    dc = DataConnection(db_file)

    dc.get_slab()
    dc.get_atom_numbers_to_optimize()

    assert dc.get_number_of_unrelaxed_candidates() == 20

    a1 = dc.get_an_unrelaxed_candidate()
    dc.mark_as_queued(a1)

    assert dc.get_number_of_unrelaxed_candidates() == 19
    assert len(dc.get_all_candidates_in_queue()) == 1

    set_raw_score(a1, 0.0)
    dc.add_relaxed_step(a1)

    assert dc.get_number_of_unrelaxed_candidates() == 19
    assert len(dc.get_all_candidates_in_queue()) == 0

    assert len(dc.get_all_relaxed_candidates()) == 1

    a2 = dc.get_an_unrelaxed_candidate()
    dc.mark_as_queued(a2)
    confid = a2.info['confid']
    assert dc.get_all_candidates_in_queue()[0] == confid

    dc.remove_from_queue(confid)
    assert len(dc.get_all_candidates_in_queue()) == 0
# (and not intramolecularly):
Z = atomic_numbers['N']
blmin = closest_distances_generator(atom_numbers=[Z],
                                    ratio_of_covalent_radii=1.3)

# The bounds for the randomly generated unit cells:
cellbounds = CellBounds(bounds={'phi': [30, 150], 'chi': [30, 150],
                                'psi': [30, 150], 'a': [3, 50],
                                'b': [3, 50], 'c': [3, 50]})

# The familiar 'slab' object, here only providing
# the PBC as there are no atoms or cell vectors
# that need to be applied.
slab = Atoms('', pbc=True)

# create the starting population
sg = StartGenerator(slab, blocks, blmin, box_volume=box_volume,
                    cellbounds=cellbounds, splits=splits,
                    number_of_variable_cell_vectors=3,
                    test_too_far=False)

# Initialize the database
da = PrepareDB(db_file_name='gadb.db', simulation_cell=slab,
               stoichiometry=[Z] * 16)

# Generate the new structures
# and add them to the database
for i in range(N):
    a = sg.get_new_candidate()
    da.add_unrelaxed_candidate(a)
Beispiel #9
0
from ase.ga.data import PrepareDB
from ase.ga.data import DataConnection
import os
import numpy as np

db_file = 'gadb.db'
if os.path.isfile(db_file):
    os.remove(db_file)

from ase.lattice.surface import fcc111

atom_numbers = np.array([78, 78, 79, 79])
slab = fcc111('Ag', size=(4, 4, 2), vacuum=10.)

d = PrepareDB(db_file_name=db_file,
              simulation_cell=slab,
              stoichiometry=atom_numbers)

assert os.path.isfile(db_file)

dc = DataConnection(db_file)

slab_get = dc.get_slab()
an_get = dc.get_atom_numbers_to_optimize()

assert len(slab) == len(slab_get)
assert np.all(slab.numbers == slab_get.numbers)
assert np.all(slab.get_positions() == slab_get.get_positions())
assert np.all(an_get == atom_numbers)

os.remove(db_file)
    e = slab.get_potential_energy()
    e_per_atom = e / len(slab)
    refs[m] = e_per_atom
    print('{0} = {1:.3f} eV/atom'.format(m, e_per_atom))

    # The mixing energy for the pure slab is 0 by definition
    set_raw_score(slab, 0.0)
    pure_slabs.append(slab)

# The population size should be at least the number of different compositions
pop_size = 2 * len(slab)

# We prepare the db and write a few constants that we are going to use later
db = PrepareDB('hull.db',
               population_size=pop_size,
               reference_energies=refs,
               metals=metals,
               lattice_constants=lattice_constants)

# We add the pure slabs to the database as relaxed because we have already
# set the raw_score
for slab in pure_slabs:
    db.add_relaxed_candidate(slab,
                             atoms_string=''.join(slab.get_chemical_symbols()))

# Now we create the rest of the candidates for the initial population
for i in range(pop_size - 2):
    # How many of each metal is picked at random, making sure that
    # we do not pick pure slabs
    nA = random.randint(0, len(slab) - 2)
    nB = len(slab) - 2 - nA
Beispiel #11
0
# controls the level of translational symmetry (within the unit
# cell) of the randomly generated structures. Here a 1:1 ratio
# of splitting factors 2 and 1 is used:
splits = {(2,): 1, (1,): 1}
# There will hence be a 50% probability that a candidate
# is constructed by repeating an randomly generated Ag12
# structure along a randomly chosen axis. In the other 50%
# of cases, no cell cell splitting will be applied.

# The 'slab' object in the GA serves as a template
# in the creation of new structures, which inherit
# the slab's atomic positions (if any), cell vectors
# (if specified), and periodic boundary conditions.
# Here only the last property is relevant:
slab = Atoms('', pbc=True)

# Initialize the random structure generator
sg = StartGenerator(slab, blocks, blmin, box_volume=volume,
                    number_of_variable_cell_vectors=3,
                    cellbounds=cellbounds, splits=splits)

# Create the database
da = PrepareDB(db_file_name='gadb.db',
               stoichiometry=[Z] * 24)

# Generate N random structures
# and add them to the database
for i in range(N):
    a = sg.get_new_candidate()
    da.add_unrelaxed_candidate(a)
Beispiel #12
0
from ase.test import must_raise
from ase.build import fcc111
from ase.ga.data import PrepareDB
from ase.ga.data import DataConnection
from ase.ga.offspring_creator import OffspringCreator
from ase.ga import set_raw_score

import os

db_file = 'gadb.db'
if os.path.isfile(db_file):
    os.remove(db_file)

db = PrepareDB(db_file)

slab1 = fcc111('Ag', size=(2, 2, 2))
db.add_unrelaxed_candidate(slab1)

slab2 = fcc111('Cu', size=(2, 2, 2))
set_raw_score(slab2, 4)
db.add_relaxed_candidate(slab2)
assert slab2.info['confid'] == 3

db = DataConnection(db_file)
assert db.get_number_of_unrelaxed_candidates() == 1

slab3 = db.get_an_unrelaxed_candidate()
old_confid = slab3.info['confid']
slab3[0].symbol = 'Au'
db.add_unrelaxed_candidate(slab3, 'mutated: Parent {0}'.format(old_confid))
new_confid = slab3.info['confid']
Beispiel #13
0
def test_basic_example_main_run(seed, testdir):
    # set up the random number generator
    rng = np.random.RandomState(seed)

    # create the surface
    slab = fcc111('Au', size=(4, 4, 1), vacuum=10.0, orthogonal=True)
    slab.set_constraint(FixAtoms(mask=len(slab) * [True]))

    # define the volume in which the adsorbed cluster is optimized
    # the volume is defined by a corner position (p0)
    # and three spanning vectors (v1, v2, v3)
    pos = slab.get_positions()
    cell = slab.get_cell()
    p0 = np.array([0., 0., max(pos[:, 2]) + 2.])
    v1 = cell[0, :] * 0.8
    v2 = cell[1, :] * 0.8
    v3 = cell[2, :]
    v3[2] = 3.

    # Define the composition of the atoms to optimize
    atom_numbers = 2 * [47] + 2 * [79]

    # define the closest distance two atoms of a given species can be to each other
    unique_atom_types = get_all_atom_types(slab, atom_numbers)
    blmin = closest_distances_generator(atom_numbers=unique_atom_types,
                                        ratio_of_covalent_radii=0.7)

    # create the starting population
    sg = StartGenerator(slab=slab,
                        blocks=atom_numbers,
                        blmin=blmin,
                        box_to_place_in=[p0, [v1, v2, v3]],
                        rng=rng)

    # generate the starting population
    population_size = 5
    starting_population = [sg.get_new_candidate() for i in range(population_size)]

    # from ase.visualize import view   # uncomment these lines
    # view(starting_population)        # to see the starting population

    # create the database to store information in
    d = PrepareDB(db_file_name=db_file,
                  simulation_cell=slab,
                  stoichiometry=atom_numbers)

    for a in starting_population:
        d.add_unrelaxed_candidate(a)

    # XXXXXXXXXX This should be the beginning of a new test,
    # but we are using some resources from the precious part.
    # Maybe refactor those things as (module-level?) fixtures.

    # Change the following three parameters to suit your needs
    population_size = 5
    mutation_probability = 0.3
    n_to_test = 5

    # Initialize the different components of the GA
    da = DataConnection('gadb.db')
    atom_numbers_to_optimize = da.get_atom_numbers_to_optimize()
    n_to_optimize = len(atom_numbers_to_optimize)
    slab = da.get_slab()
    all_atom_types = get_all_atom_types(slab, atom_numbers_to_optimize)
    blmin = closest_distances_generator(all_atom_types,
                                        ratio_of_covalent_radii=0.7)

    comp = InteratomicDistanceComparator(n_top=n_to_optimize,
                                         pair_cor_cum_diff=0.015,
                                         pair_cor_max=0.7,
                                         dE=0.02,
                                         mic=False)

    pairing = CutAndSplicePairing(slab, n_to_optimize, blmin, rng=rng)
    mutations = OperationSelector([1., 1., 1.],
                            [MirrorMutation(blmin, n_to_optimize, rng=rng),
                             RattleMutation(blmin, n_to_optimize, rng=rng),
                             PermutationMutation(n_to_optimize, rng=rng)],
                             rng=rng)

    # Relax all unrelaxed structures (e.g. the starting population)
    while da.get_number_of_unrelaxed_candidates() > 0:
        a = da.get_an_unrelaxed_candidate()
        a.calc = EMT()
        print('Relaxing starting candidate {0}'.format(a.info['confid']))
        dyn = BFGS(a, trajectory=None, logfile=None)
        dyn.run(fmax=0.05, steps=100)
        set_raw_score(a, -a.get_potential_energy())
        da.add_relaxed_step(a)

    # create the population
    population = Population(data_connection=da,
                            population_size=population_size,
                            comparator=comp,
                            rng=rng)

    # test n_to_test new candidates
    for i in range(n_to_test):
        print('Now starting configuration number {0}'.format(i))
        a1, a2 = population.get_two_candidates()
        a3, desc = pairing.get_new_individual([a1, a2])
        if a3 is None:
            continue
        da.add_unrelaxed_candidate(a3, description=desc)

        # Check if we want to do a mutation
        if rng.rand() < mutation_probability:
            a3_mut, desc = mutations.get_new_individual([a3])
            if a3_mut is not None:
                da.add_unrelaxed_step(a3_mut, desc)
                a3 = a3_mut

        # Relax the new candidate
        a3.calc = EMT()
        dyn = BFGS(a3, trajectory=None, logfile=None)
        dyn.run(fmax=0.05, steps=100)
        set_raw_score(a3, -a3.get_potential_energy())
        da.add_relaxed_step(a3)
        population.update()

    write('all_candidates.traj', da.get_all_relaxed_candidates())
Beispiel #14
0
import random

from ase import Atoms
from ase.ga.data import PrepareDB

metals = ['Al', 'Au', 'Cu', 'Ag', 'Pd', 'Pt', 'Ni']

population_size = 10

# Create database
db = PrepareDB('fcc_alloys.db', population_size=population_size, metals=metals)

# Create starting population
for i in xrange(population_size):
    atoms_string = [random.choice(metals) for _ in xrange(4)]
    db.add_unrelaxed_candidate(Atoms(atoms_string),
                               atoms_string=''.join(atoms_string))