def test_rcm_emanuel(): num_lev = 30 water_depth = 5. # Temperatures in a single column state = climlab.column_state(num_lev=num_lev, water_depth=water_depth) # Initialize a nearly dry column (small background stratospheric humidity) state['q'] = np.ones_like(state.Tatm) * 5.E-6 # ASYNCHRONOUS COUPLING -- the radiation uses a much longer timestep short_timestep = climlab.constants.seconds_per_hour # The top-level model model = climlab.TimeDependentProcess(name='Radiative-Convective Model', state=state, timestep=short_timestep) # Radiation coupled to water vapor rad = climlab.radiation.RRTMG(name='Radiation', state=state, specific_humidity=state.q, albedo=0.3, timestep=24*short_timestep) # Convection scheme -- water vapor is a state variable conv = climlab.convection.EmanuelConvection(name='Convection', state=state, timestep=short_timestep) # Surface heat flux processes shf = climlab.surface.SensibleHeatFlux(name='SHF', state=state, Cd=0.5E-3, timestep=climlab.constants.seconds_per_hour) lhf = climlab.surface.LatentHeatFlux(name='LHF', state=state, Cd=0.5E-3, timestep=short_timestep) # Couple all the submodels together for proc in [rad, conv, shf, lhf]: model.add_subprocess(proc.name, proc) model.step_forward() to_xarray(model)
def test_radiative_forcing(): '''Run a single-column radiative-convective model with RRTMG radiation out to equilibrium. Clone the model, double CO2 and measure the instantaneous change in TOA flux. It should be positive net downward flux.''' # State variables (Air and surface temperature) state = climlab.column_state(num_lev=30, water_depth=1.) # Parent model process rcm = climlab.TimeDependentProcess(state=state) # Fixed relative humidity h2o = climlab.radiation.ManabeWaterVapor(state=state) # Couple water vapor to radiation # Set icld=0 for clear-sky only (no need to call cloud overlap routine) rad = climlab.radiation.RRTMG(state=state, specific_humidity=h2o.q, icld=0) # Convective adjustment conv = climlab.convection.ConvectiveAdjustment(state=state, adj_lapse_rate=6.5) # Couple everything together rcm.add_subprocess('Radiation', rad) rcm.add_subprocess('WaterVapor', h2o) rcm.add_subprocess('Convection', conv) rcm.integrate_years(5.) assert np.abs(rcm.ASR - rcm.OLR) < 0.1 # close to energy balance rcm2 = climlab.process_like(rcm) rcm2.subprocess['Radiation'].absorber_vmr['CO2'] *= 2. rcm2.compute_diagnostics() assert (rcm2.ASR - rcm2.OLR) > 1. # positive radiative forcing # Test the xarray interface to_xarray(rcm2)
def test_latitude(): ''' Run a radiative equilibrum model with RRTMG radiation out to equilibrium with an annual mean insolation profile as a function of latitude. ''' num_lat = 8 # State variables (Air and surface temperature) state = climlab.column_state(num_lev=30, num_lat=num_lat, water_depth=1.) # Parent model process model = climlab.TimeDependentProcess(state=state) # insolation sol = climlab.radiation.AnnualMeanInsolation(domains=model.Ts.domain) # radiation module with insolation as input # Set icld=0 for clear-sky only (no need to call cloud overlap routine) rad = climlab.radiation.RRTMG(state=state, icld=0, S0=sol.S0, insolation=sol.insolation, coszen=sol.coszen) # Couple everything together model.add_subprocess('Radiation', rad) model.add_subprocess('Insolation', sol) # Run out to equilibrium model.integrate_years(2.) # Test for energy balance assert np.all(np.abs(model.ASR - model.OLR) < 0.1) # Test for reasonable surface temperature gradient # reversal of gradient at equator grad = np.diff(model.Ts, axis=0) assert np.all(grad[0:(int(num_lat/2)-1)] > 0.) assert np.all(grad[int(num_lat/2):] < 0.)
## climlab setup # create surface and atmosperic domains sfc, atm = climlab.domain.single_column(lev=g.p / 100.) # create atmosheric state state = AttrDict() # assign surface temperature and vertical temperature profiles Ts_ = climlab.Field(np.array([Ts]), domain=sfc) state['Ts'] = Ts_ Tatm = climlab.Field(g.T, domain=atm) state['Tatm'] = Tatm # Parent model process rcm = climlab.TimeDependentProcess(state=state) rad = climlab.radiation.RRTMG(state=state, specific_humidity=g.q, albedo=0.3, ozone_file=None) rad.subprocess['LW'].absorber_vmr = { 'CO2': CO2 * 1.e-6, 'CH4': 0., 'N2O': 0., 'O2': 0., 'CFC11': 0., 'CFC12': 0., 'CFC22': 0., 'CCL4': 0., 'O3': 0. }
def init_ram_no_advection( ds, m, CO2, timestep, surface_diffk=None, albedo=.77 #<- calculated value vs. first estimate = .8 ): #create two domains: atm and surface sfc, atm = climlab.domain.single_column( lev=ds['Pressure'].sel(month=m).values, water_depth=1.) #create an atmospheric state state = AttrDict() #set up a surface temperature profile Ts_dict = {} for month in ds['month'].values: Ts_dict[month] = (ds['Temperature'].sel(month=month)[-1] - 52 * (ds['Temperature'].sel(month=month)[-2] - ds['Temperature'].sel(month=month)[-1]) / (ds['Altitude'].sel(month=month)[-2] - ds['Altitude'].sel(month=month)[-1])).values T_s = climlab.Field(Ts_dict[m], domain=sfc) state['Ts'] = T_s #K #set up an atmospheric temperature profile T_atm = climlab.Field(ds['Temperature'].sel(month=m).values, domain=atm) state['Tatm'] = T_atm #K #radiation model setup rad = climlab.radiation.RRTMG( name='Radiation(all gases)', state=state, specific_humidity=ds['spec_humidity'].sel(month=m).values, albedo=albedo, timestep=timestep, ozone_file=None, S0=1365.2, insolation=ds['monthly_insolation'].sel(month=m).values, isolvar= 1 #see https://climlab.readthedocs.io/en/latest/_modules/climlab/radiation/rrtm/rrtmg_sw.html#RRTMG_SW._compute_heating_rates #1 = Solar variability (using NRLSSI2 solar # model) with solar cycle contribution # determined by fraction of solar cycle # with facular and sunspot variations # fixed to their mean variations over the # average of Solar Cycles 13-24; # two amplitude scale factors allow # facular and sunspot adjustments from # mean solar cycle as defined by indsolvar ) rad.absorber_vmr['O3'] = ds['O3'].sel(month=m).values #kg/kg rad.absorber_vmr['CO2'] = CO2 #kg/kg #create ram ram = climlab.TimeDependentProcess(state=state, timestep=timestep) #add latitude axis lat = climlab.domain.axis.Axis(axis_type='lat', points=-90.) ram.domains['Ts'].axes['lat'] = lat #add radiation ram.add_subprocess('Radiation', rad) #compute ram ram.compute() #turbulence model setup (coupled to rad model, ds, and month) turb = Turbulence(surface_diffk=surface_diffk, name='Turbulence', state=state, rad=rad, m=m, ds=ds, timestep=timestep) #add turbulence ram.add_subprocess('Turbulence', turb) #add insolation subprocess #compute ram ram.compute() return ram
def init_ram( ds, m, CO2, timestep, turbulence_on, advection_on, advection=None, surface_diffk=None, albedo=.77 #<- calculated value vs. first estimate = .8 ): #create two domains: atm and surface sfc, atm = climlab.domain.single_column( lev=ds['Pressure'].sel(month=m).values, water_depth=1.) #change the level bounds atm.axes['lev'].bounds[0] = atm.axes['lev'].bounds[1] - 2 * ( atm.axes['lev'].bounds[1] - atm.axes['lev'].points[0]) atm.axes['lev'].bounds[-1] = atm.axes['lev'].bounds[-2] + 2 * ( atm.axes['lev'].points[-1] - atm.axes['lev'].bounds[-2]) #change the level delta atm.axes['lev'].delta = atm.axes['lev'].bounds[1:] - atm.axes[ 'lev'].bounds[0:-1] #update heat capacity atm.set_heat_capacity() #create an atmospheric state state = AttrDict() #set up a surface temperature profile Ts_dict = {} for month in ds['month'].values: Ts_dict[month] = (ds['Temperature'].sel(month=month)[-1] - 52 * (ds['Temperature'].sel(month=month)[-2] - ds['Temperature'].sel(month=month)[-1]) / (ds['Altitude'].sel(month=month)[-2] - ds['Altitude'].sel(month=month)[-1])).values T_s = climlab.Field(Ts_dict[m], domain=sfc) state['Ts'] = T_s #K #set up an atmospheric temperature profile T_atm = climlab.Field(ds['Temperature'].sel(month=m).values, domain=atm) state['Tatm'] = T_atm #K #radiation model setup rad = climlab.radiation.RRTMG( name='Radiation(all gases)', state=state, specific_humidity=ds['spec_humidity'].sel(month=m).values, albedo=albedo, timestep=timestep, ozone_file=None, S0=1365.2, insolation=ds['monthly_insolation'].sel(month=m).values, isolvar= 1 #see https://climlab.readthedocs.io/en/latest/_modules/climlab/radiation/rrtm/rrtmg_sw.html#RRTMG_SW._compute_heating_rates #1 = Solar variability (using NRLSSI2 solar # model) with solar cycle contribution # determined by fraction of solar cycle # with facular and sunspot variations # fixed to their mean variations over the # average of Solar Cycles 13-24; # two amplitude scale factors allow # facular and sunspot adjustments from # mean solar cycle as defined by indsolvar ) rad.absorber_vmr['O3'] = ds['O3'].sel(month=m).values #kg/kg rad.absorber_vmr['CO2'] = CO2 #kg/kg #create ram ram = climlab.TimeDependentProcess(state=state, timestep=timestep) #add latitude axis lat = climlab.domain.axis.Axis(axis_type='lat', points=-90.) ram.domains['Ts'].axes['lat'] = lat #add radiation ram.add_subprocess('Radiation', rad) #compute ram ram.compute() if turbulence_on == True: #turbulence model setup (coupled to rad model, ds, and month) turb = Turbulence(surface_diffk=surface_diffk, name='Turbulence', state=state, rad=rad, m=m, ds=ds, timestep=timestep) #add turbulence ram.add_subprocess('Turbulence', turb) #add insolation subprocess #compute ram ram.compute() if turbulence_on == False: turb = None if advection_on: #advective model setup (coupled to rad model) adv = climlab.process.external_forcing.ExternalForcing(state=state, ram=ram, turb=turb) if turbulence_on: normal_advection = -( (ram.TdotSW_clr + ram.TdotLW_clr) / climlab.constants.seconds_per_day + turb.turb_atm_hr ) #(K/day + K/day)/(sec/day) + K/sec if advection == None: adv.forcing_tendencies['Tatm'] = normal_advection else: adv.forcing_tendencies['Tatm'] = np.copy(advection[m]) #add advection ram.add_subprocess('Advection', adv) #compute ram ram.compute() return ram