Exemplo n.º 1
0
def get_ts_guess_1d(reactant, product, bond, name, method, keywords, dr=0.1):
    """Scan the distance between two atoms and return a guess for the TS

    Arguments:
        reactant (autode.complex.ReactantComplex):
        product (autode.complex.ProductComplex):
        bond (autode.pes.ScannedBond):
        name (str): name of reaction
        method (autode.): electronic structure wrapper to use for the calcs
        keywords (autode.keywords.Keywords): keywords to use in the calcs

    Keyword Arguments:
        dr (float): Δr on the surface *absolute value* in angstroms

    Returns:
        (autode.transition_states.ts_guess.TSguess): TS guess
    """
    logger.info(
        f'Getting TS guess from 1D relaxed potential energy scan using '
        f'{bond.atom_indexes} as the active bond')

    # Create a potential energy surface in the active bonds and calculate
    pes = PES1d(reactant=reactant,
                product=product,
                rs=np.arange(
                    bond.curr_dist,
                    bond.final_dist,
                    step=dr if bond.final_dist > bond.curr_dist else -dr),
                r_idxs=bond.atom_indexes)

    pes.calculate(name=name, method=method, keywords=keywords)

    if not pes.products_made():
        logger.error('Products were not made on the whole PES')
        return None

    # Plot the line using matplotlib
    pes.print_plot(name=name, method_name=method.name)

    try:
        # May want to iterate through all saddle points not just the highest(?)
        for species in pes.get_species_saddle_point():
            return get_ts_guess(species=species,
                                reactant=reactant,
                                product=product,
                                name=name)

    except FitFailed:
        logger.error('Could not find saddle point on 1D surface')

    logger.error('No possible TSs found on the 1D surface')
    return None
Exemplo n.º 2
0
def get_ts_guess_neb(reactant, product, method, name='neb', n=10):
    """
    Get a transition state guess using a nudged elastic band calculation. The
    geometry of the reactant is used as the fixed initial point and the final
    product geometry generated by driving a linear path to products, which is
    used as the initial guess for the NEB images

    Arguments:
        reactant (autode.species.Species):
        product (autode.species.Species):
        method (autode.wrappers.base.ElectronicStructureMethod):

    Keyword Arguments:
        name (str):
        n (int): Number of images to use in the NEB

    Returns:
        (autode.transition_states.ts_guess.TSguess) or None:
    """
    assert n is not None
    logger.info('Generating a TS guess using a nudged elastic band')

    neb = CINEB(initial_species=reactant.copy(),
                final_species=product.copy(),
                num=n)

    # Calculate and generate the TS guess, in a unique directory
    try:

        @work_in(name)
        def calculate():
            return neb.calculate(method=method, n_cores=Config.n_cores)

        calculate()

    except ex.CalculationException:
        logger.error('NEB failed - could not calculate')
        return None

    return get_ts_guess(neb.get_species_saddle_point(),
                        reactant,
                        product,
                        name=name)
Exemplo n.º 3
0
def get_ts_adaptive_path(reactant,
                         product,
                         method,
                         fbonds,
                         bbonds,
                         name='adaptive'):
    """
    Generate a TS guess geometry based on an adaptive path along multiple
    breaking and/or forming bonds

    Arguments:
        reactant (autode.species.Species):
        product (autode.species.Species):
        method (autode.wrappers.base.ElectronicStructureMethod):
        fbonds (list(autode.pes.pes.FormingBond)):
        bbonds (list(autode.pes.pes.BreakingBond)):

    Keyword Arguments:
        name (str):

    Returns:
        (autode.transition_states.ts_guess.TSguess | None):
    """

    ts_path = AdaptivePath(init_species=reactant,
                           bonds=pruned_active_bonds(reactant, fbonds, bbonds),
                           method=method,
                           final_species=product)
    ts_path.generate(name=name)

    if not ts_path.contains_peak:
        logger.warning('Adaptive path had no peak')
        return None

    return get_ts_guess(ts_path[ts_path.peak_idx].species,
                        reactant,
                        product,
                        name=name)
Exemplo n.º 4
0
def get_ts_guess_2d(reactant,
                    product,
                    bond1,
                    bond2,
                    name,
                    method,
                    keywords,
                    polynomial_order=3,
                    dr=0.1):
    """Scan the distance between two sets of two atoms and return a guess for
    the TS

    Arguments:
        reactant (autode.complex.ReactantComplex):
        product (autode.complex.ProductComplex):
        bond1 (autode.pes.ScannedBond):
        bond2 (autode.pes.ScannedBond):
        name (str): name of reaction
        method (autode.wrappers.base.ElectronicStructureMethod): electronic
        structure wrapper to use for the calcs
        keywords (autode.keywords.Keywords): keywords_list to use in the calcs

    Keyword Arguments:
        polynomial_order (int): order of polynomial to fit the data to
                                (default: {3})
        dr (float): Δr on the surface *absolute value*

    Returns:
        (autode.transition_states.ts_guess.TSguess)
    """
    logger.info(f'Getting TS guess from 2D relaxed potential energy scan,'
                f' using active bonds {bond1} and {bond2}')

    # Steps of +Δr if the final distance is greater than the current else -Δr.
    # Run at least a 3x3 PES
    n_steps1 = max(int(np.abs((bond1.final_dist - bond1.curr_dist) / dr)), 3)
    n_steps2 = max(int(np.abs((bond2.final_dist - bond2.curr_dist) / dr)), 3)

    if method.name in high_level_method_names:
        logger.warning('Limiting the number of steps to a maximum of 8 so <64 '
                       'high level optimisations have to be done')
        n_steps1 = min(n_steps1, 8)
        n_steps2 = min(n_steps2, 8)

    # Create a potential energy surface in the two active bonds and calculate
    pes = PES2d(reactant=reactant,
                product=product,
                r1s=np.linspace(bond1.curr_dist, bond1.final_dist, n_steps1),
                r1_idxs=bond1.atom_indexes,
                r2s=np.linspace(bond2.curr_dist, bond2.final_dist, n_steps2),
                r2_idxs=bond2.atom_indexes)

    pes.calculate(name=name, method=method, keywords=keywords)

    # Try to fit an analytic 2D PES to the surface and plot using matplotlib
    try:
        pes.fit(polynomial_order=polynomial_order)
    except FitFailed:
        logger.error('PES fit failed')
        return None

    pes.print_plot(name=name)

    if not pes.products_made():
        logger.error('Products were not made on the whole PES')
        return None

    # Get a TSGuess for the lowest energy MEP saddle point on the surface
    species = pes.get_species_saddle_point(name=name,
                                           method=method,
                                           keywords=keywords)

    if species is not None:
        return get_ts_guess(species, reactant, product, name=name)

    logger.error('No possible TSs found on the 2D surface')
    return None
Exemplo n.º 5
0
def get_ts_guess_neb(reactant,
                     product,
                     method,
                     fbonds=None,
                     bbonds=None,
                     name='neb',
                     n=None,
                     generate_final_species=True):
    """
    Get a transition state guess using a nudged elastic band calculation. The
    geometry of the reactant is used as the fixed initial point and the final
    product geometry generated by driving a linear path to products, which is
    used as the initial guess for the NEB images

    Arguments:
        reactant (autode.species.Species):
        product (autode.species.Species):
        method (autode.wrappers.base.ElectronicStructureMethod):

    Keyword Arguments:
        fbonds (list(autode.pes.pes.FormingBond)):
        bbonds (list(autode.pes.pes.BreakingBond)):
        name (str):
        n (int): Number of images to use in the NEB
        generate_final_species (bool):

    Returns:
        (autode.transition_states.ts_guess.TSguess) or None:
    """
    logger.info('Generating a TS guess using a nudged elastic band')

    if generate_final_species and fbonds is not None and bbonds is not None:

        try:
            species_list = get_interpolated(reactant,
                                            fbonds,
                                            bbonds,
                                            max_n=calc_n_images(
                                                fbonds, bbonds),
                                            method=method)
        except ex.AtomsNotFound:
            logger.error('Failed to locate linear path')
            return None

        neb = NEB(species_list=species_list)

    # Otherwise using the reactant and product geometries
    else:
        assert n is not None
        neb = NEB(initial_species=reactant.copy(),
                  final_species=product.copy(),
                  num=n)
        neb.interpolate_geometries()

    # Calculate and generate the TS guess
    try:
        neb.calculate(method=method, n_cores=Config.n_cores)

    except ex.CouldNotGetProperty:
        logger.error('NEB failed')
        return None

    # Yield all peaks?
    for peak_species in neb.get_species_saddle_point():
        logger.info('Found peak in optimised NEB - using as TS guess')
        return get_ts_guess(peak_species, reactant, product, name=name)

    logger.warning('NEB did not generate a saddle point')
    return None