Example #1
0
    def array_call(self, raw_state, timestep):
        """
        Get convective heating and moistening.

        Args:

            raw_state (dict):
                The state dictionary of numpy arrays satisfying this
                component's input properties.

        Returns:

            tendencies (dict), diagnostics (dict):
                * The heating and moistening tendencies
                * Any diagnostics associated.

        """
        self._set_fortran_constants()

        num_cols, num_levs = raw_state['air_temperature'].shape

        max_conv_level = num_levs - 3

        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, raw_state, self.input_properties)
        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, raw_state, self.input_properties)

        q_sat = bolton_q_sat(raw_state['air_temperature'],
                             raw_state['air_pressure'] * 100, self._Cpd,
                             self._Cpv)

        _emanuel_convection.convect(
            num_levs, num_cols, max_conv_level, self._ntracers,
            timestep.total_seconds(), raw_state['air_temperature'],
            raw_state['specific_humidity'], q_sat, raw_state['eastward_wind'],
            raw_state['northward_wind'], raw_state['air_pressure'],
            raw_state['air_pressure_on_interface_levels'],
            diagnostics['convective_state'],
            diagnostics['convective_precipitation_rate'],
            diagnostics['convective_downdraft_velocity_scale'],
            diagnostics['convective_downdraft_temperature_scale'],
            diagnostics['convective_downdraft_specific_humidity_scale'],
            raw_state['cloud_base_mass_flux'],
            diagnostics['atmosphere_convective_available_potential_energy'],
            tendencies['air_temperature'], tendencies['specific_humidity'],
            tendencies['eastward_wind'], tendencies['northward_wind'])

        diagnostics['air_temperature_tendency_from_convection'][:] = (
            tendencies['air_temperature'] * 86400.)
        diagnostics['cloud_base_mass_flux'][:] = raw_state[
            'cloud_base_mass_flux']
        return tendencies, diagnostics
Example #2
0
    def array_call(self, state):
        Q = mass_to_volume_mixing_ratio(state['specific_humidity'], 18.02)
        n_layers, n_columns = state['air_temperature'].shape

        if self._calc_Tint:
            T_interface = get_interface_values(
                state['air_temperature'], state['surface_temperature'],
                state['air_pressure'],
                state['air_pressure_on_interface_levels'])
        else:
            T_interface = state['air_temperature_on_interface_levels']

        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, state, self.input_properties)
        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, state, self.input_properties)

        _rrtmg_lw.rrtm_calculate_longwave_fluxes(
            n_columns, n_layers, state['air_pressure'],
            state['air_pressure_on_interface_levels'],
            state['air_temperature'], T_interface,
            state['surface_temperature'], Q,
            state['mole_fraction_of_ozone_in_air'],
            state['mole_fraction_of_carbon_dioxide_in_air'],
            state['mole_fraction_of_methane_in_air'],
            state['mole_fraction_of_nitrous_oxide_in_air'],
            state['mole_fraction_of_oxygen_in_air'],
            state['mole_fraction_of_cfc11_in_air'],
            state['mole_fraction_of_cfc12_in_air'],
            state['mole_fraction_of_cfc22_in_air'],
            state['mole_fraction_of_carbon_tetrachloride_in_air'],
            state['surface_longwave_emissivity'],
            state['cloud_area_fraction_in_atmosphere_layer'],
            state['longwave_optical_thickness_due_to_aerosol'],
            diagnostics['upwelling_longwave_flux_in_air'],
            diagnostics['downwelling_longwave_flux_in_air'],
            tendencies['air_temperature'],
            diagnostics['upwelling_longwave_flux_in_air_assuming_clear_sky'],
            diagnostics['downwelling_longwave_flux_in_air_assuming_clear_sky'],
            diagnostics[
                'air_temperature_tendency_from_longwave_assuming_clear_sky'],
            state['longwave_optical_thickness_due_to_cloud'],
            state['mass_content_of_cloud_ice_in_atmosphere_layer'],
            state['mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
            state['cloud_ice_particle_size'],
            state['cloud_water_droplet_radius'])

        diagnostics['air_temperature_tendency_from_longwave'] = tendencies[
            'air_temperature']

        return tendencies, diagnostics
Example #3
0
 def test_empty(self):
     output_properties = {}
     input_properties = {}
     input_state = {}
     result = initialize_numpy_arrays_with_properties(
         output_properties, input_state, input_properties)
     assert result == {}
Example #4
0
    def test_two_inputs(self):
        output_properties = {
            'output1': {
                'dims': ['dim2', 'dim1'],
                'units': 'm',
            },
        }
        input_properties = {
            'input1': {
                'dims': ['dim1', 'dim2'],
                'units': 's^-1',
            },
            'input2': {
                'dims': ['dim2', 'dim1'],
                'units': 's^-1',
            }
        }
        input_state = {
            'input1': np.zeros([3, 7]),
            'input2': np.zeros([7, 3]),
        }

        result = initialize_numpy_arrays_with_properties(
            output_properties, input_state, input_properties)
        assert len(result.keys()) == 1
        assert 'output1' in result.keys()
        assert result['output1'].shape == (7, 3)
        assert np.all(result['output1'] == np.zeros([7, 3]))
Example #5
0
    def array_call(self, raw_state):
        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, raw_state, self.input_properties)
        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, raw_state, self.input_properties)

        net_heat_flux = (raw_state['downwelling_shortwave_flux_in_air'][:, 0] +
                         raw_state['downwelling_longwave_flux_in_air'][:, 0] -
                         raw_state['upwelling_shortwave_flux_in_air'][:, 0] -
                         raw_state['upwelling_longwave_flux_in_air'][:, 0] -
                         raw_state['surface_upward_sensible_heat_flux'] -
                         raw_state['surface_upward_latent_heat_flux'])

        area_type = raw_state['area_type'].astype(str)

        land_mask = np.logical_or(area_type == 'land', area_type == 'land_ice')
        sea_mask = np.logical_or(area_type == 'sea', area_type == 'sea_ice')
        land_ice_mask = area_type == 'land_ice'
        sea_ice_mask = area_type == 'sea_ice'

        net_heat_flux[land_ice_mask] = -raw_state[
            'upward_heat_flux_at_ground_level_in_soil'][land_ice_mask]
        net_heat_flux[sea_ice_mask] = raw_state[
            'heat_flux_into_sea_water_due_to_sea_ice'][sea_ice_mask]
        raw_state['surface_material_density'][sea_mask] = raw_state[
            'sea_water_density'][sea_mask]
        raw_state['surface_thermal_capacity'][land_mask] = raw_state[
            'heat_capacity_of_soil'][land_mask]
        diagnostics['depth_of_slab_surface'][sea_mask] =\
            raw_state['ocean_mixed_layer_thickness'][sea_mask]
        diagnostics['depth_of_slab_surface'][land_mask] =\
            raw_state['soil_layer_thickness'][land_mask]

        mass_surface_slab = raw_state['surface_material_density'] * \
            diagnostics['depth_of_slab_surface']
        heat_capacity_surface = mass_surface_slab * raw_state[
            'surface_thermal_capacity']

        tendencies[
            'surface_temperature'][:] = net_heat_flux / heat_capacity_surface
        tendencies['surface_temperature'][land_ice_mask] = 0
        tendencies['surface_temperature'][sea_ice_mask] = 0

        return tendencies, diagnostics
Example #6
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
Example #7
0
    def test_single_dim_wildcard(self):
        output_properties = {
            'output1': {
                'dims': ['*'],
                'units': 'm',
            }
        }
        input_properties = {
            'input1': {
                'dims': ['*'],
                'units': 's^-1',
            }
        }
        input_state = {'input1': np.zeros([10])}

        result = initialize_numpy_arrays_with_properties(
            output_properties, input_state, input_properties)
        assert len(result.keys()) == 1
        assert 'output1' in result.keys()
        assert result['output1'].shape == (10, )
        assert np.all(result['output1'] == np.zeros([10]))
Example #8
0
    def array_call(self, raw_state, timestep):
        self._update_constants()

        num_cols = raw_state['area_type'].shape[0]

        net_heat_flux = (raw_state['downwelling_shortwave_flux_in_air'][:, 0] +
                         raw_state['downwelling_longwave_flux_in_air'][:, 0] -
                         raw_state['upwelling_shortwave_flux_in_air'][:, 0] -
                         raw_state['upwelling_longwave_flux_in_air'][:, 0] -
                         raw_state['surface_upward_sensible_heat_flux'] -
                         raw_state['surface_upward_latent_heat_flux'])

        outputs = initialize_numpy_arrays_with_properties(
            self.output_properties, raw_state, self.input_properties)

        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, raw_state, self.input_properties)

        # Copy input values
        outputs['surface_temperature'][:] = raw_state['surface_temperature']
        outputs['sea_surface_temperature'][:] = raw_state[
            'sea_surface_temperature']
        outputs['land_ice_thickness'][:] = raw_state['land_ice_thickness']
        outputs['sea_ice_thickness'][:] = raw_state['sea_ice_thickness']
        outputs['surface_snow_thickness'][:] = raw_state[
            'surface_snow_thickness']
        outputs['snow_and_ice_temperature'][:] = raw_state[
            'snow_and_ice_temperature']

        for col in range(num_cols):
            area_type = raw_state['area_type'][col].astype(str)
            total_height = 0.
            surface_temperature = raw_state[
                'snow_and_ice_temperature'][:, col][-1]
            soil_surface_temperature = None

            if area_type == 'land_ice':
                total_height = raw_state['land_ice_thickness'][col] \
                    + raw_state['surface_snow_thickness'][col]
                soil_surface_temperature = raw_state[
                    'soil_surface_temperature'][col]
            elif area_type == 'sea_ice':
                if raw_state['sea_ice_thickness'][col] == 0:
                    # No sea ice, so skip calculation
                    continue
                total_height = raw_state['sea_ice_thickness'][col] \
                    + raw_state['surface_snow_thickness'][col]
            elif area_type == 'land':
                total_height = raw_state['surface_snow_thickness'][col]
                soil_surface_temperature = raw_state[
                    'soil_surface_temperature'][col]
            if total_height > self._max_height:
                raise ValueError(
                    "Total height exceeds maximum value of {} m.".format(
                        self._max_height))

            if total_height < self._epsilon:  # Some epsilon
                continue

            snow_height_fraction = raw_state['surface_snow_thickness'][
                col] / total_height

            temp_profile = raw_state['snow_and_ice_temperature'][:, col]
            num_layers = temp_profile.shape[0]
            dz = float(total_height / num_layers)

            snow_level = int((1 - snow_height_fraction) * num_layers) - 1
            levels = np.arange(num_layers - 1)

            # Create vertically varying profiles
            rho_snow_ice = self._rho_ice * np.ones(num_layers - 1)
            rho_snow_ice[levels > snow_level] = self._rho_snow

            heat_capacity_snow_ice = self._C_ice * np.ones(num_layers - 1)
            heat_capacity_snow_ice[levels > snow_level] = self._C_snow

            kappa_snow_ice = self._Kice * np.ones(num_layers - 1)
            kappa_snow_ice[levels > snow_level] = self._Ksnow

            check_melting = True
            if surface_temperature < self._melting_temperature - self._epsilon:
                check_melting = False

            new_temperature = self.calculate_new_ice_temperature(
                rho_snow_ice,
                heat_capacity_snow_ice, kappa_snow_ice, temp_profile,
                timestep.total_seconds(), dz, num_layers, surface_temperature,
                net_heat_flux[col], soil_surface_temperature)

            # Cool down from melting temperature if
            # heat flux through ice is greater than
            # net forcing heat flux at surface
            heat_flux_through_ice = (
                (new_temperature[-1] - new_temperature[-2]) *
                (kappa_snow_ice[-1] + kappa_snow_ice[-2]) * 0.5 / dz)

            if temp_profile[-1] > self._melting_temperature - self._epsilon:
                if heat_flux_through_ice > net_heat_flux[col]:
                    surface_temperature = temp_profile[-1] - 10 * self._epsilon
                    temp_profile[-1] = temp_profile[-1] - 10 * self._epsilon

                    new_temperature = self.calculate_new_ice_temperature(
                        rho_snow_ice, heat_capacity_snow_ice, kappa_snow_ice,
                        temp_profile, timestep.total_seconds(), dz, num_layers,
                        surface_temperature, net_heat_flux[col],
                        soil_surface_temperature)

                    check_melting = False

            # Energy balance for lower surface of snow/ice
            if area_type == 'sea_ice':
                # TODO Add ocean heat flux parameterization
                # At sea surface
                heat_flux_to_sea_water = (
                    new_temperature[1] - new_temperature[0]) * (
                        kappa_snow_ice[0] + kappa_snow_ice[1]) * 0.5 / dz
                heat_flux_to_sea_water = round(heat_flux_to_sea_water, 6)

                # If heat_flux_to_sea_water is positive, flux of heat into water
                # an impossible situation which means ice is above freezing point.
                assert heat_flux_to_sea_water <= 0

                height_of_growing_ice = -(heat_flux_to_sea_water *
                                          timestep.total_seconds() /
                                          (rho_snow_ice[0] * self._Lf))

                outputs['sea_ice_thickness'][col] += height_of_growing_ice
                diagnostics['heat_flux_into_sea_water_due_to_sea_ice'][col]\
                    = heat_flux_to_sea_water

            elif area_type in ['land_ice', 'land']:
                # At land surface
                heat_flux_to_land = (new_temperature[0] - new_temperature[1]
                                     ) * kappa_snow_ice[0] / dz

                diagnostics['upward_heat_flux_at_ground_level_in_soil'][col] \
                    = heat_flux_to_land

                height_of_growing_ice = 0

            else:
                continue

            # Energy balance at atmosphere surface
            heat_flux_through_ice = (
                (new_temperature[-1] - new_temperature[-2]) *
                (kappa_snow_ice[-1] + kappa_snow_ice[-2]) * 0.5 / dz)
            diagnostics['surface_downward_heat_flux_in_sea_ice'][
                col] = heat_flux_through_ice

            height_of_melting_ice = 0
            # Surface is melting
            if check_melting:
                energy_to_melt_ice = (
                    net_heat_flux[col] -
                    heat_flux_through_ice) * timestep.total_seconds()
                energy_to_melt_ice = round(energy_to_melt_ice, 6)
                if energy_to_melt_ice < 0:
                    print(net_heat_flux[col], heat_flux_through_ice)
                    assert False

                height_of_melting_ice = (energy_to_melt_ice /
                                         (rho_snow_ice[-1] * self._Lf))

                if height_of_melting_ice > raw_state['surface_snow_thickness'][
                        col]:

                    outputs['sea_ice_thickness'][col] -= (
                        height_of_melting_ice -
                        raw_state['surface_snow_thickness'][col])
                    outputs['surface_snow_thickness'][col] = 0

                else:
                    outputs['surface_snow_thickness'][
                        col] -= height_of_melting_ice

            total_height += (height_of_growing_ice + height_of_melting_ice)

            outputs['snow_and_ice_temperature'][:, col] = new_temperature

            outputs['surface_temperature'][col] = new_temperature[-1]
            outputs['height_on_ice_interface_levels'][:, col] = np.linspace(
                0,
                total_height,
                outputs['height_on_ice_interface_levels'].shape[0],
                endpoint=True)

            if outputs['surface_snow_thickness'][col] > 0:
                diagnostics['surface_albedo_for_direct_shortwave'][col] = 0.8
                diagnostics['surface_albedo_for_diffuse_shortwave'][col] = 0.8
            elif area_type == 'sea_ice' and outputs['sea_ice_thickness'][
                    col] > 0:
                diagnostics['surface_albedo_for_direct_shortwave'][col] = 0.5
                diagnostics['surface_albedo_for_diffuse_shortwave'][col] = 0.5
            elif area_type == 'sea_ice' and outputs['sea_ice_thickness'][
                    col] > 0:
                diagnostics['surface_albedo_for_direct_shortwave'][col] = 0.5
                diagnostics['surface_albedo_for_diffuse_shortwave'][col] = 0.5

            if height_of_melting_ice > 0:
                diagnostics['surface_albedo_for_direct_shortwave'][col] = 0.2
                diagnostics['surface_albedo_for_diffuse_shortwave'][col] = 0.2

        return diagnostics, outputs
Example #9
0
    def array_call(self, state):
        Q = mass_to_volume_mixing_ratio(state['specific_humidity'], 18.02)
        n_layers, n_columns = state['air_temperature'].shape

        if self._calc_Tint:
            T_interface = get_interface_values(
                state['air_temperature'], state['surface_temperature'],
                state['air_pressure'],
                state['air_pressure_on_interface_levels'])
        else:
            T_interface = state['air_temperature_on_interface_levels']

        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, state, self.input_properties)
        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, state, self.input_properties)

        if self._mcica:

            # First, define extra arrays needed for mcica.
            # The values for these arrays are calculated from state in the
            # first part of _rrtmg_sw.rrtm_calculate_longwave_fluxes_mcica.
            # Specifically they are calculated by mcica_subcol_gen_lw.f90
            # and are input to rrtmg_lw_rad.f90
            num_reduced_g_intervals = self.num_reduced_g_intervals
            mid_levels = state['air_pressure'].shape[0]

            try:
                num_cols = state['air_pressure'].shape[1]
            except IndexError:
                num_cols = 1

            mcica_properties = {
                'cloud_area_fraction_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'mass_content_of_cloud_ice_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'mass_content_of_cloud_liquid_water_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'cloud_ice_particle_size':
                np.zeros((mid_levels, num_cols)),
                'cloud_water_droplet_radius':
                np.zeros((mid_levels, num_cols)),
                'longwave_optical_thickness_due_to_cloud':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals))
            }

            _rrtmg_lw.rrtm_calculate_longwave_fluxes_mcica(
                self.rrtm_iplon, n_columns, n_layers, state['air_pressure'],
                state['air_pressure_on_interface_levels'],
                state['air_temperature'], T_interface,
                state['surface_temperature'], Q,
                state['mole_fraction_of_ozone_in_air'],
                state['mole_fraction_of_carbon_dioxide_in_air'],
                state['mole_fraction_of_methane_in_air'],
                state['mole_fraction_of_nitrous_oxide_in_air'],
                state['mole_fraction_of_oxygen_in_air'],
                state['mole_fraction_of_cfc11_in_air'],
                state['mole_fraction_of_cfc12_in_air'],
                state['mole_fraction_of_cfc22_in_air'],
                state['mole_fraction_of_carbon_tetrachloride_in_air'],
                state['surface_longwave_emissivity'],
                state['cloud_area_fraction_in_atmosphere_layer'],
                state['longwave_optical_thickness_due_to_aerosol'],
                diagnostics['upwelling_longwave_flux_in_air'],
                diagnostics['downwelling_longwave_flux_in_air'],
                tendencies['air_temperature'], diagnostics[
                    'upwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'downwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'air_temperature_tendency_from_longwave_assuming_clear_sky'],
                state['longwave_optical_thickness_due_to_cloud'],
                state['mass_content_of_cloud_ice_in_atmosphere_layer'], state[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                state['cloud_ice_particle_size'],
                state['cloud_water_droplet_radius'],
                mcica_properties['cloud_area_fraction_in_atmosphere_layer'],
                mcica_properties['longwave_optical_thickness_due_to_cloud'],
                mcica_properties[
                    'mass_content_of_cloud_ice_in_atmosphere_layer'],
                mcica_properties[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                mcica_properties['cloud_ice_particle_size'],
                mcica_properties['cloud_water_droplet_radius'])

        else:
            _rrtmg_lw.rrtm_calculate_longwave_fluxes(
                n_columns, n_layers, state['air_pressure'],
                state['air_pressure_on_interface_levels'],
                state['air_temperature'], T_interface,
                state['surface_temperature'], Q,
                state['mole_fraction_of_ozone_in_air'],
                state['mole_fraction_of_carbon_dioxide_in_air'],
                state['mole_fraction_of_methane_in_air'],
                state['mole_fraction_of_nitrous_oxide_in_air'],
                state['mole_fraction_of_oxygen_in_air'],
                state['mole_fraction_of_cfc11_in_air'],
                state['mole_fraction_of_cfc12_in_air'],
                state['mole_fraction_of_cfc22_in_air'],
                state['mole_fraction_of_carbon_tetrachloride_in_air'],
                state['surface_longwave_emissivity'],
                state['cloud_area_fraction_in_atmosphere_layer'],
                state['longwave_optical_thickness_due_to_aerosol'],
                diagnostics['upwelling_longwave_flux_in_air'],
                diagnostics['downwelling_longwave_flux_in_air'],
                tendencies['air_temperature'], diagnostics[
                    'upwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'downwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'air_temperature_tendency_from_longwave_assuming_clear_sky'],
                state['longwave_optical_thickness_due_to_cloud'],
                state['mass_content_of_cloud_ice_in_atmosphere_layer'], state[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                state['cloud_ice_particle_size'],
                state['cloud_water_droplet_radius'])

        diagnostics['air_temperature_tendency_from_longwave'] = tendencies[
            'air_temperature']

        return tendencies, diagnostics
Example #10
0
    def array_call(self, state):
        """
        Get heating tendencies and shortwave fluxes.

        Args:

            state (dict):
                The model state dictionary.

        Returns:

            tendencies (dict), diagnostics (dict):

                * The shortwave heating tendency.
                * The upward/downward shortwave fluxes for cloudy and clear
                  sky conditions.

        """
        Q = mass_to_volume_mixing_ratio(state['specific_humidity'], 18.02)
        assert state['air_pressure'].shape[0] + 1 == state[
            'air_pressure_on_interface_levels'].shape[0]

        Tint = get_interface_values(state['air_temperature'],
                                    state['surface_temperature'],
                                    state['air_pressure'],
                                    state['air_pressure_on_interface_levels'])

        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, state, self.input_properties)
        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, state, self.input_properties)

        model_time = state['time']
        if self._ignore_day_of_year:
            day_of_year = 0
        else:
            day_of_year = model_time.timetuple().tm_yday
        cos_zenith_angle = np.cos(state['zenith_angle'])

        if self._mcica:

            # First, define extra arrays needed for mcica.
            # The values for these arrays are calculated from state in the
            # first part of _rrtmg_sw.rrtm_calculate_shortwave_fluxes_mcica.
            # Specifically they are calculated by mcica_subcol_gen_sw.f90
            # and are input to rrtmg_sw_rad.f90
            num_reduced_g_intervals = self.num_reduced_g_intervals
            mid_levels = state['air_pressure'].shape[0]
            try:
                num_cols = state['air_pressure'].shape[1]
            except IndexError:
                num_cols = 1

            mcica_properties = {
                'cloud_area_fraction_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'mass_content_of_cloud_ice_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'mass_content_of_cloud_liquid_water_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'cloud_ice_particle_size':
                np.zeros((mid_levels, num_cols)),
                'cloud_water_droplet_radius':
                np.zeros((mid_levels, num_cols)),
                'shortwave_optical_thickness_due_to_cloud':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'single_scattering_albedo_due_to_cloud':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'cloud_asymmetry_parameter':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'cloud_forward_scattering_fraction':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals))
            }

            # Change parameter for random number generator - each time the
            # radiation is called, with the same state / input properties,
            # a different result is obtained, because the wavelengths which
            # see cloud differ between each call.
            if self._random_number_generator == 0:
                # KISS algorithm: The seed determines the number of times
                # the random number generator is called iteratively to create a
                # new random number. The value range of the seed is limited to
                # avoid a performance decrease.
                self._permute_seed = np.random.randint(0, 1024)
            elif self._random_number_generator == 1:
                # Mersenne Twister: Use random seed from the full 32bit range.
                self._permute_seed = np.random.randint(0, 2**31 - 1)

            _rrtmg_sw.initialise_rrtm_radiation_mcica(
                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, self._permute_seed,
                self._random_number_generator)

            _rrtmg_sw.rrtm_calculate_shortwave_fluxes_mcica(
                self.rrtm_iplon, state['air_temperature'].shape[1],
                state['air_temperature'].shape[0], day_of_year,
                state['solar_cycle_fraction'],
                state['flux_adjustment_for_earth_sun_distance'],
                state['air_pressure'],
                state['air_pressure_on_interface_levels'],
                state['air_temperature'], Tint, state['surface_temperature'],
                Q, state['mole_fraction_of_ozone_in_air'],
                state['mole_fraction_of_carbon_dioxide_in_air'],
                state['mole_fraction_of_methane_in_air'],
                state['mole_fraction_of_nitrous_oxide_in_air'],
                state['mole_fraction_of_oxygen_in_air'],
                state['surface_albedo_for_direct_shortwave'],
                state['surface_albedo_for_direct_near_infrared'],
                state['surface_albedo_for_diffuse_shortwave'],
                state['surface_albedo_for_diffuse_near_infrared'],
                cos_zenith_angle,
                state['cloud_area_fraction_in_atmosphere_layer'],
                diagnostics['upwelling_shortwave_flux_in_air'],
                diagnostics['downwelling_shortwave_flux_in_air'],
                tendencies['air_temperature'], diagnostics[
                    'upwelling_shortwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'downwelling_shortwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'air_temperature_tendency_from_shortwave_assuming_clear_sky'],
                state['shortwave_optical_thickness_due_to_aerosol'],
                state['single_scattering_albedo_due_to_aerosol'],
                state['aerosol_asymmetry_parameter'],
                state['aerosol_optical_depth_at_55_micron'],
                state['shortwave_optical_thickness_due_to_cloud'],
                state['single_scattering_albedo_due_to_cloud'],
                state['cloud_asymmetry_parameter'],
                state['cloud_forward_scattering_fraction'],
                state['mass_content_of_cloud_ice_in_atmosphere_layer'], state[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                state['cloud_ice_particle_size'],
                state['cloud_water_droplet_radius'],
                mcica_properties['cloud_area_fraction_in_atmosphere_layer'],
                mcica_properties['shortwave_optical_thickness_due_to_cloud'],
                mcica_properties['single_scattering_albedo_due_to_cloud'],
                mcica_properties['cloud_asymmetry_parameter'],
                mcica_properties['cloud_forward_scattering_fraction'],
                mcica_properties[
                    'mass_content_of_cloud_ice_in_atmosphere_layer'],
                mcica_properties[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                mcica_properties['cloud_ice_particle_size'],
                mcica_properties['cloud_water_droplet_radius'])
        else:
            _rrtmg_sw.rrtm_calculate_shortwave_fluxes(
                state['air_temperature'].shape[1],
                state['air_temperature'].shape[0], day_of_year,
                state['solar_cycle_fraction'],
                state['flux_adjustment_for_earth_sun_distance'],
                state['air_pressure'],
                state['air_pressure_on_interface_levels'],
                state['air_temperature'], Tint, state['surface_temperature'],
                Q, state['mole_fraction_of_ozone_in_air'],
                state['mole_fraction_of_carbon_dioxide_in_air'],
                state['mole_fraction_of_methane_in_air'],
                state['mole_fraction_of_nitrous_oxide_in_air'],
                state['mole_fraction_of_oxygen_in_air'],
                state['surface_albedo_for_direct_shortwave'],
                state['surface_albedo_for_direct_near_infrared'],
                state['surface_albedo_for_diffuse_shortwave'],
                state['surface_albedo_for_diffuse_near_infrared'],
                cos_zenith_angle,
                state['cloud_area_fraction_in_atmosphere_layer'],
                diagnostics['upwelling_shortwave_flux_in_air'],
                diagnostics['downwelling_shortwave_flux_in_air'],
                tendencies['air_temperature'], diagnostics[
                    'upwelling_shortwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'downwelling_shortwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'air_temperature_tendency_from_shortwave_assuming_clear_sky'],
                state['shortwave_optical_thickness_due_to_aerosol'],
                state['single_scattering_albedo_due_to_aerosol'],
                state['aerosol_asymmetry_parameter'],
                state['aerosol_optical_depth_at_55_micron'],
                state['shortwave_optical_thickness_due_to_cloud'],
                state['single_scattering_albedo_due_to_cloud'],
                state['cloud_asymmetry_parameter'],
                state['cloud_forward_scattering_fraction'],
                state['mass_content_of_cloud_ice_in_atmosphere_layer'], state[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                state['cloud_ice_particle_size'],
                state['cloud_water_droplet_radius'])

        diagnostics['air_temperature_tendency_from_shortwave'][:] = tendencies[
            'air_temperature']

        return tendencies, diagnostics
Example #11
0
    def array_call(self, state, timestep, prognostic_tendencies=None):
        """ Step the dynamical core by one step

        Args:
            state (dict): The state dictionary of numpy arrays.

        Returns:
            new_state, diagnostics (dict):
                The new state and associated diagnostics.
        """
        prognostic_tendencies = prognostic_tendencies or {}
        self._update_constants()
        nlev, nlat, nlon = state['air_temperature'].shape
        if nlat < 16:
            raise GFSError('GFS requires at least 16 latitudes.')
        if nlon < 12:
            raise GFSError('GFS requires at least 12 longitudes')
        if not self.initialized:
            self._initialize_model(state, timestep)
        if nlev != self._num_levs:
            raise GFSError(
                'Number of vertical levels may not change between successive '
                'calls to GFS. Last time was {}, this time is {}'.format(
                    self._num_levs, nlev))
        if nlat != self._num_lats:
            raise GFSError(
                'Number of latitudes may not change between successive '
                'calls to GFS. Last time was {}, this time is {}'.format(
                    self._num_lats, nlat))
        if nlon != self._num_lons:
            raise GFSError(
                'Number of longitudes may not change between successive '
                'calls to GFS. Last time was {}, this time is {}'.format(
                    self._num_lons, nlon))
        if timestep.total_seconds() != self._time_step.total_seconds():
            raise GFSError(
                'GFSDynamicalCore can only be run with a constant timestep.')

        outputs = initialize_numpy_arrays_with_properties(
            self.output_properties,
            state,
            self.input_properties,
            prepend_tracers=self.prepend_tracers,
            tracer_dims=self.tracer_dims,
        )

        lnsp = np.log(state['surface_air_pressure'])
        t_virt = state['air_temperature'] * (
            1 + self._fvirt * state['tracers'][0, :, :, :])

        outputs['air_pressure_on_interface_levels'][:] = (
            state['air_pressure_on_interface_levels'][::-1, :, :])
        for name in (
                'air_pressure',
                'tracers',
                'eastward_wind',
                'northward_wind',
                'divergence_of_wind',
                'atmosphere_relative_vorticity',
                'surface_air_pressure',
        ):
            if np.product(outputs[name].shape) > 0:
                outputs[name][:] = state[name]

        _gfs_dynamics.assign_grid_arrays(
            outputs['eastward_wind'], outputs['northward_wind'], t_virt, lnsp,
            outputs['tracers'], outputs['atmosphere_relative_vorticity'],
            outputs['divergence_of_wind'])

        _gfs_dynamics.assign_pressure_arrays(
            outputs['surface_air_pressure'], outputs['air_pressure'],
            outputs['air_pressure_on_interface_levels'])

        _gfs_dynamics.set_topography(state['surface_geopotential'])

        _gfs_dynamics.calculate_pressure()

        np.testing.assert_allclose(outputs['air_pressure'],
                                   state['air_pressure'])
        np.testing.assert_allclose(
            outputs['air_pressure_on_interface_levels'][::-1, :, :],
            state['air_pressure_on_interface_levels'])

        self._update_spectral_arrays(state)

        tendency_arrays = \
            self._get_tendency_arrays(
                prognostic_tendencies, state['air_temperature'].shape)

        # see Pg. 12 in gfsModelDoc.pdf
        virtual_temp_tend = tendency_arrays['air_temperature']*(
            1 + self._fvirt*state['tracers'][0, :, :, :]) + \
            self._fvirt*t_virt*tendency_arrays['tracers'][0, :, :, :]

        # dlnps/dt = (1/ps)*dps/dt
        lnps_tend = ((1. / state['surface_air_pressure']) *
                     tendency_arrays['surface_air_pressure'])

        _gfs_dynamics.assign_tendencies(tendency_arrays['eastward_wind'],
                                        tendency_arrays['northward_wind'],
                                        virtual_temp_tend, lnps_tend,
                                        tendency_arrays['tracers'])

        _gfs_dynamics.take_one_step()
        _gfs_dynamics.convert_to_grid()
        _gfs_dynamics.calculate_pressure()

        if self._zero_negative_moisture:
            set_negatives_to_zero(outputs['tracers'][0, :, :, :])
        outputs['air_temperature'][:] = t_virt / (
            1 + self._fvirt * outputs['tracers'][0, :, :, :])

        outputs['air_pressure_on_interface_levels'][:] = \
            outputs['air_pressure_on_interface_levels'][::-1, :, :]

        outputs['time'] = state['time']

        return {}, outputs
Example #12
0
    def array_call(self, state):
        Q = mass_to_volume_mixing_ratio(state['specific_humidity'], 18.02)
        n_layers, n_columns = state['air_temperature'].shape

        if self._calc_Tint:
            T_interface = get_interface_values(
                state['air_temperature'], state['surface_temperature'],
                state['air_pressure'],
                state['air_pressure_on_interface_levels'])
        else:
            T_interface = state['air_temperature_on_interface_levels']

        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, state, self.input_properties)
        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, state, self.input_properties)

        if self._mcica:

            # First, define extra arrays needed for mcica.
            # The values for these arrays are calculated from state in the
            # first part of _rrtmg_sw.rrtm_calculate_longwave_fluxes_mcica.
            # Specifically they are calculated by mcica_subcol_gen_lw.f90
            # and are input to rrtmg_lw_rad.f90
            num_reduced_g_intervals = self.num_reduced_g_intervals
            mid_levels = state['air_pressure'].shape[0]

            try:
                num_cols = state['air_pressure'].shape[1]
            except IndexError:
                num_cols = 1

            mcica_properties = {
                'cloud_area_fraction_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'mass_content_of_cloud_ice_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'mass_content_of_cloud_liquid_water_in_atmosphere_layer':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals)),
                'cloud_ice_particle_size':
                np.zeros((mid_levels, num_cols)),
                'cloud_water_droplet_radius':
                np.zeros((mid_levels, num_cols)),
                'longwave_optical_thickness_due_to_cloud':
                np.zeros((mid_levels, num_cols, num_reduced_g_intervals))
            }

            # Change parameter for random number generator - each time the
            # radiation is called, with the same state / input properties,
            # a different result is obtained, because the wavelengths which
            # see cloud differ between each call.
            if self._random_number_generator == 0:
                # KISS algorithm: The seed determines the number of times
                # the random number generator is called iteratively to create a
                # new random number. The value range of the seed is limited to
                # avoid a performance decrease.
                self._permute_seed = np.random.randint(0, 1024)
            elif self._random_number_generator == 1:
                # Mersenne Twister: Use random seed from the full 32bit range.
                self._permute_seed = np.random.randint(0, 2**31 - 1)

            _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)

            _rrtmg_lw.rrtm_calculate_longwave_fluxes_mcica(
                self.rrtm_iplon, n_columns, n_layers, state['air_pressure'],
                state['air_pressure_on_interface_levels'],
                state['air_temperature'], T_interface,
                state['surface_temperature'], Q,
                state['mole_fraction_of_ozone_in_air'],
                state['mole_fraction_of_carbon_dioxide_in_air'],
                state['mole_fraction_of_methane_in_air'],
                state['mole_fraction_of_nitrous_oxide_in_air'],
                state['mole_fraction_of_oxygen_in_air'],
                state['mole_fraction_of_cfc11_in_air'],
                state['mole_fraction_of_cfc12_in_air'],
                state['mole_fraction_of_cfc22_in_air'],
                state['mole_fraction_of_carbon_tetrachloride_in_air'],
                state['surface_longwave_emissivity'],
                state['cloud_area_fraction_in_atmosphere_layer'],
                state['longwave_optical_thickness_due_to_aerosol'],
                diagnostics['upwelling_longwave_flux_in_air'],
                diagnostics['downwelling_longwave_flux_in_air'],
                tendencies['air_temperature'], diagnostics[
                    'upwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'downwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'air_temperature_tendency_from_longwave_assuming_clear_sky'],
                state['longwave_optical_thickness_due_to_cloud'],
                state['mass_content_of_cloud_ice_in_atmosphere_layer'], state[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                state['cloud_ice_particle_size'],
                state['cloud_water_droplet_radius'],
                mcica_properties['cloud_area_fraction_in_atmosphere_layer'],
                mcica_properties['longwave_optical_thickness_due_to_cloud'],
                mcica_properties[
                    'mass_content_of_cloud_ice_in_atmosphere_layer'],
                mcica_properties[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                mcica_properties['cloud_ice_particle_size'],
                mcica_properties['cloud_water_droplet_radius'])

        else:
            _rrtmg_lw.rrtm_calculate_longwave_fluxes(
                n_columns, n_layers, state['air_pressure'],
                state['air_pressure_on_interface_levels'],
                state['air_temperature'], T_interface,
                state['surface_temperature'], Q,
                state['mole_fraction_of_ozone_in_air'],
                state['mole_fraction_of_carbon_dioxide_in_air'],
                state['mole_fraction_of_methane_in_air'],
                state['mole_fraction_of_nitrous_oxide_in_air'],
                state['mole_fraction_of_oxygen_in_air'],
                state['mole_fraction_of_cfc11_in_air'],
                state['mole_fraction_of_cfc12_in_air'],
                state['mole_fraction_of_cfc22_in_air'],
                state['mole_fraction_of_carbon_tetrachloride_in_air'],
                state['surface_longwave_emissivity'],
                state['cloud_area_fraction_in_atmosphere_layer'],
                state['longwave_optical_thickness_due_to_aerosol'],
                diagnostics['upwelling_longwave_flux_in_air'],
                diagnostics['downwelling_longwave_flux_in_air'],
                tendencies['air_temperature'], diagnostics[
                    'upwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'downwelling_longwave_flux_in_air_assuming_clear_sky'],
                diagnostics[
                    'air_temperature_tendency_from_longwave_assuming_clear_sky'],
                state['longwave_optical_thickness_due_to_cloud'],
                state['mass_content_of_cloud_ice_in_atmosphere_layer'], state[
                    'mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
                state['cloud_ice_particle_size'],
                state['cloud_water_droplet_radius'])

        diagnostics['air_temperature_tendency_from_longwave'] = tendencies[
            'air_temperature']

        return tendencies, diagnostics
Example #13
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
Example #14
0
    def array_call(self, state):
        """
        Get heating tendencies and shortwave fluxes.

        Args:

            state (dict):
                The model state dictionary.

        Returns:

            tendencies (dict), diagnostics (dict):

                * The shortwave heating tendency.
                * The upward/downward shortwave fluxes for cloudy and clear
                  sky conditions.

        """
        Q = mass_to_volume_mixing_ratio(state['specific_humidity'], 18.02)
        assert state['air_pressure'].shape[0] + 1 == state[
            'air_pressure_on_interface_levels'].shape[0]

        Tint = get_interface_values(state['air_temperature'],
                                    state['surface_temperature'],
                                    state['air_pressure'],
                                    state['air_pressure_on_interface_levels'])

        diagnostics = initialize_numpy_arrays_with_properties(
            self.diagnostic_properties, state, self.input_properties)
        tendencies = initialize_numpy_arrays_with_properties(
            self.tendency_properties, state, self.input_properties)
        model_time = state['time']
        if self._ignore_day_of_year:
            day_of_year = 0
        else:
            day_of_year = model_time.timetuple().tm_yday
        cos_zenith_angle = np.cos(state['zenith_angle'])

        _rrtmg_sw.rrtm_calculate_shortwave_fluxes(
            state['air_temperature'].shape[1],
            state['air_temperature'].shape[0], day_of_year,
            state['solar_cycle_fraction'],
            state['flux_adjustment_for_earth_sun_distance'],
            state['air_pressure'], state['air_pressure_on_interface_levels'],
            state['air_temperature'], Tint, state['surface_temperature'], Q,
            state['mole_fraction_of_ozone_in_air'],
            state['mole_fraction_of_carbon_dioxide_in_air'],
            state['mole_fraction_of_methane_in_air'],
            state['mole_fraction_of_nitrous_oxide_in_air'],
            state['mole_fraction_of_oxygen_in_air'],
            state['surface_albedo_for_direct_shortwave'],
            state['surface_albedo_for_direct_near_infrared'],
            state['surface_albedo_for_diffuse_shortwave'],
            state['surface_albedo_for_diffuse_near_infrared'],
            cos_zenith_angle, state['cloud_area_fraction_in_atmosphere_layer'],
            diagnostics['upwelling_shortwave_flux_in_air'],
            diagnostics['downwelling_shortwave_flux_in_air'],
            tendencies['air_temperature'],
            diagnostics['upwelling_shortwave_flux_in_air_assuming_clear_sky'],
            diagnostics[
                'downwelling_shortwave_flux_in_air_assuming_clear_sky'],
            diagnostics[
                'air_temperature_tendency_from_shortwave_assuming_clear_sky'],
            state['shortwave_optical_thickness_due_to_aerosol'],
            state['single_scattering_albedo_due_to_aerosol'],
            state['aerosol_asymmetry_parameter'],
            state['aerosol_optical_depth_at_55_micron'],
            state['shortwave_optical_thickness_due_to_cloud'],
            state['single_scattering_albedo_due_to_cloud'],
            state['cloud_asymmetry_parameter'],
            state['cloud_forward_scattering_fraction'],
            state['mass_content_of_cloud_ice_in_atmosphere_layer'],
            state['mass_content_of_cloud_liquid_water_in_atmosphere_layer'],
            state['cloud_ice_particle_size'],
            state['cloud_water_droplet_radius'])

        diagnostics['air_temperature_tendency_from_shortwave'][:] = tendencies[
            'air_temperature']

        return tendencies, diagnostics