def main():
    """
    Checks whether ASE's rattle modifies fixed atoms.
    '"""
    # Constructs test system
    slab = fcc100("Cu", size=(3, 3, 3))
    ads = molecule("CO")
    add_adsorbate(slab, ads, 4, offset=(1, 1))
    fix_mask = [
        atom.index for atom in slab if (atom.tag == 2 or atom.tag == 3)
    ]
    free_mask = [
        atom.index for atom in slab if (atom.tag != 2 and atom.tag != 3)
    ]
    # Apply constraint to fix the bottom 2 layers of the slab.
    cons = FixAtoms(fix_mask)
    slab.set_constraint(cons)

    original_positions = slab.positions

    ### Rattle system
    rattled_image = slab.copy()
    rattled_image.rattle(stdev=1, seed=23794)

    rattled_positions = rattled_image.positions

    assert (original_positions[fix_mask].all() == rattled_positions[fix_mask].
            all()), "Fixed atoms have been rattled!"

    assert (original_positions[free_mask].all() !=
            rattled_positions[free_mask].all()), "Remaining atoms not rattled!"

    print("Test passed! rattle() does not modify fixed atoms")
Exemplo n.º 2
0
def test_dimer_method():
    # Set up a small "slab" with an adatoms
    atoms = fcc100('Pt', size=(2, 2, 1), vacuum=10.0)
    add_adsorbate(atoms, 'Pt', 1.611, 'hollow')

    # Freeze the "slab"
    mask = [atom.tag > 0 for atom in atoms]
    atoms.set_constraint(FixAtoms(mask=mask))

    # Calculate using EMT
    atoms.set_calculator(EMT())
    atoms.get_potential_energy()

    # Set up the dimer
    d_control = DimerControl(initial_eigenmode_method = 'displacement', \
                             displacement_method = 'vector', logfile = None, \
                             mask = [0, 0, 0, 0, 1])
    d_atoms = MinModeAtoms(atoms, d_control)

    # Displace the atoms
    displacement_vector = [[0.0] * 3] * 5
    displacement_vector[-1][1] = -0.1
    d_atoms.displace(displacement_vector=displacement_vector)

    # Converge to a saddle point
    dim_rlx = MinModeTranslate(d_atoms, trajectory = 'dimer_method.traj', \
                               logfile = None)
    dim_rlx.run(fmax=0.001)

    # Test the results
    tolerance = 1e-3
    assert (d_atoms.get_barrier_energy() - 1.03733136918 < tolerance)
    assert (abs(d_atoms.get_curvature() + 0.900467048707) < tolerance)
    assert (d_atoms.get_eigenmode()[-1][1] < -0.99)
    assert (abs(d_atoms.get_positions()[-1][1]) < tolerance)
Exemplo n.º 3
0
    def create_surface_Al(self, miller_index, N_x, N_y, N_z, lattice_param):
        if miller_index == '111':
            obj = fcc111('Al', size=(N_x, N_y, N_z), a=lattice_param, vacuum=7.5)
            obj.set_calculator(calc)
            cell = obj.get_cell()  # Unit cell object of the Al FCC surface
            area = np.linalg.norm(np.cross(cell[0], cell[1]))  # Calc. surface area

            surface = {'object': obj,
                       'size': (N_x, N_y, N_z),
                       'a': lattice_param,
                       'area': area,
                       'energy': 0,
                       'sigma': 0}

        elif miller_index == '100':
            obj = fcc100('Al', size=(N_x, N_y, N_z), a=lattice_param, vacuum=7.5)
            obj.set_calculator(calc)
            cell = obj.get_cell()  # Unit cell object of the Al FCC surface
            area = np.linalg.norm(np.cross(cell[0], cell[1]))  # Calc. surface area

            surface = {'object': obj,
                       'size': (N_x, N_y, N_z),
                       'a': lattice_param,
                       'area': area,
                       'energy': 0,
                       'sigma': 0}
        else:
            return 1

        self.surface.center(axis=2)
        self.surfaces[miller_index].append(surface)
        return 0
def test_dimer_method(testdir):
    # Set up a small "slab" with an adatoms
    atoms = fcc100('Pt', size=(2, 2, 1), vacuum=10.0)
    add_adsorbate(atoms, 'Pt', 1.611, 'hollow')

    # Freeze the "slab"
    mask = [atom.tag > 0 for atom in atoms]
    atoms.set_constraint(FixAtoms(mask=mask))

    # Calculate using EMT
    atoms.calc = EMT()
    atoms.get_potential_energy()

    # Set up the dimer
    with DimerControl(initial_eigenmode_method='displacement',
                      displacement_method='vector',
                      logfile=None,
                      mask=[0, 0, 0, 0, 1]) as d_control:
        d_atoms = MinModeAtoms(atoms, d_control)

        # Displace the atoms
        displacement_vector = [[0.0] * 3] * 5
        displacement_vector[-1][1] = -0.1
        d_atoms.displace(displacement_vector=displacement_vector)

        # Converge to a saddle point
        with MinModeTranslate(d_atoms,
                              trajectory='dimer_method.traj',
                              logfile="dimer_method.log") as dim_rlx:
            dim_rlx.run(fmax=0.001)
Exemplo n.º 5
0
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)
Exemplo n.º 6
0
def energy(N, k, a=4.05):
    fcc = fcc100('Al', (1, 1, N), a=a, vacuum=7.5)
    fcc.center(axis=2)
    calc = GPAW(nbands=N * 3, kpts=(k, k, 1), h=0.25, txt='slab-%d.txt' % N)
    fcc.set_calculator(calc)
    e = fcc.get_potential_energy()
    calc.write('slab-%d.gpw' % N)
    return e
Exemplo n.º 7
0
    def attach_leads(self):
        leadl = build.fcc100('Au', [3, 3, 6])
        leadr = build.fcc100('Au', [3, 3, 6])
        self.num_leadatoms = leadl.get_number_of_atoms()

        dAuC = 1.6
        Lcl = leadl[49]
        Lcr = leadr[4]
        Mcl = self.mol[0]
        Mcr = self.mol[-1]
        xs = Lcl.x - (Mcl.x + Mcr.x) / 2
        ys = Lcl.y - (Mcl.y + Mcr.y) / 2

        self.mol.translate([xs, ys, Lcl.z - Mcl.z + dAuC])
        leadr.translate([0.4, -0.4, Mcr.z - Lcr.z + dAuC])

        self.mol = leadl + self.mol + leadr
Exemplo n.º 8
0
def attach_leads(mol):
    leadl = build.fcc100('Au', [3, 3, 6])
    leadr = build.fcc100('Au', [3, 3, 6])
    #num_leadatoms = leadl.get_number_of_atoms()

    dAuN = dAuC = 1.6
    Lcl = leadl[49]
    Lcr = leadr[4]
    Mcl = mol[0]
    Mcr = mol[-4]
    xs = Lcl.x - (Mcl.x + Mcr.x) / 2
    ys = Lcl.y - (Mcl.y + Mcr.y) / 2

    mol.translate([xs, ys, Lcl.z - Mcl.z + dAuN])
    leadr.translate([0.4, -0.4, Mcr.z - Lcr.z + dAuC])

    return leadl + mol + leadr
def get_mgsi_surface100_si_si():
    from ase.build import fcc100
    atoms = fcc100("Al", size=(10, 10, 5))
    for atom in atoms:
        if atom.tag % 2 == 0:
            atom.symbol = "Mg"
        else:
            atom.symbol = "Si"
    return atoms
def prepare_Au_on_Al_slab():
    atoms = fcc100("Al", size=(2, 2, 3))
    add_adsorbate(atoms, "Au", 1.7, "hollow")
    atoms.center(axis=2, vacuum=4.0)
    atoms.set_calculator(EMT())
    # Fix second and third layers:
    mask = [atom.tag > 1 for atom in atoms]
    atoms.set_constraint(FixAtoms(mask=mask))
    #
    #atoms.write("STRUCT.xsf")
    #
    return atoms
Exemplo n.º 11
0
def traj(tmpdir_factory):
    slab = fcc100('Al', size=(2, 2, 3))
    add_adsorbate(slab, 'Au', 1.7, 'hollow')
    slab.center(axis=2, vacuum=4.0)
    mask = [atom.tag > 1 for atom in slab]
    fixlayers = FixAtoms(mask=mask)
    plane = FixedPlane(-1, (1, 0, 0))
    slab.set_constraint([fixlayers, plane])
    slab.set_calculator(EMT())

    fn = tmpdir_factory.mktemp("data").join("AlAu.traj")  # see /tmp/pytest-xx
    qn = QuasiNewton(slab, trajectory=str(fn))
    qn.run(fmax=0.02)
    return fn
Exemplo n.º 12
0
def run_relaxation(calculator, filename, steps=500):
    slab = fcc100("Cu", size=(3, 3, 3))
    ads = molecule("CO")
    add_adsorbate(slab, ads, 4, offset=(1, 1))
    cons = FixAtoms(indices=[
        atom.index for atom in slab if (atom.tag == 2 or atom.tag == 3)
    ])
    slab.set_constraint([cons])
    slab.center(vacuum=13.0, axis=2)
    slab.set_pbc(True)
    slab.set_calculator(calculator)
    print("### Generating data")
    dyn = BFGS(slab, trajectory=filename, logfile=None)
    dyn.run(fmax=0.01, steps=steps)
Exemplo n.º 13
0
def get_atoms():
    # 2x2-Al(001) surface with 3 layers and an
    # Au atom adsorbed in a hollow site:
    slab = fcc100('Al', size=(2, 2, 3))
    add_adsorbate(slab, 'Au', 1.7, 'hollow')
    slab.center(axis=2, vacuum=4.0)

    # Fix second and third layers:
    mask = [atom.tag > 1 for atom in slab]
    slab.set_constraint(FixAtoms(mask=mask))

    # Use EMT potential:
    slab.set_calculator(EMT())

    # Initial state:
    qn = QuasiNewton(slab, logfile=None)
    qn.run(fmax=0.05)
    initial = slab.copy()

    # Final state:
    slab[-1].x += slab.get_cell()[0, 0] / 2
    qn = QuasiNewton(slab, logfile=None)
    qn.run(fmax=0.05)
    final = slab.copy()

    # Setup a NEB calculation
    constraint = FixAtoms(mask=[atom.tag > 1 for atom in initial])

    images = [initial]
    for i in range(3):
        image = initial.copy()
        image.set_constraint(constraint)
        images.append(image)

    images.append(final)

    neb = NEB(images, parallel=mpi.parallel)
    neb.interpolate()

    def set_calculator(calc):
        i = 0
        for image in neb.images[1:-1]:
            if not mpi.parallel or mpi.rank // (mpi.size // 3) == i:
                image.set_calculator(calc)
            i += 1

    neb.set_calculator = set_calculator

    return neb
Exemplo n.º 14
0
def traj(tmp_path_factory):
    slab = fcc100('Al', size=(2, 2, 3))
    add_adsorbate(slab, 'Au', 1.7, 'hollow')
    slab.center(axis=2, vacuum=4.0)
    mask = [atom.tag > 1 for atom in slab]
    fixlayers = FixAtoms(mask=mask)
    plane = FixedPlane(-1, (1, 0, 0))
    slab.set_constraint([fixlayers, plane])
    slab.calc = EMT()

    temp_path = tmp_path_factory.mktemp("data")
    trajectory = temp_path / 'AlAu.traj'
    qn = QuasiNewton(slab, trajectory=str(trajectory))
    qn.run(fmax=0.02)
    return str(trajectory)
Exemplo n.º 15
0
def get_atoms():
    # 2x2-Al(001) surface with 3 layers and an
    # Au atom adsorbed in a hollow site:
    slab = fcc100('Al', size=(2, 2, 3))
    add_adsorbate(slab, 'Au', 1.7, 'hollow')
    slab.center(axis=2, vacuum=4.0)

    # Fix second and third layers:
    mask = [atom.tag > 1 for atom in slab]
    slab.set_constraint(FixAtoms(mask=mask))

    # Use EMT potential:
    slab.set_calculator(EMT())

    # Initial state:
    qn = QuasiNewton(slab, logfile=None)
    qn.run(fmax=0.05)
    initial = slab.copy()

    # Final state:
    slab[-1].x += slab.get_cell()[0, 0] / 2
    qn = QuasiNewton(slab, logfile=None)
    qn.run(fmax=0.05)
    final = slab.copy()

    # Setup a NEB calculation
    constraint = FixAtoms(mask=[atom.tag > 1 for atom in initial])

    images = [initial]
    for i in range(3):
        image = initial.copy()
        image.set_constraint(constraint)
        images.append(image)

    images.append(final)

    neb = NEB(images, parallel=mpi.parallel)
    neb.interpolate()

    def set_calculator(calc):
        i = 0
        for image in neb.images[1:-1]:
            if not mpi.parallel or mpi.rank // (mpi.size // 3) == i:
                image.set_calculator(calc)
            i += 1
    neb.set_calculator = set_calculator

    return neb
Exemplo n.º 16
0
def test_harmonic_thermo():
    atoms = fcc100('Cu', (2, 2, 2), vacuum=10.)
    atoms.calc = EMT()
    add_adsorbate(atoms, 'Pt', 1.5, 'hollow')
    atoms.set_constraint(FixAtoms(indices=[atom.index for atom in atoms
                                           if atom.symbol == 'Cu']))
    QuasiNewton(atoms).run(fmax=0.01)
    vib = Vibrations(atoms, name='harmonicthermo-vib',
                     indices=[atom.index for atom in atoms
                              if atom.symbol != 'Cu'])
    vib.run()
    vib.summary()
    vib_energies = vib.get_energies()

    thermo = HarmonicThermo(vib_energies=vib_energies,
                            potentialenergy=atoms.get_potential_energy())
    thermo.get_helmholtz_energy(temperature=298.15)
Exemplo n.º 17
0
def construct_geometries(parent_calc, ml2relax):
    counter_calc = parent_calc
    # Initial structure guess
    initial_slab = fcc100("Cu", size=(2, 2, 3))
    add_adsorbate(initial_slab, "C", 1.7, "hollow")
    initial_slab.center(axis=2, vacuum=4.0)
    mask = [atom.tag > 1 for atom in initial_slab]
    initial_slab.set_constraint(FixAtoms(mask=mask))
    initial_slab.set_pbc(True)
    initial_slab.wrap(pbc=[True] * 3)
    initial_slab.set_calculator(counter_calc)

    # Final structure guess
    final_slab = initial_slab.copy()
    final_slab[-1].x += final_slab.get_cell()[0, 0] / 3
    final_slab.set_calculator(counter_calc)
    if not ml2relax:
        print("BUILDING INITIAL")
        qn = BFGS(initial_slab,
                  trajectory="initial.traj",
                  logfile="initial_relax_log.txt")
        qn.run(fmax=0.01, steps=100)
        print("BUILDING FINAL")
        qn = BFGS(final_slab,
                  trajectory="final.traj",
                  logfile="final_relax_log.txt")
        qn.run(fmax=0.01, steps=100)
        initial_slab = read("initial.traj", "-1")
        final_slab = read("final.traj", "-1")
        # If there is already a pre-existing initial and final relaxed parent state we can read
        # that to use as a starting point
        # initial_slab = read("/content/parent_initial.traj")
        # final_slab = read("/content/parent_final.traj")
    else:
        initial_slab = initial_slab
        final_slab = final_slab

    # initial_force_calls = counter_calc.force_calls
    return initial_slab, final_slab  # , initial_force_calls
Exemplo n.º 18
0
def slabgen(termination, size, adsorbate, position):
    if termination == '100':
        prim = fcc100('Cu',
                      a=3.6302862146117354,
                      size=(1, 1, 5),
                      vacuum=15,
                      orthogonal=True,
                      periodic=True)
    elif termination == '111':
        prim = fcc111_root('Cu',
                           root=3,
                           a=3.6302862146117354,
                           size=(1, 1, 5),
                           vacuum=15)

    super = make_supercell(prim, size)
    add_adsorbate(slab=super,
                  adsorbate=adsorbate,
                  height=ads_height,
                  position=position)
    constr = FixAtoms(
        indices=[atom.index for atom in super if atom.position[2] < 19])
    super.set_constraint(constr)
    return super
Exemplo n.º 19
0
def aual100(site, height, calc=None):
    slab = fcc100('Al', size=(2, 2, 2))
    slab.center(axis=2, vacuum=3.0)
    add_adsorbate(slab, 'Au', height, site)
    mask = [atom.symbol == 'Al' for atom in slab]
    fixlayer = FixAtoms(mask=mask)
    slab.set_constraint(fixlayer)

    if calc is None:
        calc = GPAW(mode=PW(200),
                    kpts=(2, 2, 1),
                    xc='PBE',
                    txt=site + '.txt',
                    eigensolver='rmm-diis',
                    nbands=40)

    slab.set_calculator(calc)
    qn = QuasiNewton(slab, trajectory=site + calc.name + '.traj')
    qn.run(fmax=0.05)

    if isinstance(calc, GPAW):
        calc.write(site + '.gpw')

    return slab.get_potential_energy()
Exemplo n.º 20
0
from ase.build import surface, fcc100, add_adsorbate
from ase.constraints import FixAtoms
from ase.io import read
import numpy as np
from ase.visualize import view

#bulk = read('../bulk/converged_bulk.traj')
#a=3.89
#a = np.linalg.norm(bulk.cell[0])

vac = 6

#atoms = fcc100('Pd', (2,2,4), a=a, vacuum=10)
atoms = fcc100('Pd', (2, 2, {l}), vacuum=vac)
nitrate = read('nitrate.xyz')
add_adsorbate(atoms, nitrate, 1.5, 'ontop')
c = FixAtoms(mask=[a.z < vac + 2 for a in atoms])
atoms.set_constraint(c)
#atoms *= (2,2,1)

atoms.write('structure.traj')
Exemplo n.º 21
0
                    algo='Normal',
                    ncore=4,
                    xc='PBE',
                    gga='RP',
                    lreal=False,
                    ediff=1e-4,
                    ispin=1,
                    nelm=100,
                    encut=400,
                    lwave=False,
                    lcharg=False,
                    nsw=0,
                    kpts=(1, 1, 1))

    # Define initial set of images, can be as few as 1. If 1, make sure to
    slab = fcc100("Cu", size=(3, 3, 3))
    ads = molecule("CO")
    add_adsorbate(slab, ads, 3, offset=(1, 1))
    cons = FixAtoms(indices=[atom.index for atom in slab if (atom.tag == 3)])
    slab.set_constraint(cons)
    slab.center(vacuum=13.0, axis=2)
    slab.set_pbc(True)
    slab.wrap(pbc=True)
    slab.set_calculator(copy.copy(dft_calc))
    sample_energy = slab.get_potential_energy(apply_constraint=False)
    sample_forces = slab.get_forces(apply_constraint=False)
    slab.set_calculator(
        sp(atoms=slab, energy=sample_energy, forces=sample_forces))
    ase.io.write("./slab.traj", slab)

    images = [slab]
Exemplo n.º 22
0
from ase import Atom, Atoms
from ase.build import bulk, fcc100, add_adsorbate, add_vacuum
from ase.calculators.vasp import Vasp
from ase.calculators.kim.kim import KIM
from ase.calculators.qmmm import ForceQMMM, RescaledCalculator
from ase.constraints import StrainFilter
from ase.optimize import LBFGS
from ase.visualize import view

atoms = bulk("Pd", "fcc", a=3.5, cubic=True)
atoms.calc = KIM("MEAM_LAMMPS_JeongParkDo_2018_PdMo__MO_356501945107_000")
opt = LBFGS(StrainFilter(atoms), logfile=None)
opt.run(0.03, steps=30)
length = atoms.cell.cellpar()[0]

atoms = fcc100("Pd", (2,2,5), a=length, vacuum=10, periodic=True)
add_adsorbate(atoms, Atoms([Atom("Mo")]), 1.2)


qm_mask = [len(atoms)-1, len(atoms)-2]
qm_calc = Vasp(directory="./qmmm")
mm_calc = KIM("MEAM_LAMMPS_JeongParkDo_2018_PdMo__MO_356501945107_000")
mm_calc = RescaledCalculator(mm_calc, 1, 1, 1, 1)
qmmm = ForceQMMM(atoms, qm_mask, qm_calc, mm_calc, buffer_width=3)
qmmm.initialize_qm_buffer_mask(atoms)
atoms.pbc=True
atoms.calc = qmmm

print(atoms.get_forces())

Exemplo n.º 23
0
def Nanoparticle_Builder(metal,lc,surfaces,layers,adsorbate,site,coverage,cell_height,subsys_height,unmasked_layers,E_cut,kpoints,ads_cutoff,ads111,ads100,subsys111_relaxed,subsys100_relaxed,relax):
    ###
    ### Function to set up the Nanoparticle base
    ###
    
    #Input pparameters
#     metal: The metal comprising the substrate/nanoparticle. For example 'Au'.
#     lc: Lattice constant. For example 4.0800.
#     surfaces: The surfaces in the NP. For example [(1, 0, 0),(1, 1, 1)].
#     layers: The number of layers from the cetner of the NP to each surface. For example: [6,5]
#     adsorbate: The molecule to be adsorbed on top. Should be an object which ase can read. For example: molecule('CO')
#     site: Either 'OnTop' or 'Hollow'. Should be 'OnTop' for 100% coverages.
#     coverage: Desired coverage. Must be 1/n where n is whole number. 
#     cell_height: The height of the subsystem unit cell. For example 6*lc.
#     subsys_height: Height of subsystem - no. of atom  layers. For example: 4. If reading the relaxed subsystem from a traj file MAKE SURE THE HEIGHTS MATCH.
#     unmasked_layers: The number of layers in the NP subsystem (from the top) that is allowed to move during DFT relaxation.
#     E_cut: Cutoff energy for DFT PW.
#     kpoints: k-point grid in the first Brillouin zone. 
#     ads_cutoff: The cutoff for adsorption energy. This determines whether adsorption has occurred for a surface or not.
#     ads111: If providing a relaxed subsystem, this is the adsorption energy for the 111 surface.
#     ads100: If providing a relaxed subsystem, this is the adsorption energy for the 100 surface.
#     subsys111_relaxed: This is an ASE object containing the relaxed subsystem for 111. Necessary to skip DFT.
#     subsys100_relaxed: This is an ASE object containing the relaxed subsystem for 100. Necessary to skip DFT.
#     relax: A boolean to determine whether or not DFT calculations have to be run or not. If relax=False, make sure to provide subsys111_relaxed and subsys100_relaxed along with ads111 and ads100.

    if site==None:
        site='OnTop'
    if cell_height==None:
        cell_height=6*lc
    if subsys_height==None:
        subsys_height=3
    if unmasked_layers==None:
        unmasked_layers=1
    if E_cut==None:
        E_cut=200
    if kpoints==None:
        kpoints=(6,6,1)
    if ads_cutoff==None:
        ads_cutoff=0
    
    #The bulk structure is created.
    Nanoparticle = FaceCenteredCubic(metal, surfaces, layers, latticeconstant=lc)
    Reference = FaceCenteredCubic(metal, surfaces, layers, latticeconstant=lc)  #A reference is made for TEM imaging without adsorbates.

    ##Alternative wulff_construction-based setup. This requires N_atoms and surf_energies list to be set up (for gold, use surf_energies=[1.23,1]).
    #Nanoparticle = wulff_construction(metal, surfaces, surf_energies,size=N_atoms, 'fcc',rounding='above', latticeconstant=lc)
    #Reference=wulff_construction(metal, surfaces, surf_energies,size=N_atoms, 'fcc',rounding='above', latticeconstant=lc)

    surf_atoms=[] #This list will contain indeces for each atom that is on a surface of the nanoparticle.
    #Each surface is rotated to the top of the unit cell. The corresponding surface atoms are then the atoms with highest y-position.
    for i in Nanoparticle.get_surfaces():
        Nanoparticle.rotate(i,[0,1,0],center="COU")
        y_max=0
        for j in Nanoparticle:
            if j.position[1]>y_max:
                y_max=j.position[1]
        for j in Nanoparticle:
            if round(j.position[1],2)==round(y_max,2):
                surf_atoms.append(j.index)
        Nanoparticle.rotate([0,1,0],i,center="COU")

    #Now we need to identify the edge atoms. These are the atoms that are part of 2 or more surfaces in the nanoparticle. 
    #Therefore, they will be the atoms that appear more than once in surf_atoms:
    marked=[]
    edge_atoms=[]
    for i in surf_atoms:
        if i in marked:
            edge_atoms.append(i)
        else:
            marked.append(i)
            
    #A subsystem of the bulk is defined. This will be the basis of the DFT calculation. We also define relevant functions to
    #translate between bulk atom coordinates and the subsystem coordinates. 

    def sizesetup(coverage): #Define the function to set up the size of the unit cell.
        invconverage = math.floor(1/coverage)
        for i in range(1,invconverage+1):
            for j in range(1,invconverage+1):
                if j/i**2==coverage:
                    return (i,j)
                    break

    #This function wraps lattice coordinates (i,j) back into the corresponding coordinate in the unit cell.
    def coordreference(i,j,ucx,ucy,direction):
        if direction==1:
            ri = i%ucx
            ry = j%ucy
        if direction==3:
            #If the unit cell is not orthogonal:
            if ucx%2!=0 and ucy%2!=0:
                ri = i%ucx
                ry = j%ucy            

            #If the unit cell is orthogonal:
            else:
                i = i+j/2-(j%ucy)/2 #Moving along j also corresponds to movement along i.
                ri = i%ucx
                ry = j%ucy
        return (ri,ry)


    ss = sizesetup(coverage)
    ucx = ss[0]
    ucy = ss[0]
    height = subsys_height
    n_adsorbates=ss[1]

    #Check if the requirement for orthogonal unit cell is met:
    if ss[0]%2==0:
        orthogonal=True
    else:
        orthogonal=False

    size = [ucx,ucy,height]  #Size of the FCC bulk structure. 
    
    
    #Set up subsystems for the 111 and 100 directions.
    subsys111 = fcc111(symbol=metal, size=size,a=lc, vacuum=None,orthogonal=orthogonal)
    subsys100=fcc100(symbol=metal, size=size,a=lc, vacuum=None, orthogonal=True)

    
    # Give all atoms in top layer a coordinate
    atomorigo = ucx*ucy*(height-1)
    n = ucx*ucy*height
    subsys_coordinates={}
    i = 0
    j = 0
    for q in range(atomorigo,n):    
        if (i==ucx):
            j += 1
            i = 0    
        subsys_coordinates[q] = [i,j,0]
        i += 1

    #Now we have to find a set of basis vectors describing the subsystem surface. 
    if ss[0]>1:
        #For 111:
        v1_111=subsys111[atomorigo+1].position-subsys111[atomorigo].position
        v1_111=np.array([v1_111[0],v1_111[1],0])
        v2_111=subsys111[atomorigo+ss[0]].position-subsys111[atomorigo].position
        v2_111=np.array([v2_111[0],v2_111[1],0])
        #For 100:
        v1_100=subsys100[atomorigo+1].position-subsys100[atomorigo].position
        v1_100=np.array([v1_100[0],v1_100[1],0])
        v2_100=subsys100[atomorigo+ss[0]].position-subsys100[atomorigo].position
        v2_100=np.array([v2_100[0],v2_100[1],0])
    else:
        v1_111=np.array([0,0,0])
        v2_111=np.array([0,0,0])
        v1_100=np.array([0,0,0])
        v2_100=np.array([0,0,0])

        
    #Now we add adsorbates matching the coverage. They are added along the diagonal in the unit cell.
    if site=='OnTop':
        position100=[0,0,0]
        position111=[0,0,0]
    else:
        position100=1/2*v1_100+1/2*v2_100
        position111=1/2*v1_111+[0,1/2*v2_111[1],0]

    zig=True #If zig is false, then the 111 adsorbate won't zag.
    zags=0
    adsorbate_atom_links=[]#This list will link adsorbates to an atom in the surface.
    for i in range(0,n_adsorbates):
        zig = not zig
        if zig and i>1:
            zags=zags+1
        for j in adsorbate:
            j.tag=i
        scale=ss[0]/n_adsorbates
        adsorbate_atom_links.append([i*scale,i*scale])
        pos111=position111+i*scale*v1_111+i*scale*v2_111-zags*v1_111
        pos100=position100+i*scale*v1_100+i*scale*v2_100
        add_adsorbate(subsys111,adsorbate,height=1*lc,position=(pos111[0],pos111[1]),mol_index=0)
        add_adsorbate(subsys100,adsorbate,height=1*lc,position=(pos100[0],pos100[1]),mol_index=0)


    subsys111.set_cell([subsys111.cell[0],subsys111.cell[1],([0.,0.,cell_height])])
    subsys100.set_cell([subsys100.cell[0],subsys100.cell[1],([0.,0.,cell_height])])


    #Create vectors with initial coordinates for each atom. Offsets from these coordinates are found after the DFT is run.
    x111_i=[]
    y111_i=[]
    z111_i=[]
    x100_i=[]
    y100_i=[]
    z100_i=[]
    for i in range(0,n):
        x111_i.append(subsys111[i].position[0])
        y111_i.append(subsys111[i].position[1])
        z111_i.append(subsys111[i].position[2])
        x100_i.append(subsys100[i].position[0])
        y100_i.append(subsys100[i].position[1])
        z100_i.append(subsys100[i].position[2])
        
    
    if relax:
        #A subsystem of the bulk is defined. This will be the basis of the DFT calculation. We also define relevant functions to
        #translate between bulk atom coordinates and the subsystem coordinates. 

        ss = sizesetup(coverage)
        ucx = ss[0]
        ucy = ss[0]
        height = subsys_height
        n_adsorbates=ss[1]

        #Check if the requirement for orthogonal unit cell is met:
        if ss[0]%2==0:
            orthogonal=True
        else:
            orthogonal=False

        size = [ucx,ucy,height]  #Size of the FCC bulk structure. Preferably size_z is odd.
        
        #Redefine subsystem for energy calculations:
        subsys111 = fcc111(symbol=metal, size=size,a=lc, vacuum=None,orthogonal=orthogonal)
        subsys100=fcc100(symbol=metal, size=size,a=lc, vacuum=None, orthogonal=True)

        # Give all atoms in top layer a coordinate
        atomorigo = ucx*ucy*(height-1)
        n = ucx*ucy*height
        subsys_coordinates={}
        i = 0
        j = 0
        for q in range(atomorigo,n):    
            if (i==ucx):
                j += 1
                i = 0    
            subsys_coordinates[q] = [i,j,0]
            i += 1

        # Calculate system energies:   
        energyfile = open('energies-%s-%s.txt' % (str(coverage),"butanethiolate_hollow"), 'w')
        energies = {}
        for i in ['adsorbate', 'subsys111', 'subsys100']:
           system = globals()[i].copy()
           if i=='adsorbate':
               system.center(vacuum=5)
               system.set_pbc((1,1,0))
           else:
               system.set_cell([system.cell[0],system.cell[1],([0.,0.,cell_height])])

           calc = GPAW(mode=PW(E_cut),kpts=kpoints,xc='BEEF-vdW',txt='energy-%s.txt' % i)
           system.set_calculator(calc)

           energy = system.get_potential_energy()
           energies[i] = energy 

        #Now we have to find a set of basis vectors describing the subsystem surface. 
        if ss[0]>1:
            #For 111:
            v1_111=subsys111[atomorigo+1].position-subsys111[atomorigo].position
            v1_111=np.array([v1_111[0],v1_111[1],0])
            v2_111=subsys111[atomorigo+ss[0]].position-subsys111[atomorigo].position
            v2_111=np.array([v2_111[0],v2_111[1],0])
            #For 100:
            v1_100=subsys100[atomorigo+1].position-subsys100[atomorigo].position
            v1_100=np.array([v1_100[0],v1_100[1],0])
            v2_100=subsys100[atomorigo+ss[0]].position-subsys100[atomorigo].position
            v2_100=np.array([v2_100[0],v2_100[1],0])
        else:
            v1_111=np.array([0,0,0])
            v2_111=np.array([0,0,0])
            v1_100=np.array([0,0,0])
            v2_100=np.array([0,0,0])

        #Now we add adsorbates matching the coverage. They are added along the diagonal in the unit cell.
        if site=='OnTop':
            position100=[0,0,0]
            position111=[0,0,0]
        else:
            position100=1/2*v1_100+1/2*v2_100
            position111=1/2*v1_111+[0,1/2*v2_111[1],0]

        zig=True #If zig is false, then the 111 adsorbate won't zag.
        zags=0   #This is the number of zags that have been performed.
        adsorbate_atom_links=[]#This list will link adsorbates to an atom in the surface.
        for i in range(0,n_adsorbates):
            zig = not zig
            if zig and i>1:
                zags=zags+1
            for j in adsorbate:
                j.tag=i
            scale=ss[0]/n_adsorbates
            adsorbate_atom_links.append([i*scale,i*scale])
            #pos111=position111+((i*scale)/2)*v1_111+[0,i*scale*v2_111[1],0]
            pos111=position111+i*scale*v1_111+i*scale*v2_111-zags*v1_111
            pos100=position100+i*scale*v1_100+i*scale*v2_100
            add_adsorbate(subsys111,adsorbate,height=1*lc,position=(pos111[0],pos111[1]),mol_index=0)
            add_adsorbate(subsys100,adsorbate,height=1*lc,position=(pos100[0],pos100[1]),mol_index=0)


        subsys111.set_cell([subsys111.cell[0],subsys111.cell[1],([0.,0.,cell_height])])
        #subsys110.set_cell([subsys110.cell[0],subsys110.cell[1],([0.,0.,cell_height])])
        subsys100.set_cell([subsys100.cell[0],subsys100.cell[1],([0.,0.,cell_height])])


        #Create vectors with initial coordinates for each atom. Offsets from these coordinates are found after the DFT is run.
        x111_i=[]
        y111_i=[]
        z111_i=[]
        x100_i=[]
        y100_i=[]
        z100_i=[]
        for i in range(0,n):
            x111_i.append(subsys111[i].position[0])
            y111_i.append(subsys111[i].position[1])
            z111_i.append(subsys111[i].position[2])
            x100_i.append(subsys100[i].position[0])
            y100_i.append(subsys100[i].position[1])
            z100_i.append(subsys100[i].position[2])

        #The calculator is set.
        calc111 = GPAW(mode=PW(E_cut),kpts=kpoints, xc='BEEF-vdW',txt='calc111.out')
        subsys111.set_calculator(calc111)
        #The bottom layers of the subsystem are masked such that these atoms do not move during QuasiNewton minimization/relaxation.
        mask = [i.tag > unmasked_layers and i.symbol==metal for i in subsys100]
        fixedatoms=FixAtoms(mask=mask)
        subsys111.set_constraint(fixedatoms)
        #The subsystem is relaxed until all forces on atoms are below fmax=0.02. 
        relax = QuasiNewton(subsys111, trajectory='relax111.traj')
        relax.run(fmax=0.02)

        #The calculator is set.
        calc100 = GPAW(mode=PW(E_cut),kpts=kpoints, xc='BEEF-vdW',txt='calc100.out')
        subsys100.set_calculator(calc100)
        #The bottom layer of the subsystem is masked such that these atoms do not move during QuasiNewton minimization/relaxation.
        subsys100.set_constraint(fixedatoms)
        #The subsystem is relaxed until all forces on atoms are below fmax=0.02. 
        relax = QuasiNewton(subsys100, trajectory='relax100.traj')
        relax.run(fmax=0.02)

        ## Calculate new energies
        for i in ['subsys111', 'subsys100']:
           system = globals()[i]
           energy = system.get_potential_energy()
           energies["relax"+i[6:]] = energy
        e_bond = {}
        e_bond['subsys111'] = energies['relax111'] - energies['subsys111'] - n_adsorbates*energies['adsorbate']
        e_bond['subsys100'] = energies['relax100'] - energies['subsys100'] - n_adsorbates*energies['adsorbate']
        print(energies,e_bond, file=energyfile)
        energyfile.close()
        
        ads111=e_bond['subsys111']
        ads100=e_bond['subsys100']
    
    if subsys100_relaxed!=None:
        subsys100=subsys100_relaxed
    
    if subsys111_relaxed!=None:
        subsys111=subsys111_relaxed
    
    #Check if adsorption has occurred. If not, remove adsorbates from corresponding subsystem.
    if ads111>=ads_cutoff:
        subsys111_prov=subsys111.copy()
        subsys111=Atoms()
        for i in subsys111_prov:
            if i.symbol==metal:
                subsys111.append(i)
    
    if ads100>=ads_cutoff:
        subsys100_prov=subsys100.copy()
        subsys100=Atoms()
        for i in subsys100_prov:
            if i.symbol==metal:
                subsys100.append(i)
    
    #Now to find offsets for each atom in the subsystems after DFT:
    x111_offset=[]
    y111_offset=[]
    z111_offset=[]
    x100_offset=[]
    y100_offset=[]
    z100_offset=[]
    for i in range(0,n):
        x111_offset.append(subsys111[i].position[0]-x111_i[i])
        y111_offset.append(subsys111[i].position[1]-y111_i[i])
        z111_offset.append(subsys111[i].position[2]-z111_i[i])
        x100_offset.append(subsys100[i].position[0]-x100_i[i])
        y100_offset.append(subsys100[i].position[1]-y100_i[i])
        z100_offset.append(subsys100[i].position[2]-z100_i[i])

        
    
    
    # Define dictionary of indexed surfaces for use in TEM
    indexed_surfaces= {}

    #Sadly, we now have to do all the rotations again:
    surface_coordinates={} #For convenience this dictionary will contain v1,v2 coordinates for all the surfaces - indexed by their
    #respective origo atom's index.
    for i in Nanoparticle.get_surfaces():
        surface=[] #This list will contain the atoms on the specific surface at the top.
        Nanoparticle.rotate(i,[0,1,0],center="COU")
        y_max=0
        for j in Nanoparticle:
            if j.position[1]>y_max and j.symbol==metal:
                y_max=j.position[1]
        for j in Nanoparticle:
            if round(j.position[1],2)==round(y_max,2) and j.symbol==metal:
                surface.append(j.index)
        #Now surface contains the indeces of atoms of the specific surface that is at the top in this rotation.
        direction=abs(i[0])+abs(i[1])+abs(i[2]) #This number determines the surface direction family - 100, 110, 111.

        #Define a dictionary with all indeces of atoms of surface i
        indexed_surfaces[tuple(i)] = surface

        
        #Find maximum z and x values for the surface:
        x_max=0
        z_max=0
        for k in surface:
            if Nanoparticle[k].position[0]>x_max:
                x_max=Nanoparticle[k].position[0]
            if Nanoparticle[k].position[2]>z_max:
                z_max=Nanoparticle[k].position[2]
        x_min=x_max
        z_min=z_max
        for k in surface:
            if Nanoparticle[k].position[0]<x_min:
                x_min=Nanoparticle[k].position[0]
            if Nanoparticle[k].position[2]<z_min:
                z_min=Nanoparticle[k].position[2]
        bot_row=[] #This will contain the indeces of the bottom (low z) row of atoms.
        #Find the atoms in the bottom row:
        for k in surface:
            if round(Nanoparticle[k].position[2],1)==round(z_min,1):
                bot_row.append(k)
                
        #Find the atom in the corner of the surface:
        corner_atom=bot_row[0]
        for k in bot_row:
            if Nanoparticle[k].position[0]<Nanoparticle[corner_atom].position[0]:
                corner_atom=k
        distance_1=2*lc #The distance between corner_atom and the nearest neighbour is at least smaller than this.

        neighbour_1="d" #placeholder for neighbour 1.
        neighbour_2="d" #placeholder for neighbour 2.

        ## Find the unit cell neighbours to corner_atom.
        v1=[]
        v2=[]
        for k in surface:
            if k!=corner_atom and k in edge_atoms:  #The v1-axis should lie along some edge.
                if np.linalg.norm(Nanoparticle[k].position-Nanoparticle[corner_atom].position)<distance_1:
                    distance_1=np.linalg.norm(Nanoparticle[k].position-Nanoparticle[corner_atom].position)
                    neighbour_1=k

        #Construct the first basis vector for the surface using the first nearest neighbour coordinate.
        v1=Nanoparticle[neighbour_1].position-Nanoparticle[corner_atom].position
        v1[1]=0 #The y-coordinate of the surface basis vector is set to 0. 

        # To find the second neighbour, we have to align the v1 vector with the x-axis:
        Nanoparticle.rotate(v1,[1,0,0],center='COU')
        for k in surface:
            if k!=corner_atom and k!=neighbour_1:
                dist_vector=Nanoparticle[k].position-Nanoparticle[corner_atom].position
                # We require that the angle between dist_vector and v1 is <=90. 
                if math.acos(round(np.dot(dist_vector,v1)/(np.linalg.norm(dist_vector)*np.linalg.norm(v1)),5))<=90:
                    # We check for a dist_vector which corresponds to one of the lattice vectors defined for the subsystem.
                    if direction==1:
                        if round(dist_vector[0],5)==round(v2_100[0],5) and round(dist_vector[2],5)==round(v2_100[1],5):
                            neighbour_2=k
                        if round(dist_vector[0],5)==round(v2_100[0],5) and round(dist_vector[2],5)==-round(v2_100[1],5):
                            neighbour_2=k
                    if direction==3:
                        if round(dist_vector[0],5)==round(v2_111[0],5) and round(dist_vector[2],5)==round(v2_111[1],5):
                            neighbour_2=k
                        if round(dist_vector[0],5)==round(v2_111[0],5) and round(dist_vector[2],5)==-round(v2_111[1],5):
                            neighbour_2=k

        # Rotate the system back after finding the second neighbour.
        Nanoparticle.rotate([1,0,0],v1,center='COU')

        #Construct the second basis vector for the surface using the nearest neighbour coordinate.
        v2=Nanoparticle[neighbour_2].position-Nanoparticle[corner_atom].position

        v2[1]=0 #The y-coordinate of the surface basis vector is set to 0. 

        Transform_matrix=np.linalg.inv(np.array([v1,v2,[0,1,0]]).transpose()) #This transforms x-y-z coordinates to v1-v2-y.
        #Now to find v1,v2-coordinates for all the atoms in the surface and replace them with atoms from DFT subsystem accordingly:

        surface.sort
        for k in surface:
            if k not in edge_atoms:
                flag = False #Flag to determine wether the z-axis was flipped.

                #Find the coordinate of the atom in v1,v2-basis. 
                coordinate=np.round(Transform_matrix.dot(Nanoparticle[k].position-Nanoparticle[corner_atom].position),0)

                #We want the origo of the surface system to be off the surface edge. Therefore, we translate the coordinates:
                coordinate[0]=coordinate[0]-1
                coordinate[1]=coordinate[1]-1

                reference=coordreference(coordinate[0],coordinate[1],ucx,ucy,direction) #This references the matching atom in the subsystem

                #The system is rotated again such that the bottom row of atoms lie along the x-direction.
                Nanoparticle.rotate(v1,[1,0,0],center="COU")
                #Check if v2 is in the positive z-direction. If not, rotate the system 180 degrees:
                if Nanoparticle[neighbour_2].position[2]-Nanoparticle[corner_atom].position[2]<0:
                    Nanoparticle.rotate([0,0,-1],[0,0,1],center='COU')
                    flag = True #Flag is set indicating the system has been flipped.
                for l in subsys_coordinates:
                    if subsys_coordinates[l]==[reference[0],reference[1],0]: #This atom in the subsystem matches the atom in the Nanoparticle surface.
                        if direction==1:
                            #Apply the corresponding offset from the 100 list:
                            Nanoparticle[k].position=Nanoparticle[k].position+[x100_offset[l],z100_offset[l],y100_offset[l]]
                        if direction==3:
                            #Apply the corresponding offset from the 111 list:
                            Nanoparticle[k].position=Nanoparticle[k].position+[x111_offset[l],z111_offset[l],y111_offset[l]]
                if [reference[0],reference[1]] in adsorbate_atom_links: #Checks if the subsystem reference atom is linked to an adsorbate molecule.
                    for u in range(0,len(adsorbate_atom_links)): #Find the linked adsorbate molecule tag (it's the index of adsorbate_atom_links)
                        if adsorbate_atom_links[u] == [reference[0],reference[1]]: #Check if the reference coordinates exists in the list of linked atoms coordinates.
                            adsorbate_tag=u #This is the tag assigned to the adsorbate that is linked to the reference atom.
                    #Calculate the reference atom's index in the subsystem (from the v1/v2-coordinates).
                    tagged_atom_index=int(atomorigo+((adsorbate_atom_links[adsorbate_tag][1])%ucy)*ucx+adsorbate_atom_links[adsorbate_tag][0]%ucx)
                    if direction==1:
                        for m in subsys100:
                            if m.symbol!=metal and m.tag==adsorbate_tag: #Single out the adsorbate with the correct tag.
                                m_old_position=m.position.copy() #Save the adsorbate's original position.
                                m.position=m.position-subsys100[tagged_atom_index].position #Calculate the vector from the reference atom to the adsorbate.
                                #Now calculate and set the position to that which the adsorbate atom should have in the Nanoparticle system:
                                m.position=[m.position[0]+Nanoparticle[k].position[0],m.position[2]+Nanoparticle[k].position[1],m.position[1]+Nanoparticle[k].position[2]]
                                Nanoparticle.append(m) #Finally, add the adsorbate.
                                m.position=m_old_position #Reset the subsystem (set the adsorbate position to it's old, saved value).
                    if direction==3:
                        #Do exactly the same below as for the 100 surface above:
                        for m in subsys111:
                            if m.symbol!=metal and m.tag==adsorbate_tag:
                                m_old_position=m.position.copy()
                                m.position=m.position-subsys111[tagged_atom_index].position
                                m.position=[m.position[0]+Nanoparticle[k].position[0],m.position[2]+Nanoparticle[k].position[1],m.position[1]+Nanoparticle[k].position[2]]
                                Nanoparticle.append(m)
                                m.position=m_old_position


                #Check if the z-axis was flipped. If it was, flip it back:
                if flag:
                    Nanoparticle.rotate([0,0,1],[0,0,-1],center='COU')

                #The system is then rotated back.
                Nanoparticle.rotate([1,0,0],v1,center="COU") #First the x-axis alignment. 

        Nanoparticle.rotate([0,1,0],i,center="COU") #Now rotate the surface back to it's original direction.

        
        
    ## Find the actual coverage of the Nanoparticle:
    ## This procedure is outdated, but it still works. 

    #First we need to count the number of surface atoms (including edges). First we turn surf_atoms into a dictionary and back into
    # a list in order to remove duplicate values (edge atoms should only be counted once):
    surf_atoms = list(dict.fromkeys(surf_atoms))

    #The number of surf atoms is then:
    n_surf_atoms=len(surf_atoms)

    #Now to count the number of adsorbed molecules. First we count the number of non-gold atoms:
    non_gold_atoms=0
    for i in Nanoparticle:
        if i.symbol!=metal:
            non_gold_atoms+=1
    #Then we count the number of atoms in the adsorbate molecules:
    adsorbate_size=len(adsorbate)

    #The number of adsorbed molecules:
    n_adsorbate=non_gold_atoms/adsorbate_size

    #The actual coverage is then:
    actual_coverage=n_adsorbate/n_surf_atoms
    
    
    
    
    Nanoparticle.center(vacuum=4) #Center the nanoparticle for TEM imaging.
    
    return Nanoparticle,indexed_surfaces,subsys111,subsys100 #Depending on what is needed, return the different objects.
Exemplo n.º 24
0
    calc = EMT()

    cu_bulk.set_calculator(calc)

    e = cu_bulk.get_potential_energy()
    energies.append(e)
    volumes.append(cu_bulk.get_volume())

eos = EquationOfState(volumes, energies)
v0, e0, B = eos.fit()
aref = 3.6
vref = bulk("Cu", "fcc", a=aref).get_volume()

copper_lattice_constant = (v0 / vref)**(1 / 3) * aref

slab = fcc100("Cu", a=copper_lattice_constant, size=(2, 2, 3))
ads = molecule("C")
add_adsorbate(slab, ads, 3, offset=(1, 1))
cons = FixAtoms(indices=[atom.index for atom in slab if (atom.tag == 3)])
slab.set_constraint(cons)
slab.center(vacuum=13.0, axis=2)
slab.set_pbc(True)
slab.wrap(pbc=[True] * 3)
slab.set_calculator(copy.copy(parent_calc))
slab.set_initial_magnetic_moments()

images = [slab]

Gs = {
    "default": {
        "G2": {
Exemplo n.º 25
0
def test_fps_memory():
    slab = fcc100("Cu", size=(3, 3, 3))
    ads = molecule("CO")
    add_adsorbate(slab, ads, 4, offset=(1, 1))
    cons = FixAtoms(indices=[
        atom.index for atom in slab if (atom.tag == 2 or atom.tag == 3)
    ])
    slab.set_constraint(cons)
    slab.center(vacuum=13.0, axis=2)
    slab.set_pbc(True)
    slab.wrap(pbc=[True] * 3)
    slab.set_calculator(EMT())

    images = [slab]

    Gs = {}
    Gs["G2_etas"] = [2]
    Gs["G2_rs_s"] = [0]
    Gs["G4_etas"] = [0.005]
    Gs["G4_zetas"] = [1.0]
    Gs["G4_gammas"] = [1.0]
    Gs["cutoff"] = 6.5

    elements = np.array([atom.symbol for atoms in images for atom in atoms])
    _, idx = np.unique(elements, return_index=True)
    elements = list(elements[np.sort(idx)])

    G = make_symmetry_functions(elements=elements,
                                type="G2",
                                etas=Gs["G2_etas"])
    G += make_symmetry_functions(
        elements=elements,
        type="G4",
        etas=Gs["G4_etas"],
        zetas=Gs["G4_zetas"],
        gammas=Gs["G4_gammas"],
    )
    G = {"O": G, "C": G, "Cu": G}

    snn_hashes = new_hash(images, Gs=Gs)
    base = AtomsDataset(images,
                        SNN_Gaussian,
                        Gs,
                        forcetraining=True,
                        label="test",
                        cores=10)

    for idx in range(len(images)):
        s_nn_hash = list(snn_hashes.keys())[idx]
        # SimpleNN
        with open("amp-data-fingerprints.ampdb/loose/" + s_nn_hash, "rb") as f:
            simple_nn = load(f)
        os.system("rm amp-data-fingerprints.ampdb/loose/" + s_nn_hash)

        with open("amp-data-fingerprint-primes.ampdb/loose/" + s_nn_hash,
                  "rb") as f:
            simple_nn_prime = load(f)
        os.system("rm amp-data-fingerprint-primes.ampdb/loose/" + s_nn_hash)

        test = TestDataset(images[idx],
                           base.elements,
                           base.base_descriptor,
                           Gs,
                           base.fprange,
                           'test2',
                           cores=2)
        test_fp = test.fps
        test_prime = test.fp_primes

        key = simple_nn_prime.keys()

        for s, am in zip(simple_nn, test_fp):
            for i, j in zip(s[1], am[1]):
                assert abs(i -
                           j) <= 1e-4, "Fingerprints do not match! %s, %s" % (
                               i, j)
        for idx in key:
            for s, am in zip(simple_nn_prime[idx], test_prime[idx]):
                assert abs(s - am) <= 1e-4, "Fingerprint primes do not match!"
Exemplo n.º 26
0
# creates: o2pt100.png
import numpy as np

from ase.io import write
from ase.build import fcc100, add_adsorbate

# the metal slab
atoms = fcc100('Pt', size=[4, 10, 3], vacuum=10)
transmittances = [0 for a in atoms]
bonded_atoms = []

upper_layer_idx = [a.index for a in atoms if a.tag == 1]
middle = atoms.positions[upper_layer_idx, :2].max(axis=0) / 2

# the dissociating oxygen... fake some dissociation curve
gas_dist = 1.1
max_height = 8.
min_height = 1.
max_dist = 6

# running index for the bonds
index = len(atoms)

for i, x in enumerate(np.linspace(0, 1.5, 6)):
    height = (max_height - min_height) * np.exp(-2 * x) + min_height
    d = np.exp(1.5 * x) / np.exp(1.5**2) * max_dist + gas_dist
    pos = middle + [0, d / 2]
    add_adsorbate(atoms, 'O', height=height, position=pos)
    pos = middle - [0, d / 2]
    add_adsorbate(atoms, 'O', height=height, position=pos)
    transmittances += [x / 2] * 2
Exemplo n.º 27
0
 def opt_fcc100(self) -> None:
     ''' Optimize fcc100 slab '''
     slab = fcc100(self.symbol, self.repeats_surface, self.a, self.vacuum)
     self.prepare_slab_opt(slab)
Exemplo n.º 28
0
def test_thermochemistry():
    """Tests of the major methods (HarmonicThermo, IdealGasThermo,
    CrystalThermo) from the thermochemistry module."""

    # Ideal gas thermo.
    atoms = Atoms('N2', positions=[(0, 0, 0), (0, 0, 1.1)], calculator=EMT())
    QuasiNewton(atoms).run(fmax=0.01)
    energy = atoms.get_potential_energy()
    vib = Vibrations(atoms, name='idealgasthermo-vib')
    vib.run()
    vib_energies = vib.get_energies()

    thermo = IdealGasThermo(vib_energies=vib_energies,
                            geometry='linear',
                            atoms=atoms,
                            symmetrynumber=2,
                            spin=0,
                            potentialenergy=energy)
    thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325.)

    # Harmonic thermo.

    atoms = fcc100('Cu', (2, 2, 2), vacuum=10.)
    atoms.set_calculator(EMT())
    add_adsorbate(atoms, 'Pt', 1.5, 'hollow')
    atoms.set_constraint(
        FixAtoms(indices=[atom.index for atom in atoms
                          if atom.symbol == 'Cu']))
    QuasiNewton(atoms).run(fmax=0.01)
    vib = Vibrations(
        atoms,
        name='harmonicthermo-vib',
        indices=[atom.index for atom in atoms if atom.symbol != 'Cu'])
    vib.run()
    vib.summary()
    vib_energies = vib.get_energies()

    thermo = HarmonicThermo(vib_energies=vib_energies,
                            potentialenergy=atoms.get_potential_energy())
    thermo.get_helmholtz_energy(temperature=298.15)

    # Crystal thermo.
    atoms = bulk('Al', 'fcc', a=4.05)
    calc = EMT()
    atoms.set_calculator(calc)
    energy = atoms.get_potential_energy()

    # Phonon calculator
    N = 7
    ph = Phonons(atoms, calc, supercell=(N, N, N), delta=0.05)
    ph.run()

    ph.read(acoustic=True)
    phonon_energies, phonon_DOS = ph.dos(kpts=(4, 4, 4), npts=30, delta=5e-4)

    thermo = CrystalThermo(phonon_energies=phonon_energies,
                           phonon_DOS=phonon_DOS,
                           potentialenergy=energy,
                           formula_units=4)
    thermo.get_helmholtz_energy(temperature=298.15)

    # Hindered translator / rotor.
    # (Taken directly from the example given in the documentation.)

    vibs = np.array([
        3049.060670, 3040.796863, 3001.661338, 2997.961647, 2866.153162,
        2750.855460, 1436.792655, 1431.413595, 1415.952186, 1395.726300,
        1358.412432, 1335.922737, 1167.009954, 1142.126116, 1013.918680,
        803.400098, 783.026031, 310.448278, 136.112935, 112.939853, 103.926392,
        77.262869, 60.278004, 25.825447
    ])
    vib_energies = vibs / 8065.54429  # Convert to eV from cm^-1.
    trans_barrier_energy = 0.049313  # eV
    rot_barrier_energy = 0.017675  # eV
    sitedensity = 1.5e15  # cm^-2
    rotationalminima = 6
    symmetrynumber = 1
    mass = 30.07  # amu
    inertia = 73.149  # amu Ang^-2

    thermo = HinderedThermo(vib_energies=vib_energies,
                            trans_barrier_energy=trans_barrier_energy,
                            rot_barrier_energy=rot_barrier_energy,
                            sitedensity=sitedensity,
                            rotationalminima=rotationalminima,
                            symmetrynumber=symmetrynumber,
                            mass=mass,
                            inertia=inertia)

    helmholtz = thermo.get_helmholtz_energy(temperature=298.15)
    target = 1.593  # Taken from documentation example.
    assert (helmholtz - target) < 0.001
Exemplo n.º 29
0
from ase.build import fcc100, add_adsorbate
from ase.constraints import FixAtoms
from ase.calculators.emt import EMT
from ase.dimer import DimerControl, MinModeAtoms, MinModeTranslate

# Set up a small "slab" with an adatoms
atoms = fcc100('Pt', size = (2, 2, 1), vacuum = 10.0)
add_adsorbate(atoms, 'Pt', 1.611, 'hollow')

# Freeze the "slab"
mask = [atom.tag > 0 for atom in atoms]
atoms.set_constraint(FixAtoms(mask = mask))

# Calculate using EMT
atoms.set_calculator(EMT())
relaxed_energy = atoms.get_potential_energy()

# Set up the dimer
d_control = DimerControl(initial_eigenmode_method = 'displacement', \
                         displacement_method = 'vector', logfile = None, \
                         mask = [0, 0, 0, 0, 1])
d_atoms = MinModeAtoms(atoms, d_control)

# Displace the atoms
displacement_vector = [[0.0]*3]*5
displacement_vector[-1][1] = -0.1
d_atoms.displace(displacement_vector = displacement_vector)

# Converge to a saddle point
dim_rlx = MinModeTranslate(d_atoms, trajectory = 'dimer_method.traj', \
                           logfile = None)
Exemplo n.º 30
0
# creates: o2pt100.png
import numpy as np

from ase.io import write
from ase.build import fcc100, add_adsorbate

# the metal slab
atoms = fcc100('Pt', size=[4, 10, 3], vacuum=10)
transmittances = [0 for a in atoms]
bonded_atoms = []

upper_layer_idx = [a.index for a in atoms if a.tag == 1]
middle = atoms.positions[upper_layer_idx, :2].max(axis=0) / 2

# the dissociating oxygen... fake some dissociation curve
gas_dist = 1.1
max_height = 8.
min_height = 1.
max_dist = 6

# running index for the bonds
index = len(atoms)

for i, x in enumerate(np.linspace(0, 1.5, 6)):
    height = (max_height - min_height) * np.exp(-2 * x) + min_height
    d = np.exp(1.5 * x) / np.exp(1.5**2) * max_dist + gas_dist
    pos = middle + [0, d / 2]
    add_adsorbate(atoms, 'O', height=height, position=pos)
    pos = middle - [0, d / 2]
    add_adsorbate(atoms, 'O', height=height, position=pos)
    transmittances += [x / 2] * 2
Exemplo n.º 31
0
from ase.build import fcc100, add_adsorbate
from ase.constraints import FixAtoms, FixedPlane
from ase.calculators.emt import EMT
from ase.optimize import QuasiNewton

# 2x2-Al(001) surface with 3 layers and an
# Au atom adsorbed in a hollow site:
slab = fcc100('Al', size=(2, 2, 3))
add_adsorbate(slab, 'Au', 1.7, 'hollow')
slab.center(axis=2, vacuum=4.0)

# Make sure the structure is correct:
#from ase.visualize import view
#view(slab)

# Fix second and third layers:
mask = [atom.tag > 1 for atom in slab]
#print(mask)
fixlayers = FixAtoms(mask=mask)

# Constrain the last atom (Au atom) to move only in the yz-plane:
plane = FixedPlane(-1, (1, 0, 0))

slab.set_constraint([fixlayers, plane])

# Use EMT potential:
slab.set_calculator(EMT())

for i in range(5):
    qn = QuasiNewton(slab, trajectory='mep%d.traj' % i)
    qn.run(fmax=0.05)
Exemplo n.º 32
0
from ase.build import fcc100, add_adsorbate
from ase.constraints import FixAtoms
from ase.calculators.emt import EMT
from ase.optimize import QuasiNewton

# 2x2-Al(001) surface with 3 layers and an
# Au atom adsorbed in a hollow site:
slab = fcc100('Al', size=(2, 2, 3))
add_adsorbate(slab, 'Au', 1.7, 'hollow')
slab.center(axis=2, vacuum=4.0)

# Make sure the structure is correct:
#view(slab)

# Fix second and third layers:
mask = [atom.tag > 1 for atom in slab]
#print(mask)
slab.set_constraint(FixAtoms(mask=mask))

# Use EMT potential:
slab.set_calculator(EMT())

# Initial state:
qn = QuasiNewton(slab, trajectory='initial.traj')
qn.run(fmax=0.05)

# Final state:
slab[-1].x += slab.get_cell()[0, 0] / 2
qn = QuasiNewton(slab, trajectory='final.traj')
qn.run(fmax=0.05)
Exemplo n.º 33
0
                         [5.00000011, 6.30002353, 5.9163716],
                         [5.88571848, 5.0122839, 6.82246859],
                         [5.88625613, 5.01308931, 5.01214155],
                         [7.14329342, 7.18115393, 6.81640316],
                         [7.14551332, 7.17200869, 5.00879027],
                         [8.41609966, 5.00661165, 5.02355167],
                         [8.41971183, 5.0251482, 6.83462168],
                         [9.69568096, 7.18645894, 6.8078633],
                         [9.68914668, 7.16663649, 5.00000011],
                         [10.95518898, 5.02163182, 6.8289018],
                         [11.83752486, 6.29836826, 5.90274952],
                         [10.94464142, 5.00000011, 5.01802495]])
systems.append((atoms, 'Pentane molecule'))

#
slab = fcc100('Cu', size=(2, 2, 2), vacuum=3.5)
add_adsorbate(slab, 'C', 1.5, 'hollow')
mask = [a.tag > 1 for a in slab]
constraint = FixAtoms(mask=mask)
slab.set_constraint(constraint)
systems.append((slab, 'C/Cu(100)'))

#
surfaces = [(1, 0, 0), (1, 1, 0), (1, 1, 1)]
esurf = [0.9151, 0.9771, 0.7953]  # Surface energies
size = 10  # number of atoms
atoms = wulff_construction('Al', surfaces, esurf, size, 'fcc',
                           rounding='above')
atoms.center(vacuum=6)
atoms.rattle(0.2)
systems.append((atoms, 'Alumninum cluster'))
Exemplo n.º 34
0
structure.cell = cell
structure.append(Atom('H', (2.0, 2.0, 2.0)))
species = [['Au', 'Pd'], ['H', 'V']]
sizes = range(1, 5)
correct_count = 1500
count_structures(structure, sizes, species, correct_count, tag)

tag = 'HCP'
structure = bulk('Au', crystalstructure='hcp', a=4.0)
species = ['Au', 'Pd']
sizes = range(1, 6)
correct_count = 984
count_structures(structure, sizes, species, correct_count, tag)

tag = 'Surface'
structure = fcc100('Au', (1, 1, 1), a=4.0, vacuum=2.0)
species = ['Au', 'Pd']
sizes = range(1, 9)
correct_count = 271
count_structures(structure, sizes, species, correct_count, tag)

tag = 'Chain'
structure = bulk('Au', a=4.0)
structure.set_pbc((False, False, True))
species = ['Au', 'Pd']
sizes = range(1, 9)
correct_count = 62
count_structures(structure, sizes, species, correct_count, tag)

tag = 'FCC, concentration restricted'
structure = bulk('Au', crystalstructure='fcc')
Exemplo n.º 35
0
              positions=[(0, 0, 0), (0, 0, 1.1)],
              calculator=EMT())
QuasiNewton(atoms).run(fmax=0.01)
energy = atoms.get_potential_energy()
vib = Vibrations(atoms, name='idealgasthermo-vib')
vib.run()
vib_energies = vib.get_energies()

thermo = IdealGasThermo(vib_energies=vib_energies, geometry='linear',
                        atoms=atoms, symmetrynumber=2, spin=0,
                        potentialenergy=energy)
thermo.get_gibbs_energy(temperature=298.15, pressure=2 * 101325.)

# Harmonic thermo.

atoms = fcc100('Cu', (2, 2, 2), vacuum=10.)
atoms.set_calculator(EMT())
add_adsorbate(atoms, 'Pt', 1.5, 'hollow')
atoms.set_constraint(FixAtoms(indices=[atom.index for atom in atoms
                                       if atom.symbol == 'Cu']))
QuasiNewton(atoms).run(fmax=0.01)
vib = Vibrations(atoms, name='harmonicthermo-vib',
                 indices=[atom.index for atom in atoms
                          if atom.symbol != 'Cu'])
vib.run()
vib.summary()
vib_energies = vib.get_energies()

thermo = HarmonicThermo(vib_energies=vib_energies,
                        potentialenergy=atoms.get_potential_energy())
thermo.get_helmholtz_energy(temperature=298.15)