def dewpoint_to_vapour_pressure(dewpoints_kelvins, temperatures_kelvins, total_pressures_pascals): """Converts each dewpoint to vapour pressure. Source: https://content.meteoblue.com/hu/specifications/weather-variables/humidity :param dewpoints_kelvins: numpy array (any shape) of dewpoints. :param temperatures_kelvins: numpy array (same shape) of temperatures. :param total_pressures_pascals: numpy array (same shape) of total air pressures. :return: vapour_pressures_pascals: numpy array (same shape) of vapour pressures. """ error_checking.assert_is_geq_numpy_array( dewpoints_kelvins, 0., allow_nan=True ) error_checking.assert_is_geq_numpy_array( temperatures_kelvins, 0., allow_nan=True ) error_checking.assert_is_numpy_array( temperatures_kelvins, exact_dimensions=numpy.array(dewpoints_kelvins.shape, dtype=int) ) error_checking.assert_is_geq_numpy_array( total_pressures_pascals, 0., allow_nan=True ) error_checking.assert_is_numpy_array( total_pressures_pascals, exact_dimensions=numpy.array(dewpoints_kelvins.shape, dtype=int) ) dewpoints_deg_c = temperature_conv.kelvins_to_celsius(dewpoints_kelvins) temperatures_deg_c = temperature_conv.kelvins_to_celsius( temperatures_kelvins ) numerator_coeffs = numpy.full( temperatures_deg_c.shape, MAGNUS_NUMERATOR_COEFF_WATER ) numerator_coeffs[temperatures_deg_c < 0] = MAGNUS_NUMERATOR_COEFF_ICE numerators = numerator_coeffs * dewpoints_deg_c denominator_coeffs = numpy.full( temperatures_deg_c.shape, MAGNUS_DENOMINATOR_COEFF_WATER ) denominator_coeffs[temperatures_deg_c < 0] = MAGNUS_DENOMINATOR_COEFF_ICE denominators = denominator_coeffs + dewpoints_deg_c vapour_pressures_pascals = ( BASE_VAPOUR_PRESSURE_PASCALS * numpy.exp(numerators / denominators) ) vapour_pressures_pascals[ numpy.invert(numpy.isfinite(vapour_pressures_pascals)) ] = 0. vapour_pressures_pascals[denominators <= 0] = 0. return numpy.minimum(vapour_pressures_pascals, total_pressures_pascals)
def test_kelvins_to_celsius(self): """Ensures correct output from kelvins_to_celsius.""" these_temperatures_deg_c = temperature_conversions.kelvins_to_celsius( TEMPERATURES_KELVINS) self.assertTrue( numpy.allclose(these_temperatures_deg_c, TEMPERATURES_DEG_C, atol=TOLERANCE))
def vapour_pressure_to_dewpoint(vapour_pressures_pascals, temperatures_kelvins): """Converts each vapour pressure to dewpoint. Source: https://content.meteoblue.com/hu/specifications/weather-variables/humidity :param vapour_pressures_pascals: numpy array (any shape) of vapour pressures. :param temperatures_kelvins: numpy array (same shape) of temperatures. :return: dewpoints_kelvins: numpy array (same shape) of dewpoints. """ error_checking.assert_is_geq_numpy_array( vapour_pressures_pascals, 0., allow_nan=True ) error_checking.assert_is_geq_numpy_array( temperatures_kelvins, 0., allow_nan=True ) error_checking.assert_is_numpy_array( temperatures_kelvins, exact_dimensions=numpy.array(vapour_pressures_pascals.shape, dtype=int) ) logarithms = numpy.log( vapour_pressures_pascals / BASE_VAPOUR_PRESSURE_PASCALS ) temperatures_deg_c = temperature_conv.kelvins_to_celsius( temperatures_kelvins ) numerator_coeffs = numpy.full( temperatures_deg_c.shape, MAGNUS_DENOMINATOR_COEFF_WATER ) numerator_coeffs[temperatures_deg_c < 0] = MAGNUS_DENOMINATOR_COEFF_ICE numerators = numerator_coeffs * logarithms denominator_coeffs = numpy.full( temperatures_deg_c.shape, MAGNUS_NUMERATOR_COEFF_WATER ) denominator_coeffs[temperatures_deg_c < 0] = MAGNUS_NUMERATOR_COEFF_ICE denominators = denominator_coeffs - logarithms dewpoints_deg_c = numerators / denominators dewpoints_kelvins = temperature_conv.celsius_to_kelvins(dewpoints_deg_c) dewpoints_kelvins[numpy.invert(numpy.isfinite(dewpoints_kelvins))] = 0. dewpoints_kelvins[dewpoints_deg_c + numerator_coeffs < 0] = 0. return dewpoints_kelvins
def soundings_to_metpy_dictionaries(sounding_matrix, field_names, height_levels_m_agl=None, storm_elevations_m_asl=None): """Converts soundings to format required by MetPy. If `sounding_matrix` contains pressures, `height_levels_m_agl` and `storm_elevations_m_asl` will not be used. Otherwise, `height_levels_m_agl` and `storm_elevations_m_asl` will be used to estimate the pressure levels for each sounding. :param sounding_matrix: numpy array (E x H_s x F_s) of soundings. :param field_names: list (length F_s) of field names, in the order that they appear in `sounding_matrix`. :param height_levels_m_agl: numpy array (length H_s) of height levels (metres above ground level), in the order that they appear in `sounding_matrix`. :param storm_elevations_m_asl: length-E numpy array of storm elevations (metres above sea level). :return: list_of_metpy_dictionaries: length-E list of dictionaries. The format of each dictionary is described in the input doc for `sounding_plotting.plot_sounding`. """ error_checking.assert_is_string_list(field_names) error_checking.assert_is_numpy_array(numpy.array(field_names), num_dimensions=1) check_soundings(sounding_matrix=sounding_matrix, num_fields=len(field_names)) try: pressure_index = field_names.index(soundings.PRESSURE_NAME) pressure_matrix_pascals = sounding_matrix[..., pressure_index] except ValueError: error_checking.assert_is_geq_numpy_array(height_levels_m_agl, 0) error_checking.assert_is_numpy_array(height_levels_m_agl, num_dimensions=1) error_checking.assert_is_numpy_array_without_nan( storm_elevations_m_asl) error_checking.assert_is_numpy_array(storm_elevations_m_asl, num_dimensions=1) num_height_levels = len(height_levels_m_agl) num_examples = len(storm_elevations_m_asl) check_soundings(sounding_matrix=sounding_matrix, num_examples=num_examples, num_height_levels=num_height_levels) height_matrix_m_asl = numpy.full((num_examples, num_height_levels), numpy.nan) for i in range(num_examples): height_matrix_m_asl[i, ...] = (height_levels_m_agl + storm_elevations_m_asl[i]) pressure_matrix_pascals = standard_atmo.height_to_pressure( height_matrix_m_asl) try: temperature_index = field_names.index(soundings.TEMPERATURE_NAME) temperature_matrix_kelvins = sounding_matrix[..., temperature_index] except ValueError: virtual_pot_temp_index = field_names.index( soundings.VIRTUAL_POTENTIAL_TEMPERATURE_NAME) temperature_matrix_kelvins = ( temperature_conversions.temperatures_from_potential_temperatures( potential_temperatures_kelvins=sounding_matrix[ ..., virtual_pot_temp_index], total_pressures_pascals=pressure_matrix_pascals)) try: specific_humidity_index = field_names.index( soundings.SPECIFIC_HUMIDITY_NAME) dewpoint_matrix_kelvins = ( moisture_conversions.specific_humidity_to_dewpoint( specific_humidities_kg_kg01=sounding_matrix[ ..., specific_humidity_index], total_pressures_pascals=pressure_matrix_pascals)) except ValueError: relative_humidity_index = field_names.index( soundings.RELATIVE_HUMIDITY_NAME) dewpoint_matrix_kelvins = ( moisture_conversions.relative_humidity_to_dewpoint( relative_humidities=sounding_matrix[..., relative_humidity_index], temperatures_kelvins=temperature_matrix_kelvins, total_pressures_pascals=pressure_matrix_pascals)) temperature_matrix_celsius = temperature_conversions.kelvins_to_celsius( temperature_matrix_kelvins) dewpoint_matrix_celsius = temperature_conversions.kelvins_to_celsius( dewpoint_matrix_kelvins) try: u_wind_index = field_names.index(soundings.U_WIND_NAME) v_wind_index = field_names.index(soundings.V_WIND_NAME) include_wind = True except ValueError: include_wind = False num_examples = sounding_matrix.shape[0] list_of_metpy_dictionaries = [None] * num_examples for i in range(num_examples): list_of_metpy_dictionaries[i] = { soundings.PRESSURE_COLUMN_METPY: pressure_matrix_pascals[i, :] * PASCALS_TO_MB, soundings.TEMPERATURE_COLUMN_METPY: temperature_matrix_celsius[i, :], soundings.DEWPOINT_COLUMN_METPY: dewpoint_matrix_celsius[i, :], } if include_wind: list_of_metpy_dictionaries[i].update({ soundings.U_WIND_COLUMN_METPY: (sounding_matrix[i, ..., u_wind_index] * METRES_PER_SECOND_TO_KT), soundings.V_WIND_COLUMN_METPY: (sounding_matrix[i, ..., v_wind_index] * METRES_PER_SECOND_TO_KT) }) return list_of_metpy_dictionaries
def plot_predictors( example_dict, example_index, predictor_names, predictor_colours, predictor_line_widths, predictor_line_styles, use_log_scale, include_units=True, handle_dict=None): """Plots several predictors on the same set of axes. P = number of predictors to plot (must all be profiles) :param example_dict: See doc for `example_io.read_file`. :param example_index: Will plot the [i]th example, where i = `example_index`. :param predictor_names: length-P list with names of predictors to plot. :param predictor_colours: length-P list of colours (each colour in any format accepted by matplotlib). :param predictor_line_widths: length-P numpy array of line widths. :param predictor_line_styles: length-P list of line styles (each style in any format accepted by matplotlib). :param use_log_scale: Boolean flag. If True, will plot height (y-axis) in logarithmic scale. If False, will plot height in linear scale. :param include_units: Boolean flag. If True, axis titles will include units and values will be converted from default to plotting units. If False, axis titles will *not* include units and this method will *not* convert units. :param handle_dict: See output doc. If None, will create new figure on the fly. :return: handle_dict: Dictionary with the following keys. handle_dict['figure_object']: Figure handle (instance of `matplotlib.figure.Figure`). handle_dict['axes_objects']: length-P list of axes handles (each an instance of `matplotlib.axes._subplots.AxesSubplot`). """ # Check input args. error_checking.assert_is_integer(example_index) error_checking.assert_is_geq(example_index, 0) error_checking.assert_is_boolean(use_log_scale) error_checking.assert_is_boolean(include_units) error_checking.assert_is_string_list(predictor_names) num_predictors = len(predictor_names) error_checking.assert_is_leq(num_predictors, 4) for k in range(num_predictors): assert predictor_names[k] in example_utils.ALL_PREDICTOR_NAMES # assert predictor_names[k] in example_utils.ALL_VECTOR_PREDICTOR_NAMES assert len(predictor_colours) == num_predictors assert len(predictor_line_widths) == num_predictors assert len(predictor_line_styles) == num_predictors # Housekeeping. _set_font_size(FANCY_FONT_SIZE) if handle_dict is None: figure_object, first_axes_object = pyplot.subplots( 1, 1, figsize=(FANCY_FIGURE_WIDTH_INCHES, FANCY_FIGURE_HEIGHT_INCHES) ) axes_objects = [first_axes_object] figure_object.subplots_adjust(bottom=0.75) if use_log_scale: pyplot.yscale('log') for k in range(1, num_predictors): axes_objects.append(axes_objects[0].twiny()) if k == 2: axes_objects[k].spines['top'].set_position(('axes', 1.15)) _make_spines_invisible(axes_objects[k]) axes_objects[k].spines['top'].set_visible(True) if k == 3: axes_objects[k].xaxis.set_ticks_position('bottom') axes_objects[k].xaxis.set_label_position('bottom') axes_objects[k].spines['bottom'].set_position(('axes', -0.15)) _make_spines_invisible(axes_objects[k]) axes_objects[k].spines['bottom'].set_visible(True) else: figure_object = handle_dict[FIGURE_HANDLE_KEY] axes_objects = handle_dict[AXES_OBJECTS_KEY] heights_km_agl = METRES_TO_KM * example_dict[example_utils.HEIGHTS_KEY] tick_mark_dict = dict(size=4, width=1.5) for k in range(num_predictors): if predictor_names[k] in example_utils.ALL_SCALAR_PREDICTOR_NAMES: # TODO(thunderhoser): This is a HACK to deal with saliency maps. j = example_dict[example_utils.SCALAR_PREDICTOR_NAMES_KEY].index( predictor_names[k] ) these_predictor_values = ( example_dict[example_utils.SCALAR_PREDICTOR_VALS_KEY][ example_index, :, j ] ) else: these_predictor_values = example_utils.get_field_from_dict( example_dict=example_dict, field_name=predictor_names[k] )[example_index, ...] if include_units: if predictor_names[k] == example_utils.TEMPERATURE_NAME: these_predictor_values = temperature_conv.kelvins_to_celsius( these_predictor_values ) else: these_predictor_values = ( PREDICTOR_NAME_TO_CONV_FACTOR[predictor_names[k]] * these_predictor_values ) axes_objects[k].plot( these_predictor_values, heights_km_agl, color=predictor_colours[k], linewidth=predictor_line_widths[k], linestyle=predictor_line_styles[k] ) x_label_string = copy.deepcopy( PREDICTOR_NAME_TO_VERBOSE[predictor_names[k]] ) if not include_units: x_label_string = x_label_string.split(' (')[0] axes_objects[k].set_xlabel(x_label_string) axes_objects[k].xaxis.label.set_color(predictor_colours[k]) axes_objects[k].tick_params( axis='x', colors=predictor_colours[k], **tick_mark_dict ) axes_objects[0].set_ylabel('Height (km AGL)') axes_objects[0].set_ylim([ numpy.min(heights_km_agl), numpy.max(heights_km_agl) ]) height_strings = create_height_labels( tick_values_km_agl=axes_objects[0].get_yticks(), use_log_scale=use_log_scale ) axes_objects[0].set_yticklabels(height_strings) axes_objects[0].tick_params(axis='y', **tick_mark_dict) return { FIGURE_HANDLE_KEY: figure_object, AXES_OBJECTS_KEY: axes_objects }
STORM_ELEVATIONS_M_ASL[1] + HEIGHT_LEVELS_M_AGL) SECOND_PRESSURES_PASCALS = numpy.reshape(SECOND_PRESSURES_PASCALS, (len(SECOND_PRESSURES_PASCALS), 1)) THIS_SECOND_MATRIX = numpy.hstack( (SECOND_PRESSURES_PASCALS, THIS_SECOND_MATRIX)) SOUNDING_MATRIX_UNNORMALIZED = numpy.stack( (THIS_FIRST_MATRIX, THIS_SECOND_MATRIX), axis=0) FIRST_DEWPOINTS_KELVINS = moisture_conversions.specific_humidity_to_dewpoint( specific_humidities_kg_kg01=THIS_FIRST_MATRIX[:, 5], total_pressures_pascals=THIS_FIRST_MATRIX[:, 0]) FIRST_METPY_DICT = { soundings.TEMPERATURE_COLUMN_METPY: temperature_conversions.kelvins_to_celsius(THIS_FIRST_MATRIX[:, 2]), soundings.U_WIND_COLUMN_METPY: METRES_PER_SECOND_TO_KT * THIS_FIRST_MATRIX[:, 3], soundings.V_WIND_COLUMN_METPY: METRES_PER_SECOND_TO_KT * THIS_FIRST_MATRIX[:, 4], soundings.DEWPOINT_COLUMN_METPY: temperature_conversions.kelvins_to_celsius(FIRST_DEWPOINTS_KELVINS), soundings.PRESSURE_COLUMN_METPY: THIS_FIRST_MATRIX[:, 0] * PASCALS_TO_MB } SECOND_DEWPOINTS_KELVINS = moisture_conversions.specific_humidity_to_dewpoint( specific_humidities_kg_kg01=THIS_SECOND_MATRIX[:, 5], total_pressures_pascals=THIS_SECOND_MATRIX[:, 0]) SECOND_METPY_DICT = {