Beispiel #1
0
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
Beispiel #2
0
 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
Beispiel #4
0
 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')
Beispiel #5
0
 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,
     }
Beispiel #6
0
 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
Beispiel #7
0
    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
Beispiel #8
0
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']
Beispiel #9
0
 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)
Beispiel #10
0
 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')
Beispiel #11
0
 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')
Beispiel #12
0
 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)
Beispiel #13
0
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
Beispiel #16
0
# -*- 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
}

Beispiel #17
0
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()
Beispiel #18
0
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
Beispiel #19
0
    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
Beispiel #20
0
    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)
Beispiel #21
0
    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)