def test_minimahop(): # Make Pt 111 slab with Cu2 adsorbate. atoms = fcc111('Pt', (2, 2, 1), vacuum=7., orthogonal=True) adsorbate = Atoms([ Atom('Cu', atoms[2].position + (0., 0., 2.5)), Atom('Cu', atoms[2].position + (0., 0., 5.0)) ]) atoms.extend(adsorbate) # Constrain the surface to be fixed and a Hookean constraint between # the adsorbate atoms. constraints = [ FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == 'Pt']), Hookean(a1=4, a2=5, rt=2.6, k=15.), Hookean(a1=4, a2=(0., 0., 1., -15.), k=15.) ] atoms.set_constraint(constraints) # Set the calculator. calc = EMT() atoms.set_calculator(calc) # Instantiate and run the minima hopping algorithm. hop = MinimaHopping(atoms, Ediff0=2.5, T0=2000., beta1=1.2, beta2=1.2, mdmin=1) hop(totalsteps=3) # Test ability to restart and temperature stopping. hop(maxtemp=3000)
def _constrain(self): """Puts Hookean constraint on Pb atoms.""" # self._Pb_positions = self._atoms.positions[self._Pb_indices] # self._Br_positions = self._atoms.positions[self._Br_indices] constraints_inorganic_Hookean = [ Hookean(a1=int(self._Pb_indices[i]), a2=int(j), rt=self._atoms.get_distances( int(self._Pb_indices[i]), int(j), mic=True) + self._rt1, k=self._k1) for i in range(len(self._Pb_indices)) for j in self._indices_list[i] ] constraint_Br1 = [ Hookean(a1=self._Br_index1, a2=self._Br_index4, rt=self._atoms.get_distances( self._Br_index1, self._Br_index4, mic=True) + self._rt2, k=self._k2) ] constraint_Br2 = [ Hookean(a1=self._Br_index2, a2=self._Br_index3, rt=self._atoms.get_distances( self._Br_index2, self._Br_index3, mic=True) + self._rt2, k=self._k2) ] # Pb_z = self._Pb_positions[:,2] # Pb_average_z = np.average(Pb_z) # Pb_upper_indices = self._Pb_indices[np.where(Pb_z > Pb_average_z)] # Pb_bottom_indices = self._Pb_indices[np.where(Pb_z < Pb_average_z)] # constraint_fix = [FixAtoms(indices=[Pb_upper_indices[0]])] # constraint_upper_to_fix = [Hookean(a1=Pb_upper_indices[0], a2=int(i), rt=self._atoms.get_distance(Pb_upper_indices[0], i, mic=True) + 0.1, k=5.) for i in Pb_upper_indices[1:]] # constraint_upper = [Hookean(a1=int(i), a2=int(j), rt=self._atoms.get_distance(i, j, mic=True) + 0.1, k=5.) for i in Pb_upper_indices[1:] for j in Pb_upper_indices[1:] if i < j] # constraint_bottom = [Hookean(a1=int(i), a2=int(j), rt=self._atoms.get_distance(i, j, mic=True) + 0.1, k=5.) for i in Pb_bottom_indices for j in Pb_bottom_indices if i < j] constraints_non_flat = [ constrain for constrain in [constraints_inorganic_Hookean, constraint_Br1, constraint_Br2] if constrain != [] ] constraints = [ item for sublist in constraints_non_flat for item in sublist ] # constraints = [Hookean(a1=self._Pb_indices[i], a2=self._Pb_positions[i], rt=0.01, k=15.) for i in range(len(self._Pb_indices))] # self._atoms.set_constraint(constraints) self._atoms.set_constraint(constraints)
def test_momenta_hookean(atoms): atoms.set_constraint(Hookean(0, 1, rt=1., k=10.)) atoms.set_momenta(np.zeros(atoms.get_momenta().shape)) actual = atoms.get_momenta() desired = np.zeros(atoms.get_momenta().shape) # Why zero memoenta? Should we not test something juicier? assert (actual == desired).all()
def test_set_momenta(): """Test that set_momenta behaves as expected when constraints are involved.""" import numpy as np from ase import Atoms, Atom from ase.constraints import Hookean, FixAtoms # FixAtoms check atoms = Atoms([Atom('H', (0., 0., 0.)), Atom('H', (2., 0., 0.))]) atoms.set_constraint(FixAtoms(indices=[0])) atoms.set_momenta(np.ones(atoms.get_momenta().shape)) desired = np.ones(atoms.get_momenta().shape) desired[0] = 0. actual = atoms.get_momenta() assert (actual == desired).all() # Hookean check atoms = Atoms([Atom('H', (0., 0., 0.)), Atom('H', (2., 0., 0.))]) atoms.set_constraint(Hookean(0, 1, rt=1., k=10.)) atoms.set_momenta(np.zeros(atoms.get_momenta().shape)) actual = atoms.get_momenta() desired = np.zeros(atoms.get_momenta().shape)
def _shift_constraints(shift, rigid_atoms, bonds, angles, dihedrals, hookean_lst): """Helper function for place_and_preoptimize_adsorbates Args: shift (int) : constant by which to shift the atom indices rigid_atoms (list) : indices of atoms to be fixed bonds (list) : each element contains a tuple of bondlength and atom indices angles (list) : each element contains a tuple of angle and atom indices dihedrals (list) : each element contains a tuple of dihedral and atom indices hookean_lst (list) : ase.constraints.Hookean bond constraints Returns: tuple : All indices of rigid_atoms, bonds, angles, dihedrals and hookean_lst are shifted by shift """ new_rigid_atoms = [] new_bonds = [] new_angles = [] new_dihedrals = [] new_hookean_lst = [] for rigid_atom in rigid_atoms: new_rigid_atoms.append(rigid_atom + shift) for value, bond in bonds: new_bonds.append([value, [bond[0]+shift, bond[1]+shift]]) c = Hookean(a1=int(bond[0]) + shift, a2=int(bond[1]) + shift, rt=value, k=200.) new_hookean_lst.append(c) for value, angle in angles: new_angles.append([value, [angle[0]+shift,angle[1]+shift,angle[2]+shift]]) for value, dihedral in dihedrals: new_dihedrals.append([value, [dihedral[0]+shift,dihedral[1]+shift,dihedral[2]+shift, dihedral[3]+shift ]]) return new_rigid_atoms, new_bonds, new_angles, new_dihedrals, new_hookean_lst
def generate_data(count, filename, temp, hook, cons_t=False): """Generates test or training data with a simple MD simulation.""" traj = ase.io.Trajectory(filename, "w") slab = fcc100("Cu", size=(3, 3, 3)) ads = molecule("CO") add_adsorbate(slab, ads, 5, offset=(1, 1)) cons = FixAtoms(indices=[ atom.index for atom in slab if (atom.tag == 2 or atom.tag == 3) ]) if hook: cons2 = Hookean(a1=28, a2=27, rt=1.58, k=10.0) slab.set_constraint([cons, cons2]) else: slab.set_constraint(cons) slab.center(vacuum=13., axis=2) slab.set_pbc(True) slab.wrap(pbc=[True] * 3) slab.set_calculator(EMT()) slab.get_forces() dyn = QuasiNewton(slab) dyn.run(fmax=0.05) traj.write(slab) if cons_t is True: dyn = Langevin(slab, 1.0 * units.fs, temp * units.kB, 0.002) else: dyn = VelocityVerlet(slab, dt=1.0 * units.fs) for step in range(count): dyn.run(20) traj.write(slab)
def _constrain(self): """Puts Hookean constraint on Pb atoms.""" self._Pb_positions = self._atoms.positions[self._Pb_indices] constraints = [ Hookean(a1=self._Pb_indices[i], a2=self._Pb_positions[i], rt=0.01, k=15.) for i in range(len(self._Pb_indices)) ] self._atoms.set_constraint(constraints)
def _hookean_bonds(atoms, nb_lst): """Helper function for place_and_preoptimize_adsorbates. Args: atoms (ase.Atoms) : adsorbate molecule nb_lst (ase.neighborlist.NeighborList) : neighborlist Returns: ase.constraints.Hookean : Hookean bond contraints of all bonds in the molecule """ hookean_lst = [] for neighbors in nb_lst: c = Hookean(a1=int(neighbors[0]), a2=int(neighbors[1]), rt=atoms.get_distance(neighbors[0], neighbors[1]), k=20.) hookean_lst.append(c) return hookean_lst
def generate_data(count, filename, temp, hook, cons_t=False): """Generates test or training data with a simple MD simulation.""" traj = ase.io.Trajectory(filename, "w") pair = molecule("CO") cons = Hookean(a1=0, a2=1, rt=1.58, k=10.0) # pair.set_constraint(cons) pair.set_calculator(EMT()) pair.get_potential_energy() dyn = QuasiNewton(pair, trajectory=(filename[:-5] + "_relax.traj")) dyn.run(fmax=0.05) traj.write(pair) MaxwellBoltzmannDistribution(pair, temp * units.kB) if cons_t is True: dyn = Langevin(pair, 5 * units.fs, temp * units.kB, 0.002) else: dyn = VelocityVerlet(pair, dt=1.0 * units.fs) for step in range(count - 1): dyn.run(50) traj.write(pair)
def test_getindices(): from ase.build import fcc111 from ase.constraints import (FixAtoms, FixBondLengths, FixLinearTriatomic, FixInternals, Hookean, constrained_indices) slab = fcc111('Pt', (4, 4, 4)) C1 = FixAtoms([0, 2, 4]) C2 = FixBondLengths([[0, 1], [0, 2]]) C3 = FixInternals(bonds=[[1, [7, 8]], [1, [8, 9]]]) C4 = Hookean(a1=30, a2=40, rt=1.79, k=5.) C5 = FixLinearTriatomic(triples=[(0, 1, 2), (3, 4, 5)]) slab.set_constraint([C1, C2, C3, C4, C5]) assert all( constrained_indices(slab, (FixAtoms, FixBondLengths)) == [0, 1, 2, 4]) assert all( constrained_indices(slab, (FixBondLengths, FixLinearTriatomic)) == [0, 1, 2, 3, 4, 5]) assert all( constrained_indices(slab) == [0, 1, 2, 3, 4, 5, 7, 8, 9, 30, 40])
def test_hookean_pbc(): from ase import Atoms from ase.calculators.emt import EMT from ase.constraints import Hookean L = 8. # length of the cubic box d = 2.3 # Au-Au distance cell = [L] * 3 positions = [[(L - d/2) % L , L/2, L/2], [(L + d/2) % L, L/2, L/2]] a = Atoms('AuAu', cell=cell, positions=positions, pbc=True) a.set_calculator(EMT()) e1 = a.get_potential_energy() constraint = Hookean(a1=0, a2=1, rt=1.1*d, k=10.) a.set_constraint(constraint) e2 = a.get_potential_energy() a.set_pbc([False, True, True]) e3 = a.get_potential_energy() assert abs(e1 - e2) < 1e-8 assert not abs(e1 - e3) < 1e-8
def _constrain(self): """Constrain atoms.""" self._inorganic_positions = self._atoms.positions[ self._inorganic_indices] constraints = [ Hookean(a1=self._inorganic_indices[i], a2=self._inorganic_positions[i], rt=0.1, k=15.) for i in range(len(self._inorganic_indices)) ] # self._Pb_positions = self._atoms.positions[self._Pb_indices] # Pb_z = self._Pb_positions[:,2] # Pb_average_z = np.average(Pb_z) # Pb_upper_indices = self._Pb_indices[np.where(Pb_z > Pb_average_z)] # Pb_bottom_indices = self._Pb_indices[np.where(Pb_z < Pb_average_z)] # constraint_fix = [FixAtoms(indices=self._inorganic_indices)] # constraint_upper_to_fix = [Hookean(a1=Pb_upper_indices[0], a2=int(i), rt=self._atoms.get_distance(Pb_upper_indices[0], i, mic=True) + 0.1, k=5.) for i in Pb_upper_indices[1:]] # constraint_upper = [Hookean(a1=int(i), a2=int(j), rt=self._atoms.get_distance(i, j, mic=True) + 0.1, k=5.) for i in Pb_upper_indices[1:] for j in Pb_upper_indices[1:] if i < j] # constraint_bottom = [Hookean(a1=int(i), a2=int(j), rt=self._atoms.get_distance(i, j, mic=True) + 0.1, k=5.) for i in Pb_bottom_indices for j in Pb_bottom_indices if i < j] # constraints_non_flat = [constrain for constrain in [constraint_fix, constraint_upper_to_fix, constraint_upper, constraint_bottom] if constrain != []] # constraints = [item for sublist in constraints_non_flat for item in sublist] # constraints = [Hookean(a1=self._Pb_indices[i], a2=self._Pb_positions[i], rt=0.01, k=15.) for i in range(len(self._Pb_indices))] self._atoms.set_constraint(constraints)
def test_hookean(): """ Test of Hookean constraint. Checks for activity in keeping a bond, preventing vaporization, and that energy is conserved in NVE dynamics. """ import numpy as np from ase import Atoms, Atom from ase.build import fcc110 from ase.calculators.emt import EMT from ase.constraints import FixAtoms, Hookean from ase.md import VelocityVerlet from ase import units class SaveEnergy: """Class to save energy.""" def __init__(self, atoms): self.atoms = atoms self.energies = [] def __call__(self): self.energies.append(atoms.get_total_energy()) # Make Pt 110 slab with Cu2 adsorbate. atoms = fcc110('Pt', (2, 2, 2), vacuum=7.) adsorbate = Atoms([ Atom('Cu', atoms[7].position + (0., 0., 2.5)), Atom('Cu', atoms[7].position + (0., 0., 5.0)) ]) atoms.extend(adsorbate) calc = EMT() atoms.calc = calc # Constrain the surface to be fixed and a Hookean constraint between # the adsorbate atoms. constraints = [ FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == 'Pt']), Hookean(a1=8, a2=9, rt=2.6, k=15.), Hookean(a1=8, a2=(0., 0., 1., -15.), k=15.) ] atoms.set_constraint(constraints) # Give it some kinetic energy. momenta = atoms.get_momenta() momenta[9, 2] += 20. momenta[9, 1] += 2. atoms.set_momenta(momenta) # Propagate in Velocity Verlet (NVE). dyn = VelocityVerlet(atoms, timestep=1.0 * units.fs) energies = SaveEnergy(atoms) dyn.attach(energies) dyn.run(steps=100) # Test the max bond length and position. bondlength = np.linalg.norm(atoms[8].position - atoms[9].position) assert bondlength < 3.0 assert atoms[9].z < 15.0 # Test that energy was conserved. assert max(energies.energies) - min(energies.energies) < 0.01 # Make sure that index shuffle works. neworder = list(range(len(atoms))) neworder[8] = 9 # Swap two atoms. neworder[9] = 8 atoms = atoms[neworder] assert atoms.constraints[1].indices[0] == 9 assert atoms.constraints[1].indices[1] == 8 assert atoms.constraints[2].index == 9
def delete_single_atom_with_constraint(atoms=None, indice_to_delete=None): if indice_to_delete is None: return # nothing to delete elif indice_to_delete > len(atoms)-1: raise RuntimeError("try too remove too many atoms?") # I have to teach each fix objects individually, how can I make it smarter? hookean_pairs = [] fix_atoms_indices = [] fix_bondlengths_indices = None never_delete_indices = [] fix_lines_indices = [] for c in atoms.constraints: if isinstance(c, FixAtoms): fix_atoms_indices.append(c.get_indices()) elif isinstance(c, Hookean): hookean_pairs.append([c.get_indices(), c.threshold, c.spring]) elif isinstance(c, FixBondLengths): if fix_bondlengths_indices is not None: raise RuntimeError("Do you have more than one FixBondLengths?") fix_bondlengths_indices = c.pairs.copy() elif isinstance(c, NeverDelete): for ind in c.get_indices(): never_delete_indices.append(ind) elif isinstance(c, FixedLine): fix_lines_indices.append([c.a, c.dir]) else: try: cn = c.__class__.__name__ except AttributeError: cn = "Unknown" raise RuntimeError("constraint type %s is not supported" % cn) new_constraints = [] for old_inds in fix_atoms_indices: new_inds = [] for ind in old_inds: if ind < indice_to_delete: new_inds.append(ind) elif ind > indice_to_delete: new_inds.append(ind - 1) else: continue if len(new_inds) > 0: new_constraints.append(FixAtoms(indices=new_inds)) for old_inds, rt, k in hookean_pairs: if indice_to_delete in old_inds: continue new_inds = [] for ind in old_inds: if ind < indice_to_delete: new_inds.append(ind) else: new_inds.append(ind-1) new_constraints.append(Hookean(a1=new_inds[0], a2=new_inds[1], rt=rt, k=k)) for ind, direction in fix_lines_indices: if ind == indice_to_delete: continue elif ind < indice_to_delete: new_constraints.append(FixedLine(ind, direction=direction)) else: new_constraints.append(FixedLine(ind-1,direction=direction)) if fix_bondlengths_indices is not None: number_of_cons, ncols = fix_bondlengths_indices.shape assert ncols == 2 new_inds = [] for ic in range(number_of_cons): ind1, ind2 = fix_bondlengths_indices[ic][0], fix_bondlengths_indices[ic][1] if ind1 == indice_to_delete or ind2 == indice_to_delete: continue else: pairs = [] if ind1 < indice_to_delete: pairs.append(ind1) else: pairs.append(ind1-1) if ind2 < indice_to_delete: pairs.append(ind2) else: pairs.append(ind2-1) new_inds.append(pairs) if len(new_inds) > 0: new_constraints.append(FixBondLengths(pairs=new_inds)) if len(never_delete_indices) > 0: new_inds = [] for ind in never_delete_indices: if ind < indice_to_delete: new_inds.append(ind) elif ind > indice_to_delete: new_inds.append(ind - 1) if len(new_inds) > 0: new_constraints.append(NeverDelete(indices=new_inds)) # remove all the constraints atoms.set_constraint() del atoms[indice_to_delete] # add back the constraints atoms.set_constraint(new_constraints) return
"""Test that set_momenta behaves as expected when constraints are involved.""" import numpy as np from ase import Atoms, Atom from ase.constraints import Hookean, FixAtoms # FixAtoms check atoms = Atoms([Atom('H', (0., 0., 0.)), Atom('H', (2., 0., 0.))]) atoms.set_constraint(FixAtoms(indices=[0])) atoms.set_momenta(np.ones(atoms.get_momenta().shape)) desired = np.ones(atoms.get_momenta().shape) desired[0] = 0. actual = atoms.get_momenta() assert (actual == desired).all() # Hookean check atoms = Atoms([Atom('H', (0., 0., 0.)), Atom('H', (2., 0., 0.))]) atoms.set_constraint(Hookean(0, 1, rt=1., k=10.)) atoms.set_momenta(np.zeros(atoms.get_momenta().shape)) actual = atoms.get_momenta() desired = np.zeros(atoms.get_momenta().shape) # Disabled for now: # assert (actual == desired).all()
from ase.optimize.minimahopping import MinimaHopping from ase.calculators.emt import EMT from ase.constraints import FixAtoms, Hookean # Make Pt 111 slab with Cu2 adsorbate. atoms = fcc111('Pt', (2, 2, 1), vacuum=7., orthogonal=True) adsorbate = Atoms([ Atom('Cu', atoms[2].position + (0., 0., 2.5)), Atom('Cu', atoms[2].position + (0., 0., 5.0)) ]) atoms.extend(adsorbate) # Constrain the surface to be fixed and a Hookean constraint between # the adsorbate atoms. constraints = [ FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == 'Pt']), Hookean(a1=4, a2=5, rt=2.6, k=15.), Hookean(a1=4, a2=(0., 0., 1., -15.), k=15.) ] atoms.set_constraint(constraints) # Set the calculator. calc = EMT() atoms.set_calculator(calc) # Instantiate and run the minima hopping algorithm. hop = MinimaHopping(atoms, Ediff0=2.5, T0=2000., beta1=1.2, beta2=1.2, mdmin=1) hop(totalsteps=3) # Test ability to restart and temperature stopping. hop(maxtemp=3000)
from ase.calculators.emt import EMT from ase.constraints import FixAtoms, Hookean from ase.optimize import BFGS # Make the Pt 110 slab. atoms = fcc110('Pt', (2, 2, 2), vacuum=7.) # Add the Cu2 adsorbate. adsorbate = Atoms([ Atom('Cu', atoms[7].position + (0., 0., 2.5)), Atom('Cu', atoms[7].position + (0., 0., 5.0)) ]) atoms.extend(adsorbate) # Constrain the surface to be fixed and a Hookean constraint between # the adsorbate atoms. constraints = [ FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == 'Pt']), Hookean(a1=8, a2=9, rt=2.6, k=15.), Hookean(a1=8, a2=(0., 0., 1., -15.), k=15.), ] atoms.set_constraint(constraints) # Set the calculator. calc = EMT() atoms.set_calculator(calc) # Instantiate and run the minima hopping algorithm. hop = MinimaHopping(atoms, Ediff0=2.5, optimizer=BFGS, T0=4000.) hop(totalsteps=10)
from ase.build import fcc111 from ase.constraints import (FixAtoms, FixBondLengths, FixInternals, Hookean, constrained_indices) slab = fcc111('Pt', (4, 4, 4)) C1 = FixAtoms([0, 2, 4]) C2 = FixBondLengths([[0, 1], [0, 2]]) C3 = FixInternals(bonds=[[1, [7, 8]], [1, [8, 9]]]) C4 = Hookean(a1=30, a2=40, rt=1.79, k=5.) slab.set_constraint([C1, C2, C3, C4]) assert all( constrained_indices(slab, (FixAtoms, FixBondLengths)) == [0, 1, 2, 4]) assert all(constrained_indices(slab) == [0, 1, 2, 4, 7, 8, 9, 30, 40])
from ase import Atoms from ase.calculators.emt import EMT from ase.constraints import Hookean L = 8. # length of the cubic box d = 2.3 # Au-Au distance cell = [L]*3 positions = [[(L - d/2) % L , L/2, L/2], [(L + d/2) % L, L/2, L/2]] a = Atoms('AuAu', cell=[L]*3, positions=positions, pbc=True) a.set_calculator(EMT()) e1 = a.get_potential_energy() constraint = Hookean(a1=0, a2=1, rt=1.1*d, k=10.) a.set_constraint(constraint) e2 = a.get_potential_energy() a.set_pbc([False, True, True]) e3 = a.get_potential_energy() assert abs(e1 - e2) < 1e-8 assert not abs(e1 - e3) < 1e-8