Ejemplo n.º 1
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
Ejemplo n.º 2
0
    def __init__(self,
                 blocks,
                 blmin,
                 volume,
                 cellbounds=None,
                 cell=None,
                 splits={(1, ): 1}):

        self.volume = volume
        self.cellbounds = cellbounds
        self.cell = cell

        # normalize splitting probabilities:
        tot = sum([v for v in splits.values()])
        self.splits = {k: v * 1. / tot for k, v in splits.items()}

        # pre-process blocks and blmin:
        self.blocks = []
        numbers = []
        for block, count in blocks:
            if isinstance(block, Atoms):
                pass
            elif block in atomic_numbers:
                block = Atoms(block)
            else:
                block = molecule(block)
            self.blocks.append((block, count))
            numbers.extend(block.get_atomic_numbers())
        numbers = np.unique(numbers)

        if type(blmin) == dict:
            self.blmin = blmin
        else:
            self.blmin = closest_distances_generator(numbers, blmin)
Ejemplo n.º 3
0
def prepare_startGenerator():
    
    cell = np.array([[24, 0, 0],
                     [0, 24, 0],
                     [0, 0, 24]])
    pbc = [False, False, False]
    
    # Define template
    slab = Atoms('',
                 cell=cell,
                 pbc=pbc)
    
    # Define the box to place the atoms within
    # The volume is defined by a corner position (p0) and three spanning vectors (v)
    v = np.array([[4, 0, 0],
                  [0, 4, 0],
                  [0, 0, 4]])
    p0 = np.diag((cell-v)/2)
    
    # Define the composition of the atoms to optimize
    atom_numbers = [6]*24  # 24 carbon atoms
    
    # 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)
    cd = closest_distances_generator(atom_numbers=unique_atom_types,
                                     ratio_of_covalent_radii=0.7)
    # create the starting population
    sg = StartGenerator(slab = slab,
                        atom_numbers = atom_numbers, 
                        closest_allowed_distances = cd,
                        box_to_place_in = [p0, v],
                        elliptic = False,
                        cluster = True)
        
    return sg
def run_ga(n_to_test):
    """
    This method specifies how to run the GA once the
    initial random structures have been stored in godb.db.
    """
    # Various initializations:
    population_size = 10  # maximal size of the population
    da = DataConnection('godb.db')
    atom_numbers_to_optimize = da.get_atom_numbers_to_optimize()  # = [14] * 7
    n_to_optimize = len(atom_numbers_to_optimize)  # = 7
    # This defines how close the Si atoms are allowed to get
    # in candidate structures generated by the genetic operators:
    blmin = closest_distances_generator(atom_numbers_to_optimize,
                                        ratio_of_covalent_radii=0.4)
    # This is our OFPComparator instance which will be
    # used to judge whether or not two structures are identical:
    comparator = OFPComparator(n_top=None, dE=1.0, cos_dist_max=1e-3,
                               rcut=10., binwidth=0.05, pbc=[False]*3,
                               sigma=0.1, nsigma=4, recalculate=False)

    # Defining a typical combination of genetic operators:
    pairing = CutAndSplicePairing(da.get_slab(), n_to_optimize, blmin)
    rattlemut = RattleMutation(blmin, n_to_optimize, rattle_prop=0.8,
                               rattle_strength=1.5)
    operators = OperationSelector([2., 1.], [pairing, rattlemut])

    # Relax the randomly generated initial candidates:
    while da.get_number_of_unrelaxed_candidates() > 0:
        a = da.get_an_unrelaxed_candidate()
        a = relax_one(a)
        da.add_relaxed_step(a)

    # Create the population
    population = Population(data_connection=da,
                            population_size=population_size,
                            comparator=comparator,
                            logfile='log.txt')
    current_pop = population.get_current_population()

    # Test n_to_test new candidates
    for step in range(n_to_test):
        print('Starting configuration number %d' % step, flush=True)

        a3 = None
        while a3 is None:
            a1, a2 = population.get_two_candidates()
            a3, description = operators.get_new_individual([a1, a2])

        da.add_unrelaxed_candidate(a3, description=description)
        a3 = relax_one(a3)
        da.add_relaxed_step(a3)

        population.update()
        best = population.get_current_population()[0]
        print('Highest raw score at this point: %.3f' % get_raw_score(best))

    print('GA finished after step %d' % step)
    write('all_candidates.traj', da.get_all_relaxed_candidates())
    write('current_population.traj', population.get_current_population())
Ejemplo n.º 5
0
    def __init__(self, atoms, rcut=5, ratio_of_covalent_radii=0.7):
        self.rcut = rcut

        self.pbc = atoms.get_pbc()
        self.cell = atoms.get_cell()

        self.cell_displacements = self.__get_neighbour_cells_displacement(self.pbc, self.cell)
        self.Ncells = len(self.cell_displacements)

        num = atoms.get_atomic_numbers()
        self.blmin = closest_distances_generator(num, ratio_of_covalent_radii=ratio_of_covalent_radii)
Ejemplo n.º 6
0
def relax_one(t):
    ''' This method defines how to locally minimize a given
    atoms object 't'.
    '''
    # The provided structure will often contain atoms separated
    # by relatively short distances. Pushing these atoms a bit
    # apart using a soft potential will reduce the number of
    # subsequent ionic steps and will help avoid DFTB convergence
    # problems.
    pos = t.get_positions()
    numbers = list(set(t.get_atomic_numbers()))
    blmin = closest_distances_generator(numbers, 0.5)
    t = push_apart(t, blmin, variable_cell=False)

    print('Starting relaxation', flush=True)
    clock = time()
    t.wrap()

    # Define the DFTB+ calculator:
    calc = DftbPlusCalculator(t, kpts=(1, 1, 1), use_spline=True,
                              maximum_angular_momenta={'Si': 1})

    # Start the actual relaxation using the 
    # tango.relax_utils.relax_precon method.
    # This wraps around the preconditioned
    # optimizers in ASE and also takes care of
    # setting the raw score etc.:
    try:
        t = relax_precon(t, calc, fmax=1e-2, variable_cell=False,
                         logfile=None, trajfile=None)
    except IOError:
        # the DFTB+ ASE calculator throws an IOError
        # in case it couldn't find the 'results.tag'
        # output file, which may sporadically happen
        # due to SCC converge issues when e.g. a Si7
        # cluster is breaking into fragments. We simply
        # handle this by aborting the relaxation and
        # assigning a very high energy to the structure:
        finalize(t, energy=1e9, forces=None, stress=None)

    print('Relaxing took %.3f seconds.' % (time() - clock), flush=True)
    return t
Ejemplo n.º 7
0
    def ga_init(self, ddiff, dmax, dE):
        self.ddiff = ddiff
        self.dmax = dmax
        self.dE = dE

        da = DataConnection(self.db_name)
        atom_numbers_to_optimize = da.get_atom_numbers_to_optimize(
        )  # adsorbate atom numbers to optimize
        n_to_optimize = len(
            atom_numbers_to_optimize)  # number of atoms 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=.7)  # closest distance atoms can be

        comp = InteratomicDistanceComparator(
            n_top=None,
            pair_cor_cum_diff=self.ddiff,
            pair_cor_max=dmax,
            dE=dE,
            mic=True)  # comparator to determine if parents should make childer

        pairing = CutAndSplicePairing(
            blmin, None, use_tags=True, p1=.2
        )  # how children are generated (make sure your adsorbates are uniquely tagged)

        population = Population(data_connection=da,
                                population_size=self.pop,
                                comparator=comp)

        for i in range(self.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])
            #print(a3.info)
            #view(a3)
            if a3 is None:
                continue
            da.add_unrelaxed_candidate(a3, description=desc)
def test_cutandsplicepairing(seed):
    from ase.ga.startgenerator import StartGenerator
    from ase.ga.utilities import closest_distances_generator, atoms_too_close
    from ase.ga.cutandsplicepairing import CutAndSplicePairing
    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)

    # first create two random starting candidates
    slab = fcc111('Au', size=(4, 4, 2), vacuum=10.0, orthogonal=True)
    slab.set_constraint(FixAtoms(mask=slab.positions[:, 2] <= 10.))

    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.

    blmin = closest_distances_generator(atom_numbers=[47, 79],
                                        ratio_of_covalent_radii=0.7)

    atom_numbers = 2 * [47] + 2 * [79]

    sg = StartGenerator(slab=slab,
                        blocks=atom_numbers,
                        blmin=blmin,
                        box_to_place_in=[p0, [v1, v2, v3]],
                        rng=rng)

    c1 = sg.get_new_candidate()
    c1.info['confid'] = 1
    c2 = sg.get_new_candidate()
    c2.info['confid'] = 2

    n_top = len(atom_numbers)

    pairing = CutAndSplicePairing(slab, n_top, blmin, rng=rng)

    c3, desc = pairing.get_new_individual([c1, c2])

    # verify that the stoichiometry is preserved
    assert np.all(c3.numbers == c1.numbers)
    top1 = c1[-n_top:]
    top2 = c2[-n_top:]
    top3 = c3[-n_top:]

    # verify that the positions in the new candidate come from c1 or c2
    n1 = -1 * np.ones((n_top, ))
    n2 = -1 * np.ones((n_top, ))
    for i in range(n_top):
        for j in range(n_top):
            if np.allclose(top1.positions[j, :], top3.positions[i, :], 1e-12):
                n1[i] = j
                break
            elif np.allclose(top2.positions[j, :], top3.positions[i, :],
                             1e-12):
                n2[i] = j
                break
        assert (n1[i] > -1 and n2[i] == -1) or (n1[i] == -1 and n2[i] > -1)

    # verify that c3 includes atoms from both c1 and c2
    assert len(n1[n1 > -1]) > 0 and len(n2[n2 > -1]) > 0

    # verify no atoms too close
    assert not atoms_too_close(top3, blmin)
Ejemplo n.º 9
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])
Ejemplo n.º 10
0
def test_mutations(seed):
    from ase.ga.startgenerator import StartGenerator
    from ase.ga.utilities import closest_distances_generator
    from ase.ga.standardmutations import RattleMutation, PermutationMutation
    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)

    # first create two random starting candidates
    slab = fcc111('Au', size=(4, 4, 2), vacuum=10.0, orthogonal=True)
    slab.set_constraint(FixAtoms(mask=slab.positions[:, 2] <= 10.))

    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.

    blmin = closest_distances_generator(atom_numbers=[47, 79],
                                        ratio_of_covalent_radii=0.7)

    atom_numbers = 2 * [47] + 2 * [79]
    n_top = len(atom_numbers)
    sg = StartGenerator(slab=slab,
                        blocks=atom_numbers,
                        blmin=blmin,
                        box_to_place_in=[p0, [v1, v2, v3]],
                        rng=rng)

    c1 = sg.get_new_candidate()
    c1.info['confid'] = 1

    # first verify that the rattle mutation works
    rmut = RattleMutation(blmin, n_top, rattle_strength=0.8, rattle_prop=0.4,
                          rng=rng)

    c2, desc = rmut.get_new_individual([c1])

    assert np.all(c1.numbers == c2.numbers)

    top1 = c1[-n_top:]
    top2 = c2[-n_top:]
    slab2 = c2[0:(len(c1) - n_top)]

    assert len(slab) == len(slab2)
    assert np.all(slab.get_positions() == slab2.get_positions())

    dp = np.sum((top2.get_positions() - top1.get_positions())**2, axis=1)**0.5

    # check that all displacements are smaller than the rattle strength we
    # cannot check if 40 % of the structures have been rattled since it is
    # probabilistic and because the probability will be lower if two atoms
    # get too close
    for p in dp:
        assert p < 0.8 * 3**0.5

    # now we check the permutation mutation

    mmut = PermutationMutation(n_top, probability=0.5, rng=rng)

    c3, desc = mmut.get_new_individual([c1])
    assert np.all(c1.numbers == c3.numbers)

    top1 = c1[-n_top:]
    top2 = c3[-n_top:]
    slab2 = c3[0:(len(c1) - n_top)]

    assert len(slab) == len(slab2)
    assert np.all(slab.get_positions() == slab2.get_positions())
    dp = np.sum((top2.get_positions() - top1.get_positions())**2, axis=1)**0.5

    # verify that two positions have been changed
    assert len(dp[dp > 0]) == 2
Ejemplo n.º 11
0
def relax_one(t, kptdensity=1.5):
    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.5, 20],
            'b': [1.5, 20],
            'c': [1.5, 20]
        })

    if not cellbounds.is_within_bounds(t.get_cell()):
        print('Candidate outside cellbounds -- skipping')
        finalize(t, energy=1e9, forces=None, stress=None)
        return t

    pos = t.get_positions()
    numbers = list(set(t.get_atomic_numbers()))
    blmin = closest_distances_generator(numbers, 0.5)
    t = push_apart(t, blmin, variable_cell=True)

    print('Starting relaxation', flush=True)
    clock = time()
    t.wrap()
    calc = DftbPlusCalc(t,
                        kpts=0.66 * kptdensity,
                        use_spline=True,
                        read_chg=True)

    try:
        t = relax_precon(t,
                         calc,
                         fmax=5e-1,
                         smax=5e-2,
                         variable_cell=True,
                         optimizer='LBFGS',
                         a_min=1e-4,
                         cellbounds=cellbounds,
                         logfile='opt_first.log',
                         trajfile='opt_first.traj')
    except IOError as err:
        # probably convergence problem
        print(err.message)
    except TypeError as err:
        if 'Cannot cast array data' in err.message:
            # Rare precon failure
            print(err.message)
        else:
            raise
    except RuntimeError as err:
        print(err.message)

    del t.constraints
    t.wrap()
    calc = DftbPlusCalc(t, kpts=kptdensity, use_spline=True, read_chg=True)
    try:
        t = relax_precon(t,
                         calc,
                         fmax=5e-1,
                         smax=5e-2,
                         variable_cell=True,
                         optimizer='LBFGS',
                         a_min=1e-4,
                         cellbounds=cellbounds,
                         logfile='opt.log',
                         trajfile='opt.traj')
    except (IOError, TypeError, RuntimeError) as err:
        # probably convergence problem
        print(err.message)
        if isinstance(err, TypeError):
            if 'Cannot cast array data' not in err.message:
                raise
        elif isinstance(err, RuntimeError):
            if 'dftb_my in . returned an error:' not in err.message:
                raise
        try:
            t = read('opt.traj@-1')
            energy = t.get_potential_energy()
            forces = t.get_forces()
            stress = t.get_stress()
        except UnknownFileTypeError as err:
            print(err.message)
            energy, forces, stress = (1e9, None, None)
        finalize(t, energy=energy, forces=forces, stress=stress)

    print('Relaxing took %.3f seconds.' % (time() - clock), flush=True)
    os.system('mv opt_first.traj prev_first.traj')
    os.system('mv opt_first.log prev_first.log')
    os.system('mv opt.log prev.log')
    os.system('mv opt.traj prev.traj')
    penalize(t)
    return t
Ejemplo n.º 12
0
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:])
Ejemplo n.º 13
0
    def construct_init_parent(self, ads_cell, ads_pos):
        """ construct the initial set of parents """
        self.ads_cell = ads_cell
        self.ads_pos = ads_pos
        Ads_vol = ads_cell[0] * ads_cell[1] * ads_cell[2]
        Ads_cell = [[ads_cell[0], 0, 0], [0, ads_cell[1], 0],
                    [0, 0, ads_cell[2]]]

        if self.n_ads == 1:
            Atom_Num = self.Ads.get_atomic_numbers(
            )  # get atomic numbers of your adsorbate
        if self.n_ads == 2:
            TEMP_for_num = self.Ads[0] + self.Ads[1]
            Atom_Num = TEMP_for_num.get_atomic_numbers()
            #Atom_Num.append(self.Ads[1].get_atomic_numbers())

        unique_atom_types = get_all_atom_types(
            self.FW, Atom_Num)  # get atomic numbers of your system
        cd = closest_distances_generator(
            atom_numbers=unique_atom_types, ratio_of_covalent_radii=0.7
        )  # Generate a dictionary of closest distances

        pop = self.pop_size

        if self.n_ads == 1:

            sg = StartGenerator(
                [(self.Ads, self.n_ads)],  # Generator Parameters
                cd,
                Ads_vol,
                cell=Ads_cell)

            starting_population = [sg.get_new_candidate() for i in range(pop)]

            for i in range(pop):
                TEMPMOL = self.FW + starting_population[
                    i]  # Add the adsorbates to the frame work
                self.Start_Set.append(TEMPMOL)

            num = len(self.Ads)

        if self.n_ads == 2:

            sg = StartGenerator([(self.Ads[0], 1), (self.Ads[1], 1)],
                                cd,
                                Ads_vol,
                                cell=Ads_cell)

            starting_population = [sg.get_new_candidate() for i in range(pop)]

            for i in range(pop):
                TEMPMOL = self.FW + starting_population[i]
                self.Start_Set.append(TEMPMOL)

            num = len(self.Ads[0]) + len(self.Ads[1])

        Cent_Pos = self.ads_pos
        #num = len(self.Ads)*self.n_ads
        Fin_atoms = np.linspace(0, num - 1, num)

        for i in range(pop):
            for j in Fin_atoms:
                Coord = self.Start_Set[i].get_positions()[-(
                    int(j) + 1
                )] + Cent_Pos  # Move the corner of the adsorbate cell to p.o.i.
                self.Start_Set[i][-(int(j) + 1)].x = Coord[0] - Ads_cell[0][
                    0] / 2  # Then you have to fudge the box so its centered
                self.Start_Set[i][-(int(j) + 1)].y = Coord[
                    1] - Ads_cell[1][1] / 2  #      around the p.o.i.
                self.Start_Set[i][-(int(j) +
                                    1)].z = Coord[2] - Ads_cell[2][2] / 2

            self.Start_Set[i].wrap()
Ejemplo n.º 14
0
# 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,
                    atom_numbers,
                    blmin,
                    box_to_place_in=[p0, [v1, v2, v3]])

# generate the starting population
population_size = 20
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
from ase.ga.standardmutations import MirrorMutation
from ase.ga.standardmutations import RattleMutation
from ase.ga.standardmutations import PermutationMutation

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

# 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)
mutations = OperationSelector([1., 1., 1.], [
    MirrorMutation(blmin, n_to_optimize),
    RattleMutation(blmin, n_to_optimize),
    PermutationMutation(n_to_optimize)
])

# Relax all unrelaxed structures (e.g. the starting population)
Ejemplo n.º 16
0
def run_calc(dbfile, Calculator, kptdensity=None, relax=False, vc_relax=False,
             precon=True, maxsteps=20, maximum_angular_momenta=None,
             atomic_energies={}, referencing='atomic'):
    ''' Runs a calculator on each unrelaxed candidate in a database.

    dbfile: name of the database
    Calculator: a suitable calculator DFT or DFTB calculator class 
                (see tango.main)
    kptdensity: the k-point density to apply (in 1/A)
    relax: whether to do a short relaxation or only 
           perform a single-point calculation
    vc_relax: if also the cell vectors are to be varied
    precon: whether to use the preconditioned optimizers
    maxsteps: maximum number of ionic steps for the local optimizer
    maximum_angular_momenta: a dictionary with maximum angular momenta 
             for each element in the structure for DFTB calculations
    atomic_energies: dictionary with the DFT energies of the isolated
                     atoms. Used to calculate the reference energies
                     in the 'atomic' referencing scheme.
    referencing: the referencing scheme (see main.py)
    '''
    if vc_relax:
        assert precon

    db = connect(dbfile)
    relaxed_ids = set([row.gaid for row in db.select(relaxed=1)])

    for row in db.select(relaxed=0):
        if row.gaid in relaxed_ids:
            continue

        atoms = row.toatoms()
        mp = get_kpts(atoms, kptdensity)
        if maximum_angular_momenta is None:
            calc = Calculator(atoms, kpts=mp)
        else:
            calc = Calculator(atoms, kpts=mp,
                              maximum_angular_momenta=maximum_angular_momenta)
        atoms.set_calculator(calc)

        E = atoms.get_potential_energy()
        F = atoms.get_forces()
        try:
            S = atoms.get_stress() 
        except PropertyNotImplementedError:
            S = None
        finalize(atoms, energy=E, forces=F, stress=S)

        relax = relax and maxsteps > 0
        if relax:
            atoms2 = atoms.copy()
            numbers = list(set(atoms2.get_atomic_numbers()))
            blmin = closest_distances_generator(numbers, 0.5)
            atoms2 = push_apart(atoms2, blmin)
            atoms2.set_calculator(calc)
            atoms2 = do_short_relax(atoms2, index=row.gaid,
                                    precon=precon, vc_relax=vc_relax, 
                                    maxsteps=maxsteps)
            if vc_relax:
                # Additional single-point run
                calc.exit()
                mp = get_kpts(atoms2, kptdensity)
                if maximum_angular_momenta is None:
                    calc = Calculator(atoms2, kpts=mp)
                else:
                    calc = Calculator(atoms2, kpts=mp,
                             maximum_angular_momenta=maximum_angular_momenta)
                atoms2.set_calculator(calc)

            E = atoms2.get_potential_energy()
            F = atoms2.get_forces()
            try:
                S = atoms2.get_stress()
            except PropertyNotImplementedError:
                S = None
            finalize(atoms2, energy=E, forces=F, stress=S)

        # Calculate energy and force references
        for a in [atoms] if not relax else [atoms, atoms2]:
            e_ref = []
            f_ref = np.zeros((len(atoms), 3))
            if referencing == 'atomic':
                sym = a.get_chemical_symbols()
                e_ref.extend([atomic_energies['%s_DFT' % s] for s in sym])
            else:
                for indices in referencing:
                    b = a[indices]
                    b.set_calculator(calc)
                    e_ref.append(b.get_potential_energy())
                    f_ref[indices] = b.get_forces()

            a.info['key_value_pairs']['e_dft_ref'] = convert_array(e_ref)
            a.info['key_value_pairs']['f_dft_ref'] = convert_array(f_ref)
            # Add the structure to the database:
            db.write(a, relaxed=1, gaid=row.gaid, **a.info['key_value_pairs'])
        calc.exit()
    return
from ase.ga.offspring_creator import OperationSelector
from ase.ga.cutandsplicepairing import CutAndSplicePairing
from ase.ga.standardmutations import (RattleMutation, StrainMutation,
                                      RotationalMutation,
                                      RattleRotationalMutation)
from ase.ga.soft_mutation import SoftMutation
from ga_molecular_crystal_relax import relax


da = DataConnection('gadb.db')

# Various items needed for initializing the genetic operators
slab = da.get_slab()
atom_numbers_to_optimize = da.get_atom_numbers_to_optimize()
n_top = len(atom_numbers_to_optimize)
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,
Ejemplo n.º 18
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())
Ejemplo n.º 19
0
    def __init__(self,
                 slab,
                 blocks,
                 blmin,
                 number_of_variable_cell_vectors=0,
                 box_to_place_in=None,
                 box_volume=None,
                 splits=None,
                 cellbounds=None,
                 test_dist_to_slab=True,
                 test_too_far=True,
                 rng=np.random):

        self.slab = slab

        self.blocks = []
        for item in blocks:
            if isinstance(item, tuple) or isinstance(item, list):
                assert len(item) == 2, 'Item length %d != 2' % len(item)
                block, count = item
            else:
                block, count = item, 1

            # Convert block into Atoms object
            if isinstance(block, Atoms):
                pass
            elif block in atomic_numbers:
                block = Atoms(block)
            elif isinstance(block, str):
                block = molecule(block)
            elif block in atomic_numbers.values():
                block = Atoms(numbers=[block])
            else:
                raise ValueError('Cannot parse this block:', block)

            # Add to self.blocks, taking into account that
            # we want to group the same blocks together.
            # This is important for the cell splitting.
            for i, (b, c) in enumerate(self.blocks):
                if block == b:
                    self.blocks[i][1] += count
                    break
            else:
                self.blocks.append([block, count])

        if isinstance(blmin, dict):
            self.blmin = blmin
        else:
            numbers = np.unique([b.get_atomic_numbers() for b in self.blocks])
            self.blmin = closest_distances_generator(
                numbers, ratio_of_covalent_radii=blmin)

        self.number_of_variable_cell_vectors = number_of_variable_cell_vectors
        assert self.number_of_variable_cell_vectors in range(4)
        if len(self.slab) > 0:
            msg = 'Including atoms in the slab only makes sense'
            msg += ' if there are no variable unit cell vectors'
            assert self.number_of_variable_cell_vectors == 0, msg
        for i in range(self.number_of_variable_cell_vectors):
            msg = 'Unit cell %s-vector is marked as variable ' % ('abc'[i])
            msg += 'and slab must then also be periodic in this direction'
            assert self.slab.pbc[i], msg

        if box_to_place_in is None:
            p0 = np.array([0., 0., 0.])
            cell = self.slab.get_cell()
            self.box_to_place_in = [p0, [cell[0, :], cell[1, :], cell[2, :]]]
        else:
            self.box_to_place_in = box_to_place_in

        if box_volume is None:
            assert self.number_of_variable_cell_vectors == 0
            box_volume = abs(np.linalg.det(self.box_to_place_in[1]))
        else:
            assert self.number_of_variable_cell_vectors > 0
        self.box_volume = box_volume
        assert self.box_volume > 0

        if splits is None:
            splits = {(1, ): 1}
        tot = sum([v for v in splits.values()])  # normalization
        self.splits = {k: v * 1. / tot for k, v in splits.items()}

        self.cellbounds = cellbounds
        self.test_too_far = test_too_far
        self.test_dist_to_slab = test_dist_to_slab
        self.rng = rng
Ejemplo n.º 20
0
def test_bulk_operators():
    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]})

    sg = StartGenerator(blocks, blmin, volume, cellbounds=cellbounds,
                        splits=splits)

    # 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
    pairing = CutAndSplicePairing(blmin, p1=1., p2=0., minfrac=0.15,
                                  cellbounds=cellbounds, use_tags=True)

    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,
                               use_tags=True)
    softmut = SoftMutation(blmin, bounds=[2., 5.], used_modes_file=None,
                           use_tags=True)
    rotmut = RotationalMutation(blmin, fraction=0.3, min_angle=0.5 * np.pi)
    rattlemut = RattleMutation(blmin, n_top, rattle_prop=0.3, rattle_strength=0.5,
                               use_tags=True, test_dist_to_slab=False)
    rattlerotmut = RattleRotationalMutation(rattlemut, rotmut)
    permut = PermutationMutation(n_top, probability=0.33, test_dist_to_slab=False,
                                 use_tags=True, blmin=blmin)
    combmut = CombinationMutation(rattlemut, rotmut, verbose=True)
    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_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)
Ejemplo n.º 21
0
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
cd = 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,
                    atom_numbers=atom_numbers,
                    closest_allowed_distances=cd,
                    box_to_place_in=[p0, [v1, v2, v3]])

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

d = PrepareDB(db_file_name=db_file,
              simulation_cell=slab,
Ejemplo n.º 22
0
def run_ga(n_to_test, kptdensity=None):
    ''' This method specifies how to run the GA once the
    initial random structures have been stored in godb.db.
    '''
    # Various initializations:
    population_size = 10
    da = DataConnection('godb.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.05)

    # Defining the mix of genetic operators:
    mutation_probability = 0.3333
    pairing = CutAndSplicePairing(slab, n_to_optimize, blmin)
    rattlemut = RattleMutation(blmin, n_to_optimize,
                               rattle_prop=0.8, rattle_strength=1.5)
    mirrormut = MirrorMutation(blmin, n_to_optimize)
    mutations = OperationSelector([1., 1.], [rattlemut, mirrormut])

    if True:
        # Recalculate raw scores of any relaxed candidates
        # present in the godb.db database (only applies to 
        # iter007).
        structures = da.get_all_relaxed_candidates()
        for atoms in structures:
            atoms = singlepoint(atoms)
            da.c.delete([atoms.info['relax_id']])
            if 'data' not in atoms.info:
                atoms.info['data'] = {}
            da.add_relaxed_step(atoms)
        print('Finished recalculating raw scores')

    # Relax the randomly generated initial candidates:
    while da.get_number_of_unrelaxed_candidates() > 0:
        a = da.get_an_unrelaxed_candidate()
        a.wrap()
        a = relax_one(a)
        da.add_relaxed_step(a)

    # Create the population
    population = Population(data_connection=da,
                            population_size=population_size,
                            comparator=comparator,
                            logfile='log.txt')
    current_pop = population.get_current_population()

    # Test n_to_test new candidates
    ga_raw_scores = []
    step = 0
    for step in range(n_to_test):
        print('Starting configuration number %d' % step, flush=True)

        clock = time()
        a3 = None
        r = random()
        if r > mutation_probability:
            while a3 is None:
                a1, a2 = population.get_two_candidates()
                a3, desc = pairing.get_new_individual([a1, a2])
        else:
            while a3 is None:
                a1 = population.get_one_candidate()
                a3, desc = mutations.get_new_individual([a1])

        dt = time() - clock
        op = 'pairing' if r > mutation_probability else 'mutating'
        print('Time for %s candidate(s): %.3f' % (op, dt), flush=True)

        a3.wrap()
        da.add_unrelaxed_candidate(a3, description=desc)

        a3 = relax_one(a3)
        da.add_relaxed_step(a3)

        # Various updates:
        population.update()
        current_pop = population.get_current_population()
        write('current_population.traj', current_pop)

        # Print out information for easy analysis/plotting afterwards:
        if r > mutation_probability:
            print('Step %d %s %.3f %.3f %.3f' % (step, desc,\
                   get_raw_score(a1), get_raw_score(a2), get_raw_score(a3)))
        else:
            print('Step %d %s %.3f %.3f' % (step, desc,\
                   get_raw_score(a1), get_raw_score(a3)))

        print('Step %d highest raw score in pop: %.3f' % \
              (step, get_raw_score(current_pop[0])))
        ga_raw_scores.append(get_raw_score(a3))
        print('Step %d highest raw score generated by GA: %.3f' % \
              (step, max(ga_raw_scores)))

    emin = population.pop[0].get_potential_energy()
    print('GA finished after step %d' % step)
    print('Lowest energy = %8.3f eV' % emin, flush=True)
    write('all_candidates.traj', da.get_all_relaxed_candidates())
    write('current_population.traj', population.get_current_population())
Ejemplo n.º 23
0
# 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)
cd = closest_distances_generator(atom_numbers=unique_atom_types,
                                 ratio_of_covalent_radii=0.7)

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

# generate the starting population
population_size = 5
starting_population = [sg.get_new_candidate() for i in xrange(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
Ejemplo n.º 24
0
volume = 240.

# Specify the 'building blocks' from which the initial structures
# will be constructed. Here we take single Ag atoms as building
# blocks, 24 in total.
blocks = [('Ag', 24)]

# From these blocks we can determine the stoichiometry
# (as a list of atomic numbers)
stoichiometry = [
    atomic_numbers[atom] for atom, count in blocks for _ in range(count)
]

# Generate a dictionary with the closest allowed interatomic distances
atom_numbers = list(set(stoichiometry))
blmin = closest_distances_generator(atom_numbers=atom_numbers,
                                    ratio_of_covalent_radii=0.5)

# Specify reasonable bounds on the minimal and maximal
# cell vector lengths (in angstrom) and angles (in degrees)
cellbounds = CellBounds(
    bounds={
        'phi': [35, 145],
        'chi': [35, 145],
        'psi': [35, 145],
        'a': [3, 50],
        'b': [3, 50],
        'c': [3, 50]
    })

# Choose an (optional) 'cell splitting' scheme which basically
# controls the level of translational symmetry (within the unit
from ase.ga.standardmutations import MirrorMutation
from ase.ga.standardmutations import RattleMutation
from ase.ga.standardmutations import PermutationMutation

# 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)
mutations = OperationSelector(
    [1.0, 1.0, 1.0],
    [MirrorMutation(blmin, n_to_optimize), RattleMutation(blmin, n_to_optimize), PermutationMutation(n_to_optimize)],
)

# Relax all unrelaxed structures (e.g. the starting population)
while da.get_number_of_unrelaxed_candidates() > 0:
    a = da.get_an_unrelaxed_candidate()
    a.set_calculator(EMT())
    print("Relaxing starting candidate {0}".format(a.info["confid"]))
    dyn = BFGS(a, trajectory=None, logfile=None)
Ejemplo n.º 26
0
def run_ga(n_to_test, kptdensity=3.5):
    population_size = 20
    da = DataConnection('godb.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, 0.05)  # 0.5

    # defining genetic operators:
    mutation_probability = 0.75
    pairing = CutAndSplicePairing(blmin,
                                  p1=1.,
                                  p2=0.,
                                  minfrac=0.15,
                                  use_tags=False)
    cellbounds = CellBounds(
        bounds={
            'phi': [0.2 * 180., 0.8 * 180.],
            'chi': [0.2 * 180., 0.8 * 180.],
            'psi': [0.2 * 180., 0.8 * 180.]
        })
    strainmut = StrainMutation(blmin,
                               stddev=0.7,
                               cellbounds=cellbounds,
                               use_tags=False)
    blmin_soft = closest_distances_generator(all_atom_types, 0.1)
    softmut = SoftMutation(blmin_soft, bounds=[2., 5.], use_tags=False)
    rattlemut = RattleMutation(blmin,
                               n_to_optimize,
                               rattle_prop=0.8,
                               rattle_strength=2.5,
                               use_tags=False)
    mutations = OperationSelector([4., 4., 2], [softmut, strainmut, rattlemut])

    if True:
        # recalculate raw scores
        structures = da.get_all_relaxed_candidates()
        for atoms in structures:
            atoms = singlepoint(atoms, kptdensity=kptdensity)
            da.c.delete([atoms.info['relax_id']])
            if 'data' not in atoms.info:
                atoms.info['data'] = {}
            da.add_relaxed_step(atoms)
        print('Finished recalculating raw scores')

    # relaxing the initial candidates:
    while da.get_number_of_unrelaxed_candidates() > 0:
        a = da.get_an_unrelaxed_candidate()
        a.wrap()
        a = relax_one(a, kptdensity=kptdensity)
        da.add_relaxed_step(a)

    # create the population
    population = Population(data_connection=da,
                            population_size=population_size,
                            comparator=comparator,
                            logfile='log.txt')

    current_pop = population.get_current_population()
    strainmut.update_scaling_volume(current_pop, w_adapt=0.5, n_adapt=4)
    pairing.update_scaling_volume(current_pop, w_adapt=0.5, n_adapt=4)

    # Test n_to_test new candidates
    ga_raw_scores = []
    step = 0
    for step in range(n_to_test):
        print('Starting configuration number %d' % step, flush=True)

        clock = time()
        a3 = None
        r = random()
        if r > mutation_probability:
            while a3 is None:
                a1, a2 = population.get_two_candidates()
                a3, desc = pairing.get_new_individual([a1, a2])
        else:
            while a3 is None:
                a1 = population.get_one_candidate()
                a3, desc = mutations.get_new_individual([a1])

        dt = time() - clock
        op = 'pairing' if r > mutation_probability else 'mutating'
        print('Time for %s candidate(s): %.3f' % (op, dt), flush=True)

        a3.wrap()
        da.add_unrelaxed_candidate(a3, description=desc)

        a3 = relax_one(a3, kptdensity=kptdensity)
        da.add_relaxed_step(a3)

        # Various updates:
        population.update()
        current_pop = population.get_current_population()

        if step % 10 == 0:
            strainmut.update_scaling_volume(current_pop,
                                            w_adapt=0.5,
                                            n_adapt=4)
            pairing.update_scaling_volume(current_pop, w_adapt=0.5, n_adapt=4)
            write('current_population.traj', current_pop)

        # Print out information for easy analysis/plotting afterwards:
        if r > mutation_probability:
            print('Step %d %s %.3f %.3f %.3f' % (step, desc,\
                   get_raw_score(a1), get_raw_score(a2), get_raw_score(a3)))
        else:
            print('Step %d %s %.3f %.3f' % (step, desc,\
                   get_raw_score(a1), get_raw_score(a3)))

        print('Step %d highest raw score in pop: %.3f' % \
              (step, get_raw_score(current_pop[0])))
        ga_raw_scores.append(get_raw_score(a3))
        print('Step %d highest raw score generated by GA: %.3f' % \
              (step, max(ga_raw_scores)))

    emin = population.pop[0].get_potential_energy()
    print('GA finished after step %d' % step)
    print('Lowest energy = %8.3f eV' % emin, flush=True)
    write('all_candidates.traj', da.get_all_relaxed_candidates())
    write('current_population.traj', population.get_current_population())
# By writing 'N2', the generator will automatically
# get the N2 geometry using ase.build.molecule.

# A guess for the cell volume in Angstrom^3
box_volume = 30. * 8

# The cell splitting scheme:
splits = {(2,):1, (1,):1}

# The minimal interatomic distances which the
# initial structures must satisfy. We can take these
# a bit larger than usual because these minimal
# distances will only be applied intermolecularly
# (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,
Ejemplo n.º 28
0
def relax_one(t, kptdensity=3.5):
    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.5, 20],
            'b': [1.5, 20],
            'c': [1.5, 20]
        })

    if not cellbounds.is_within_bounds(t.get_cell()):
        print('Candidate outside cellbounds -- skipping')
        finalize(t, energy=1e9, forces=None, stress=None)
        return t

    pos = t.get_positions()
    numbers = list(set(t.get_atomic_numbers()))
    blmin = closest_distances_generator(numbers, 0.5)
    t = push_apart(t, blmin, variable_cell=True)

    print('Starting relaxation', flush=True)
    clock = time()
    t.wrap()
    calc = DftbPlusCalculator(t,
                              kpts=0.66 * kptdensity,
                              use_spline=True,
                              read_chg=True,
                              maximum_angular_momenta={'C': 1})

    try:
        t = relax_precon(t,
                         calc,
                         fmax=2e-1,
                         smax=1e-2,
                         variable_cell=True,
                         optimizer='LBFGS',
                         a_min=1e-4,
                         cellbounds=cellbounds,
                         logfile='opt_first.log',
                         trajfile='opt_first.traj')
    except (IOError, TypeError, RuntimeError, UnboundLocalError) as err:
        # SCC or geometry optimization convergence problem
        print(err)

    del t.constraints
    t.wrap()
    calc = DftbPlusCalculator(t,
                              kpts=kptdensity,
                              use_spline=True,
                              read_chg=True,
                              maximum_angular_momenta={'C': 1})

    try:
        t = relax_precon(t,
                         calc,
                         fmax=1e-1,
                         smax=5e-3,
                         variable_cell=True,
                         optimizer='LBFGS',
                         a_min=1e-4,
                         cellbounds=cellbounds,
                         logfile='opt.log',
                         trajfile='opt.traj')
    except (IOError, TypeError, RuntimeError, UnboundLocalError) as err:
        # SCC or geometry optimization convergence problem
        print(err)
        try:
            t = read('opt.traj@-1')
            energy = t.get_potential_energy()
            forces = t.get_forces()
            stress = t.get_stress()
        except (FileNotFoundError, UnknownFileTypeError) as err:
            print(err)
            energy, forces, stress = (1e9, None, None)
        finalize(t, energy=energy, forces=forces, stress=stress)

    print('Relaxing took %.3f seconds.' % (time() - clock), flush=True)
    os.system('mv opt_first.traj prev_first.traj')
    os.system('mv opt_first.log prev_first.log')
    os.system('mv opt.log prev.log')
    os.system('mv opt.traj prev.traj')
    penalize(t)
    return t
Ejemplo n.º 29
0
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
Ejemplo n.º 30
0
                 positions=np.concatenate((tmp0, tmp1, tmp2)),
                 cell=[[3.93588, 0.0, 0.0], [0.0, 15.74352, 0.0],
                       [0.0, 0.0, 21.4528356]],
                 pbc=[True, True, False],
                 constraint=FixAtoms(indices=range(12)))
    c = slab.get_cell()
    v1 = np.array((c[0][0], 0., 0.))
    v2 = np.array((0., c[1][1], 0.))
    v3 = np.array((0., 0., 6.))
    p0 = np.array((0., 0., 8.))
    box = [p0, [v1, v2, v3]]
    stoichiometry = 5 * [22] + 10 * [8]

    print 'slab', buildFeature(slab, 6, [8, 22])

    dmin = closest_distances_generator(atom_numbers=[22, 8],
                                       ratio_of_covalent_radii=0.6)

    sg = StartGenerator(
        slab=slab,  # Generator to generate initial structures
        atom_numbers=stoichiometry,
        closest_allowed_distances=dmin,
        box_to_place_in=box)

    calc = MorsePotential()
    test = sg.get_new_candidate()
    test.set_calculator(calc)
    test.info['confid'] = 1
    view(test)
    cd = ClusterDistanceMutation(slab,
                                 len(stoichiometry),
                                 dmin,