Latitude-dependent grey radiation

Here is a quick example of using the climlab.GreyRadiationModel with a latitude dimension and seasonally varying insolation.


In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import climlab

In [2]:
np.__version__


Out[2]:
'1.10.4'

In [3]:
model = climlab.GreyRadiationModel(num_lev=30, num_lat=90)
print model


climlab Process of type <class 'climlab.model.column.GreyRadiationModel'>. 
State variables and domain shapes: 
  Tatm: (90, 30) 
  Ts: (90, 1) 
The subprocess tree: 
top: <class 'climlab.model.column.GreyRadiationModel'>
   LW: <class 'climlab.radiation.greygas.GreyGas'>
   SW: <class 'climlab.radiation.greygas.GreyGasSW'>
   insolation: <class 'climlab.radiation.insolation.FixedInsolation'>


In [4]:
print model.lat


[-89. -87. -85. -83. -81. -79. -77. -75. -73. -71. -69. -67. -65. -63. -61.
 -59. -57. -55. -53. -51. -49. -47. -45. -43. -41. -39. -37. -35. -33. -31.
 -29. -27. -25. -23. -21. -19. -17. -15. -13. -11.  -9.  -7.  -5.  -3.  -1.
   1.   3.   5.   7.   9.  11.  13.  15.  17.  19.  21.  23.  25.  27.  29.
  31.  33.  35.  37.  39.  41.  43.  45.  47.  49.  51.  53.  55.  57.  59.
  61.  63.  65.  67.  69.  71.  73.  75.  77.  79.  81.  83.  85.  87.  89.]

In [5]:
insolation = climlab.radiation.insolation.DailyInsolation(domains=model.Ts.domain)

In [6]:
model.add_subprocess('insolation', insolation)
model.subprocess.SW.flux_from_space = insolation.insolation

In [7]:
print model


climlab Process of type <class 'climlab.model.column.GreyRadiationModel'>. 
State variables and domain shapes: 
  Tatm: (90, 30) 
  Ts: (90, 1) 
The subprocess tree: 
top: <class 'climlab.model.column.GreyRadiationModel'>
   LW: <class 'climlab.radiation.greygas.GreyGas'>
   SW: <class 'climlab.radiation.greygas.GreyGasSW'>
   insolation: <class 'climlab.radiation.insolation.DailyInsolation'>


In [8]:
model.step_forward()

In [9]:
plt.plot(model.lat, model.SW_down_TOA)


Out[9]:
[<matplotlib.lines.Line2D at 0x111bafd90>]

In [10]:
model.Tatm.shape


Out[10]:
(90, 30)

In [11]:
model.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 1.00207478763 years.
/Users/br546577/code/climlab/climlab/model/column.py:127: RuntimeWarning: divide by zero encountered in divide
  self.subprocess['SW'].flux_from_space)

In [12]:
plt.plot(model.lat, model.Ts)


Out[12]:
[<matplotlib.lines.Line2D at 0x111c9bf10>]

In [13]:
model.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 2.00141166601 years.

In [14]:
plt.plot(model.lat, model.timeave['Ts'])


Out[14]:
[<matplotlib.lines.Line2D at 0x111dd4ed0>]

In [15]:
def plot_temp_section(model, timeave=True):
    fig = plt.figure()
    ax = fig.add_subplot(111)
    if timeave:
        field = model.timeave['Tatm'].transpose()
    else:
        field = model.Tatm.transpose()
    cax = ax.contourf(model.lat, model.lev, field)
    ax.invert_yaxis()
    ax.set_xlim(-90,90)
    ax.set_xticks([-90, -60, -30, 0, 30, 60, 90])
    fig.colorbar(cax)

In [16]:
plot_temp_section(model)



In [17]:
model2 = climlab.RadiativeConvectiveModel(num_lev=30, num_lat=90)
insolation = climlab.radiation.insolation.DailyInsolation(domains=model2.Ts.domain)
model2.add_subprocess('insolation', insolation)
model2.subprocess.SW.flux_from_space = insolation.insolation

In [18]:
model2.step_forward()

In [19]:
model2.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 1.00207478763 years.

In [20]:
model2.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 2.00141166601 years.

In [21]:
plot_temp_section(model2)


Testing out multi-dimensional Band Models


In [22]:
import climlab
import numpy as np

#  Put in some ozone
import netCDF4 as nc

datapath = "http://ramadda.atmos.albany.edu:8080/repository/opendap/latest/Top/Users/Brian+Rose/CESM+runs/"
endstr = "/entry.das"

topo = nc.Dataset( datapath + 'som_input/USGS-gtopo30_1.9x2.5_remap_c050602.nc' + endstr )
ozone = nc.Dataset( datapath + 'som_input/ozone_1.9x2.5_L26_2000clim_c091112.nc' + endstr )

#  Dimensions of the ozone file
lat = ozone.variables['lat'][:]
lon = ozone.variables['lon'][:]
lev = ozone.variables['lev'][:]

# Taking annual, zonal average of the ozone data
O3_zon = np.mean( ozone.variables['O3'],axis=(0,3) )

In [23]:
import climlab
import numpy as np
#  make a model on the same grid as the ozone
model3 = climlab.BandRCModel(lev=lev, lat=lat)
insolation = climlab.radiation.insolation.DailyInsolation(domains=model3.Ts.domain)
model3.add_subprocess('insolation', insolation)
model3.subprocess.SW.flux_from_space = insolation.insolation
print model3


climlab Process of type <class 'climlab.model.column.BandRCModel'>. 
State variables and domain shapes: 
  Tatm: (96, 26) 
  Ts: (96, 1) 
The subprocess tree: 
top: <class 'climlab.model.column.BandRCModel'>
   LW: <class 'climlab.radiation.nband.FourBandLW'>
   H2O: <class 'climlab.radiation.water_vapor.ManabeWaterVapor'>
   convective adjustment: <class 'climlab.convection.convadj.ConvectiveAdjustment'>
   SW: <class 'climlab.radiation.nband.ThreeBandSW'>
   insolation: <class 'climlab.radiation.insolation.DailyInsolation'>


In [24]:
#  Set the ozone mixing ratio
O3_trans = np.transpose(O3_zon)
#  model and ozone data are on the same grid, after the transpose.
print O3_trans.shape
print lev
print model3.lev


(96, 26)
[   3.544638     7.3888135   13.967214    23.944625    37.23029     53.114605
   70.05915     85.439115   100.514695   118.250335   139.115395   163.66207
  192.539935   226.513265   266.481155   313.501265   368.81798    433.895225
  510.455255   600.5242     696.79629    787.70206    867.16076    929.648875
  970.55483    992.5561   ]
[   3.544638     7.3888135   13.967214    23.944625    37.23029     53.114605
   70.05915     85.439115   100.514695   118.250335   139.115395   163.66207
  192.539935   226.513265   266.481155   313.501265   368.81798    433.895225
  510.455255   600.5242     696.79629    787.70206    867.16076    929.648875
  970.55483    992.5561   ]

In [25]:
# Put in the ozone
model3.absorber_vmr['O3'] = O3_trans

In [26]:
print model3.absorber_vmr['O3'].shape
print model3.Tatm.shape


(96, 26)
(96, 26)

In [27]:
model3.step_forward()

In [28]:
model3.integrate_years(1.)


Integrating for 365 steps, 365.2422 days, or 1.0 years.
Total elapsed time is 1.00207478763 years.

In [29]:
model3.integrate_years(1.)


Integrating for 365 steps, 365.2422 days, or 1.0 years.
Total elapsed time is 2.00141166601 years.

In [30]:
#plt.contour(model3.lat, model3.lev, model3.Tatm.transpose())
plot_temp_section(model3)


This is now working. Will need to do some model tuning.

And start to add dynamics!


In [31]:
testmodel = climlab.BandRCModel(num_lat=90, num_lev=30)

In [32]:
testmodel.step_forward()
testmodel.step_forward()
testmodel.step_forward()

In [33]:
%timeit testmodel.step_forward()


100 loops, best of 3: 11.6 ms per loop

In [34]:
np.__version__


Out[34]:
'1.10.4'

Definitely get better performance with numpy version 1.9 and above due to vectorization of numpy.tril() (lower triangle operator) for multi-dimensional arrays.

Experimental... adding meridional diffusion!


In [35]:
print model2


climlab Process of type <class 'climlab.model.column.RadiativeConvectiveModel'>. 
State variables and domain shapes: 
  Tatm: (90, 30) 
  Ts: (90, 1) 
The subprocess tree: 
top: <class 'climlab.model.column.RadiativeConvectiveModel'>
   convective adjustment: <class 'climlab.convection.convadj.ConvectiveAdjustment'>
   LW: <class 'climlab.radiation.greygas.GreyGas'>
   SW: <class 'climlab.radiation.greygas.GreyGasSW'>
   insolation: <class 'climlab.radiation.insolation.DailyInsolation'>


In [36]:
diffmodel = climlab.process_like(model2)

In [37]:
# thermal diffusivity in W/m**2/degC
D = 0.05
# meridional diffusivity in 1/s
K = D / diffmodel.Tatm.domain.heat_capacity[0]
print K


1.46414342629e-07

In [38]:
d = climlab.dynamics.diffusion.MeridionalDiffusion(K=K, state={'Tatm': diffmodel.state['Tatm']}, **diffmodel.param)

In [39]:
diffmodel.add_subprocess('diffusion', d)

In [40]:
print diffmodel


climlab Process of type <class 'climlab.model.column.RadiativeConvectiveModel'>. 
State variables and domain shapes: 
  Tatm: (90, 30) 
  Ts: (90, 1) 
The subprocess tree: 
top: <class 'climlab.model.column.RadiativeConvectiveModel'>
   convective adjustment: <class 'climlab.convection.convadj.ConvectiveAdjustment'>
   LW: <class 'climlab.radiation.greygas.GreyGas'>
   diffusion: <class 'climlab.dynamics.diffusion.MeridionalDiffusion'>
   SW: <class 'climlab.radiation.greygas.GreyGasSW'>
   insolation: <class 'climlab.radiation.insolation.DailyInsolation'>


In [41]:
diffmodel.step_forward()

In [42]:
diffmodel.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 3.00348645365 years.

In [43]:
diffmodel.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 4.00282333202 years.

In [44]:
plot_temp_section(model2)
plot_temp_section(diffmodel)


Amazingly... this actually works!

As long as K is a constant.

The diffusion operation is broadcast over all vertical levels without any special code.


In [45]:
def inferred_heat_transport( energy_in, lat_deg ):
    '''Returns the inferred heat transport (in PW) by integrating the net energy imbalance from pole to pole.'''
    from scipy import integrate
    from climlab import constants as const
    lat_rad = np.deg2rad( lat_deg )
    return ( 1E-15 * 2 * np.math.pi * const.a**2 * integrate.cumtrapz( np.cos(lat_rad)*energy_in,
            x=lat_rad, initial=0. ) )

In [46]:
#  Plot the northward heat transport in this model
Rtoa = np.squeeze(diffmodel.timeave['ASR'] - diffmodel.timeave['OLR'])
plt.plot(diffmodel.lat, inferred_heat_transport(Rtoa, diffmodel.lat))


Out[46]:
[<matplotlib.lines.Line2D at 0x11515ac50>]

Band model with diffusion


In [47]:
diffband = climlab.process_like(model3)

In [48]:
# thermal diffusivity in W/m**2/degC
D = 0.05
# meridional diffusivity in 1/s
K = D / diffband.Tatm.domain.heat_capacity[0]
print K


8.92760732994e-07

In [49]:
d = climlab.dynamics.diffusion.MeridionalDiffusion(K=K, state={'Tatm': diffband.state['Tatm']}, **diffband.param)
diffband.add_subprocess('diffusion', d)
print diffband


climlab Process of type <class 'climlab.model.column.BandRCModel'>. 
State variables and domain shapes: 
  Tatm: (96, 26) 
  Ts: (96, 1) 
The subprocess tree: 
top: <class 'climlab.model.column.BandRCModel'>
   diffusion: <class 'climlab.dynamics.diffusion.MeridionalDiffusion'>
   LW: <class 'climlab.radiation.nband.FourBandLW'>
   H2O: <class 'climlab.radiation.water_vapor.ManabeWaterVapor'>
   convective adjustment: <class 'climlab.convection.convadj.ConvectiveAdjustment'>
   SW: <class 'climlab.radiation.nband.ThreeBandSW'>
   insolation: <class 'climlab.radiation.insolation.DailyInsolation'>


In [50]:
diffband.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 3.00074854439 years.

In [51]:
diffband.integrate_years(1)


Integrating for 365 steps, 365.2422 days, or 1 years.
Total elapsed time is 4.00008542277 years.

In [52]:
plot_temp_section(model3)
plot_temp_section(diffband)



In [53]:
plt.plot(diffband.lat, diffband.timeave['ASR'] - diffband.timeave['OLR'])


Out[53]:
[<matplotlib.lines.Line2D at 0x115add290>]

In [54]:
#  Plot the northward heat transport in this model
Rtoa = np.squeeze(diffband.timeave['ASR'] - diffband.timeave['OLR'])
plt.plot(diffband.lat, inferred_heat_transport(Rtoa, diffband.lat))


Out[54]:
[<matplotlib.lines.Line2D at 0x1157d6690>]

In [ ]: