climSIRS

Seceptible-Infectious-Recovered-Sceptible (SIRS) model coupled to climate.

The old problematic MERRA2 weekly clim data

/tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/merra_weekly_clim.nc

is replaced by the updated one

/tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/INDIVIDUAL_YEARS/MERRA_DATA/merra_weekly_climo.nc.

In [18]:
!ncdump -h /tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/merra_weekly_clim.nc
netcdf merra_weekly_clim {
dimensions:
	LON = 576 ;
	LAT = 361 ;
	TT = UNLIMITED ; // (52 currently)
variables:
	double LON(LON) ;
		LON:long_name = "longitude" ;
		LON:units = "degrees_east" ;
		LON:axis = "X" ;
		LON:modulo = 360. ;
		LON:point_spacing = "even" ;
		LON:standard_name = "longitude" ;
	double LAT(LAT) ;
		LAT:long_name = "latitude" ;
		LAT:units = "degrees_north" ;
		LAT:axis = "Y" ;
		LAT:point_spacing = "even" ;
		LAT:standard_name = "latitude" ;
	double TT(TT) ;
		TT:units = "day since 1901-01-15 00:00:00" ;
		TT:axis = "T" ;
		TT:modulo = " " ;
		TT:time_origin = "15-JAN-1901" ;
		TT:standard_name = "time" ;
	double WEEK_QV2M(TT, LAT, LON) ;
		WEEK_QV2M:missing_value = -1.e+34 ;
		WEEK_QV2M:_FillValue = -1.e+34 ;
		WEEK_QV2M:long_name = "Weekly-mean 2-meter specific humidity from MERRA2" ;
		WEEK_QV2M:units = "kg/kg" ;
		WEEK_QV2M:history = "From /tigress/samueltb/MERRA2/Daily/merged/QV2M/MERRA2.tavg1_2d_slv_Nx.198001-201808.nc" ;
		WEEK_QV2M:climatology_time_range = "JAN-1980:AUG-2018" ;
		WEEK_QV2M:long_name_mod = "regrid: 7 day on T@MOD" ;

// global attributes:
		:history = "PyFerret V7.4 (optimized) 13-Apr-20" ;
		:Conventions = "CF-1.6" ;
}
In [19]:
!ncdump -h /tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/INDIVIDUAL_YEARS/MERRA_DATA/merra_weekly_climo.nc
netcdf merra_weekly_climo {
dimensions:
	LON = 576 ;
	LAT = 361 ;
	TWEEK = UNLIMITED ; // (52 currently)
variables:
	double LON(LON) ;
		LON:long_name = "longitude" ;
		LON:units = "degrees_east" ;
		LON:axis = "X" ;
		LON:modulo = 360. ;
		LON:point_spacing = "even" ;
		LON:standard_name = "longitude" ;
	double LAT(LAT) ;
		LAT:long_name = "latitude" ;
		LAT:units = "degrees_north" ;
		LAT:axis = "Y" ;
		LAT:point_spacing = "even" ;
		LAT:standard_name = "latitude" ;
	double TWEEK(TWEEK) ;
		TWEEK:units = "day since 1901-01-15 00:00:00" ;
		TWEEK:axis = "T" ;
		TWEEK:calendar = "GREGORIAN" ;
		TWEEK:time_origin = "15-JAN-1901" ;
		TWEEK:standard_name = "time" ;
	double WEEK_QV2M(TWEEK, LAT, LON) ;
		WEEK_QV2M:missing_value = -1.e+34 ;
		WEEK_QV2M:_FillValue = -1.e+34 ;
		WEEK_QV2M:long_name = "Weekly-mean 2-meter specific humidity from MERRA2" ;
		WEEK_QV2M:units = "kg/kg" ;
		WEEK_QV2M:history = "From /tigress/samueltb/MERRA2/Daily/merged/QV2M/MERRA2.tavg1_2d_slv_Nx.198001-201808.nc" ;

// global attributes:
		:history = "Tue Apr 28 14:30:16 2020: ncea MERRA_DATA/merra_weekly_1981.nc MERRA_DATA/merra_weekly_1982.nc MERRA_DATA/merra_weekly_1983.nc MERRA_DATA/merra_weekly_1984.nc MERRA_DATA/merra_weekly_1985.nc MERRA_DATA/merra_weekly_1986.nc MERRA_DATA/merra_weekly_1987.nc MERRA_DATA/merra_weekly_1988.nc MERRA_DATA/merra_weekly_1989.nc MERRA_DATA/merra_weekly_1990.nc MERRA_DATA/merra_weekly_1991.nc MERRA_DATA/merra_weekly_1992.nc MERRA_DATA/merra_weekly_1993.nc MERRA_DATA/merra_weekly_1994.nc MERRA_DATA/merra_weekly_1995.nc MERRA_DATA/merra_weekly_1996.nc MERRA_DATA/merra_weekly_1997.nc MERRA_DATA/merra_weekly_1998.nc MERRA_DATA/merra_weekly_1999.nc MERRA_DATA/merra_weekly_2000.nc MERRA_DATA/merra_weekly_2001.nc MERRA_DATA/merra_weekly_2002.nc MERRA_DATA/merra_weekly_2003.nc MERRA_DATA/merra_weekly_2004.nc MERRA_DATA/merra_weekly_2005.nc MERRA_DATA/merra_weekly_2006.nc MERRA_DATA/merra_weekly_2007.nc MERRA_DATA/merra_weekly_2008.nc MERRA_DATA/merra_weekly_2009.nc MERRA_DATA/merra_weekly_2010.nc MERRA_DATA/merra_weekly_2011.nc MERRA_DATA/merra_weekly_2012.nc MERRA_DATA/merra_weekly_2013.nc MERRA_DATA/merra_weekly_2014.nc MERRA_DATA/merra_weekly_2015.nc MERRA_DATA/merra_weekly_2016.nc MERRA_DATA/merra_weekly_2017.nc merra_weekly_climo.nc\n",
			"PyFerret V7.4 (optimized) 17-Apr-20" ;
		:Conventions = "CF-1.6" ;
		:NCO = "\"4.5.4\"" ;
		:nco_openmp_thread_number = 1 ;
}
In [1]:
# init
%matplotlib inline
import sys
wython = '/tiger/scratch/gpfs/GEOCLIM/wenchang/wython'
if wython not in sys.path:
    sys.path.append(wython)
%run -im wystart
# https://www.dataquest.io/blog/jupyter-notebook-tips-tricks-shortcuts/
# from IPython.core.interactiveshell import InteractiveShell
# InteractiveShell.ast_node_interactivity = 'last' # options: 'all', 'none'
# https://stackoverflow.com/questions/41125690/matplotlib-notebook-showing-a-blank-histogram
# in case to switch back to the notebook backend, run the 2 lines below, 
# reload(plt)
# %matplotlib notebook
# import xaddon, xfilter, xtc
import scipy as sp
import matplotlib as mpl
print()
print(f'{sp.__name__}({sp.__version__})')
[2020-05-28_10:45:35]: start /tiger/scratch/gpfs/GEOCLIM/wenchang/wython/wystart.py
[imported]: os.path, sys, os, datetime, glob
[imported]: xarray(0.15.1) as xr, numpy(1.18.1) as np, pandas(1.0.3) as pd, matplotlib(3.1.1) as mpl
[imported]: import matplotlib.pyplot as plt

**wython plot settings**
[config]: plt.rcParams['figure.dpi'] = 128
[config]: plt.rcParams['figure.figsize'] = [6.4, 6.4*9/16]
[config]: plt.rcParams['figure.constrained_layout.use'] = True
[registered colormaps]: tc and tc_r
[registered colormaps]: turbo and turbo_r
[registered colormaps]: parula and parula_r
[imported]: import misc.colormaps
[config]: xr.set_options(cmap_sequential="parula")
[config]: xr.set_options(cmap_divergent="turbo")
[iPython config]: InlineBackend.figure_format ='retina'
[added]: PROJ_LIB = /home/wenchang/anaconda3/share/proj
[imported]: from matplotlib.pyplot import plot, figure, close
[executed]: plt.ion()

[2020-05-28_10:45:44]: **done**; **8** seconds from "start /tiger/scratch/gpfs/GEOCLIM/wenchang/wython/wystart.py"

scipy(1.4.1)
In [2]:
from scipy.integrate import odeint
from scipy.integrate import solve_ivp

#lat and lon for multiple cities
regions = dict(
    London=(51.5074, 0.1278),
    NYC=(40.7128, -74.0060+360),
    LA=(34.0522, -118.2437+360),
    Wuhan=(30.5928, 114.3055),
    Delhi=(28.7041, 77.1025),
    Maracaibo=(10.6427, -71.6125+360),
    Kinshasa=(-4.4419, 15.2663),
    Jakarta=(-6.2088, 106.8456),
    Johannesburg=(-26.2041, 28.0473),
    Buenos_Aires=(-34.6037, -58.3816+360),
    Melbourne=(-37.8136, 144.9631)
    
)
In [3]:
from numpy import pi as Pi
def get_q(case='cos', qmin=0.002, qmax=0.014, qrange=None, phi0=None, qyear=None):
    '''obtain specific humidity annual cycle'''
#     case = 'merra2'
#     qmin, qmax = 0.002, 0.018# units: kg/kg   
    if case == 'cos':
        if phi0 is None:
            phi0 = -Pi
        if qrange is None:
            qrange = qmax - qmin
        else: #overide qmax according to qmin and qrange
            qmax = qmin + qrange
        t = np.arange(0, 365)
        t = xr.DataArray(t, dims='time', coords=[t])
        t.attrs['units'] = 'day'
        qmean = (qmin + qmax)/2
        cycle = np.cos(2*Pi*t/365 + phi0) # normalized to have range of [0, 1]
        q = qmean + (qrange/2)*cycle
        q.name = 'q'
        q.attrs['units'] = 'kg/kg'
        s = f'cos-curve q: '
        if not hasattr(qmin, 'ndim'):
            s += f'qmin = {qmin}; '
        if not hasattr(qmax, 'ndim'):
            s += f'qmax = {qmax}; '
        if not hasattr(phi0, 'ndim'):
            s += f'phi0 = {phi0/Pi:.1f}xPi; '
        q.attrs['note'] = s
    elif case == 'era5':
        ifile = '/tigress/wenchang/data/era5/analysis_wy/2m_specific_humidity/daily/clim/q2m.run7clim.2010-2019.nc'
        q = ( 
            xr.open_dataset(ifile)
            ['q2m']
            .rename(dayofyear='time')
            .load()
        )
        q.attrs['note'] = case
    elif case == 'era5_single_year':
        ifiles = f'/tigress/wenchang/data/era5/analysis_wy/2m_specific_humidity/daily/era5.2m_specific_humidity.daily.{qyear}-??.nc'
        q = ( 
            xr.open_mfdataset(ifiles, combine='by_coords')
            ['q2m']
#             .load()
        )
        q.attrs['note'] = f'{case} {qyear}'
    elif case == 'merra2':
#         ifile = '/tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/merra_weekly_clim.nc'
        ifile = '/tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/INDIVIDUAL_YEARS/MERRA_DATA/merra_weekly_climo.nc'
        q = ( 
            xr.open_dataset(ifile)
            .rename(WEEK_QV2M='q2m', TWEEK='time', LAT='latitude', LON='longitude')
            ['q2m']
            .pipe(lambda x: x.assign_coords(time=x.time.dt.dayofyear))
            .reindex(time=np.arange(1, 366), method='nearest')
            .load()
        )
        # shift from 0-center to 180E-center
        if q.longitude.min() < 0:
            q = q.roll(longitude=q.longitude.size//2)
            q = q.assign_coords(
                longitude=q.longitude.where(q.longitude>=0, other=q.longitude+360).values
            )
        q.attrs['note'] = case
        
    return q
q = get_q()
q.plot()
plt.title(q.note)

# q.isel(time=0).plot()
# plt.title(case)
# plt.figure()
# for city,(latx, lonx) in regions.items():
#     q.sel(latitude=latx, longitude=lonx, method='nearest').plot(label=city)
# print()
# plt.legend()
# plt.title(case)
Out[3]:
Text(0.5, 1.0, 'cos-curve q: qmin = 0.002; qmax = 0.014; phi0 = -1.0xPi; ')
In [4]:
climdepens ={
    'HKU1': dict(a=-227.5, R0_min=1.5, R0_max=2.5),
    'OC43': dict(a=-32.5, R0_min=1.5, R0_max=2.5)
}
def q2R0(q, a, R0_min, R0_max):
    '''R0 dependence on climate (specific humidity)'''
    R0 = (R0_max - R0_min) * np.exp(a*q) + R0_min
    if isinstance(R0, xr.DataArray):
        R0.name = 'R0'
    
    return R0
In [5]:
def R0_at_t(R0, t, cycle=True):
    '''R0 as function of t (time) and specific humidity (q).
    q has dims of (n_time, n_grid).'''
    ndays_per_year = 364 # 52x7, to be consistent with Rachael's
    #R0_min, R0_max = 1.4, 2.5
    #a = -227.5 for HKU1 and -32.5 for OC43
    if cycle:# cycle through the first 365 daily specific humidity
        R0t = R0.isel(time=int( np.mod(t, ndays_per_year) ), drop=True)
    else:
        R0t = R0.isel(time=int(t), drop=True)
    return R0t
# func_R0(0, R0t)
In [6]:
Ldis = {
    'HKU1': 66.25*7,
    'OC43': 62.5*7
}
In [7]:
def get_ii_from_gabe(dis, city):
    #ifile = f'/tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/FIGURE_CONTROL_AllRachel_RK4/{dis}_D5_nosd_null_null_null.nc'
    ifile = f'/tigress/gvecchi/ANALYSIS/DISEASE/COVID-19/FIGURE_CONTROL_AllRachel_RK4/{dis}_D5_nosd_null_null_null.nc'
    ds_gabe = xr.open_dataset(ifile)
    new_names = {'LON': 'longitude', 'LAT': 'latitude', 'TTAFA': 't'}
    latx, lonx = regions[city]
    if lonx >= 180: 
        lonx = lonx - 360
    da = ds_gabe.IT.sel(LAT=latx, LON=lonx, method='nearest').rename('ii').rename(new_names).load()
    ds = da.to_dataset()
    ds['year'] = da.t/364

    return ds

# ds = get_ii_from_gabe('HKU1', 'NYC')
# ds

climSIRS using odeint

In [9]:
def model_climSIRS(y, t, L, D, R0):
    '''SIRS model right hand side from Baker et al., 2020.
    Input:
    -------
        y: y[0:y.size//2] is S/N; y[y.size//2:] is I/N
        t: time (units is 'day')
        L: immunity length, 7x66.25(62.5) days for HKU1 (OC43)
        D: infection period, 5 days
        R0: beta*D, scalar, 1-D array or time-dependent N-D DataArray

    Return:
    --------
        dydt: 1-D array with half d(S/N)/dt and half d(I/N)/dt
    '''
    N = y.size
    ss = y[:N//2]
    ii = y[N//2:]
    if hasattr(R0, 'time'): # R0 is time-dependent
        _R0 = R0_at_t(R0, t)
        if _R0.ndim < 1:
            _R0 = _R0.item()
    else:
        _R0 = R0
    dydt = np.array([
        (1-ss-ii)/L - _R0*ii*ss/D, 
        _R0*ii*ss/D - ii/D
    ]).ravel()
    
    return dydt
In [10]:
from scipy.integrate import odeint
def run_climSIRS(ii0=1/8e6, ss0=None, T=5*365, dt=1, tvec=None, L=None, D=5, R0=2, dis='HKU1'):
    '''Integrate SIRS model from Baker et al., 2020.

    Input:
    -------
        I0: initial I/N
        T: time stop (start is 1; units is 'day')
        dt: time step
        tvec: array, will override T and dt if not None;
        L: immunity length, 7x66.25(62.5) days for HKU1 (OC43)
        D: infection period, 5 days
        R0 = beta*D, ignored if q is not None
        dis: disease name, e.g. "HKU1" or "OC43"

    Return:
    --------
        ds: solution for the SIRS model.
    '''
    ndays_of_year = 364
    
    if L is None and dis is not None:
        L = Ldis[dis]
    if hasattr(R0, 'time'): # R0 time-dependent
        if R0.ndim > 1:# 
            grid = R0.stack(grid=R0.isel(time=0).dims).grid # grid info is saved
            zeros = np.zeros(grid.size) # broadcast array by R0.dims[1:]
        else: # only time dimension
            zeros = ii0*L*D*0 # broadcast array by ii0*L*D*a
    else: # R0 time-independent
        zeros = ii0*L*D*R0*0
    # default initial S/N value determined by initial I/N value
    if ss0 is None:
        ss0 = 1 - ii0
    # broadcast initial values by adding zeros
    ii0 = ii0 + zeros
    ss0 = ss0 + zeros
        
    y0 = np.hstack([ss0, ii0])
    if tvec is None:
        t = np.arange(0, T, dt)
    else:
        t = tvec
    sol = odeint(model_climSIRS, y0, t, args=(L, D, R0))
    ss = sol[:, 0:y0.size//2]
    ii = sol[:, y0.size//2:]
    da_ss = xr.DataArray(ss, dims=['t', 'grid'],coords=[t, np.arange(1, y0.size//2+1)])
    da_ss.attrs['long_name'] = 'S/N'
    da_ii = xr.DataArray(ii, dims=['t', 'grid'],coords=[t, np.arange(1, y0.size//2+1)])
    da_ii.attrs['long_name'] = 'I/N'
    
    if hasattr(R0, 'time') and R0.ndim > 1: # R0 has more than "time" dimensions
        da_ss = da_ss.assign_coords(grid=grid).unstack()
        da_ii = da_ii.assign_coords(grid=grid).unstack()
    
    ds = xr.Dataset(dict(ss=da_ss, ii=da_ii, year=da_ss.t/ndays_of_year))
    ds.t.attrs['units'] = 'day'
    
    return ds

# latx, lonx = regions['NYC']
# q = get_q('era5').sel(latitude=latx, longitude=lonx, method='nearest')
# q = get_q()
ds = run_climSIRS()
ds.ii.plot()
ds
Out[10]:
Show/Hide data repr Show/Hide attributes
xarray.Dataset
    • grid: 1
    • t: 1825
    • t
      (t)
      int64
      0 1 2 3 4 ... 1821 1822 1823 1824
      units :
      day
      array([   0,    1,    2, ..., 1822, 1823, 1824])
    • grid
      (grid)
      int64
      1
      array([1])
    • ss
      (t, grid)
      float64
      1.0 1.0 1.0 ... 0.5072 0.507 0.5068
      long_name :
      S/N
      array([[0.99999987],
             [0.99999982],
             [0.99999975],
             ...,
             [0.50717685],
             [0.50699453],
             [0.50680956]])
    • ii
      (t, grid)
      float64
      1.25e-07 1.528e-07 ... 0.0061
      long_name :
      I/N
      array([[1.25000000e-07],
             [1.52842391e-07],
             [1.86848714e-07],
             ...,
             [6.06583232e-03],
             [6.08304956e-03],
             [6.09986772e-03]])
    • year
      (t)
      float64
      0.0 0.002747 ... 5.008 5.011
      array([0.00000000e+00, 2.74725275e-03, 5.49450549e-03, ...,
             5.00549451e+00, 5.00824176e+00, 5.01098901e+00])

climSIRS using solve_ivp

In [11]:
# t instead of y is the first argument required by scipy.integrate.solve_ivp
def model_climSIRSpy(t, y, L, D, R0):
    return model_climSIRS(y=y, t=t, L=L, D=D, R0=R0)
In [12]:
# scipy.integrate.solve_ivp backend
from scipy.integrate import solve_ivp
def run_climSIRSpy(ii0=1/8e6, ss0=None, T=5*365, dt=1, tvec=None, L=None, D=5, R0=2, dis='HKU1'):
    '''Integrate SIRS model from Baker et al., 2020.

    Input:
    -------
        I0: initial I/N
        T: time stop (start is 1; units is 'day')
        dt: time step
        tvec: will override T and dt is not None;
        L: immunity length, 7x66.25(62.5) days for HKU1 (OC43)
        D: infection period, 5 days
        R0 = beta*D, scalar, 1-D array or time-dependent N-D DataArray
        dis: disease name, e.g. "HKU1" or "OC43"

    Return:
    --------
        ds: solution for the SIRS model.
    '''
    ndays_of_year = 364
    
    if L is None and dis is not None:
        L = Ldis[dis]
    if hasattr(R0, 'time'): # R0 time-dependent
        if R0.ndim > 1:# 
            R0 = R0.stack(grid=R0.isel(time=0).dims)
            grid = R0.grid # grid info is saved
            zeros = np.zeros(grid.size) # broadcast array by R0.dims[1:]
        else: # only time dimension
            zeros = ii0*L*D*0 # broadcast array by ii0*L*D*a
    else: # R0 time-independent
        zeros = ii0*L*D*R0*0
    # default initial S/N value determined by initial I/N value
    if ss0 is None:
        ss0 = 1 - ii0
    # broadcast initial values by adding zeros
    ii0 = ii0 + zeros
    ss0 = ss0 + zeros
        
    y0 = np.hstack([ss0, ii0])
    if tvec is None:
        t = np.arange(0, T, dt)
    else:
        t = tvec
#     # scipy.integrate.odeint backend; call FORTRAN code ultimately
#     sol = odeint(model_climSIRS, y0, t, args=(L, D, R0))
#     ss = sol[:, 0:y0.size//2]
#     ii = sol[:, y0.size//2:]
#     da_ss = xr.DataArray(ss, dims=['t', 'grid'],coords=[t, np.arange(1, y0.size//2+1)])
#     da_ss.attrs['long_name'] = 'S/N'
#     da_ii = xr.DataArray(ii, dims=['t', 'grid'],coords=[t, np.arange(1, y0.size//2+1)])
#     da_ii.attrs['long_name'] = 'I/N'
    
    # scipy.integrate.solve_ivp backend, pure Python code
#     print(t)
    sol = solve_ivp(model_climSIRSpy,[0, T], y0, t_eval=t,  args=(L, D, R0))
#     print(sol)
    ss = sol.y[0:y0.size//2, :]
    ii = sol.y[y0.size//2:, :]
#     print(ss.shape)
    da_ss = xr.DataArray(ss, dims=['grid', 't'],coords=[np.arange(1, y0.size//2+1), t])
    da_ss.attrs['long_name'] = 'S/N'
    da_ii = xr.DataArray(ii, dims=['grid', 't'],coords=[np.arange(1, y0.size//2+1), t])
    da_ii.attrs['long_name'] = 'I/N'
    
    if hasattr(R0, 'time') and R0.ndim > 1: # R0 has more than "time" dimensions
        da_ss = da_ss.assign_coords(grid=grid).unstack()
        da_ii = da_ii.assign_coords(grid=grid).unstack()
    
    ds = xr.Dataset(dict(ss=da_ss, ii=da_ii, year=da_ss.t/ndays_of_year))
    ds.t.attrs['units'] = 'day'
    
    return ds

# latx, lonx = regions['NYC']
# q = get_q('era5').sel(latitude=latx, longitude=lonx, method='nearest')
# q = get_q()
ds = run_climSIRSpy()
ds.ii.plot()
ds
Out[12]:
Show/Hide data repr Show/Hide attributes
xarray.Dataset
    • grid: 1
    • t: 1825
    • grid
      (grid)
      int64
      1
      array([1])
    • t
      (t)
      int64
      0 1 2 3 4 ... 1821 1822 1823 1824
      units :
      day
      array([   0,    1,    2, ..., 1822, 1823, 1824])
    • ss
      (grid, t)
      float64
      1.0 1.0 1.0 ... 0.5086 0.5084
      long_name :
      S/N
      array([[0.99999987, 0.99999982, 0.99999975, ..., 0.50876494, 0.50860051,
              0.50843261]])
    • ii
      (grid, t)
      float64
      1.25e-07 1.527e-07 ... 0.005982
      long_name :
      I/N
      array([[1.25000000e-07, 1.52677327e-07, 1.86581367e-07, ...,
              5.94142701e-03, 5.96209948e-03, 5.98244626e-03]])
    • year
      (t)
      float64
      0.0 0.002747 ... 5.008 5.011
      array([0.00000000e+00, 2.74725275e-03, 5.49450549e-03, ...,
             5.00549451e+00, 5.00824176e+00, 5.01098901e+00])

climSIRS using RK4 explicitly

In [13]:
def model_climSIRSwy(ss, ii, t, L, D, R0):
    '''SIRS model right hand side from Baker et al., 2020.

    Input:
    -------
        ss: S/N
        ii: I/N
        t: time (units is 'day')
        L: immunity length, 7x66.25(62.5) days for HKU1 (OC43)
        D: infection period, 5 days
        R0 = beta*D, scalar, 1-D array or time-dependent N-D DataArray

    Return:
    --------
        tuple (dsdt, didt)
        dsdt: S/N tendency
        didt: I/N tendency
    '''
    if hasattr(R0, 'time'): # R0 is time-dependent
        _R0 = R0_at_t(R0, t)
        if _R0.ndim < 1:
            _R0 = _R0.item()
    else:
        _R0 = R0
    dsdt = (1-ss-ii)/L - _R0*ii*ss/D
    didt = _R0*ii*ss/D - ii/D

    return dsdt, didt
In [14]:
def rk4_climSIRSwy(ss, ii, t, dt, L, D, R0):
    '''Step change from classic Runge–Kutta (RK4) method for SIRS model of Baker et al., 2020.

    Input:
    -------
        ss: S/N
        ii: I/N
        t: time (units is 'day')
        dt: time step
        L: immunity length, 7x66.25(62.5) days for HKU1 (OC43)
        D: infection period, 5 days
        R0 = beta*D, scalar, 1-D array or N-D time-dependent DataArray

    Return:
    --------
        tuple (dss, dii)
        dss: S/N step increase
        dii: I/N step increase
    '''
    model_climSIRS = model_climSIRSwy
    k1s, k1i = model_climSIRS(ss=ss, ii=ii, t=t, L=L, D=D, R0=R0)
    k2s, k2i = model_climSIRS(ss=ss+k1s*dt/2, ii=ii+k1i*dt/2, t=t+dt/2, L=L, D=D, R0=R0)
    k3s, k3i = model_climSIRS(ss=ss+k2s*dt/2, ii=ii+k2i*dt/2, t=t+dt/2, L=L, D=D, R0=R0)
    k4s, k4i = model_climSIRS(ss=ss+k3s*dt, ii=ii+k3i*dt, t=t+dt, L=L, D=D, R0=R0)

    dss = dt*(k1s + 2*k2s + 2*k3s + k4s)/6
    dii = dt*(k1i + 2*k2i + 2*k3i + k4i)/6

    return dss, dii
In [16]:
def run_climSIRSwy(ii0=1/8e6, ss0=None, T=5*365, dt=1, tvec=None, L=None, D=5, R0=2, dis='HKU1'):
    '''Integrate SIRS model from Baker et al., 2020.

    Input:
    -------
        I0: initial I/N
        T: time stop (start is 1; units is 'day')
        dt: time step
        tvec: will override T and dt if not None;
        L: immunity length, 7x66.25(62.5) days for HKU1 (OC43)
        D: infection period, 5 days
        R0: beta*D, scalar, 1-D array or time-dependent n-D DataArray
        dis: disease name, e.g. "HKU1" or "OC43"
        
    Return:
    --------
        ds: solution for the climSIRSwy model.
    '''
    ndays_of_year = 364
    
    if tvec is None:
        t_vec = np.arange(0, T, dt)
    else:
        t_vec = tvec
    
    if L is None and dis is not None:
        L = Ldis[dis]
    if hasattr(R0, 'time'): # R0 time-dependent
        zeros = ii0*L*D*R0.isel(time=0, drop=True)*0 # broadcast array by R0.dims[1:]
    else: # R0 time-independent
        zeros = ii0*L*D*R0*0
    # default initial S/N value determined by initial I/N value
    if ss0 is None:
        ss0 = 1 - ii0
    # broadcast initial values by adding zeros
    ii = ii0 + zeros
    ss = ss0 + zeros
    
    ss_vec = [ss,]
    ii_vec = [ii,]
    print('time step (units: day): ', end='')
    for t in t_vec[1:]:
        if np.mod(t, ndays_of_year) == 0:
            print(f'{ndays_of_year}x{t//ndays_of_year}', end='; ')
        dss, dii = rk4_climSIRSwy(ss=ss, ii=ii, t=t, dt=dt, L=L, D=D, R0=R0)
        ss = ss + dss
        ii = ii + dii
        ss_vec.append(ss)
        ii_vec.append(ii)
    print()
    if isinstance(ss, xr.DataArray):
        try:
            da_ss = xr.concat(ss_vec, dim=pd.Index(t_vec, name='t'))
            da_ii = xr.concat(ii_vec, dim=pd.Index(t_vec, name='t'))
        except MemoryError:
            ss_vec = [_ss.expand_dims('dum').chunk({'dum':1}).squeeze() for _ss in ss_vec]
            ii_vec = [_ii.expand_dims('dum').chunk({'dum':1}).squeeze() for _ii in ii_vec]
            da_ss = xr.concat(ss_vec, dim=pd.Index(t_vec, name='t'))
            da_ii = xr.concat(ii_vec, dim=pd.Index(t_vec, name='t'))
    else:
        da_ss = xr.DataArray(ss_vec, dims=['t'], coords=[t_vec])
        da_ii = xr.DataArray(ii_vec, dims=['t'], coords=[t_vec])
    da_ss.attrs['long_name'] = 'S/N'
    da_ii.attrs['long_name'] = 'I/N'
    ds = xr.Dataset(dict(ss=da_ss, ii=da_ii, year=da_ss.t/ndays_of_year))
    ds.t.attrs['units'] = 'day'
    

    return ds

ds = run_climSIRSwy()
# ds.ii.sel(latitude=latx, longitude=lonx, method='nearest').plot()
ds.ii.assign_coords(t=ds.year).rename(t='year').plot()
# da.sel(si='I/N').plot()
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 
Out[16]:
[<matplotlib.lines.Line2D at 0x7f1a6e87afd0>]

sensitivity to ODE methods

In [17]:
dis = 'HKU1'
T = 15*365
ii0 = 1/8e6
q = get_q()
q.plot()
R0 = q2R0(q, **climdepens[dis])
plt.figure()
R0.plot()
plt.figure()
ds = run_climSIRS(dis=dis, R0=R0, T=T, ii0=ii0)
ds.ii.assign_coords(t=ds.year).rename(t='year').plot()
ds = run_climSIRSpy(dis=dis, R0=R0, T=T, ii0=ii0)
ds.ii.assign_coords(t=ds.year).rename(t='year').plot()
ds = run_climSIRSwy(dis=dis, R0=R0, T=T, ii0=ii0)
ds.ii.assign_coords(t=ds.year).rename(t='year').plot()

plt.legend(['odeint', 'solve_ivp', 'RK4'])
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 364x10; 364x11; 364x12; 364x13; 364x14; 364x15; 
Out[17]:
<matplotlib.legend.Legend at 0x7f1a70c222d0>

sensitivity to dt

In [18]:
dis = 'HKU1'
ii0 = 1/8e6
city = 'NYC'
latx, lonx = regions[city]

q = get_q('era5').sel(latitude=latx, longitude=lonx, method='nearest')
q.plot()

R0 = q2R0(q, **climdepens[dis])
plt.figure()
R0.plot()

plt.figure()
dss = []
ds = run_climSIRSwy(dis=dis, R0=R0, T=10*365, ii0=ii0, dt=0.5)
dss.append(ds)
ds.ii.assign_coords(t=ds.year).rename(t='year').plot()
ds = run_climSIRSwy(dis=dis, R0=R0, T=10*365, ii0=ii0, dt=1)
dss.append(ds)
ds.ii.assign_coords(t=ds.year).rename(t='year').plot()
plt.title(f'{city} {dis}')
plt.legend(['RK4, dt = 0.5', 'RK4, dt = 1.0'])
time step (units: day): 364x1.0; 364x2.0; 364x3.0; 364x4.0; 364x5.0; 364x6.0; 364x7.0; 364x8.0; 364x9.0; 364x10.0; 
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 364x10; 
Out[18]:
<matplotlib.legend.Legend at 0x7f1a6eab9c10>
In [19]:
# sensitivity to time step
for i,dt in enumerate([0.5, 1.0]):
#     ds = run_climSIRSwy(L=66.25*7, D=5, I0=1e-5, T=5*365, dt=dt, 
#              q=q2m.sel(latitude=latx, longitude=lonx, method='nearest'), R0=2)
    ds = dss[i]
    ds.ii.sel(t=slice(0,365)).plot(color=f'C{i}', label=f'dt = {dt}')
    dss.append(ds)
plt.legend()
plt.title(f'{city} {dis} (RK4)')
Out[19]:
Text(0.5, 1.0, 'NYC HKU1 (RK4)')
In [27]:
# sensitivity to time step
for i,dt in enumerate([0.5, 1.0]):
    ds = dss[i]
    ds.ii.sel(t=slice(72,83)).plot(color=f'C{i}', label=f'dt = {dt}')
    dss.append(ds)
plt.legend()
plt.title(f'{city} {dis} (RK4)')
Out[27]:
Text(0.5, 1.0, 'NYC HKU1 (RK4)')

comparison to Gabe's: NYC

In [28]:
q2m = get_q('merra2')
q2m
/home/wenchang/anaconda3/lib/python3.7/site-packages/xarray/core/dataarray.py:2823: FutureWarning: roll_coords will be set to False in the future. Explicitly set roll_coords to silence warning.
  shifts=shifts, roll_coords=roll_coords, **shifts_kwargs
Out[28]:
Show/Hide data repr Show/Hide attributes
xarray.DataArray
'q2m'
  • time: 365
  • latitude: 361
  • longitude: 576
  • 0.0004464 0.0004464 0.0004464 ... 0.0005319 0.0005319 0.0005319
    array([[[0.00044636, 0.00044636, 0.00044636, ..., 0.00044636,
             0.00044636, 0.00044636],
            [0.00045745, 0.00045737, 0.00045729, ..., 0.00045769,
             0.00045761, 0.00045753],
            [0.00046815, 0.00046797, 0.00046779, ..., 0.00046869,
             0.00046851, 0.00046833],
            ...,
            [0.00050453, 0.00050483, 0.00050512, ..., 0.00050361,
             0.00050392, 0.00050422],
            [0.00049554, 0.00049567, 0.00049579, ..., 0.00049516,
             0.00049529, 0.00049542],
            [0.00049111, 0.00049111, 0.00049111, ..., 0.00049111,
             0.00049111, 0.00049111]],
    
           [[0.00044636, 0.00044636, 0.00044636, ..., 0.00044636,
             0.00044636, 0.00044636],
            [0.00045745, 0.00045737, 0.00045729, ..., 0.00045769,
             0.00045761, 0.00045753],
            [0.00046815, 0.00046797, 0.00046779, ..., 0.00046869,
             0.00046851, 0.00046833],
            ...,
            [0.00050453, 0.00050483, 0.00050512, ..., 0.00050361,
             0.00050392, 0.00050422],
            [0.00049554, 0.00049567, 0.00049579, ..., 0.00049516,
             0.00049529, 0.00049542],
            [0.00049111, 0.00049111, 0.00049111, ..., 0.00049111,
             0.00049111, 0.00049111]],
    
           [[0.00044636, 0.00044636, 0.00044636, ..., 0.00044636,
             0.00044636, 0.00044636],
            [0.00045745, 0.00045737, 0.00045729, ..., 0.00045769,
             0.00045761, 0.00045753],
            [0.00046815, 0.00046797, 0.00046779, ..., 0.00046869,
             0.00046851, 0.00046833],
            ...,
            [0.00050453, 0.00050483, 0.00050512, ..., 0.00050361,
             0.00050392, 0.00050422],
            [0.00049554, 0.00049567, 0.00049579, ..., 0.00049516,
             0.00049529, 0.00049542],
            [0.00049111, 0.00049111, 0.00049111, ..., 0.00049111,
             0.00049111, 0.00049111]],
    
           ...,
    
           [[0.00045266, 0.00045266, 0.00045266, ..., 0.00045266,
             0.00045266, 0.00045266],
            [0.00046562, 0.00046555, 0.00046547, ..., 0.00046584,
             0.00046577, 0.00046569],
            [0.00047774, 0.00047757, 0.0004774 , ..., 0.00047824,
             0.00047807, 0.0004779 ],
            ...,
            [0.0005453 , 0.00054557, 0.00054583, ..., 0.0005445 ,
             0.00054477, 0.00054504],
            [0.0005368 , 0.00053691, 0.00053702, ..., 0.00053647,
             0.00053658, 0.00053669],
            [0.00053189, 0.00053189, 0.00053189, ..., 0.00053189,
             0.00053189, 0.00053189]],
    
           [[0.00045266, 0.00045266, 0.00045266, ..., 0.00045266,
             0.00045266, 0.00045266],
            [0.00046562, 0.00046555, 0.00046547, ..., 0.00046584,
             0.00046577, 0.00046569],
            [0.00047774, 0.00047757, 0.0004774 , ..., 0.00047824,
             0.00047807, 0.0004779 ],
            ...,
            [0.0005453 , 0.00054557, 0.00054583, ..., 0.0005445 ,
             0.00054477, 0.00054504],
            [0.0005368 , 0.00053691, 0.00053702, ..., 0.00053647,
             0.00053658, 0.00053669],
            [0.00053189, 0.00053189, 0.00053189, ..., 0.00053189,
             0.00053189, 0.00053189]],
    
           [[0.00045266, 0.00045266, 0.00045266, ..., 0.00045266,
             0.00045266, 0.00045266],
            [0.00046562, 0.00046555, 0.00046547, ..., 0.00046584,
             0.00046577, 0.00046569],
            [0.00047774, 0.00047757, 0.0004774 , ..., 0.00047824,
             0.00047807, 0.0004779 ],
            ...,
            [0.0005453 , 0.00054557, 0.00054583, ..., 0.0005445 ,
             0.00054477, 0.00054504],
            [0.0005368 , 0.00053691, 0.00053702, ..., 0.00053647,
             0.00053658, 0.00053669],
            [0.00053189, 0.00053189, 0.00053189, ..., 0.00053189,
             0.00053189, 0.00053189]]])
    • time
      (time)
      int64
      1 2 3 4 5 6 ... 361 362 363 364 365
      array([  1,   2,   3, ..., 363, 364, 365])
    • longitude
      (longitude)
      float64
      0.0 0.625 1.25 ... 358.8 359.4
      array([  0.   ,   0.625,   1.25 , ..., 358.125, 358.75 , 359.375])
    • latitude
      (latitude)
      float64
      -90.0 -89.5 -89.0 ... 89.5 90.0
      long_name :
      latitude
      units :
      degrees_north
      axis :
      Y
      point_spacing :
      even
      standard_name :
      latitude
      array([-90. , -89.5, -89. , ...,  89. ,  89.5,  90. ])
  • long_name :
    Weekly-mean 2-meter specific humidity from MERRA2
    units :
    kg/kg
    history :
    From /tigress/samueltb/MERRA2/Daily/merged/QV2M/MERRA2.tavg1_2d_slv_Nx.198001-201808.nc
    note :
    merra2

HKU1 NYC

In [29]:
dis = 'HKU1'
city = 'NYC'
In [30]:
latx, lonx = regions[city]
q = q2m.sel(latitude=latx, longitude=lonx, method='nearest')
q.rename(time='day_of_year').plot()
Out[30]:
[<matplotlib.lines.Line2D at 0x7f1a600a7790>]
In [31]:
R0 = q2R0(q, **climdepens[dis])
R0.rename('day_of_year').plot()
Out[31]:
[<matplotlib.lines.Line2D at 0x7f1a673f7b90>]
In [35]:
dss = {}
ii0 = 1/8e6
T = 10*364
dt = 1
dss['odeint'] = run_climSIRS(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
In [36]:
dt = 1
dss['rk4'] = run_climSIRSwy(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
In [37]:
dt = 7
dss['rk4_dt7'] = run_climSIRSwy(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
In [38]:
dss['Gabe'] = get_ii_from_gabe(dis=dis, city=city)
In [43]:
label = 'odeint'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, color='k')
label = 'rk4'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
label = 'rk4_dt7'
ds = dss[label]
# ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls=':')
label = 'Gabe'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label='Gabe', ls=':')

plt.legend()
Out[43]:
<matplotlib.legend.Legend at 0x7f1a6ebac610>
In [47]:
label = 'odeint'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, color='k')
label = 'rk4'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
label = 'rk4_dt7'
ds = dss[label]
# ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
label = 'Gabe'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label='Gabe', ls=':')

plt.legend()
plt.xlim(0.18, .3)
Out[47]:
(0.18, 0.3)
In [49]:
label = 'odeint'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, color='k')
label = 'rk4'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
label = 'rk4_dt7'
ds = dss[label]
# ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
label = 'Gabe'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label='Gabe', ls=':')

plt.legend()
plt.xlim(1.9, 2.1)
Out[49]:
(1.9, 2.1)

HKU1 Wuhan

In [51]:
dis = 'HKU1'
city = 'Wuhan'
In [52]:
latx, lonx = regions[city]
q = q2m.sel(latitude=latx, longitude=lonx, method='nearest')
q.rename(time='day_of_year').plot()
Out[52]:
[<matplotlib.lines.Line2D at 0x7f1a66ec1d50>]
In [53]:
R0 = q2R0(q, **climdepens[dis])
R0.rename('day_of_year').plot()
Out[53]:
[<matplotlib.lines.Line2D at 0x7f1a67bfd950>]
In [54]:
if 'dss' not in globals():
    dss = {}
ii0 = 1/8e6
T = 11*364
dt = 1
dss['odeint'] = run_climSIRS(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
In [55]:
dt = 1
dss['rk4'] = run_climSIRSwy(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 364x10; 
In [56]:
dt = 7
dss['rk4_dt7'] = run_climSIRSwy(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 364x10; 
In [57]:
dss['Gabe'] = get_ii_from_gabe(dis=dis, city=city)
In [59]:
label = 'odeint'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, color='k')
label = 'rk4'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
label = 'rk4_dt7'
ds = dss[label]
# ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
label = 'Gabe'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label='Gabe', ls=':')

plt.legend()
plt.title(f'{city} {dis}', loc='left', y=1.05)
Out[59]:
Text(0.0, 1.05, 'Wuhan HKU1')
In [60]:
label = 'odeint'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, color='k')
label = 'rk4'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
label = 'rk4_dt7'
ds = dss[label]
# ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
label = 'Gabe'
ds = dss[label]
ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label='Gabe', ls=':')

plt.legend()
plt.xlim(0.2, .3)
Out[60]:
(0.2, 0.3)

comparison to Gabe's: more cities

computation

In [73]:
if 'dss' not in globals():
    dss = {}
q2m = get_q('merra2')
ii0 = 1/8e6
T = 10*364
diseases = ['HKU1', 'OC43']
for dis in diseases:
    print(dis)
    for city,(latx, lonx) in regions.items():
        print(city, f'lat = {latx}', f'lon = {lonx}')
        q = q2m.sel(latitude=latx, longitude=lonx, method='nearest')
        R0 = q2R0(q, **climdepens[dis])
        
        # odeint
        dt = 1
        label = f'{dis}_{city}_odeint'
        print(label)
        dss[label] = run_climSIRS(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
        
        # RK4
        dt = 1
        label = f'{dis}_{city}_RK4'
        print(label)
        dss[label] = run_climSIRSwy(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
        
        # RK4 dt = 7
        dt = 7
        label = f'{dis}_{city}_RK4dt7'
        print(label)
        dss[label] = run_climSIRSwy(ii0=ii0, T=T, dt=dt, R0=R0, dis=dis)
        
        #Gabe
        label = f'{dis}_{city}_Gabe'
        print(label)
        dss[label] = get_ii_from_gabe(dis=dis, city=city)
HKU1
London lat = 51.5074 lon = 0.1278
HKU1_London_odeint
HKU1_London_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_London_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_London_Gabe
NYC lat = 40.7128 lon = 285.994
HKU1_NYC_odeint
HKU1_NYC_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_NYC_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_NYC_Gabe
LA lat = 34.0522 lon = 241.7563
HKU1_LA_odeint
HKU1_LA_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_LA_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_LA_Gabe
Wuhan lat = 30.5928 lon = 114.3055
HKU1_Wuhan_odeint
HKU1_Wuhan_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Wuhan_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Wuhan_Gabe
Delhi lat = 28.7041 lon = 77.1025
HKU1_Delhi_odeint
HKU1_Delhi_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Delhi_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Delhi_Gabe
Maracaibo lat = 10.6427 lon = 288.3875
HKU1_Maracaibo_odeint
HKU1_Maracaibo_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Maracaibo_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Maracaibo_Gabe
Kinshasa lat = -4.4419 lon = 15.2663
HKU1_Kinshasa_odeint
HKU1_Kinshasa_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Kinshasa_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Kinshasa_Gabe
Jakarta lat = -6.2088 lon = 106.8456
HKU1_Jakarta_odeint
HKU1_Jakarta_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Jakarta_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Jakarta_Gabe
Johannesburg lat = -26.2041 lon = 28.0473
HKU1_Johannesburg_odeint
HKU1_Johannesburg_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Johannesburg_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Johannesburg_Gabe
Buenos_Aires lat = -34.6037 lon = 301.6184
HKU1_Buenos_Aires_odeint
HKU1_Buenos_Aires_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Buenos_Aires_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Buenos_Aires_Gabe
Melbourne lat = -37.8136 lon = 144.9631
HKU1_Melbourne_odeint
HKU1_Melbourne_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Melbourne_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
HKU1_Melbourne_Gabe
OC43
London lat = 51.5074 lon = 0.1278
OC43_London_odeint
OC43_London_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_London_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_London_Gabe
NYC lat = 40.7128 lon = 285.994
OC43_NYC_odeint
OC43_NYC_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_NYC_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_NYC_Gabe
LA lat = 34.0522 lon = 241.7563
OC43_LA_odeint
OC43_LA_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_LA_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_LA_Gabe
Wuhan lat = 30.5928 lon = 114.3055
OC43_Wuhan_odeint
OC43_Wuhan_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Wuhan_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Wuhan_Gabe
Delhi lat = 28.7041 lon = 77.1025
OC43_Delhi_odeint
OC43_Delhi_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Delhi_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Delhi_Gabe
Maracaibo lat = 10.6427 lon = 288.3875
OC43_Maracaibo_odeint
OC43_Maracaibo_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Maracaibo_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Maracaibo_Gabe
Kinshasa lat = -4.4419 lon = 15.2663
OC43_Kinshasa_odeint
OC43_Kinshasa_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Kinshasa_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Kinshasa_Gabe
Jakarta lat = -6.2088 lon = 106.8456
OC43_Jakarta_odeint
OC43_Jakarta_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Jakarta_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Jakarta_Gabe
Johannesburg lat = -26.2041 lon = 28.0473
OC43_Johannesburg_odeint
OC43_Johannesburg_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Johannesburg_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Johannesburg_Gabe
Buenos_Aires lat = -34.6037 lon = 301.6184
OC43_Buenos_Aires_odeint
OC43_Buenos_Aires_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Buenos_Aires_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Buenos_Aires_Gabe
Melbourne lat = -37.8136 lon = 144.9631
OC43_Melbourne_odeint
OC43_Melbourne_RK4
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Melbourne_RK4dt7
time step (units: day): 364x1; 364x2; 364x3; 364x4; 364x5; 364x6; 364x7; 364x8; 364x9; 
OC43_Melbourne_Gabe

plot: 10 years

In [79]:
# plot
diseases = ['HKU1', 'OC43']
for dis in diseases:
    for city,(latx, lonx) in regions.items():
        plt.figure()
        
        # odeint
        label = f'{dis}_{city}_odeint'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
        
        # RK4
        label = f'{dis}_{city}_RK4'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
        
        # RK4dt7
        label = f'{dis}_{city}_RK4dt7'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls=':')
        
        # Gabe
        label = f'{dis}_{city}_Gabe'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
        
        plt.legend()
        if dis == 'HKU1':
            plt.ylim(None, 0.15)
        elif dis == 'OC43':
            plt.ylim(None, 0.25)
        plt.tight_layout()
        
        figname = f'climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_{dis}_{city}.png'
        plt.savefig(figname)
        print('[saved]:', figname)
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_London.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_NYC.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_LA.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Wuhan.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Delhi.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Maracaibo.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Kinshasa.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Jakarta.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Johannesburg.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Buenos_Aires.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_HKU1_Melbourne.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_London.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_NYC.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_LA.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Wuhan.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Delhi.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Maracaibo.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Kinshasa.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Jakarta.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Johannesburg.png
/tiger/scratch/gpfs/GEOCLIM/wenchang/wython/wystart.py:5: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
  from misc.timer import Timer
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Buenos_Aires.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_10years_OC43_Melbourne.png

plot: first year

In [82]:
# plot
diseases = ['HKU1', 'OC43']
for dis in diseases:
    for city,(latx, lonx) in regions.items():
        plt.figure()
        
        # odeint
        label = f'{dis}_{city}_odeint'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
        
        # RK4
        label = f'{dis}_{city}_RK4'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
        
        # RK4dt7
        label = f'{dis}_{city}_RK4dt7'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls=':')
        
        # Gabe
        label = f'{dis}_{city}_Gabe'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
        
        plt.legend()
        plt.xlim(0, 1)
        if dis == 'HKU1':
            plt.ylim(None, 0.15)
        elif dis == 'OC43':
            plt.ylim(None, 0.25)
        plt.tight_layout()
        
        figname = f'climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_{dis}_{city}.png'
        plt.savefig(figname)
        print('[saved]:', figname)
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_London.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_NYC.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_LA.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Wuhan.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Delhi.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Maracaibo.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Kinshasa.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Jakarta.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Johannesburg.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Buenos_Aires.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_HKU1_Melbourne.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_London.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_NYC.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_LA.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Wuhan.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Delhi.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Maracaibo.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Kinshasa.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Jakarta.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Johannesburg.png
/tiger/scratch/gpfs/GEOCLIM/wenchang/wython/wystart.py:5: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
  from misc.timer import Timer
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Buenos_Aires.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_firstyear_OC43_Melbourne.png

plot: year 1-3

In [84]:
# plot
diseases = ['HKU1', 'OC43']
for dis in diseases:
    for city,(latx, lonx) in regions.items():
        plt.figure()
        
        # odeint
        label = f'{dis}_{city}_odeint'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
        
        # RK4
        label = f'{dis}_{city}_RK4'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label)
        
        # RK4dt7
        label = f'{dis}_{city}_RK4dt7'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls=':')
        
        # Gabe
        label = f'{dis}_{city}_Gabe'
        ds = dss[label]
        ds.ii.assign_coords(t=ds.year).rename(t='year').plot(label=label, ls='--')
        
        plt.legend()
        plt.xlim(1, 3)
        if dis == 'HKU1':
            plt.ylim(None, 0.15)
        elif dis == 'OC43':
            plt.ylim(None, 0.25)
        plt.tight_layout()
        
        figname = f'climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_{dis}_{city}.png'
        plt.savefig(figname)
        print('[saved]:', figname)
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_London.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_NYC.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_LA.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Wuhan.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Delhi.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Maracaibo.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Kinshasa.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Jakarta.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Johannesburg.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Buenos_Aires.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_HKU1_Melbourne.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_London.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_NYC.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_LA.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Wuhan.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Delhi.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Maracaibo.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Kinshasa.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Jakarta.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Johannesburg.png
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Buenos_Aires.png
/tiger/scratch/gpfs/GEOCLIM/wenchang/wython/wystart.py:5: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
  from misc.timer import Timer
[saved]: climSIRS/figs/R0min1p5_newMERRA2clim_comparison_year1to3_OC43_Melbourne.png

WY

In [132]:
%%html
<script src="https://cdn.rawgit.com/parente/4c3e6936d0d7a46fd071/raw/65b816fb9bdd3c28b4ddf3af602bfd6015486383/code_toggle.js">
</script>