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
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
def test_empty(self): output_properties = {} input_properties = {} input_state = {} result = initialize_numpy_arrays_with_properties( output_properties, input_state, input_properties) assert result == {}
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]))
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
def array_call(self, state): toa_pressure = get_constant('top_of_model_pressure', 'Pa') rd = get_constant('gas_constant_of_dry_air', 'J kg^-1 K^-1') cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J kg^-1 K^-1') longitude = np.radians(state['longitude']) latitude = np.radians(state['latitude']) diagnostics = initialize_numpy_arrays_with_properties( self.diagnostic_properties, state, self.input_properties) if self._condition_type is 'baroclinic_wave': u, v, t, q, p_surface, phi_surface = _dcmip.get_baroclinic_wave_ics( state['air_pressure'], longitude, latitude, perturb=self._add_perturbation, moist_sim=self._moist) elif self._condition_type is 'tropical_cyclone': u, v, t, q, p_surface, phi_surface = _dcmip.get_tropical_cyclone_ics( state['air_pressure'], longitude, latitude, perturb=self._add_perturbation, moist_sim=self._moist) diagnostics['eastward_wind'][:] = u diagnostics['northward_wind'][:] = v diagnostics['air_temperature'][:] = t diagnostics['surface_geopotential'][:] = phi_surface diagnostics['specific_humidity'][:] = q diagnostics['surface_air_pressure'][:] = p_surface p_interface = (state['ak'] + state['bk'] * (p_surface - toa_pressure)) delta_p = p_interface[1:, :] - p_interface[:-1, :] rk = rd / cpd diagnostics['air_pressure_on_interface_levels'][:] = p_interface diagnostics['air_pressure'][:] = ( (p_interface[1:, :]**(rk + 1) - p_interface[:-1, :]**(rk + 1)) / ((rk + 1) * delta_p))**(1. / rk) return diagnostics
def test_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]))
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
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
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
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
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
def array_call(self, state, time_step): self._Cpd = get_constant('heat_capacity_of_dry_air_at_constant_pressure', 'J/kg/degK') self._Cvap = get_constant('heat_capacity_of_vapor_phase', 'J/kg/K') self._Rdair = get_constant('gas_constant_of_dry_air', 'J/kg/degK') self._Pref = get_constant('reference_air_pressure', 'Pa') self._Rv = get_constant('gas_constant_of_vapor_phase', 'J/kg/K') q = state['specific_humidity'] output_arrays = initialize_numpy_arrays_with_properties( self.output_properties, state, self.input_properties ) output_temperature = output_arrays['air_temperature'] output_temperature[:] = state['air_temperature'] output_q = output_arrays['specific_humidity'] output_q[:] = q rd_cp = self.gas_constant(q)/self.heat_capacity(q) theta = state['air_temperature']*(self._Pref/state['air_pressure'])**rd_cp num_levels = q.shape[0] for column in range(q.shape[-1]): for level in range(num_levels-1, -1, -1): dp = state['P_int'][:-1, column] - state['P_int'][1:, column] theta_q = theta*(1 + output_q*self._Rv/self._Rdair - output_q) theta_sum = np.cumsum(theta_q[level::, column]) divisor = np.arange(1, num_levels - level+1) theta_avg = (theta_sum/divisor)[1::] theta_lesser = (theta_avg > theta_q[level+1::, column]) if np.sum(theta_lesser) == 0: continue convect_to_level = len(theta_lesser) - np.argmax(theta_lesser[::-1]) if level == 0: convect_to_level = max(convect_to_level, 1) if convect_to_level == 0: continue stable_level = level + convect_to_level q_conv = output_q[level:stable_level, column] t_conv = output_temperature[level:stable_level, column] dp_conv = dp[level:stable_level] p_conv_high = state['P_int'][level, column] p_conv_low = state['P_int'][stable_level, column] enthalpy = self.heat_capacity(q_conv)*t_conv integral_enthalpy = np.sum(enthalpy*dp_conv) mean_conv_q = np.sum(q_conv*dp_conv)/(p_conv_high - p_conv_low) output_q[level:stable_level, column] = mean_conv_q rdcp_conv = self.gas_constant(mean_conv_q)/self.heat_capacity(mean_conv_q) theta_coeff = ( state['air_pressure'][level:stable_level, column]/self._Pref)**rdcp_conv integral_theta_den = np.sum(self.heat_capacity(q_conv)*theta_coeff*dp_conv) mean_theta = integral_enthalpy/integral_theta_den output_temperature[level:stable_level, column] = mean_theta*theta_coeff return {}, output_arrays
def 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