def mixing_ratio_to_specific_humidity(mixing_ratios_kg_kg01): """Converts one or more mixing ratios to specific humidities. :param mixing_ratios_kg_kg01: numpy array of mixing ratios (kg per kg). :return: specific_humidities_kg_kg01: equivalent-size numpy array of specific humidities (kg per kg). """ error_checking.assert_is_real_numpy_array(mixing_ratios_kg_kg01) return mixing_ratios_kg_kg01 / (1 + mixing_ratios_kg_kg01)
def fahrenheit_to_celsius(temperatures_deg_f): """Converts temperatures from Fahrenheit (deg F) to Celsius (deg C). :param temperatures_deg_f: numpy array of temperatures in deg F. :return: temperatures_deg_c: equivalent-size numpy array of temperatures in deg C. """ error_checking.assert_is_real_numpy_array(temperatures_deg_f) return ((temperatures_deg_f + FAHRENHEIT_TO_CELSIUS_ADDEND) * FAHRENHEIT_TO_CELSIUS_RATIO)
def specific_humidity_to_mixing_ratio(specific_humidities_kg_kg01): """Converts one or more specific humidities to mixing ratios. :param specific_humidities_kg_kg01: numpy array of specific humidities (kg per kg). :return: mixing_ratios_kg_kg01: equivalent-size numpy array of mixing ratios (kg per kg). """ error_checking.assert_is_real_numpy_array(specific_humidities_kg_kg01) return specific_humidities_kg_kg01 / (1 - specific_humidities_kg_kg01)
def celsius_to_fahrenheit(temperatures_deg_c): """Converts temperatures from Celsius (deg C) to Fahrenheit (deg F). :param temperatures_deg_c: numpy array of temperatures in deg C. :return: temperatures_deg_f: equivalent-size numpy array of temperatures in deg F. """ error_checking.assert_is_real_numpy_array(temperatures_deg_c) return (temperatures_deg_c / FAHRENHEIT_TO_CELSIUS_RATIO) - FAHRENHEIT_TO_CELSIUS_ADDEND
def get_echo_tops(reflectivity_matrix_dbz, grid_point_heights_m_asl, critical_reflectivity_dbz): """Finds echo top at each horizontal location. "Echo top" = maximum height with >= critical reflectivity. M = number of rows (unique grid-point latitudes) N = number of columns (unique grid-point longitudes) H = number of height levels (unique grid-point heights) :param reflectivity_matrix_dbz: H-by-M-by-N matrix of reflectivities. :param grid_point_heights_m_asl: length-H numpy array of grid-point heights (metres above sea level). Must be sorted in ascending order, which means that height must increase with the first index of reflectivity_matrix_dbz. :param critical_reflectivity_dbz: Critical reflectivity. :return: echo_top_matrix_m_asl: M-by-N matrix of echo tops (metres above sea level). :raises: ValueError: grid_point_heights_m_asl not sorted in ascending order. """ error_checking.assert_is_numpy_array(reflectivity_matrix_dbz, num_dimensions=3) error_checking.assert_is_real_numpy_array(reflectivity_matrix_dbz) error_checking.assert_is_greater(critical_reflectivity_dbz, 0.) num_grid_heights = reflectivity_matrix_dbz.shape[0] num_grid_rows = reflectivity_matrix_dbz.shape[1] num_grid_columns = reflectivity_matrix_dbz.shape[2] error_checking.assert_is_numpy_array(grid_point_heights_m_asl, exact_dimensions=numpy.array( [num_grid_heights])) error_checking.assert_is_geq_numpy_array(grid_point_heights_m_asl, 0.) sorted_heights_m_asl = numpy.sort(grid_point_heights_m_asl) if not numpy.array_equal(sorted_heights_m_asl, grid_point_heights_m_asl): raise ValueError('grid_point_heights_m_asl are not sorted in ' 'ascending order.') echo_top_matrix_m_asl = numpy.full((num_grid_rows, num_grid_columns), numpy.nan) for i in range(num_grid_rows): for j in range(num_grid_columns): echo_top_matrix_m_asl[i, j] = ( radar_utils.get_echo_top_single_column( reflectivities_dbz=reflectivity_matrix_dbz[:, i, j], heights_m_asl=grid_point_heights_m_asl, critical_reflectivity_dbz=critical_reflectivity_dbz, check_args=False)) return echo_top_matrix_m_asl
def rowcol_to_latlng(grid_rows, grid_columns, nw_grid_point_lat_deg, nw_grid_point_lng_deg, lat_spacing_deg, lng_spacing_deg): """Converts radar coordinates from row-column to lat-long. P = number of input grid points :param grid_rows: length-P numpy array with row indices of grid points (increasing from north to south). :param grid_columns: length-P numpy array with column indices of grid points (increasing from west to east). :param nw_grid_point_lat_deg: Latitude (deg N) of northwesternmost grid point. :param nw_grid_point_lng_deg: Longitude (deg E) of northwesternmost grid point. :param lat_spacing_deg: Spacing (deg N) between meridionally adjacent grid points. :param lng_spacing_deg: Spacing (deg E) between zonally adjacent grid points. :return: latitudes_deg: length-P numpy array with latitudes (deg N) of grid points. :return: longitudes_deg: length-P numpy array with longitudes (deg E) of grid points. """ error_checking.assert_is_real_numpy_array(grid_rows) error_checking.assert_is_geq_numpy_array(grid_rows, -0.5, allow_nan=True) error_checking.assert_is_numpy_array(grid_rows, num_dimensions=1) num_points = len(grid_rows) error_checking.assert_is_real_numpy_array(grid_columns) error_checking.assert_is_geq_numpy_array(grid_columns, -0.5, allow_nan=True) error_checking.assert_is_numpy_array(grid_columns, exact_dimensions=numpy.array( [num_points])) error_checking.assert_is_valid_latitude(nw_grid_point_lat_deg) nw_grid_point_lng_deg = lng_conversion.convert_lng_positive_in_west( nw_grid_point_lng_deg, allow_nan=False) error_checking.assert_is_greater(lat_spacing_deg, 0.) error_checking.assert_is_greater(lng_spacing_deg, 0.) latitudes_deg = rounder.round_to_nearest( nw_grid_point_lat_deg - lat_spacing_deg * grid_rows, lat_spacing_deg / 2) longitudes_deg = rounder.round_to_nearest( nw_grid_point_lng_deg + lng_spacing_deg * grid_columns, lng_spacing_deg / 2) return latitudes_deg, lng_conversion.convert_lng_positive_in_west( longitudes_deg, allow_nan=True)
def latlng_field_grid_points_to_edges(field_matrix=None, min_latitude_deg=None, min_longitude_deg=None, lat_spacing_deg=None, lng_spacing_deg=None): """Re-references lat-long field from grid points to edges. M = number of rows (unique grid-point latitudes) N = number of columns (unique grid-point longitudes) :param field_matrix: M-by-N numpy array with values of some variable (examples: temperature, radar reflectivity, etc.). Latitude should increase while traveling down a column, and longitude should increase while traveling right across a row. :param min_latitude_deg: See documentation for get_latlng_grid_points. :param min_longitude_deg: See documentation for get_latlng_grid_points. :param lat_spacing_deg: See documentation for get_latlng_grid_points. :param lng_spacing_deg: See documentation for get_latlng_grid_points. :param num_rows: See documentation for get_latlng_grid_points. :param num_columns: See documentation for get_latlng_grid_points. :return: field_matrix: Same as input, except that dimensions are now (M + 1) by (N + 1). The last row and last column contain only NaN's. :return: grid_cell_edge_latitudes_deg: length-(M + 1) numpy array with latitudes of grid-cell edges (deg N). :return: grid_cell_edge_longitudes_deg: length-(N + 1) numpy array with longitudes of grid-cell edges (deg E). """ error_checking.assert_is_real_numpy_array(field_matrix) error_checking.assert_is_numpy_array(field_matrix, num_dimensions=2) num_rows = field_matrix.shape[0] num_columns = field_matrix.shape[1] (grid_cell_edge_latitudes_deg, grid_cell_edge_longitudes_deg) = get_latlng_grid_cell_edges( min_latitude_deg=min_latitude_deg, min_longitude_deg=min_longitude_deg, lat_spacing_deg=lat_spacing_deg, lng_spacing_deg=lng_spacing_deg, num_rows=num_rows, num_columns=num_columns) nan_row = numpy.full((1, num_columns), numpy.nan) field_matrix = numpy.vstack((field_matrix, nan_row)) nan_column = numpy.full((num_rows + 1, 1), numpy.nan) field_matrix = numpy.hstack((field_matrix, nan_column)) return (field_matrix, grid_cell_edge_latitudes_deg, grid_cell_edge_longitudes_deg)
def project_xy_to_latlng(x_coords_metres, y_coords_metres, projection_object=None, false_easting_metres=0., false_northing_metres=0.): """Converts from projection (x-y) to lat-long coordinates. P = number of points :param x_coords_metres: length-P numpy array of x-coordinates. :param y_coords_metres: length-P numpy array of y-coordinates. :param projection_object: Projection object created by `pyproj.Proj`. :param false_easting_metres: False easting. Will be subtracted from all x- coordinates before conversion. :param false_northing_metres: False northing. Will be subtracted from all y-coordinates before conversion. :return: latitudes_deg: length-P numpy array of latitudes (deg N). :return: longitudes_deg: length-P numpy array of longitudes (deg E). """ error_checking.assert_is_real_numpy_array(x_coords_metres) shape_of_coord_arrays = x_coords_metres.shape error_checking.assert_is_numpy_array( y_coords_metres, exact_dimensions=numpy.asarray(shape_of_coord_arrays)) error_checking.assert_is_real_numpy_array(y_coords_metres) error_checking.assert_is_not_nan(false_easting_metres) error_checking.assert_is_not_nan(false_northing_metres) (longitudes_deg, latitudes_deg) = projection_object( x_coords_metres - false_easting_metres, y_coords_metres - false_northing_metres, inverse=True) num_points = x_coords_metres.size nan_flags = numpy.logical_or( numpy.isnan(numpy.reshape(x_coords_metres, num_points)), numpy.isnan(numpy.reshape(y_coords_metres, num_points))) nan_indices = numpy.where(nan_flags)[0] latitudes_deg_flat = numpy.reshape(latitudes_deg, num_points) latitudes_deg_flat[nan_indices] = numpy.nan longitudes_deg_flat = numpy.reshape(longitudes_deg, num_points) longitudes_deg_flat[nan_indices] = numpy.nan longitudes_deg_flat = lng_conversion.convert_lng_positive_in_west( longitudes_deg_flat, allow_nan=True) return (numpy.reshape(latitudes_deg_flat, shape_of_coord_arrays), numpy.reshape(longitudes_deg_flat, shape_of_coord_arrays))
def add_colour_bar(axes_object, values_to_colour=None, colour_map=None, colour_norm_object=None, orientation=DEFAULT_COLOUR_BAR_ORIENTATION, extend_min=True, extend_max=True): """Adds colour bar to existing plot. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param values_to_colour: numpy array of values to which the colour map will be applied. :param colour_map: Instance of `matplotlib.pyplot.cm`. :param colour_norm_object: Instance of `matplotlib.colors.Normalize`. :param orientation: Orientation (either "horizontal" or "vertical"). :param extend_min: Boolean flag. If extend_min = True, will add arrow to bottom end of colour bar. Otherwise, bottom of colour bar will be rectangular. :param extend_max: Same as extend_min, but for upper end of colour bar. :return: colour_bar_object: Instance of `matplotlib.pyplot.colorbar` created by this method. """ error_checking.assert_is_real_numpy_array(values_to_colour) error_checking.assert_is_boolean(extend_min) error_checking.assert_is_boolean(extend_max) scalar_mappable_object = pyplot.cm.ScalarMappable(cmap=colour_map, norm=colour_norm_object) scalar_mappable_object.set_array(values_to_colour) if extend_min and extend_max: extend_argument = 'both' elif extend_min: extend_argument = 'min' elif extend_max: extend_argument = 'max' else: extend_argument = 'neither' if orientation == 'horizontal': this_padding = PADDING_FOR_HORIZ_COLOUR_BAR else: this_padding = PADDING_FOR_VERTICAL_COLOUR_BAR return pyplot.colorbar(ax=axes_object, mappable=scalar_mappable_object, orientation=orientation, pad=this_padding, extend=extend_argument)
def round_to_half_integer(input_value): """Rounds numbers to nearest half-integer that is not also an integer. :param input_value: Either numpy array of real numbers or scalar real number. :return: output_value: Same as input_value, except rounded. """ if isinstance(input_value, collections.Iterable): error_checking.assert_is_real_numpy_array(input_value) else: error_checking.assert_is_real_number(input_value) return numpy.round(input_value + 0.5) - 0.5
def find_invalid_latitudes(latitudes_deg): """Returns array indices of invalid latitudes. :param latitudes_deg: 1-D numpy array of latitudes (deg N). :return: invalid_indices: 1-D numpy array with array indices of invalid latitudes. """ error_checking.assert_is_real_numpy_array(latitudes_deg) error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1) valid_flags = numpy.logical_and(latitudes_deg >= MIN_LATITUDE_DEG, latitudes_deg <= MAX_LATITUDE_DEG) return numpy.where(numpy.invert(valid_flags))[0]
def xy_field_grid_points_to_edges(field_matrix=None, x_min_metres=None, y_min_metres=None, x_spacing_metres=None, y_spacing_metres=None): """Re-references x-y field from grid points to edges. M = number of rows (unique grid-point x-coordinates) N = number of columns (unique grid-point y-coordinates) :param field_matrix: M-by-N numpy array with values of some variable (examples: temperature, radar reflectivity, etc.). y should increase while traveling down a column, and x should increase while traveling right across a row. :param x_min_metres: Minimum x-coordinate over all grid points. :param y_min_metres: Minimum y-coordinate over all grid points. :param x_spacing_metres: Spacing between adjacent grid points in x- direction. :param y_spacing_metres: Spacing between adjacent grid points in y- direction. :return: field_matrix: Same as input, except that dimensions are now (M + 1) by (N + 1). The last row and last column contain only NaN's. :return: grid_cell_edge_x_metres: length-(N + 1) numpy array with x- coordinates of grid-cell edges. :return: grid_cell_edge_y_metres: length-(M + 1) numpy array with y- coordinates of grid-cell edges. """ error_checking.assert_is_real_numpy_array(field_matrix) error_checking.assert_is_numpy_array(field_matrix, num_dimensions=2) num_rows = field_matrix.shape[0] num_columns = field_matrix.shape[1] grid_cell_edge_x_metres, grid_cell_edge_y_metres = get_xy_grid_cell_edges( x_min_metres=x_min_metres, y_min_metres=y_min_metres, x_spacing_metres=x_spacing_metres, y_spacing_metres=y_spacing_metres, num_rows=num_rows, num_columns=num_columns) nan_row = numpy.full((1, num_columns), numpy.nan) field_matrix = numpy.vstack((field_matrix, nan_row)) nan_column = numpy.full((num_rows + 1, 1), numpy.nan) field_matrix = numpy.hstack((field_matrix, nan_column)) return field_matrix, grid_cell_edge_x_metres, grid_cell_edge_y_metres
def get_spatial_statistics(radar_field, statistic_names=DEFAULT_STATISTIC_NAMES, percentile_levels=DEFAULT_PERCENTILE_LEVELS): """Computes spatial statistics for a single radar field. "Single field" = one variable at one elevation, one time step, many spatial locations. Radar field may have any number of dimensions (1-D, 2-D, etc.). N = number of non-percentile-based statistics P = number of percentile levels :param radar_field: numpy array. Each position in the array should be a different spatial location. :param statistic_names: length-N list of non-percentile-based statistics. :param percentile_levels: length-P numpy array of percentile levels. :return: statistic_values: length-N numpy with values of non-percentile- based statistics. :return: percentile_values: length-P numpy array of percentiles. """ error_checking.assert_is_real_numpy_array(radar_field) percentile_levels = _check_statistic_params(statistic_names, percentile_levels) num_statistics = len(statistic_names) statistic_values = numpy.full(num_statistics, numpy.nan) for i in range(num_statistics): if statistic_names[i] == AVERAGE_NAME: statistic_values[i] = numpy.nanmean(radar_field) elif statistic_names[i] == STANDARD_DEVIATION_NAME: statistic_values[i] = numpy.nanstd(radar_field, ddof=1) elif statistic_names[i] == SKEWNESS_NAME: statistic_values[i] = scipy.stats.skew(radar_field, bias=False, nan_policy='omit', axis=None) elif statistic_names[i] == KURTOSIS_NAME: statistic_values[i] = scipy.stats.kurtosis(radar_field, fisher=True, bias=False, nan_policy='omit', axis=None) percentile_values = numpy.nanpercentile(radar_field, percentile_levels, interpolation='linear') return statistic_values, percentile_values
def rotate_winds(u_winds_grid_relative_m_s01=None, v_winds_grid_relative_m_s01=None, rotation_angle_cosines=None, rotation_angle_sines=None): """Rotates wind vectors from grid-relative to Earth-relative. The equation is as follows, where alpha is the rotation angle. u_Earth = u_grid * cos(alpha) + v_grid * sin(alpha) v_Earth = v_grid * cos(alpha) - u_grid * sin(alpha) :param u_winds_grid_relative_m_s01: numpy array of grid-relative u-winds (towards positive x-direction). :param v_winds_grid_relative_m_s01: equivalent-shape numpy array of grid- relative v-winds (towards positive y-direction). :param rotation_angle_cosines: equivalent-shape numpy array with cosines of rotation angles. :param rotation_angle_sines: equivalent-shape numpy array with sines of rotation angles. :return: u_winds_earth_relative_m_s01: equivalent-shape numpy array of Earth-relative (northward) u-winds. :return: v_winds_earth_relative_m_s01: equivalent-shape numpy array of Earth-relative (eastward) v-winds. """ error_checking.assert_is_real_numpy_array(u_winds_grid_relative_m_s01) array_dimensions = numpy.asarray(u_winds_grid_relative_m_s01.shape) error_checking.assert_is_real_numpy_array(v_winds_grid_relative_m_s01) error_checking.assert_is_numpy_array(v_winds_grid_relative_m_s01, exact_dimensions=array_dimensions) error_checking.assert_is_geq_numpy_array(rotation_angle_cosines, -1) error_checking.assert_is_leq_numpy_array(rotation_angle_cosines, 1) error_checking.assert_is_numpy_array(rotation_angle_cosines, exact_dimensions=array_dimensions) error_checking.assert_is_geq_numpy_array(rotation_angle_sines, -1) error_checking.assert_is_leq_numpy_array(rotation_angle_sines, 1) error_checking.assert_is_numpy_array(rotation_angle_sines, exact_dimensions=array_dimensions) u_winds_earth_relative_m_s01 = ( rotation_angle_cosines * u_winds_grid_relative_m_s01 + rotation_angle_sines * v_winds_grid_relative_m_s01) v_winds_earth_relative_m_s01 = ( rotation_angle_cosines * v_winds_grid_relative_m_s01 - rotation_angle_sines * u_winds_grid_relative_m_s01) return u_winds_earth_relative_m_s01, v_winds_earth_relative_m_s01
def vapour_pressure_to_dewpoint(vapour_pressures_pascals): """Converts one or more vapour pressures to dewpoints. :param vapour_pressures_pascals: numpy array of vapour pressures (Pa). :return: dewpoints_kelvins: equivalent-size numpy array of dewpoints (K). """ error_checking.assert_is_real_numpy_array(vapour_pressures_pascals) log_coefficient = (WATER_VAPOUR_GAS_CONSTANT_J_KG01_K01 / LATENT_HEAT_OF_CONDENSATION_J_KG01) logarithms = numpy.log(vapour_pressures_pascals / BASE_VAPOUR_PRESSURE_PASCALS) return (BASE_TEMPERATURE_KELVINS**-1 - log_coefficient * logarithms)**-1
def split_array_by_nan(input_array): """Splits numpy array into list of contiguous subarrays without NaN. :param input_array: 1-D numpy array. :return: list_of_arrays: 1-D list of 1-D numpy arrays. Each numpy array is without NaN. """ error_checking.assert_is_real_numpy_array(input_array) error_checking.assert_is_numpy_array(input_array, num_dimensions=1) return [ input_array[i] for i in numpy.ma.clump_unmasked(numpy.ma.masked_invalid(input_array)) ]
def fill_nans(data_matrix): """Fills NaN's with nearest neighbours. This method is adapted from the method `fill`, which you can find here: https://stackoverflow.com/posts/9262129/revisions :param data_matrix: numpy array of real-valued data. :return: data_matrix: Same but without NaN's. """ error_checking.assert_is_real_numpy_array(data_matrix) indices = distance_transform_edt(numpy.isnan(data_matrix), return_distances=False, return_indices=True) return data_matrix[tuple(indices)]
def _check_longitudes(longitudes_deg): """Finds invalid longitudes. N = number of longitudes. :param longitudes_deg: length-N numpy array of longitudes (deg E). :return: invalid_indices: 1-D numpy array with indices of invalid longitudes. """ error_checking.assert_is_real_numpy_array(longitudes_deg) error_checking.assert_is_numpy_array(longitudes_deg, num_dimensions=1) valid_flags = numpy.logical_and(longitudes_deg >= MIN_LONGITUDE_DEG, longitudes_deg <= MAX_LONGITUDE_DEG) return numpy.where(numpy.invert(valid_flags))[0]
def round_to_nearest(input_value, rounding_base): """Rounds numbers to nearest x, where x is a positive real number. :param input_value: Either numpy array of real numbers or scalar real number. :param rounding_base: Numbers will be rounded to this base. :return: output_value: Same as input_value, except rounded. """ if isinstance(input_value, collections.Iterable): error_checking.assert_is_real_numpy_array(input_value) else: error_checking.assert_is_real_number(input_value) error_checking.assert_is_greater(rounding_base, 0) return rounding_base * numpy.round(input_value / rounding_base)
def get_column_max_reflectivity(reflectivity_matrix_dbz): """Finds column-max reflectivity at each horizontal location. M = number of rows (unique grid-point latitudes) N = number of columns (unique grid-point longitudes) H = number of height levels (unique grid-point heights) :param reflectivity_matrix_dbz: H-by-M-by-N matrix of reflectivities. :return: column_max_refl_matrix_dbz: M-by-N matrix of column-max reflectivities. """ error_checking.assert_is_numpy_array(reflectivity_matrix_dbz, num_dimensions=3) error_checking.assert_is_real_numpy_array(reflectivity_matrix_dbz) return numpy.nanmax(reflectivity_matrix_dbz, axis=0)
def dewpoint_to_vapour_pressure(dewpoints_kelvins): """Converts one or more dewpoints to vapour pressures. :param dewpoints_kelvins: numpy array of dewpoints (K). :return: vapour_pressures_pascals: equivalent-size numpy array of vapour pressures (Pa). """ error_checking.assert_is_real_numpy_array(dewpoints_kelvins) temperature_coefficient = (LATENT_HEAT_OF_CONDENSATION_J_KG01 / WATER_VAPOUR_GAS_CONSTANT_J_KG01_K01) temperature_diffs_kelvins = (BASE_TEMPERATURE_KELVINS**-1 - dewpoints_kelvins**-1) return BASE_VAPOUR_PRESSURE_PASCALS * numpy.exp( temperature_coefficient * temperature_diffs_kelvins)
def _check_vertex_arrays(x_coordinates, y_coordinates, allow_nan=True): """Checks vertex arrays for errors. x- and y-coordinates may be in one of three formats (see docstring at top of file). V = number of vertices :param x_coordinates: length-V numpy array with x-coordinates of vertices. The first NaN separates the exterior from the first hole, and the [i]th NaN separates the [i - 1]th hole from the [i]th hole. :param y_coordinates: Same as above, except for y-coordinates. :param allow_nan: Boolean flag. If True, input arrays may contain NaN's (however, NaN's must occur at the exact same positions in the two arrays). :raises: ValueError: if allow_nan = True but NaN's do not occur at the same positions in the two arrays. """ error_checking.assert_is_boolean(allow_nan) if allow_nan: error_checking.assert_is_real_numpy_array(x_coordinates) error_checking.assert_is_real_numpy_array(y_coordinates) else: error_checking.assert_is_numpy_array_without_nan(x_coordinates) error_checking.assert_is_numpy_array_without_nan(y_coordinates) error_checking.assert_is_numpy_array(x_coordinates, num_dimensions=1) num_vertices = len(x_coordinates) error_checking.assert_is_numpy_array(y_coordinates, exact_dimensions=numpy.array( [num_vertices])) x_nan_indices = numpy.where(numpy.isnan(x_coordinates))[0] y_nan_indices = numpy.where(numpy.isnan(y_coordinates))[0] if not numpy.array_equal(x_nan_indices, y_nan_indices): error_string = ( '\nNaN' 's occur at the following positions in `x_coordinates`:\n' + str(x_nan_indices) + '\nand the following positions in `y_coordinates`:\n' + str(y_nan_indices) + '\nNaN' 's should occur at the same positions in the two arrays.') raise ValueError(error_string)
def _check_wind_directions(wind_directions_deg): """Finds invalid wind directions. N = number of observations :param wind_directions_deg: length-N numpy array of wind directions (degrees of origin). :return: invalid_indices: 1-D numpy array with indices of invalid directions. """ error_checking.assert_is_real_numpy_array(wind_directions_deg) error_checking.assert_is_numpy_array(wind_directions_deg, num_dimensions=1) valid_flags = numpy.logical_and( wind_directions_deg >= MIN_WIND_DIRECTION_DEG, wind_directions_deg <= MAX_WIND_DIRECTION_DEG) return numpy.where(numpy.invert(valid_flags))[0]
def _check_elevations(elevations_m_asl): """Finds invalid surface elevations. N = number of elevations :param elevations_m_asl: length-N numpy array of elevations (metres above sea level). :return: invalid_indices: 1-D numpy array with indices of invalid surface elevations. For example, if 5th and 12th elevations are invalid, this array will contain 4 and 11. """ error_checking.assert_is_real_numpy_array(elevations_m_asl) error_checking.assert_is_numpy_array(elevations_m_asl, num_dimensions=1) valid_flags = numpy.logical_and(elevations_m_asl >= MIN_ELEVATION_M_ASL, elevations_m_asl <= MAX_ELEVATION_M_ASL) return numpy.where(numpy.invert(valid_flags))[0]
def _check_longitudes_positive_in_west(longitudes_deg): """Finds invalid longitudes. N = number of longitudes. :param longitudes_deg: length-N numpy array of longitudes (deg E), where values in western hemisphere are positive. :return: invalid_indices: 1-D numpy array with indices of invalid longitudes. """ error_checking.assert_is_real_numpy_array(longitudes_deg) error_checking.assert_is_numpy_array(longitudes_deg, num_dimensions=1) valid_flags = numpy.logical_and( longitudes_deg >= MIN_LNG_POSITIVE_IN_WEST_DEG, longitudes_deg <= MAX_LNG_POSITIVE_IN_WEST_DEG) return numpy.where(numpy.invert(valid_flags))[0]
def temperatures_to_potential_temperatures(temperatures_kelvins, total_pressures_pascals): """Converts one or more temperatures to potential temperatures. :param temperatures_kelvins: numpy array of temperatures (K). :param total_pressures_pascals: equivalent-size numpy array of total air pressures (Pa). :return: potential_temperatures_kelvins: equivalent-size numpy array of potential temperatures (K). """ error_checking.assert_is_real_numpy_array(temperatures_kelvins) error_checking.assert_is_real_numpy_array(total_pressures_pascals) temperature_dimensions = numpy.array(temperatures_kelvins.shape) error_checking.assert_is_numpy_array( total_pressures_pascals, exact_dimensions=temperature_dimensions) return (temperatures_kelvins * (REFERENCE_PRESSURE_PASCALS / total_pressures_pascals)**KAPPA)
def mixing_ratio_to_vapour_pressure(mixing_ratios_kg_kg01, total_pressures_pascals): """Converts one or more mixing ratios to vapour pressures. :param mixing_ratios_kg_kg01: numpy array of mixing ratios (kg per kg). :param total_pressures_pascals: equivalent-size numpy array of total air pressures (Pa). :return: vapour_pressures_pascals: equivalent-size numpy array of water vapour pressures (Pa). """ error_checking.assert_is_real_numpy_array(mixing_ratios_kg_kg01) error_checking.assert_is_real_numpy_array(total_pressures_pascals) mixing_ratio_dimensions = numpy.asarray(mixing_ratios_kg_kg01.shape) error_checking.assert_is_numpy_array( total_pressures_pascals, exact_dimensions=mixing_ratio_dimensions) return (mixing_ratios_kg_kg01 * total_pressures_pascals) / (EPSILON + mixing_ratios_kg_kg01)
def vapour_pressure_to_mixing_ratio(vapour_pressures_pascals, total_pressures_pascals): """Converts one or more vapour pressures to mixing ratios. :param vapour_pressures_pascals: numpy array of vapour pressures (Pa). :param total_pressures_pascals: equivalent-size numpy array of total air pressures (K). :return: mixing_ratios_kg_kg01: equivalent-size numpy array of mixing ratios (kg per kg). """ error_checking.assert_is_real_numpy_array(vapour_pressures_pascals) error_checking.assert_is_real_numpy_array(total_pressures_pascals) vapour_pressure_dimensions = numpy.asarray(vapour_pressures_pascals.shape) error_checking.assert_is_numpy_array( total_pressures_pascals, exact_dimensions=vapour_pressure_dimensions) return (vapour_pressures_pascals * EPSILON) / (total_pressures_pascals - vapour_pressures_pascals)
def temperature_to_virtual_temperature(temperatures_kelvins, total_pressures_pascals, vapour_pressures_pascals): """Converts one or more temperatures to virtual temperatures. :param temperatures_kelvins: numpy array of air temperatures (K). :param total_pressures_pascals: equivalent-size numpy array of total air pressures (Pa). :param vapour_pressures_pascals: equivalent-size numpy array of vapour pressures (Pa). :return: virtual_temperatures_kelvins: equivalent-size numpy array of virtual air temperatures (K). """ error_checking.assert_is_real_numpy_array(temperatures_kelvins) error_checking.assert_is_real_numpy_array(total_pressures_pascals) error_checking.assert_is_real_numpy_array(vapour_pressures_pascals) temperature_dimensions = numpy.asarray(temperatures_kelvins.shape) error_checking.assert_is_numpy_array( total_pressures_pascals, exact_dimensions=temperature_dimensions) error_checking.assert_is_numpy_array( vapour_pressures_pascals, exact_dimensions=temperature_dimensions) denominator_values = 1. - ( (vapour_pressures_pascals / total_pressures_pascals) * (1. - EPSILON)) return temperatures_kelvins / denominator_values
def find_invalid_longitudes(longitudes_deg, sign_in_western_hemisphere=POSITIVE_LONGITUDE_ARG): """Returns array indices of invalid longitudes. :param longitudes_deg: 1-D numpy array of longitudes (deg E). :param sign_in_western_hemisphere: Required sign in western hemisphere. May be "positive", "negative", or "either". :return: invalid_indices: 1-D numpy array with array indices of invalid longitudes. :raises: ValueError: if `sign_in_western_hemisphere` is not one of the 3 aforelisted options. """ error_checking.assert_is_real_numpy_array(longitudes_deg) error_checking.assert_is_numpy_array(longitudes_deg, num_dimensions=1) error_checking.assert_is_string(sign_in_western_hemisphere) if sign_in_western_hemisphere == POSITIVE_LONGITUDE_ARG: valid_flags = numpy.logical_and( longitudes_deg >= MIN_LONGITUDE_POSITIVE_IN_WEST_DEG, longitudes_deg <= MAX_LONGITUDE_POSITIVE_IN_WEST_DEG) elif sign_in_western_hemisphere == NEGATIVE_LONGITUDE_ARG: valid_flags = numpy.logical_and( longitudes_deg >= MIN_LONGITUDE_NEGATIVE_IN_WEST_DEG, longitudes_deg <= MAX_LONGITUDE_NEGATIVE_IN_WEST_DEG) elif sign_in_western_hemisphere == EITHER_SIGN_LONGITUDE_ARG: valid_flags = numpy.logical_and( longitudes_deg >= MIN_LONGITUDE_NEGATIVE_IN_WEST_DEG, longitudes_deg <= MAX_LONGITUDE_POSITIVE_IN_WEST_DEG) else: error_string = ( '\n\n{0:s}Valid options for `sign_in_western_hemisphere` are listed' ' above and do not include "{1:s}".').format( str(VALID_LONGITUDE_SIGN_ARGS), sign_in_western_hemisphere) raise ValueError(error_string) return numpy.where(numpy.invert(valid_flags))[0]