os.makedirs(save_dir)
        print(f'Made directory at {save_dir}')
    with open(
            save_dir +
            f'/eps_{epsilon:.3f}_delta_{delta:.3f}_results'.replace('.', '_') +
            '.pickle', 'wb') as handle:
        pickle.dump(experiment_results, handle)
    print(
        f'\nSaved Results at {save_dir}/eps_{epsilon:.3f}_delta_{delta:.3f}_results\n'
        .replace('.', '_') + '.pickle')


last_success_block = 0

# Setting up diffeqpy solver
prob = de.SDEProblem(numba_f, numba_g, ic, tspan, p)

####################################
### Running Experiment
####################################

experiment_header([epsilon, delta])
start = tm.time()

for i in range(number_of_searches):  # Looped Search for Transitions

    print(f'Solving for {prob.tspan}\n')

    # Integrate only saving T variable
    sol = de.solve(prob,
                   de.EM(),

# cold_file = '/Users/cfn18/Documents/PhD-Work/Third-Year/Instanton-Work/L96-EBM-Instanton/Deterministic-Model/Attractor-Data/k50_symmetric/Cold-State/1.nc'
# hot_file = '/Users/cfn18/Documents/PhD-Work/Third-Year/Instanton-Work/L96-EBM-Instanton/Deterministic-Model/Attractor-Data/k50_symmetric/Hot-State/1.nc'

cold_file = '/rds/general/user/cfn18/home/Instantons/L96-EBM-Instanton/Boundary-Conditions/Data/K_50_Symmetric/cold1.nc'

hot_file = '/rds/general/user/cfn18/home/Instantons/L96-EBM-Instanton/Boundary-Conditions/Data/K_50_Symmetric/hot1.nc'

if start_cold:
    ic = get_random_point(cold_file)
else:
    ic = get_random_point(hot_file)

# Setting up SDEProblem Object
prob = de.SDEProblem(numba_f, numba_g, ic, tspan, p, saveat=time_points)


# Callbacks determine when we end integrations
def entered_hot_condition(u, t, integrator):
    return np.any(np.array(u).flatten() > 295)


def entered_cold_condition(u, t, integrator):
    return np.any(np.array(u)[K].flatten() < 258)


if start_cold:
    entry_cb = de.DiscreteCallback(entered_hot_condition, de.terminate_b)
else:
    entry_cb = de.DiscreteCallback(entered_cold_condition, de.terminate_b)
예제 #3
0
def run_l96_ebm_multiplicative(p,
                               u0,
                               block_length,
                               number_of_blocks,
                               sd=None,
                               dt=0.1):
    """
    Use diffeqpy solver to stochastically integrate the L96 EBM Equations w multiplicative noise.

    Arguments
    ------------
    p, list:
        Parameters for the model run.

    ic, np array:
        The intial condition for the model run.

    block_length, int:
        How often model output is saved.

    number_of_blocks, int:
        How many times we save model output.
        Note no. of obs = (blocklength * number of blocks)/dt

    sd, string:
        Where model output is saved.

    dt, float:
        Time between model observations.
        Note integrator uses adaptive timestepper that may be smaller.
    """

    # Setting up diffeqpy solver
    t = 0.
    tspan = (0., block_length)
    prob = de.SDEProblem(numba_f, numba_g, u0, tspan, p)

    # Creating Observer Object to do saving
    looker = SolutionObserver(prob.p)

    # Loop with intermitment saves
    for i in range(number_of_blocks):
        print(f'Solving for {prob.tspan}\n')

        # Integrate
        sol = de.solve(prob, de.SRIW1(), reltol=1e-3, abstol=1e-3, saveat=dt)
        looker.look(sol)

        # Save Observations
        if sd is not None:
            looker.dump(sd)

        # Update Step
        t += block_length
        prob = de.remake(prob, u0=sol.u[-1], tspan=(t, t + block_length))

    # Output results if no save directory
    if sd is None:
        return looker.observations
    else:
        return
def run_experiment(S=10, epsilon=5, delta=1, cold=True):
    """
    S, float - reduced solar constant.
    epsilon, float - noise strength.
    cold, boolean - whether we start on cold attractor or not.
    """

    ####################################
    ### Fixed Experiment Settings
    ####################################

    # Time Set Up
    end_time = 1000.  # Length of integration where we look for a transitions
    dt = 1.0  # How often output is saved, since we're not saving integrations it can be coarse
    number_of_searches = int(1.e4)  # How many integration runs we do
    tspan = (0., end_time)
    max_iters = 1.e20

    # Fixed L96 EBM Parameters
    K = 50
    a0 = 0.5
    a1 = 0.4
    sigma = 1 / 180**4
    F = 8.
    Tref = 270.
    delT = 60.
    alpha = 2.
    beta = 1.

    p = np.array(
        [K, S, a0, a1, sigma, F, Tref, delT, alpha, beta, epsilon, delta])

    # Initialising Dictionary to Store Experiment Results
    global experiment_results
    global cpu_time
    global integration_time
    experiment_results = {
        'epsilon': epsilon,
        'delta': delta,
        'S': S,
        'cpu_times(s)': [],
        'integration_times': [],
        'number_of_transitions': 0,
        'parameters': p
    }

    # Setting IC & Callbacks, File locations will need updating for cluster run
    if cold:
        ic = get_random_cold_point(S=S)
        cb_condition = get_entered_hot_condition(S, K)
        cb = de.DiscreteCallback(cb_condition, de.terminate_b)
    else:
        ic = get_random_hot_point(S=S)
        cb_condition = get_entered_cold_condition(S, K)
        cb = de.DiscreteCallback(cb_condition, de.terminate_b)

    # Setting up diffeqpy solver
    prob = de.SDEProblem(numba_f, numba_multiplicative_g, ic, tspan, p)

    ####################################
    ### Looped Search for Transitions
    ####################################

    experiment_header(epsilon, delta, S, cold)
    start = tm.time()  # CPU Clock begins
    last_successful_block = -1

    for i in range(number_of_searches):
        print()
        print(
            f'Search number {i + 1}/{number_of_searches}. Solving for {prob.tspan}.\n'
        )

        # Integrate only saving T variable
        sol = de.solve(prob,
                       de.SOSRI(),
                       saveat=dt,
                       callback=cb,
                       maxiters=max_iters)

        # If we find a transition, save the result & reset experiment
        if sol.retcode == 'Terminated':
            print(
                f'Found transition in search number {i + 1}. Saving Results.\n'
            )

            # CPU Time Since Last Success
            end = tm.time()
            cpu_time = end - start

            # Integration Time Since Last Success
            completed_blocks_since_last_success = i - (last_successful_block +
                                                       1)
            block_length = end_time
            integration_time_in_this_block = sol.t[-1]
            integration_time = completed_blocks_since_last_success * block_length + integration_time_in_this_block
            update_results()
            save_results(pd=experiment_results_pd,
                         S=S,
                         epsilon=epsilon,
                         cold=cold,
                         delta=delta)

            # Check if we have found enough samples and can stop
            if experiment_results['number_of_transitions'] == 100:
                print(f'Found 100 transitions - will quit.')
                quit()

            # Reset Experiment
            start = tm.time()
            last_successful_block = i
            if cold:
                ic = get_random_cold_point(S=S)
            else:
                ic = get_random_hot_point(S=S)
            prob = de.remake(prob, u0=ic, tspan=tspan)

        # If we don't find a transition, remake the problem
        else:
            print(f'Exited due to {sol.retcode}\n')
            prob = de.remake(prob, u0=sol.u[-1], tspan=(0, end_time))
    return
    def __init__(self,
                 p,
                 ic,
                 transition_cb,
                 sd,
                 block_length=1000,
                 number_of_blocks=10000,
                 dt=1,
                 transition_limit=100):
        """
        ---------------
        Inputs
        ---------------
        p, np.array
            Parameters for the L96-EBM model.
            np.array([K, S, a0, a1, sigma, F, Tref, delT, alpha, beta, epsilon, delta])

        ic, np.array
            Initial condition for stochastic simulation

        transition_cb, callback function
            Callback used to terminate integration in case of transition.
            See: https://diffeq.sciml.ai/stable/features/callback_functions/.

        sd, string
            Directory where results are saved.

        block_length, int
            Length of blocks in which we look for transitions.
            Note if no transition is found in a block we throw it away.

        number_of_blocks, int
            How many blocks we look for transition in.
            Total integration =  number_of_blocks * block_length

        dt, float
            How often we save output from the integration.

        transition_limit, int
            Limit the number of transitions we are looking for

        ---------------
        Outputs
        ---------------
        residence_times, dictionary
            Contains information of residence times for all the transitions we find.

        transition_paths, xarray
            Integration block featuring transition.
            Residence time and run parameters will be saved in attrs

        """

        # Unpacking User Experiment Settings
        self.p = p
        self.epsilon = self.p[-2]
        self.ic = ic
        self.transition_cb = transition_cb
        self.sd = sd
        self.transition_limit = transition_limit
        self.block_length = block_length  # Length of integration where we look for a transitions
        self.dt = dt  # How often output is saved
        self.number_of_blocks = number_of_blocks  # How many blocks we run

        # Time Set Up
        self.tspan = (0., self.block_length)
        self.max_iters = 1.e20
        self.current_block = 0
        self.last_successful_block = -1

        #Initialising Timing Results Dictionary
        self.experiment_time_results = {
            'cpu_times(s)': [],
            'residence_times': [],
            'number_of_transitions': 0,
            'parameters': self.p
        }

        # Setting up diffeqpy problem
        self.prob = de.SDEProblem(numba_f, numba_additive_g, self.ic,
                                  self.tspan, self.p)
        self.experiment_header()

        # Setting up looker object for paths
        self.looker = SolutionObserver(self.p)

        # Setting up directories
        self.path_sd = self.sd + '/Transition-Paths/'
        if not os.path.exists(self.path_sd):
            os.makedirs(self.path_sd)
            print(f'Made directory at {self.path_sd}')

        self.timing_file = self.sd + f'residence_times'.replace(
            '.', '_') + '.pickle'
        return