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 do_short_relax(atoms, index=None, vc_relax=False, precon=True, maxsteps=20): ''' Performs a (usually short) local optimization. atoms: an Atoms object index: index to be used as suffix for the output files vc_relax: whether to also optimize the cell vectors (after having run several steps with fixed cell) precon: whether to use the preconditioned optimizers maxsteps: maximum number of ionic steps ''' if vc_relax: assert precon t = time() label = 'opt' if index is None else 'opt_' + str(index) logfile = '%s.log' % label trajfile = '%s.traj' % label traj = Trajectory(trajfile, 'a', atoms) nsteps = 0 maxsteps_no_vc = maxsteps / 2 if vc_relax else maxsteps fmax = 2. if vc_relax else 0.1 try: if precon: dyn = PreconLBFGS_My(atoms, precon=Exp(A=3), variable_cell=False, use_armijo=True, a_min=1e-2, logfile=logfile) else: dyn = BFGS(atoms, maxstep=0.4, logfile=logfile) dyn.attach(traj) dyn.run(fmax=fmax, steps=maxsteps_no_vc) except RuntimeError: nsteps += dyn.get_number_of_steps() if precon: dyn = PreconFIRE_My(atoms, precon=Exp(A=3), variable_cell=False, use_armijo=False, logfile=logfile, dt=0.1, maxmove=0.5, dtmax=1.0, finc=1.1) else: dyn = FIRE(atoms, logfile=logfile, dt=0.1, maxmove=0.5, dtmax=1.0, finc=1.1) dyn.attach(traj) steps = maxsteps_no_vc - nsteps dyn.run(fmax=fmax, steps=steps) nsteps += dyn.get_number_of_steps() if vc_relax: L = atoms.get_volume() / 4. # largest cell vector length allowed cellbounds = CellBounds(bounds={'phi':[20., 160.], 'a':[1.5, L], 'chi':[20., 160.], 'b':[1.5, L], 'psi':[20., 160.], 'c':[1.5, L]}) try: dyn = PreconLBFGS_My(atoms, precon=Exp(A=3), variable_cell=True, use_armijo=True, logfile=logfile, cellbounds=cellbounds, a_min=1e-2) dyn.e1 = None try: dyn._just_reset_hessian except AttributeError: dyn._just_reset_hessian = True dyn.attach(traj) steps = maxsteps - nsteps dyn.run(fmax=0., smax=0., steps=steps) except RuntimeError: nsteps += dyn.get_number_of_steps() dyn = PreconFIRE_My(atoms, precon=Exp(A=3), variable_cell=True, use_armijo=False, logfile=logfile, cellbounds=cellbounds, dt=0.1, maxmove=0.5, dtmax=1.0, finc=1.1) dyn.attach(traj) steps = maxsteps - nsteps dyn.run(fmax=0., steps=steps) name = atoms.calc.name print('%s relaxation took %.3f seconds' % (name, time()-t)) return atoms
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()
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
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())
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 # 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.
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)
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 tags = t.get_tags() pos = t.get_positions() pairs = [] for tag in list(set(tags)): indices = list(np.where(tags == tag)[0]) if len(indices) == 2: pairs.append(indices) c = FixBondLengths(pairs) t.set_constraint(c) blmin = {(1, 1): 1.8, (1, 8): 0.9, (1, 46): 1.8, (8, 8): 2.0, (8, 46): 1.5, (46, 46): 1.5} t = push_apart(t, blmin, variable_cell=True) del t.constraints oh_bondlength = 0.97907 for (o_atom, h_atom) in pairs: vec = t.get_distance(o_atom, h_atom, mic=True, vector=True) pos[h_atom] = pos[o_atom] + vec * oh_bondlength / np.linalg.norm(vec) t.set_positions(pos) 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={'Pd': 2, 'H': 0, 'O': 1}) try: t = relax_precon(t, calc, fmax=2e-1, smax=1e-2, variable_cell=True, optimizer='LBFGS', a_min=1e-4, cellbounds=cellbounds, fix_bond_lengths_pairs=pairs, logfile='opt_first.log', trajfile='opt_first.traj') except (IOError, TypeError, RuntimeError, UnboundLocalError) as err: # SCC or geometry optimization convergence problem print(err) if isinstance(t, Filter): t = t.atoms del t.constraints t.wrap() calc = DftbPlusCalculator(t, kpts=kptdensity, use_spline=True, read_chg=True, maximum_angular_momenta={'Pd': 2, 'H': 0, 'O': 1}) try: t = relax_precon(t, calc, fmax=1e-1, smax=5e-3, variable_cell=True, optimizer='LBFGS', a_min=1e-4, cellbounds=cellbounds, fix_bond_lengths_pairs=pairs, 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) if isinstance(t, Filter): t = t.atoms 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
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
rcut=10., binwidth=0.05, pbc=[True, True, True], sigma=0.05, nsigma=4, recalculate=False) # Define the cell and interatomic distance bounds # that the candidates must obey blmin = closest_distances_generator(atom_numbers_to_optimize, 0.5) cellbounds = CellBounds( bounds={ 'phi': [20, 160], 'chi': [20, 160], 'psi': [20, 160], 'a': [2, 60], 'b': [2, 60], 'c': [2, 60] }) # Define a pairing operator with 100% (0%) chance that the first # (second) parent will be randomly translated, and with each parent # contributing to at least 15% of the child's scaled coordinates pairing = CutAndSplicePairing(blmin, p1=1., p2=0., minfrac=0.15, cellbounds=cellbounds, use_tags=False)