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)
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