def iterate_runs(V, initial_aerosols, T, P, dt=0.01, dt_iters=2, max_steps=500): """ Iterate through several different strategies for integrating the parcel model. """ aerosols = initial_aerosols if V <= 0: return 0., 0., 0. ## Check that there are actually aerosols to deal with aerosol_N = [a.distribution.N for a in initial_aerosols] if len(aerosol_N) == 1: if aerosol_N[0] < 0.01: return (-9999., -9999., -9999.) else: new_aerosols = [] for i in xrange(len(aerosol_N)): if aerosol_N[i] > 0.01: new_aerosols.append(initial_aerosols[i]) aerosols = new_aerosols[:] S_max_arg, _ = arg2000(V, T, P, aerosols) S_max_fn, _ = fn2005(V, T, P, aerosols) dt_orig = dt*1. finished = False S_max = None ## Strategy 1: Try CVODE with modest tolerances. print " Trying CVODE with default tolerance" S_max = run_model(V, aerosols, T, P, dt, max_steps=2000, solver='cvode') ## Strategy 2: Iterate over some increasingly relaxed tolerances for LSODA. if not S_max: while dt > dt_orig/(2**dt_iters): print " Trying LSODA, dt = %1.3e, max_steps = %d" % (dt, max_steps) S_max = run_model(V, aerosols, T, P, dt, max_steps, solver='lsoda') if not S_max: dt = dt/2. print " Retrying..." else: finished = True break ## Strategy 3: Last ditch numerical integration with LSODE. This will likely take a ## a very long time. if not finished and not S_max: print " Trying LSODE" S_max = run_model(V, aerosols, T, P, dt_orig, max_steps=1000, solver='lsode') ## Strategy 4: If all else fails return -9999. if not S_max: S_max = -9999. print " failed", V, dt return S_max, S_max_arg, S_max_fn
from lognorm import Lognorm from parcel import AerosolSpecies from pce_params import pce_deg1, pce_deg2, pce_deg3, pce_deg4 from activation import arg2000, fn2005 P0 = 80000. # Pressure, Pa T0 = 283.15 # Temperature, K S0 = -0.00 # Supersaturation. 1-RH from wv term V = 0.7076312079 # m/s aerosol1 = AerosolSpecies('(NH4)2SO4', Lognorm(mu=0.02494149518, sigma=1.301854178, N=2299.298741 ), bins=200, kappa=0.4983795899) pce1_Smax, pce1_ratio = pce_deg1(V, T0, P0, aerosol1) pce2_Smax, pce2_ratio = pce_deg2(V, T0, P0, aerosol1) pce3_Smax, pce3_ratio = pce_deg3(V, T0, P0, aerosol1) pce4_Smax, pce4_ratio = pce_deg4(V, T0, P0, aerosol1) ghan_Smax, ghan_ratio = arg2000(V, T0, P0, [aerosol1, ]) nenes_Smax, nenes_ratio = fn2005(V, T0, P0, [aerosol1, ])
def iterate_runs(V, initial_aerosols, T, P, S0=-0.0, dt=0.01, dt_iters=2, t_end=500., max_steps=500, output='smax', fail_easy=True): """ Iterate through several different strategies for integrating the parcel model. As long as `fail_easy` is set to `False`, the strategies this method implements are: 1. **CVODE** with a 10 second time limit and 2000 step limit. 2. **LSODA** with up to `dt_iters` iterations, where the timestep `dt` is halved each time. 3. **LSODE** with coarse tolerance and the original timestep. If these strategies all fail, the model will print a statement indicating such and return either -9999 if `output` was 'smax', or an empty array or DataFrame accordingly. Parameters ---------- V, T, P : float Updraft speed and parcel initial temperature and pressure. S0 : float, optional, default 0.0 Initial supersaturation, as a percent. Defaults to 100% relative humidity. initial_aerosols : array_like of :class:`AerosolSpecies` Set of aerosol populations contained in the parcel. dt : float Solver timestep, in seconds. dt_iters : int, optional, default 2 Number of times to halve `dt` when attempting **LSODA** solver. max_steps : int, optional, default 1000 Maximum number of steps per solver iteration. Defaults to 1000; setting excessively high could produce extremely long computation times. t_end : float, optional, default 500.0 Model time in seconds after which the integration will stop. solver : string, optional, default 'lsoda' Alias of which solver to use; see :class:`Integrator` for all options. output : string, optional, default 'smax' Alias indicating which output format to use; see :class:`ParcelModel` for all options. fail_easy : boolean, optional, default `True` If `True`, then stop after the first strategy (**CVODE**) Returns ------- Smax : (user-defined) Output from parcel model simulation based on user-specified `output` argument. See :class:`ParcelModel` for details. """ aerosols = initial_aerosols if V <= 0: return 0., 0., 0. ## Check that there are actually aerosols to deal with aerosol_N = [a.distribution.N for a in initial_aerosols] if len(aerosol_N) == 1: if aerosol_N[0] < 0.01: return (-9999., -9999., -9999.) else: new_aerosols = [] for i in xrange(len(aerosol_N)): if aerosol_N[i] > 0.01: new_aerosols.append(initial_aerosols[i]) aerosols = new_aerosols[:] S_max_arg, _, _ = arg2000(V, T, P, aerosols) S_max_fn, _, _ = mbn2014(V, T, P, aerosols) dt_orig = dt*1. finished = False S_max = None ## Strategy 1: Try CVODE with modest tolerances. print " Trying CVODE with default tolerance" S_max = run_model(V, aerosols, T, P, dt, S0=S0, max_steps=2000, solver='cvode', t_end=t_end, output=output, solver_args={'iter': 'Newton', 'time_limit': 10.0, 'linear_solver': "DENSE"}) ## Strategy 2: Iterate over some increasingly relaxed tolerances for LSODA. if not S_max and not fail_easy: while dt > dt_orig/(2**dt_iters): print " Trying LSODA, dt = %1.3e, max_steps = %d" % (dt, max_steps) S_max = run_model(V, aerosols, T, P, dt, S0, max_steps, solver='lsoda', t_end=t_end) if not S_max: dt /= 2. print " Retrying..." else: finished = True break ## Strategy 3: Last ditch numerical integration with LSODE. This will likely take a ## a very long time. if not finished and not S_max and not fail_easy: print " Trying LSODE" S_max = run_model(V, aerosols, T, P, dt_orig, max_steps=1000, solver='lsode', t_end=t_end, S0=S0) ## Strategy 4: If all else fails return -9999. if not S_max: if output == "smax": S_max = -9999. elif output == "arrays": S_max = empty([0]), empty([0]) elif output == "dataframes": S_max = DataFrame(data={"S": [nan]}), DataFrame(data={"aerosol1": [nan]}) else: S_max = nan print " failed", V, dt return S_max, S_max_arg, S_max_fn