Source code for climlab.model.column

"""Object-oriented code for radiative-convective models with grey-gas radiation.

Code developed by Brian Rose, University at Albany
brose@albany.edu

Note that the column models by default represent global, time averages.
Thus the insolation is a prescribed constant.

Here is an example to implement seasonal insolation at 45 degrees North

    :Example:

        .. code-block:: python

            import climlab

            #  create the column model object
            col = climlab.GreyRadiationModel()

            #  create a new latitude axis with a single point
            lat = climlab.domain.Axis(axis_type='lat', points=45.)

            #  add this new axis to the surface domain
            col.Ts.domain.axes['lat'] = lat

            #  create a new insolation process using this domain
            Q = climlab.radiation.insolation.DailyInsolation(domains=col.Ts.domain, **col.param)

            #  replace the fixed insolation subprocess in the column model
            col.add_subprocess('insolation', Q)


This model is now a single column with seasonally varying insolation
calculated for 45N.

"""
from __future__ import division
import numpy as np
from climlab import constants as const
from climlab.process.time_dependent_process import TimeDependentProcess
from climlab.domain.initial import column_state
from climlab.domain.field import Field
from climlab.radiation.insolation import FixedInsolation
from climlab.radiation.greygas import GreyGas, GreyGasSW
from climlab.convection.convadj import ConvectiveAdjustment
from climlab.radiation.nband import ThreeBandSW, FourBandLW, FourBandSW
from climlab.radiation.water_vapor import ManabeWaterVapor

[docs] class GreyRadiationModel(TimeDependentProcess): def __init__(self, num_lev=30, num_lat=1, lev=None, lat=None, water_depth=1.0, albedo_sfc=0.299, timestep=1. * const.seconds_per_day, Q=341.3, # absorption coefficient in m**2 / kg abs_coeff=1.229E-4, **kwargs): # Check to see if an initial state is already provided # If not, make one if 'state' not in kwargs: state = column_state(num_lev, num_lat, lev, lat, water_depth) kwargs.update({'state': state}) super(GreyRadiationModel, self).__init__(timestep=timestep, **kwargs) self.param['water_depth'] = water_depth self.param['albedo_sfc'] = albedo_sfc self.param['Q'] = Q self.param['abs_coeff'] = abs_coeff sfc = self.Ts.domain atm = self.Tatm.domain # create sub-models for longwave and shortwave radiation dp = self.Tatm.domain.lev.delta absorbLW = compute_layer_absorptivity(self.param['abs_coeff'], dp) absorbLW = Field(np.tile(absorbLW, sfc.shape), domain=atm) absorbSW = np.zeros_like(absorbLW) longwave = GreyGas(state=self.state, absorptivity=absorbLW, albedo_sfc=0) shortwave = GreyGasSW(state=self.state, absorptivity=absorbSW, albedo_sfc=self.param['albedo_sfc']) # sub-model for insolation ... here we just set constant Q thisQ = self.param['Q']*np.ones_like(self.Ts) Q = FixedInsolation(S0=thisQ, domains=sfc, **self.param) self.add_subprocess('LW', longwave) self.add_subprocess('SW', shortwave) self.add_subprocess('insolation', Q) newdiags = ['OLR', 'LW_down_sfc', 'LW_up_sfc', 'LW_absorbed_sfc', 'LW_absorbed_atm', 'LW_emission', 'ASR', 'SW_absorbed_sfc', 'SW_absorbed_atm', 'SW_up_sfc', 'SW_up_TOA', 'SW_down_TOA', 'planetary_albedo'] for name in newdiags: self.add_diagnostic(name) # This process has to handle the coupling between # insolation and column radiation self.subprocess['SW'].flux_from_space = \ self.subprocess['insolation'].diagnostics['insolation'] def _compute(self): # set diagnostics self.do_diagnostics() # no tendencies for the parent process tendencies = {} for name, var in self.state.items(): tendencies[name] = var * 0. return tendencies
[docs] def do_diagnostics(self): '''Set all the diagnostics from long and shortwave radiation.''' self.OLR = self.subprocess['LW'].flux_to_space self.LW_down_sfc = self.subprocess['LW'].flux_to_sfc self.LW_up_sfc = self.subprocess['LW'].flux_from_sfc self.LW_absorbed_sfc = self.LW_down_sfc - self.LW_up_sfc self.LW_absorbed_atm = self.subprocess['LW'].absorbed self.LW_emission = self.subprocess['LW'].emission # contributions to OLR from surface and atm. levels #self.diagnostics['OLR_sfc'] = self.flux['sfc2space'] #self.diagnostics['OLR_atm'] = self.flux['atm2space'] self.ASR = (self.subprocess['SW'].flux_from_space - self.subprocess['SW'].flux_to_space) #self.SW_absorbed_sfc = (self.subprocess['surface'].SW_from_atm - # self.subprocess['surface'].SW_to_atm) self.SW_absorbed_atm = self.subprocess['SW'].absorbed self.SW_down_sfc = self.subprocess['SW'].flux_to_sfc self.SW_up_sfc = self.subprocess['SW'].flux_from_sfc self.SW_absorbed_sfc = self.SW_down_sfc - self.SW_up_sfc self.SW_up_TOA = self.subprocess['SW'].flux_to_space self.SW_down_TOA = self.subprocess['SW'].flux_from_space self.planetary_albedo = (self.subprocess['SW'].flux_to_space / self.subprocess['SW'].flux_from_space)
[docs] class RadiativeConvectiveModel(GreyRadiationModel): def __init__(self, # lapse rate for convective adjustment, in K / km adj_lapse_rate=6.5, **kwargs): super(RadiativeConvectiveModel, self).__init__(**kwargs) self.param['adj_lapse_rate'] = adj_lapse_rate self.add_subprocess('convective adjustment', \ ConvectiveAdjustment(state=self.state, **self.param))
[docs] class BandRCModel(RadiativeConvectiveModel): def __init__(self, **kwargs): super(BandRCModel, self).__init__(**kwargs) # Initialize specific humidity h2o = ManabeWaterVapor(state=self.state, **self.param) self.add_subprocess('H2O', h2o) # q is an input field for this process, which is set by subproc # (though in this sense it is actually diagnostic...) newinput = ['q'] self.add_input('q') self.q = self.subprocess['H2O'].q # initialize radiatively active gas inventories self.absorber_vmr = {} self.absorber_vmr['CO2'] = 380.E-6 * np.ones_like(self.Tatm) self.absorber_vmr['O3'] = np.zeros_like(self.Tatm) # water vapor is actually specific humidity, not VMR. self.absorber_vmr['H2O'] = self.q longwave = FourBandLW(state=self.state, absorber_vmr=self.absorber_vmr, albedo_sfc=0.) shortwave = ThreeBandSW(state=self.state, absorber_vmr=self.absorber_vmr, emissivity_sfc=0., albedo_sfc=self.param['albedo_sfc']) self.add_subprocess('LW', longwave) self.add_subprocess('SW', shortwave) # This process has to handle the coupling between # insolation and column radiation self.subprocess['SW'].flux_from_space = \ self.subprocess['insolation'].diagnostics['insolation']
[docs] def compute_layer_absorptivity(abs_coeff, dp): '''Compute layer absorptivity from a constant absorption coefficient.''' return (2. / (1 + 2. * const.g / abs_coeff / (dp * const.mb_to_Pa)))