def heat_capacity(q): Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') Cvap = get_constant('heat_capacity_of_vapor_phase', 'J/kg/K') return Cpd * (1 - q) + Cvap * q
def _update_constants(self): self._radius = get_constant('planetary_radius', 'm') self._omega = get_constant('planetary_rotation_rate', 's^-1') self._R = get_constant('universal_gas_constant', 'J/mole/K') self._Rd = get_constant('gas_constant_of_dry_air', 'J/kg/K') self._Rv = get_constant('gas_constant_of_vapor_phase', 'J/kg/K') self._g = get_constant('gravitational_acceleration', 'm/s^2') self._Cp = get_constant( 'heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/K') self._Cvap = get_constant('heat_capacity_of_vapor_phase', 'J/kg/K') self._fvirt = (1 - self._Rd / self._Rv) / (self._Rd / self._Rv) self._dry_pressure = get_constant('reference_air_pressure', 'Pa') self._toa_pressure = get_constant('top_of_model_pressure', 'Pa')
def get_moist_enthalpy(state): Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') Lv = get_constant('latent_heat_of_condensation', 'J/kg') dry_enthalpy = vertical_integral( state, Cpd * state['air_temperature'].to_units('degK')) moisture_enthalpy = 0.0 if 'specific_humidity' in state: moisture_enthalpy = vertical_integral( state, Lv * state['specific_humidity'].to_units('kg/kg')) return dry_enthalpy + moisture_enthalpy
def _update_constants(self): self._Kice = get_constant('thermal_conductivity_of_solid_phase_as_ice', 'W/m/degK') self._Ksnow = get_constant('thermal_conductivity_of_solid_phase_as_snow', 'W/m/degK') self._rho_ice = get_constant('density_of_solid_phase_as_ice', 'kg/m^3') self._C_ice = get_constant('heat_capacity_of_solid_phase_as_ice', 'J/kg/degK') self._rho_snow = get_constant('density_of_solid_phase_as_snow', 'kg/m^3') self._C_snow = get_constant('heat_capacity_of_solid_phase_as_snow', 'J/kg/degK') self._Lf = get_constant('latent_heat_of_fusion', 'J/kg') self._temp_melt = get_constant('freezing_temperature_of_liquid_phase', 'degK')
def array_call(self, state): model_top_pressure = get_constant('top_of_model_pressure', 'Pa') p_interface = ( state['a_coord'] + state['b_coord'] * (state['surface_air_pressure'][None, :] - model_top_pressure)) delta_p = p_interface[1:, :] - p_interface[:-1, :] Rd = get_constant('gas_constant_of_dry_air', 'J kg^-1 K^-1') Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J kg^-1 K^-1') rk = Rd / Cpd p = ((p_interface[1:, :]**(rk + 1) - p_interface[:-1, :]**(rk + 1)) / ((rk + 1) * delta_p))**(1. / rk) assert not np.any(np.isnan(p)) return { 'air_pressure': p, 'air_pressure_on_interface_levels': p_interface, }
def array_call(self, state): (downward_flux, upward_flux, net_lw_flux, lw_temperature_tendency, tau) = get_longwave_fluxes( state['sl'], state['p_interface'], state['T_surface'], state['tau'], get_constant('stefan_boltzmann_constant', 'W/m^2/K^4'), get_constant('gravitational_acceleration', 'm/s^2'), get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/K')) tendencies = { 'sl': lw_temperature_tendency, } diagnostics = { 'lw_down': downward_flux, 'lw_up': upward_flux, 'longwave_heating_rate': lw_temperature_tendency * 86400. } return tendencies, diagnostics
def array_call(self, state): toa_pressure = get_constant('top_of_model_pressure', 'Pa') rd = get_constant('gas_constant_of_dry_air', 'J kg^-1 K^-1') cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J kg^-1 K^-1') longitude = np.radians(state['longitude']) latitude = np.radians(state['latitude']) diagnostics = initialize_numpy_arrays_with_properties( self.diagnostic_properties, state, self.input_properties) if self._condition_type is 'baroclinic_wave': u, v, t, q, p_surface, phi_surface = _dcmip.get_baroclinic_wave_ics( state['air_pressure'], longitude, latitude, perturb=self._add_perturbation, moist_sim=self._moist) elif self._condition_type is 'tropical_cyclone': u, v, t, q, p_surface, phi_surface = _dcmip.get_tropical_cyclone_ics( state['air_pressure'], longitude, latitude, perturb=self._add_perturbation, moist_sim=self._moist) diagnostics['eastward_wind'][:] = u diagnostics['northward_wind'][:] = v diagnostics['air_temperature'][:] = t diagnostics['surface_geopotential'][:] = phi_surface diagnostics['specific_humidity'][:] = q diagnostics['surface_air_pressure'][:] = p_surface p_interface = (state['ak'] + state['bk'] * (p_surface - toa_pressure)) delta_p = p_interface[1:, :] - p_interface[:-1, :] rk = rd / cpd diagnostics['air_pressure_on_interface_levels'][:] = p_interface diagnostics['air_pressure'][:] = ( (p_interface[1:, :]**(rk + 1) - p_interface[:-1, :]**(rk + 1)) / ((rk + 1) * delta_p))**(1. / rk) return diagnostics
def test_adding_constant(): set_constants_from_dict(sample_constants) for constant in sample_constants.keys(): constant_value = get_constant(constant, sample_constants[constant]['units']) assert constant_value == sample_constants[constant]['value']
def _set_fortran_constants(self): self._g = get_constant('gravitational_acceleration', 'm/s^2') self._Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') self._Rair = get_constant('gas_constant_of_dry_air', 'J/kg/degK') self._Rcond = get_constant('gas_constant_of_vapor_phase', 'J/kg/degK') self._radius = get_constant('planetary_radius', 'm') self._Omega = get_constant('planetary_rotation_rate', 's^-1') self._Lv = get_constant('latent_heat_of_condensation', 'J/kg') self._rho_condensible = get_constant('density_of_liquid_water', 'kg/m^3') phys.set_physical_constants(self._g, self._Cpd, self._Rair, self._Lv, self._Rcond, self._radius, self._Omega, self._rho_condensible, self._pbl_top, self._delta_pbl, self._Ct, self._Cd0, self._Cd1, self._Cm)
def _update_constants(self): self._Cpd = get_constant( 'heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') self._Lv = get_constant('latent_heat_of_condensation', 'J/kg') self._Rd = get_constant('gas_constant_of_dry_air', 'J/kg/degK') self._Rh2O = get_constant('gas_constant_of_vapor_phase', 'J/kg/degK') self._g = get_constant('gravitational_acceleration', 'm/s^2') self._rhow = get_constant('density_of_liquid_phase', 'kg/m^3')
def _update_constants(self): self._p0 = get_constant('reference_air_pressure', 'Pa') self._Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') self._R_d = get_constant('gas_constant_of_dry_air', 'J/kg/degK') self._kappa = self._R_d/self._Cpd self._Omega = get_constant('planetary_rotation_rate', 's^-1') self._g = get_constant('gravitational_acceleration', 'm/s^2') self._r_planet = get_constant('planetary_radius', 'm')
def _set_fortran_constants(self): self._g = get_constant('gravitational_acceleration', 'm/s^2') self._Cpd = get_constant( 'heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') self._Cpv = get_constant('heat_capacity_of_vapor_phase', 'J/kg/degK') self._Rdair = get_constant('gas_constant_of_dry_air', 'J/kg/degK') self._Rcond = get_constant('gas_constant_of_vapor_phase', 'J/kg/degK') self._Lv = get_constant('latent_heat_of_condensation', 'J/kg') self._rho_condensible = get_constant('density_of_liquid_phase', 'kg/m^3') self._Cl = get_constant('specific_enthalpy_of_vapor_phase', 'J/kg') _emanuel_convection.init_emanuel_convection( self._min_conv_layer, self._crit_humidity, self._crit_temp, self._entrain_coeff, self._downdraft_area_frac, self._precip_frac_outside_cloud, self._droplet_speed, self._snow_speed, self._rain_evap, self._snow_evap, self._con_mom_txfr, self._dtmax, self._beta, self._alpha, self._mf_damp, self._Cpd, self._Cpv, self._Cl, self._Rcond, self._Rdair, self._Lv, self._g, self._rho_condensible, self._mf_timescale)
def from_u_and_v_winds(lats, lons, ubar, vbar, uprime=None, vprime=None, interp=True, linearized=False, ntrunc=None, idate=None): """ Creates ICs from numpy arrays describing the intial wind field. Args ---- lats : numpy array 1D array of global latitudes (in degrees) lons : numpy array 1D array of global longitudes (in degrees) ubar : numpy array 2D array (nlat, nlon) of mean state zonal winds vbar : numpy array 2D array (nlat, nlon) of mean state meridional winds uprime : numpy array 2D array (nlat, nlon) of perturbation zonal winds vprime : numpy array 2D array (nlat, nlon) of perturbation meridional winds interp : bool If True, fields will be interpolated to a gaussian grid. linearized : bool True if this is a linearized model. ntrunc : int Triangular trunction (e.g., 42 for T42). idate : datetime Foreast initialization date Returns ------- ics : dict Model initial state (a dictionary of DataArrays) """ # Set the init. date if not provided if idate is None: idate = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0) # If only ubar and vbar are provided, then forecast will be nonlinear if uprime is None or vprime is None: uprime = np.zeros(ubar.shape) vprime = np.zeros(vbar.shape) linearized = False # Interpolate to a gaussian grid, if necessary gridlons, gridlats = np.meshgrid(lons, lats) if interp: if ntrunc not in TRUNC_NLATS.keys(): raise ValueError( 'Truncation T{} is not in the dictionary TRUNC_NLATS'.format( ntrunc)) nlat = TRUNC_NLATS[ntrunc] lats, lons, ubar = interp_to_gaussian(gridlats, gridlons, ubar, nlat=nlat, return_latlon=True) vbar = interp_to_gaussian(gridlats, gridlons, vbar, nlat=nlat) if linearized: uprime = interp_to_gaussian(gridlats, gridlons, uprime, nlat=nlat) vprime = interp_to_gaussian(gridlats, gridlons, vprime, nlat=nlat) else: uprime = np.zeros(ubar.shape) vprime = np.zeros(vbar.shape) else: lons, lats = gridlons, gridlats # Get the mean state & perturbation vorticity from the winds s = spharm.Spharmt(lats.shape[1], lats.shape[0], gridtype='gaussian', rsphere=get_constant('planetary_radius', 'm'), legfunc='computed') vortb_spec, _ = s.getvrtdivspec(ubar, vbar, ntrunc=ntrunc) vort_bar = s.spectogrd(vortb_spec) vortp_spec, _ = s.getvrtdivspec(uprime, vprime, ntrunc=ntrunc) vort_prime = s.spectogrd(vortp_spec) # Generate the state return _generate_state(idate, lats, lons, vort_bar, vort_prime, linearized=linearized)
from climt import RRTMGShortwave, RRTMGLongwave, get_default_state from sympl import get_constant prop_cycle = rcParams['axes.prop_cycle'] colors = prop_cycle.by_key()['color'] rad_sw = RRTMGShortwave(mcica=True) state_sw = get_default_state([rad_sw]) rad_lw = RRTMGLongwave(mcica=True) state_lw = get_default_state([rad_lw]) p = state_lw['air_pressure'][:] p_interface = state_lw['air_pressure_on_interface_levels'][:] T = state_lw['air_temperature'][:] R = get_constant('gas_constant_of_dry_air', 'J kg^-1 K^-1') g = get_constant('gravitational_acceleration', 'm s^-2') density = p / (R * T) dz = -np.diff(p_interface, axis=0) / (density * g) # [m] z = np.cumsum(dz) * 10**-3 # [km] ice_density = 0.5 * 10**-3 # [kg m^-3] cloud_base = 10 # [km] cloud_top = 15 # [km] cloud_loc = np.where((z > cloud_base) & (z < cloud_top)) i = 0 for area_fraction in np.arange(0, 1.1, 0.25): mass_ice_array = area_fraction * ice_density * dz for state in state_sw, state_lw: state[ 'mass_content_of_cloud_ice_in_atmosphere_layer'][:] = mass_ice_array state['cloud_area_fraction_in_atmosphere_layer'][
def vertical_integral(state, quantity): g = get_constant('gravitational_acceleration', 'm/s^2') dp = get_pressure_thickness(state) return (quantity * dp / g).sum().values
# -*- coding: utf-8 -*- """ Module containing functions to initialize the model state. """ import numpy as np import spharm from datetime import datetime from sympl import DataArray, get_constant, add_direction_names from .util import gaussian_latlon_grid, interp_to_gaussian Omega = get_constant('planetary_rotation_rate', 's^-1') Re = get_constant('planetary_radius', 'm') TRUNC_NLATS = { 21: 32, 31: 48, 42: 64, 63: 96, 85: 128, 106: 160, 127: 192, 170: 256, 213: 320, 255: 384, 341: 512, 511: 768, 682: 1024, 1365: 2048 }
components_to_height = mb.InputPrincipalComponentsToHeight() height_to_components = mb.InputHeightToPrincipalComponents() test_era5_filename = '/home/twine/data/era5/era5-interp-2016.nc' state = mb.get_era5_state(test_era5_filename, latent=False) state.update( mb.get_era5_forcing(test_era5_filename, i_timestep=0, latent=False)) component_state = height_to_components(state) component_state.update( state) # carry over things like height profile and model time reconstructed_state = components_to_height(component_state) state = mb.AliasDict(state) reconstructed_state = mb.AliasDict(reconstructed_state) Cpd = sp.get_constant('heat_capacity_of_dry_air_at_constant_pressure', units='J/kg/degK') fig, ax = plt.subplots(1, 2) ax[0].plot(state['sl'] / Cpd, state['z'], label='truth') ax[0].plot(reconstructed_state['sl'] / Cpd, state['z'], label='reconstructed') ax[0].legend(loc='best') ax[0].set_title('Liquid Water Static Energy (K)') ax[1].plot(state['rt'], state['z'], label='truth') ax[1].plot(reconstructed_state['rt'], state['z'], label='reconstructed') ax[1].set_title('Total Water Mixing Ratio (kg/kg)') plt.tight_layout() plt.show()
def get_grid(nx=None, ny=None, nz=28, n_ice_interface_levels=10, p_surf_in_Pa=None, p_toa_in_Pa=None, proportion_sigma_levels=0.1, proportion_isobaric_levels=0.25, x_name='longitude', y_name='latitude', latitude_grid='gaussian'): """ Args: nx : int, optional Number of longitudinal points. ny : int, optional Number of latitudinal points. nz : int, optional Number of vertical mid levels. n_ice_interface_levels (int, optional): Number of vertical interface levels to use for ice. Use None to disable the ice vertical grid. p_surf_in_Pa : float, optional Surface pressure in Pa. x_name : str, optional Name of latitudinal dimension y_name : str, optional Name of longitudinal dimension latitude_grid : 'gaussian' or 'regular' Type of spacing to use for the latitudinal grid. Returns: grid_state: dict A model state containing grid quantities. """ if p_surf_in_Pa is None: p_surf_in_Pa = get_constant('reference_air_pressure', 'Pa') if p_toa_in_Pa is None: p_toa_in_Pa = get_constant('top_of_model_pressure', 'Pa') else: set_constant('top_of_model_pressure', p_toa_in_Pa, 'Pa') return_state = get_hybrid_sigma_pressure_levels( nz + 1, p_surf_in_Pa, p_toa_in_Pa, proportion_isobaric_levels, proportion_sigma_levels) return_state['surface_air_pressure'] = DataArray(p_surf_in_Pa, dims=[], attrs={'units': 'Pa'}) return_state['time'] = datetime(2000, 1, 1) return_state.update(HybridSigmaPressureDiagnosticComponent()(return_state)) if nx is not None: return_state['longitude'] = DataArray( np.linspace(0., 360., nx * 2, endpoint=False)[:-1:2], dims=[x_name], attrs={'units': 'degrees_east'}, ) if ny is not None: if latitude_grid.lower() == 'regular': return_state['latitude'] = DataArray( np.linspace(-90., 90., ny * 2 + 1, endpoint=True)[1:-1:2], dims=[y_name], attrs={'units': 'degrees_north'}, ) elif latitude_grid.lower() == 'gaussian': lat, lat_interface = gaussian_latitudes(ny) return_state['latitude'] = DataArray( lat, dims=[y_name], attrs={'units': 'degrees_north'}, ) else: raise ValueError( 'latitude_grid can be either regular or gaussian. ' + 'Other grid types are currently not supported.') if n_ice_interface_levels is not None: return_state['height_on_ice_interface_levels'] = DataArray( np.zeros(n_ice_interface_levels), dims=['ice_interface_levels'], attrs={'units': 'm'}, ) return return_state
def array_call(self, state, time_step): self._Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') self._Cvap = get_constant('heat_capacity_of_vapor_phase', 'J/kg/K') self._Rdair = get_constant('gas_constant_of_dry_air', 'J/kg/degK') self._Pref = get_constant('reference_air_pressure', 'Pa') self._Rv = get_constant('gas_constant_of_vapor_phase', 'J/kg/K') q = state['specific_humidity'] output_arrays = initialize_numpy_arrays_with_properties( self.output_properties, state, self.input_properties ) output_temperature = output_arrays['air_temperature'] output_temperature[:] = state['air_temperature'] output_q = output_arrays['specific_humidity'] output_q[:] = q rd_cp = self.gas_constant(q)/self.heat_capacity(q) theta = state['air_temperature']*(self._Pref/state['air_pressure'])**rd_cp num_levels = q.shape[0] for column in range(q.shape[-1]): for level in range(num_levels-1, -1, -1): dp = state['P_int'][:-1, column] - state['P_int'][1:, column] theta_q = theta*(1 + output_q*self._Rv/self._Rdair - output_q) theta_sum = np.cumsum(theta_q[level::, column]) divisor = np.arange(1, num_levels - level+1) theta_avg = (theta_sum/divisor)[1::] theta_lesser = (theta_avg > theta_q[level+1::, column]) if np.sum(theta_lesser) == 0: continue convect_to_level = len(theta_lesser) - np.argmax(theta_lesser[::-1]) if level == 0: convect_to_level = max(convect_to_level, 1) if convect_to_level == 0: continue stable_level = level + convect_to_level q_conv = output_q[level:stable_level, column] t_conv = output_temperature[level:stable_level, column] dp_conv = dp[level:stable_level] p_conv_high = state['P_int'][level, column] p_conv_low = state['P_int'][stable_level, column] enthalpy = self.heat_capacity(q_conv)*t_conv integral_enthalpy = np.sum(enthalpy*dp_conv) mean_conv_q = np.sum(q_conv*dp_conv)/(p_conv_high - p_conv_low) output_q[level:stable_level, column] = mean_conv_q rdcp_conv = self.gas_constant(mean_conv_q)/self.heat_capacity(mean_conv_q) theta_coeff = ( state['air_pressure'][level:stable_level, column]/self._Pref)**rdcp_conv integral_theta_den = np.sum(self.heat_capacity(q_conv)*theta_coeff*dp_conv) mean_theta = integral_enthalpy/integral_theta_den output_temperature[level:stable_level, column] = mean_theta*theta_coeff return {}, output_arrays
def __init__(self, cloud_overlap_method=None, cloud_optical_properties='liquid_and_ice_clouds', cloud_ice_properties='ebert_curry_two', cloud_liquid_water_properties='radius_dependent_absorption', solar_variability_method=0, use_solar_constant_from_fortran=False, ignore_day_of_year=False, facular_sunspot_amplitude=None, solar_variability_by_band=None, aerosol_type='no_aerosol', mcica=False, random_number_generator='mersenne_twister', **kwargs): """ Args: cloud_overlap_method (int): Choose the method to do overlap with: * 'clear_only' = Clear only (no clouds) * 'random' = Random * 'maximum_random' = Maximum/Random * 'maximum' = Maximum. cloud_optical_properties (string): Choose how cloud optical properties are calculated: * :code:`direct_input` = Cloud fraction, cloud optical depth, single scattering albedo, cloud asymmetry parameter and cloud forward scattering fraction are input. Cloud forward scattering fraction is used to scale the optical depth, single scattering albedo and asymmetry parameter. The latter three parameters are then used in the radiative transfer calculations. Other cloud properties (ie cloud particle size) are irrelevant. * :code:`single_cloud_type` = Cloud fraction and cloud physical properties are input, ice and liquid clouds are treated together, cloud absorptivity is a constant value (0.060241). Not available with McICA. * :code:`liquid_and_ice_clouds` = Cloud fraction and cloud physical properties are input, ice and liquid clouds are treated separately. Cloud optical depth, single scattering albedo and cloud asymmetry parameter are calculated from the cloud ice and water particle sizes and the mass content of cloud ice and cloud water. cloud_ice_properties (string): set bounds on ice particle size. This is not used if 'cloud_optical_properties' == 'direct_input'. * :code:`ebert_curry_one` = ice particle has effective radius >= 10.0 micron `[Ebert and Curry 1992]`_ Not available with McICA. * :code:`ebert_curry_two` = ice particle has effective radius between 13.0 and 130.0 micron `[Ebert and Curry 1992]`_ * :code:`key_streamer_manual` = ice particle has effective radius between 5.0 and 131.0 micron `[Key, Streamer Ref. Manual, 1996]`_ * :code:`fu` = ice particle has generalised effective size (dge) between 5.0 and 140.0 micron `[Fu, 1996]`_. (dge = 1.0315 * r_ec) Default value is 0. cloud_liquid_water_properties (string): set treatment of cloud liquid water. This is not used if 'cloud_optical_properties' == 'direct_input'. * :code:`radius_independent_absorption` = use radius independent absorption coefficient Not available with McICA. * :code:`radius_dependent_absorption` = use radius dependent absorption coefficient (radius between 2.5 and 60 micron) solar_variability_method (int): set the solar variability model used by RRTMG. * solar_variability_method = -1: * If :code:`use_solar_constant_from_fortran = True`: No solar variability and no solar cycle with a solar constant of 1368.22 :math:`W m^{-2}`. * If :code:`use_solar_constant_from_fortran = False`: Solar variability defined by setting non-zero scale factors in :code:`solar_variability_by_band`. * solar_variability_method = 0: * If :code:`use_solar_constant_from_fortran = True`: No solar variability and no solar cycle with a solar constant of 1360.85 :math:`W m^{-2}`, with facular and sunspot effects fixed to the mean of solar cycles 13-24. * If :code:`use_solar_constant_from_fortran = False`: No solar variability and no solar cycle. * solar_variability_method = 1: Solar variability using the NRLSSI2 solar model with solar cycle contribution determined by :code:`solar_cycle_fraction` in the model state, and facular and sunspot adjustment scale factors specified in :code:`facular_sunspot_amplitude`. * solar_variability_method = 2: Solar variability using the NRLSSI2 solar model using solar cycle determined by direct specification of **Mg** (facular) and **SB** (sunspot) indices provided in :code:`facular_sunspot_amplitude`. :code:`solar_constant` is ignored. * solar_variability_method = 3: * If :code:`use_internal_solar_constant = True`: No solar variability and no solar cycle with a solar constant of 1360.85 :math:`W m^{-2}`. * If :code:`use_internal_solar_constant = False`: scale factors in :code:`solar_variability_by_band`. use_solar_constant_from_fortran (bool): If :code:`False`, the solar constant is taken from the constants library. The default value is :code:`False`. ignore_day_of_year (bool): If :code:`True`, the solar output does not vary by day of year (i.e, higher close to the solstices and lesser close to the equinoxes). Default value is :code:`False`. facular_sunspot_amplitude (array of dimension 2): Facular and Sunspot amplitude variability parameters, described previously. solar_variability_by_band (array of dimension 14 = number of spectral bands): scale factors for solar variability in all spectral bands. aerosol_type (string): Type of aerosol inputs to RRTMG. * :code:`no_aerosol`: No Aerosol. * :code:`ecmwf`: ECMWF method. Requires aerosol optical depth at 55 micron as the state quantity :code:`aerosol_optical_depth_at_55_micron`. * :code:`all_aerosol_properties`: Input all aerosol optical properties. mcica (bool): * mcica = True: use the McICA version for the shortwave component of RRTMG * mcica = False: use the nomcica version for the shortwave component of RRTMG random_number_generator (string): Different methods of generating random numbers for McICA. * :code:`kissvec` * :code:`mersenne_twister` .. _[Ebert and Curry 1992]: http://onlinelibrary.wiley.com/doi/10.1029/91JD02472/abstract .. _[Key, Streamer Ref. Manual, 1996]: https://stratus.ssec.wisc.edu/streamer/userman.pdf .. _[Fu, 1996]: http://journals.ametsoc.org/doi/abs/10.1175/1520-0442(1996)009%3C2058%3AAAPOTS%3E2.0.CO%3B2 """ self._mcica = mcica if mcica: self._permute_seed = None self._random_number_generator = rrtmg_random_number_dict[ random_number_generator.lower()] if type(cloud_overlap_method) is str: if cloud_overlap_method.lower() == 'clear_only': logging.info("cloud_overlap_method == 'clear_only'." " This overrides all other properties. " "There are no clouds.") if cloud_optical_properties.lower() == 'single_cloud_type': logging.warning( "cloud_optical_properties must be 'direct_input' or " "'liquid_and_ice_clouds' for radiative calculations with " "clouds using McICA.") if cloud_optical_properties.lower() == 'liquid_and_ice_clouds': if cloud_ice_properties.lower() == 'ebert_curry_one': logging.warning( "cloud_ice_properties should not be set to " "'ebert_curry_one' for shortwave calculations with " "McICA.") if cloud_liquid_water_properties.lower( ) == 'radius_independent_absorption': logging.warning( "cloud_liquid_water_properties must be set to " "'radius_dependent_absorption' for use with McICA in " "the shortwave.") if cloud_overlap_method is None: cloud_overlap_method = 'random' self._cloud_overlap = rrtmg_cloud_overlap_method_dict[ cloud_overlap_method.lower()] self._cloud_optics = rrtmg_cloud_props_dict[ cloud_optical_properties.lower()] self._ice_props = rrtmg_cloud_ice_props_dict[ cloud_ice_properties.lower()] self._liq_props = rrtmg_cloud_liquid_props_dict[ cloud_liquid_water_properties.lower()] self._solar_var_flag = solar_variability_method self._ignore_day_of_year = ignore_day_of_year if facular_sunspot_amplitude is None: self._fac_sunspot_coeff = np.ones(2) else: self._fac_sunspot_coeff = facular_sunspot_amplitude if solar_variability_by_band is None: self._solar_var_by_band = np.ones(16) else: self._solar_var_by_band = solar_variability_by_band self._aerosol_type = rrtmg_aerosol_input_dict[aerosol_type.lower()] if use_solar_constant_from_fortran: self._solar_const = 0 else: self._solar_const = get_constant('stellar_irradiance', 'W/m^2') self._g = get_constant('gravitational_acceleration', 'm/s^2') self._planck = get_constant('planck_constant', 'erg s') self._boltzmann = get_constant('boltzmann_constant', 'erg K^-1') self._c = get_constant('speed_of_light', 'cm s^-1') self._Na = get_constant('avogadro_constant', 'mole^-1') self._loschmidt = get_constant('loschmidt_constant', 'cm^-3') self._R = get_constant('universal_gas_constant', 'erg mol^-1 K^-1') self._stef_boltz = get_constant('stefan_boltzmann_constant', 'W cm^-2 K^-4') self._secs_per_day = get_constant('seconds_per_day', 'dimensionless') self._Cpd = get_constant( 'heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/K') _rrtmg_sw.set_constants(numpy_pi, self._g, self._planck, self._boltzmann, self._c, self._Na, self._loschmidt, self._R, self._stef_boltz, self._secs_per_day) if not mcica: _rrtmg_sw.initialise_rrtm_radiation( self._Cpd, self._solar_const, self._fac_sunspot_coeff, self._solar_var_by_band, self._cloud_overlap, self._cloud_optics, self._ice_props, self._liq_props, self._aerosol_type, self._solar_var_flag) super(RRTMGShortwave, self).__init__(**kwargs)
def __init__(self, calculate_change_up_flux=False, cloud_overlap_method=None, cloud_optical_properties='liquid_and_ice_clouds', cloud_ice_properties='ebert_curry_two', cloud_liquid_water_properties='radius_dependent_absorption', calculate_interface_temperature=True, mcica=False, random_number_generator=0, permute_seed=112, **kwargs): """ Args: calculate_change_up_flux (bool): calculate derivative of flux change with respect to surface temperature alone. Can be used to adjust fluxes in between radiation calls only due to change of surface temperature. Default value is :code:`False`, meaning this quantity is not calculated. cloud_overlap_method (string): Choose the method to do overlap with: * :code:`clear_only` = Clear only (no clouds) * :code:`random` = Random * :code:`maximum_random` = Maximum/Random * :code:`maximum` = Maximum. cloud_optical_properties (string): Choose how cloud optical properties are calculated: * :code:`direct_input` = Both cloud fraction and cloud optical depth are input directly. Other cloud properties (ie cloud particle size) are irrelevant. * :code:`single_cloud_type` = Cloud fraction and cloud physical properties are input, ice and liquid clouds are treated together, cloud absorptivity is a constant value (0.060241). Not available with McICA. * :code:`liquid_and_ice_clouds` = Cloud fraction and cloud physical properties are input, ice and liquid clouds are treated separately. Cloud optical depth is calculated from the cloud ice and water particle sizes and the mass content of cloud ice and cloud water. cloud_ice_properties (string): set bounds on ice particle size. This is not used if 'cloud_optical_properties' == 'direct_input' * :code:`ebert_curry_one` = ice particle has effective radius >= 10.0 micron `[Ebert and Curry 1992]`_ * :code:`ebert_curry_two` = ice particle has effective radius between 13.0 and 130.0 micron `[Ebert and Curry 1992]`_ * :code:`key_streamer_manual` = ice particle has effective radius between 5.0 and 131.0 micron `[Key, Streamer Ref. Manual, 1996]`_ * :code:`fu` = ice particle has generalised effective size (dge) between 5.0 and 140.0 micron `[Fu, 1996]`_. (dge = 1.0315 * r_ec) Default value is 0. cloud_liquid_water_properties (string): set treatment of cloud liquid water. This is not used if 'cloud_optical_properties' == 'direct_input'. * :code:`radius_independent_absorption` = use radius independent absorption coefficient * :code:`radius_dependent_absorption` = use radius dependent absorption coefficient (radius between 2.5 and 60 micron) calculate_interface_temperature (bool): if :code:`True`, the interface temperature is calculated internally using a weighted interpolation routine. If :code:`False`, the quantity called :code:`air_temperature_on_interface_levels` in the input state needs to be manually updated by user code. mcica (bool): * mcica = True: use the McICA version of the longwave component of RRTMG * mcica = False: use the nomcica version of the longwave component of RRTMG random_number_generator (int): Different methods of generating random numbers for McICA. * random_number_generator = 0: kissvec * random_number_generator = 1: Mersenne Twister permute_seed (int): For McICA, permute the seed between each call to the cloud generator. .. _[Ebert and Curry 1992]: http://onlinelibrary.wiley.com/doi/10.1029/91JD02472/abstract .. _[Key, Streamer Ref. Manual, 1996]: https://stratus.ssec.wisc.edu/streamer/userman.pdf .. _[Fu, 1996]: http://journals.ametsoc.org/doi/abs/10.1175/1520-0442(1996)009%3C2058%3AAAPOTS%3E2.0.CO%3B2 """ self.input_properties = RRTMGLongwave.input_properties.copy() if calculate_change_up_flux: self._calc_dflxdt = 1 else: self._calc_dflxdt = 0 self._mcica = mcica if mcica: self._random_number_generator = random_number_generator self._permute_seed = permute_seed if type(cloud_overlap_method) is str: if cloud_overlap_method.lower() == 'clear_only': logging.info("cloud_overlap_method == 'clear_only'." " This overrides all other properties. " "There are no clouds.") if cloud_optical_properties.lower() == 'single_cloud_type': logging.warning( "cloud_optical_properties must be 'direct_input' or " "'liquid_and_ice_clouds' for radiative calculations with " "clouds using McICA.") if cloud_overlap_method is None: cloud_overlap_method = 'random' self._cloud_overlap = rrtmg_cloud_overlap_method_dict[ cloud_overlap_method.lower()] self._cloud_optics = rrtmg_cloud_props_dict[ cloud_optical_properties.lower()] self._ice_props = rrtmg_cloud_ice_props_dict[ cloud_ice_properties.lower()] self._liq_props = rrtmg_cloud_liquid_props_dict[ cloud_liquid_water_properties.lower()] self._calc_Tint = calculate_interface_temperature self._g = get_constant('gravitational_acceleration', 'm/s^2') self._planck = get_constant('planck_constant', 'erg s') self._boltzmann = get_constant('boltzmann_constant', 'erg K^-1') self._c = get_constant('speed_of_light', 'cm s^-1') self._Na = get_constant('avogadro_constant', 'mole^-1') self._loschmidt = get_constant('loschmidt_constant', 'cm^-3') self._R = get_constant('universal_gas_constant', 'erg mol^-1 K^-1') self._stef_boltz = get_constant('stefan_boltzmann_constant', 'W cm^-2 K^-4') self._secs_per_day = get_constant('seconds_per_day', 'dimensionless') self._Cpd = get_constant( 'heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/K') if not self._calc_Tint: self.input_properties['air_temperature_on_interface_levels'] = { 'dims': ['interface_levels', '*'], 'units': 'degK', } _rrtmg_lw.set_constants(PI, self._g, self._planck, self._boltzmann, self._c, self._Na, self._loschmidt, self._R, self._stef_boltz, self._secs_per_day) if mcica: _rrtmg_lw.initialise_rrtm_radiation_mcica( self._Cpd, self._cloud_overlap, self._calc_dflxdt, self._cloud_optics, self._ice_props, self._liq_props, self._permute_seed, self._random_number_generator) else: # TODO Add all other flags as well _rrtmg_lw.initialise_rrtm_radiation(self._Cpd, self._cloud_overlap, self._calc_dflxdt, self._cloud_optics, self._ice_props, self._liq_props) super(RRTMGLongwave, self).__init__(**kwargs)