Ejemplo n.º 1
0
def test_neb_methods(method, optimizer, precon, optmethod, ref_vacancy,
                     setup_images):
    # unpack the reference result
    Ef_ref, dE_ref, saddle_ref = ref_vacancy

    # now relax the MEP for comparison
    images, _, _ = setup_images

    fmax_history = []

    def save_fmax_history(mep):
        fmax_history.append(mep.get_residual())

    k = 0.1
    if precon == 'Exp':
        k = 0.01
    mep = NEB(images, k=k, method=method, precon=precon)

    if optmethod is not None:
        opt = optimizer(mep, method=optmethod)
    else:
        opt = optimizer(mep)
    opt.attach(save_fmax_history, 1, mep)
    opt.run(fmax=1e-2)

    nebtools = NEBTools(images)
    Ef, dE = nebtools.get_barrier(fit=False)
    print(f'{method},{optimizer.__name__},{precon} '
          f'=> Ef = {Ef:.3f}, dE = {dE:.3f}')

    forcefit = fit_images(images)

    output_dir = os.path.dirname(__file__)
    with open(
            f'{output_dir}/MEP_{method}_{optimizer.__name__}_{optmethod}'
            f'_{precon}.json', 'w') as f:
        json.dump(
            {
                'fmax_history': fmax_history,
                'method': method,
                'optmethod': optmethod,
                'precon': precon,
                'optimizer': optimizer.__name__,
                'path': forcefit.path,
                'energies': forcefit.energies.tolist(),
                'fit_path': forcefit.fit_path.tolist(),
                'fit_energies': forcefit.fit_energies.tolist(),
                'lines': np.array(forcefit.lines).tolist(),
                'Ef': Ef,
                'dE': dE
            }, f)

    centre = 2  # we have 5 images total, so central image has index 2
    vdiff, _ = find_mic(images[centre].positions - saddle_ref.positions,
                        images[centre].cell)
    print(f'Ef error {Ef - Ef_ref} dE error {dE - dE_ref} '
          f'position error at saddle {abs(vdiff).max()}')
    assert abs(Ef - Ef_ref) < 1e-2
    assert abs(dE - dE_ref) < 1e-2
    assert abs(vdiff).max() < 1e-2
Ejemplo n.º 2
0
def rms_distance(imageA, imageB):
    from numpy import sqrt
    from ase.geometry.geometry import find_mic
    D = imageB.positions - imageA.positions  # 2d arrays
    D_min, D_min_len = find_mic(D, imageB.cell)
    distance = sqrt((D_min**2).sum())
    return distance
Ejemplo n.º 3
0
def interpolate_images(image_list,
                       num_new_images,
                       kind='linear',
                       use_image_distance_in_spline=False):
    ''' This function interpolates a list of ASE "Atoms" to a new list of images'''
    nimages = len(image_list)
    natoms = atoms.positions.shape[0]

    if nimages == 2:
        print('Only 2 images, kind will be linear')
        kind = 'linear'
    elif nimages < 2:
        print('YOU NEED AT LEAST 2 IMAGES FOR INTERPOLATION!')

    from ase.geometry.geometry import find_mic
    from numpy import zeros, linspace, sqrt
    from scipy.interpolate import interp1d

    ####################
    distance_seq = zeros(nimages)
    position_collection = zeros((natoms, 3, nimages))
    image_index = 0  # for the first image, we don't need distances, just the orginal positions
    for atom_index in range(0, natoms):
        for dim_index in range(3):
            position_collection[
                atom_index, dim_index,
                image_index] = image_list[image_index].positions[atom_index,
                                                                 dim_index]

    for image_index in range(1, nimages):
        D = image_list[image_index].positions - image_list[image_index -
                                                           1].positions
        D_min, D_min_len = find_mic(D, cell=image_list[image_index].get_cell())
        # D_min is list of minimum image vectors
        distance = sqrt((D_min**2).sum())
        distance_seq[image_index] = distance_seq[image_index - 1] + distance
        for atom_index in range(0, natoms):
            for dim_index in range(3):
                position_collection[atom_index, dim_index, image_index] = \
                 position_collection[atom_index, dim_index, image_index-1] + D_min[atom_index][dim_index]

    seq = linspace(0, 1, nimages)
    # splines have a coordinate output and input that is image number scaled from 0 to 1.
    # we could try using the RMS distance/Frobenius distance/L2 norm along the path then scale it:
    if use_image_distance_in_spline:
        seq = distance_seq / distance_seq.max()

    # builds a spline for every atom's x,y,z coordinates
    spline_func_collection = []
    for atom_index in range(0, natoms):
        spline_func_collection.append([])
        for dim_index in range(3):
            func = interp1d(seq,
                            position_collection[atom_index, dim_index],
                            kind=kind)
            spline_func_collection[atom_index].append(func)

    ################
    mag_collection = zeros((natoms, nimages))
    for image_index in range(0, nimages):
        mag_mom = image_list[image_index].get_initial_magnetic_moments()
        #print(mag_mom)
        for atom_index in range(0, natoms):
            mag_collection[atom_index, image_index] = mag_mom[atom_index]

    #print(mag_collection)
    mag_spline_func_collection = []
    for atom_index in range(0, natoms):
        func = interp1d(seq, mag_collection[atom_index], kind=kind)
        mag_spline_func_collection.append(func)

    #############################
    from copy import deepcopy

    new_image_list = []
    new_seq = linspace(0, 1, num_new_images)
    new_mag_mom = zeros(natoms)
    for new_image_index in range(0, num_new_images):

        new_image = deepcopy(image_list[0])
        # I'm initializing new 'Atoms' objects with deepcopy, there must be a better
        # way which will also handle lattice vector changes
        pos = new_seq[new_image_index]

        for atom_index in range(0, natoms):
            for dim_index in range(3):
                new_image.positions[atom_index,
                                    dim_index] = spline_func_collection[
                                        atom_index][dim_index](pos)

        for atom_index in range(0, natoms):
            new_mag_mom[atom_index] = mag_spline_func_collection[atom_index](
                pos)
        new_image.set_initial_magnetic_moments(new_mag_mom)
        new_image_list.append(new_image)

    return new_image_list