Source code for ENSO.Oscillator

''' Conceptual model for ENSO.  This is a rewrite of a Fortran program used in
`Choi et al (2013) <http://dx.doi.org/10.1175/JCLI-D-13-00045.1>`_.

The main function is :py:func:`oscillator` which is a generator that yields ENSO
SST anomalies indefinitely after being initialised.

'''
import sys as _sys
import numpy


[docs]def wind(temp,gam,r, warmseasonal=None,coldseasonal=None,mon=1): ''' Compute the zonal wind anomaly given an SST anomaly Assume a piecewise linear relationship between the zonal wind stress anomaly and the SST anomaly (see `Choi et al (2013) <http://dx.doi.org/10.1175/JCLI-D-13-00045.1>`_.) Args: temp (number): temperature anomaly gam (number): mean regression coefficient between wind stress and temperature anomalies (i.e. gamma in Eq.2 of `Choi et al (2013) <http://dx.doi.org/10.1175/JCLI-D-13-00045.1>`_.) r (number): nonlinearity, greater than -1. and less than 1. Zero means no nonlinearity. Positive values mean a stronger air-sea coupling coefficient during warm condition than during cold condition warmseasonal (scalar or a numpy array of numbers): for varying coupling coefficient in different calendar month for the warm condition. The value is to be multiplied to the wind anomaly. Length = 12 (Jan, Feb,...). Default is 1 (i.e. no seasonality) coldseasonal (scalar or a numpy array of numbers): similar to warmseasonal, but for cold condition. mon (int): calendar month (1-12). Only meaningful when warmseasonal or coldseasonal is not 1. ''' if warmseasonal is None: warmseasonal = numpy.ones(12) if coldseasonal is None: coldseasonal = numpy.ones(12) assert len(warmseasonal) == 12 assert len(coldseasonal) == 12 if temp>0.: u = warmseasonal[mon-1]*(gam+r)*temp else: u = coldseasonal[mon-1]*(gam-r)*temp return u
[docs]def dT_func(h,T,a,b,e): ''' dT = a*h-b*T-e*(T^3.) Args: a (positivie number): regression coefficient between SST anomaly growth rate and thermocline depth anomaly b (positive number): surface damping time scale (in /month) e (positive number): cubic damping rate (i.e. :math:`\epsilon` in Eq.1 of Choi et al. 2013) Returns: numeric : dT (K/month) ''' return a*h-b*T-e*numpy.power(T,3.)
[docs]def oscillator(tstep,a,b,c,d,e,gam,r, lag_long,lag_short, T0,h0,noise_generator,noise_update_freq=0.2, warmseasonal=None,coldseasonal=None): ''' Generator for simulating ENSO SST anomaly under a conceptual framework and a nonlinear air-sea coupling coefficient. (see `Choi et al. (2013) <http://dx.doi.org/10.1175/JCLI-D-13-00045.1>`_) Args: tstep (number): time step size (in month) a (positivie number): regression coefficient between SST anomaly growth rate and thermocline depth anomaly, as in :py:func:`dT_func` b (positive number): surface damping time scale (in /month), as in :py:func:`dT_func` c (positive number): regression coefficient between SST anomaly growth rate and the zonal wind stress anomaly with a time lag characterised by the positive feedbacks (i.e. :math:`c'` in Eq.1 of Choi et al. 2013) d (positive number): negative of the regression coefficient between SST anomaly growth rate and the zonal wind stress anomaly with a time lag characterised by the negative feedbacks (i.e. :math:`d'` in Eq.1 of Choi et al. 2013) e (positive number): cubic damping rate (i.e. :math:`\epsilon` in Eq.1 of Choi et al. 2013) gam (number): mean regression coefficient between wind stress and temperature anomalies (i.e. gamma in Eq.2 of `Choi et al (2013) <http://dx.doi.org/10.1175/JCLI-D-13-00045.1>`_.) r (number): nonlinearity, greater than -1. and less than 1. Zero means no nonlinearity. Positive values mean a stronger air-sea coupling coefficient during warm condition than during cold condition lag_long (number): time lag for the negative feedback to arrive (in month) lag_short (number): time lag for the positive feedback to arrive (in month) T0 (number): Initial SST anomaly h0 (number): Initial thermocline depth anomaly noise_generator (generator): to be added to the zonal wind stress anomaly noise_update_freq (number): how frequently the noise is updated (in month) warmseasonal (scalar or an array): see :py:func:`wind` coldseasonal (scalar or an array): see :py:func:`wind` Yields: T (number): SST anomaly at the current time step ''' istep = 0 nlag_long = int(lag_long/tstep) nlag_short = int(lag_short/tstep) T = T0 h_slow = [h0,]*nlag_long h_fast = [h0,]*nlag_short while True: h_now = h_slow.pop() + h_fast.pop() dT = dT_func(h=h_now,T=T,a=a,b=b,e=e) yield T T += dT*tstep mon = int(istep*tstep % 12) + 1 if istep % int(noise_update_freq/tstep) == 0: noise = noise_generator() u = wind(temp=T,gam=gam,r=r, warmseasonal=warmseasonal, coldseasonal=coldseasonal, mon=mon) + noise h_fast.insert(0,c*u) h_slow.insert(0,d*u*-1.) istep += 1
[docs]def wave_speeds(drho,hbar,verbose=False,fout=None): ''' Calculate the Kelvin and Rossby wave speed Args: drho (number): approximate density ratio between the surface mixed layer and the deeper ocean (less than 1.) hbar (number): mean thickness of the surface mixed layer verbose (bool) fout (File Object): if None, default is :py:data:`sys.stdout` Returns: (number, number): Kelvin wave speed, Rossby wave speed, in m/s ''' if fout is None: fout = _sys.stdout g = 9.8 ck = numpy.sqrt(g*drho*hbar) cr = ck/3. if verbose: fout.write("Speed of Kelvin wave [m/s]:"+str(ck)+"\n") fout.write("Speed of Rossby wave [m/s]:"+str(cr)+"\n") fout.flush() return ck,cr
[docs]def lag_time(ck,cr,x_W,x_E,x_force): ''' Compute the lag times for (1) Kelvin waves and (2) Rossby waves + reflected Kelvin waves to reach the eastern boundary. i.e. the difference of the two is the time lag between positive feedbacks and negative feedbacks of ENSO Args: ck (number): Kelvin wave speed in m/s cr (number): Gravest Rossby wave speed in m/s x_W (number): Longitude of western boundary (in degree) x_E (number): Longitude of eastern boundary (in degree) x_force (number): Longitude of the wind forcing Returns: (number, number): lag time for positive feedbacks, lag time for negative feedbacks (units: month) ''' lag_short = (x_W - x_force)*1100./ck/864./30. lag_long = (x_force - x_W)*1100./cr/864./30.+(x_E-x_W)*1100./ck/864./30. return lag_short,lag_long
Fork me on GitHub