def latlng_vectors_to_matrices(unique_latitudes_deg, unique_longitudes_deg): """Converts vectors of lat and long coordinates to matrices. This method works only for a regular lat-long grid. Works for coordinates of either grid points or grid-cell edges. M = number of rows in grid N = number of columns in grid :param unique_latitudes_deg: length-M numpy array with latitudes (deg N) of either grid points or grid-cell edges. :param unique_longitudes_deg: length-N numpy array with longitudes (deg E) of either grid points or grid-cell edges. :return: latitude_matrix_deg: M-by-N numpy array, where latitude_matrix_deg[i, *] = unique_latitudes_deg[i]. Each column in this matrix is the same. :return: longitude_matrix_deg: M-by-N numpy array, where longitude_matrix_deg[*, j] = unique_longitudes_deg[j]. Each row in this matrix is the same. """ error_checking.assert_is_valid_lat_numpy_array(unique_latitudes_deg) error_checking.assert_is_numpy_array(unique_latitudes_deg, num_dimensions=1) error_checking.assert_is_numpy_array(unique_longitudes_deg, num_dimensions=1) unique_longitudes_deg = lng_conversion.convert_lng_positive_in_west( unique_longitudes_deg, allow_nan=False) (longitude_matrix_deg, latitude_matrix_deg) = numpy.meshgrid( unique_longitudes_deg, unique_latitudes_deg) return latitude_matrix_deg, longitude_matrix_deg
def get_wind_rotation_angles(latitudes_deg, longitudes_deg, model_name=None): """Returns wind-rotation angle for each lat-long point. These angles may be used in `rotate_winds`. :param latitudes_deg: numpy array of latitudes (deg N). :param longitudes_deg: equivalent-shape numpy array of longitudes (deg E). :param model_name: Name of model. :return: rotation_angle_cosines: equivalent-shape numpy array with cosines of rotation angles. :return: rotation_angle_sines: equivalent-shape numpy array with sines of rotation angles. """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg, allow_nan=False) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg, allow_nan=False) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=numpy.asarray( latitudes_deg.shape)) standard_latitudes_deg, central_longitude_deg = get_projection_params( model_name) rotation_angles = ( numpy.sin(standard_latitudes_deg[0] * DEGREES_TO_RADIANS) * (longitudes_deg - central_longitude_deg) * DEGREES_TO_RADIANS) return numpy.cos(rotation_angles), numpy.sin(rotation_angles)
def init_lambert_conformal_projection(standard_latitudes_deg, central_longitude_deg): """Initializes Lambert conformal projection. :param standard_latitudes_deg: length-2 numpy array with standard parallels (deg N). standard_latitudes_deg[0] is the first standard parallel; standard_latitudes_deg[1] is the second standard parallel. :param central_longitude_deg: central meridian (deg E). :return: projection_object: object created by `pyproj.Proj`, specifying the Lambert conformal projection. """ error_checking.assert_is_valid_lat_numpy_array(standard_latitudes_deg) error_checking.assert_is_numpy_array(standard_latitudes_deg, exact_dimensions=numpy.array([2])) error_checking.assert_is_non_array(central_longitude_deg) central_longitude_deg = lng_conversion.convert_lng_positive_in_west( central_longitude_deg, allow_nan=False) return Proj(proj='lcc', lat_1=standard_latitudes_deg[0], lat_2=standard_latitudes_deg[1], lon_0=central_longitude_deg, rsphere=EARTH_RADIUS_METRES, ellps='sphere')
def interp_temperature_sfc_from_nwp( radar_grid_point_lats_deg=None, radar_grid_point_lngs_deg=None, unix_time_sec=None, temperature_kelvins=None, model_name=None, grid_id=None, top_grib_directory_name=None, wgrib_exe_name=grib_io.WGRIB_EXE_NAME_DEFAULT, wgrib2_exe_name=grib_io.WGRIB2_EXE_NAME_DEFAULT): """Interpolates temperature isosurface from NWP model. M = number of rows (unique grid-point latitudes) in radar grid N = number of columns (unique grid-point longitudes) in radar grid :param radar_grid_point_lats_deg: length-M numpy array of grid-point latitudes (deg N). :param radar_grid_point_lngs_deg: length-N numpy array of grid-point longitudes (deg E). :param unix_time_sec: Target time. :param temperature_kelvins: Target temperature. :param model_name: Name of model. :param grid_id: String ID for model grid. :param top_grib_directory_name: Name of top-level directory with grib files for the given model. :param wgrib_exe_name: Path to wgrib executable. :param wgrib2_exe_name: Path to wgrib2 executable. :return: isosurface_height_matrix_m_asl: length-Q numpy array with heights of temperature isosurface (metres above sea level). """ error_checking.assert_is_numpy_array( radar_grid_point_lats_deg, num_dimensions=1) error_checking.assert_is_valid_lat_numpy_array(radar_grid_point_lats_deg) error_checking.assert_is_numpy_array( radar_grid_point_lngs_deg, num_dimensions=1) lng_conversion.convert_lng_positive_in_west( radar_grid_point_lngs_deg, allow_nan=False) radar_lat_matrix_deg, radar_lng_matrix_deg = ( grids.latlng_vectors_to_matrices( radar_grid_point_lats_deg, radar_grid_point_lngs_deg)) num_grid_rows = len(radar_grid_point_lats_deg) num_grid_columns = len(radar_grid_point_lngs_deg) radar_lat_vector_deg = numpy.reshape( radar_lat_matrix_deg, num_grid_rows * num_grid_columns) radar_lng_vector_deg = numpy.reshape( radar_lng_matrix_deg, num_grid_rows * num_grid_columns) query_point_dict = {interp.QUERY_LAT_COLUMN: radar_lat_vector_deg, interp.QUERY_LNG_COLUMN: radar_lng_vector_deg} query_point_table = pandas.DataFrame.from_dict(query_point_dict) isosurface_height_vector_m_asl = interp.interp_temperature_sfc_from_nwp( query_point_table, unix_time_sec=unix_time_sec, temperature_kelvins=temperature_kelvins, model_name=model_name, grid_id=grid_id, top_grib_directory_name=top_grib_directory_name, wgrib_exe_name=wgrib_exe_name, wgrib2_exe_name=wgrib2_exe_name, raise_error_if_missing=True) return numpy.reshape( isosurface_height_vector_m_asl, (num_grid_rows, num_grid_columns))
def get_elevations(latitudes_deg, longitudes_deg, working_dir_name=None): """Returns elevation of each point. N = number of points :param latitudes_deg: length-N numpy array of latitudes (deg N). :param longitudes_deg: length-N numpy array of longitudes (deg E). :param working_dir_name: See doc for `__init__` in class `ElevationFileHandler`. :return: elevations_m_asl: length-N numpy array of elevations (metres above sea level). """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg) error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1) num_points = len(latitudes_deg) longitudes_deg = lng_conversion.convert_lng_negative_in_west( longitudes_deg, allow_nan=False) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=numpy.array( [num_points])) srtm_data_object = None elevations_m_asl = numpy.full(num_points, numpy.nan) for i in range(num_points): elevations_m_asl[i], srtm_data_object = _get_elevation( latitude_deg=latitudes_deg[i], longitude_deg=longitudes_deg[i], srtm_data_object=srtm_data_object, working_dir_name=working_dir_name) return elevations_m_asl
def test_assert_is_valid_lat_numpy_array_true_with_nan_allowed(self): """Checks assert_is_valid_lat_numpy_array; all latitudes valid or NaN. In this case, allow_nan = True.""" error_checking.assert_is_valid_lat_numpy_array( LAT_NUMPY_ARRAY_WITH_NANS_DEG, allow_nan=True)
def get_wind_rotation_angles(latitudes_deg, longitudes_deg, model_name): """Computes wind-rotation angle for each point. These angles may be used in `rotate_winds_to_earth_relative` or `rotate_winds_to_grid_relative`. :param latitudes_deg: numpy array of latitudes (deg N). :param longitudes_deg: numpy array of longitudes (deg E) with same shape as `latitudes_deg`. :param model_name: Model name (must be accepted by `check_model_name`). :return: rotation_angle_cosines: numpy array of cosines with same shape as `latitudes_deg`. :return: rotation_angle_sines: numpy array of sines with same shape as `latitudes_deg`. """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg=latitudes_deg, allow_nan=False) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg=longitudes_deg, allow_nan=False) these_expected_dim = numpy.array(latitudes_deg.shape, dtype=int) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=these_expected_dim) standard_latitudes_deg, central_longitude_deg = get_projection_params( model_name) rotation_angles = ( numpy.sin(standard_latitudes_deg[0] * DEGREES_TO_RADIANS) * (longitudes_deg - central_longitude_deg) * DEGREES_TO_RADIANS) return numpy.cos(rotation_angles), numpy.sin(rotation_angles)
def plot_scattered_points(axes_object=None, basemap_object=None, latitudes_deg=None, longitudes_deg=None, field_values=None, marker_size=DEFAULT_MARKER_SIZE, marker_edge_width=DEFAULT_MARKER_EDGE_WIDTH, colour_map=None, colour_minimum=None, colour_maximum=None): """Plots values of a single NWP field at scattered points. These may be interpolated values. P = number of points :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`. :param latitudes_deg: length-P numpy array of latitudes (deg N). :param longitudes_deg: length-P numpy array of longitudes (deg E). :param field_values: length-P numpy array with values of field. :param marker_size: Size of each marker (circle). :param marker_edge_width: Line width of black edge around each marker (circle). :param colour_map: Instance of `matplotlib.pyplot.cm`. :param colour_minimum: Minimum value for colour map. :param colour_maximum: Maximum value for colour map. """ error_checking.assert_is_numpy_array_without_nan(field_values) error_checking.assert_is_numpy_array(field_values, num_dimensions=1) num_points = len(field_values) error_checking.assert_is_valid_lat_numpy_array(latitudes_deg) error_checking.assert_is_numpy_array(latitudes_deg, exact_dimensions=numpy.array( [num_points])) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg, allow_nan=False) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=numpy.array( [num_points])) error_checking.assert_is_greater(colour_maximum, colour_minimum) x_coords_metres, y_coords_metres = basemap_object(longitudes_deg, latitudes_deg) axes_object.scatter(x_coords_metres, y_coords_metres, s=marker_size, c=field_values, marker=MARKER_TYPE, edgecolors=MARKER_EDGE_COLOUR, linewidths=marker_edge_width, cmap=colour_map, vmin=colour_minimum, vmax=colour_maximum)
def test_assert_is_valid_lat_numpy_array_true_with_nan_banned(self): """Checks assert_is_valid_lat_numpy_array; all latitudes valid or NaN. In this case, allow_nan = False.""" with self.assertRaises(ValueError): error_checking.assert_is_valid_lat_numpy_array( LAT_NUMPY_ARRAY_WITH_NANS_DEG, allow_nan=False)
def start_points_and_displacements_to_endpoints(start_latitudes_deg, start_longitudes_deg, scalar_displacements_metres, geodetic_bearings_deg): """Computes endpoint from each start point and displacement. :param start_latitudes_deg: numpy array with latitudes (deg N) of start points. :param start_longitudes_deg: equivalent-size numpy array with longitudes (deg E) of start points. :param scalar_displacements_metres: equivalent-size numpy array of scalar displacements. :param geodetic_bearings_deg: equivalent-size numpy array of geodetic bearings (from start point to end point, measured clockwise from due north). :return: end_latitudes_deg: equivalent-size numpy array with latitudes (deg N) of endpoints. :return: end_longitudes_deg: equivalent-size numpy array with longitudes (deg E) of endpoints. """ error_checking.assert_is_valid_lat_numpy_array(start_latitudes_deg, allow_nan=False) start_longitudes_deg = lng_conversion.convert_lng_positive_in_west( start_longitudes_deg, allow_nan=False) error_checking.assert_is_numpy_array(start_longitudes_deg, exact_dimensions=numpy.array( start_latitudes_deg.shape)) error_checking.assert_is_geq_numpy_array(scalar_displacements_metres, 0.) error_checking.assert_is_numpy_array(scalar_displacements_metres, exact_dimensions=numpy.array( start_latitudes_deg.shape)) error_checking.assert_is_geq_numpy_array(geodetic_bearings_deg, 0.) error_checking.assert_is_leq_numpy_array(geodetic_bearings_deg, 360.) error_checking.assert_is_numpy_array(geodetic_bearings_deg, exact_dimensions=numpy.array( start_latitudes_deg.shape)) end_latitudes_deg = numpy.full(start_latitudes_deg.shape, numpy.nan) end_longitudes_deg = numpy.full(start_latitudes_deg.shape, numpy.nan) num_points = start_latitudes_deg.size for i in range(num_points): this_start_point_object = geopy.Point(start_latitudes_deg.flat[i], start_longitudes_deg.flat[i]) this_end_point_object = VincentyDistance( meters=scalar_displacements_metres.flat[i]).destination( this_start_point_object, geodetic_bearings_deg.flat[i]) end_latitudes_deg.flat[i] = this_end_point_object.latitude end_longitudes_deg.flat[i] = this_end_point_object.longitude end_longitudes_deg = lng_conversion.convert_lng_positive_in_west( end_longitudes_deg, allow_nan=False) return end_latitudes_deg, end_longitudes_deg
def project_latlng_to_xy(latitudes_deg, longitudes_deg, projection_object=None, false_easting_metres=0., false_northing_metres=0.): """Converts from lat-long to projection (x-y) coordinates. S = shape of coordinate arrays. :param latitudes_deg: numpy array of latitudes (deg N) with shape S. :param longitudes_deg: numpy array of longitudes (deg E) with shape S. :param projection_object: Projection object created by `pyproj.Proj`. :param false_easting_metres: False easting. Will be added to all x- coordinates. :param false_northing_metres: False northing. Will be added to all y- coordinates. :return: x_coords_metres: numpy array of x-coordinates with shape S. :return: y_coords_metres: numpy array of y-coordinates with shape S. """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg, allow_nan=True) shape_of_coord_arrays = latitudes_deg.shape error_checking.assert_is_numpy_array( longitudes_deg, exact_dimensions=numpy.asarray(shape_of_coord_arrays)) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg, allow_nan=True) error_checking.assert_is_not_nan(false_easting_metres) error_checking.assert_is_not_nan(false_northing_metres) x_coords_metres, y_coords_metres = projection_object( longitudes_deg, latitudes_deg) num_points = latitudes_deg.size nan_flags = numpy.logical_or( numpy.isnan(numpy.reshape(latitudes_deg, num_points)), numpy.isnan(numpy.reshape(longitudes_deg, num_points))) nan_indices = numpy.where(nan_flags)[0] x_coords_metres_flat = numpy.reshape(x_coords_metres, num_points) x_coords_metres_flat[nan_indices] = numpy.nan x_coords_metres = numpy.reshape( x_coords_metres_flat, shape_of_coord_arrays) + false_easting_metres y_coords_metres_flat = numpy.reshape(y_coords_metres, num_points) y_coords_metres_flat[nan_indices] = numpy.nan y_coords_metres = numpy.reshape( y_coords_metres_flat, shape_of_coord_arrays) + false_northing_metres return x_coords_metres, y_coords_metres
def start_points_and_distances_and_bearings_to_endpoints( start_latitudes_deg=None, start_longitudes_deg=None, displacements_metres=None, geodetic_bearings_deg=None): """Computes endpoint from each start point, displacement, and bearing. P = number of start points :param start_latitudes_deg: length-P numpy array of beginning latitudes (deg N). :param start_longitudes_deg: length-P numpy array of beginning longitudes (deg E). :param displacements_metres: length-P numpy array of displacements. :param geodetic_bearings_deg: length-P numpy array of geodetic bearings (from start point towards end point, measured clockwise from due north). :return: end_latitudes_deg: length-P numpy array of end latitudes (deg N). :return: end_longitudes_deg: length-P numpy array of end longitudes (deg E). """ error_checking.assert_is_valid_lat_numpy_array( start_latitudes_deg, allow_nan=False) error_checking.assert_is_numpy_array(start_latitudes_deg, num_dimensions=1) num_points = len(start_latitudes_deg) start_longitudes_deg = lng_conversion.convert_lng_positive_in_west( start_longitudes_deg, allow_nan=False) error_checking.assert_is_numpy_array( start_longitudes_deg, exact_dimensions=numpy.array([num_points])) error_checking.assert_is_geq_numpy_array(displacements_metres, 0.) error_checking.assert_is_numpy_array( displacements_metres, exact_dimensions=numpy.array([num_points])) error_checking.assert_is_geq_numpy_array(geodetic_bearings_deg, 0.) error_checking.assert_is_leq_numpy_array(geodetic_bearings_deg, 360.) error_checking.assert_is_numpy_array( geodetic_bearings_deg, exact_dimensions=numpy.array([num_points])) end_latitudes_deg = numpy.full(num_points, numpy.nan) end_longitudes_deg = numpy.full(num_points, numpy.nan) for i in range(num_points): this_start_point_object = geopy.Point( start_latitudes_deg[i], start_longitudes_deg[i]) this_end_point_object = VincentyDistance( meters=displacements_metres[i]).destination( this_start_point_object, geodetic_bearings_deg[i]) end_latitudes_deg[i] = this_end_point_object.latitude end_longitudes_deg[i] = this_end_point_object.longitude return end_latitudes_deg, lng_conversion.convert_lng_positive_in_west( end_longitudes_deg, allow_nan=False)
def plot_polyline(latitudes_deg, longitudes_deg, basemap_object, axes_object, front_type=None, line_colour=None, line_width=DEFAULT_LINE_WIDTH, line_style=DEFAULT_LINE_STYLE): """Plots either warm front or cold front as polyline. P = number of points in polyline :param latitudes_deg: length-P numpy array of latitudes (deg N). :param longitudes_deg: length-P numpy array of longitudes (deg N). :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param front_type: Type of front (string). Used only to determine line colour (if `line_colour` is left as None). :param line_colour: Colour (in any format accepted by `matplotlib.colors`). Defaults to `DEFAULT_WARM_FRONT_COLOUR` or `DEFAULT_COLD_FRONT_COLOUR`. :param line_width: Line width (real positive number). :param line_style: Line style (in any format accepted by `matplotlib.lines`). """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg) error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1) num_points = len(latitudes_deg) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=numpy.array( [num_points])) if line_colour is None: front_utils.check_front_type(front_type) if front_type == front_utils.WARM_FRONT_STRING_ID: line_colour = DEFAULT_WARM_FRONT_COLOUR else: line_colour = DEFAULT_COLD_FRONT_COLOUR x_coords_metres, y_coords_metres = basemap_object(longitudes_deg, latitudes_deg) axes_object.plot(x_coords_metres, y_coords_metres, color=line_colour, linestyle=line_style, linewidth=line_width)
def write_grid_metafile(grid_point_latitudes_deg, grid_point_longitudes_deg, netcdf_file_name): """Writes metadata for grid to NetCDF file. This file is needed only if prediction files are split by space (one per grid cell). M = number of rows in grid N = number of columns in grid :param grid_point_latitudes_deg: length-M numpy array of latitudes (deg N). :param grid_point_longitudes_deg: length-N numpy array of longitudes (deg E). :param netcdf_file_name: Path to output file. """ # Check input args. error_checking.assert_is_numpy_array(grid_point_latitudes_deg, num_dimensions=1) error_checking.assert_is_valid_lat_numpy_array(grid_point_latitudes_deg) error_checking.assert_is_numpy_array(grid_point_longitudes_deg, num_dimensions=1) grid_point_longitudes_deg = lng_conversion.convert_lng_positive_in_west( grid_point_longitudes_deg) # Write to NetCDF file. file_system_utils.mkdir_recursive_if_necessary(file_name=netcdf_file_name) dataset_object = netCDF4.Dataset(netcdf_file_name, 'w', format='NETCDF3_64BIT_OFFSET') dataset_object.createDimension(GRID_ROW_DIMENSION_KEY, len(grid_point_latitudes_deg)) dataset_object.createDimension(GRID_COLUMN_DIMENSION_KEY, len(grid_point_longitudes_deg)) dataset_object.createVariable(LATITUDES_KEY, datatype=numpy.float32, dimensions=GRID_ROW_DIMENSION_KEY) dataset_object.variables[LATITUDES_KEY][:] = grid_point_latitudes_deg dataset_object.createVariable(LONGITUDES_KEY, datatype=numpy.float32, dimensions=GRID_COLUMN_DIMENSION_KEY) dataset_object.variables[LONGITUDES_KEY][:] = grid_point_longitudes_deg dataset_object.close()
def latlng_to_rowcol(latitudes_deg, longitudes_deg, nw_grid_point_lat_deg, nw_grid_point_lng_deg, lat_spacing_deg, lng_spacing_deg): """Converts radar coordinates from lat-long to row-column. P = number of input grid points :param latitudes_deg: length-P numpy array with latitudes (deg N) of grid points. :param longitudes_deg: length-P numpy array with longitudes (deg E) of grid points. :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: grid_rows: length-P numpy array with row indices of grid points (increasing from north to south). :return: grid_columns: length-P numpy array with column indices of grid points (increasing from west to east). """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg, allow_nan=True) error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1) num_points = len(latitudes_deg) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg, allow_nan=True) error_checking.assert_is_numpy_array(longitudes_deg, 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.) grid_columns = rounder.round_to_nearest( (longitudes_deg - nw_grid_point_lng_deg) / lng_spacing_deg, 0.5) grid_rows = rounder.round_to_nearest( (nw_grid_point_lat_deg - latitudes_deg) / lat_spacing_deg, 0.5) return grid_rows, grid_columns
def init_lcc_projection(standard_latitudes_deg, central_longitude_deg, ellipsoid_name=SPHERE_NAME, earth_radius_metres=DEFAULT_EARTH_RADIUS_METRES): """Initializes LCC (Lambert conformal conic) projection. :param standard_latitudes_deg: length-2 numpy array of standard parallels (deg N). :param central_longitude_deg: Central meridian (deg E). :param ellipsoid_name: Ellipsoid (examples are "sphere" and "WGS84"). :param earth_radius_metres: [used only if ellipsoid_name = "sphere"] Earth radius. :return: projection_object: Instance of `pyproj.Proj`, specifying the LCC projection. """ error_checking.assert_is_valid_lat_numpy_array(standard_latitudes_deg) these_expected_dim = numpy.array([2], dtype=int) error_checking.assert_is_numpy_array(standard_latitudes_deg, exact_dimensions=these_expected_dim) error_checking.assert_is_non_array(central_longitude_deg) central_longitude_deg = lng_conversion.convert_lng_positive_in_west( central_longitude_deg, allow_nan=False) _check_ellipsoid(ellipsoid_name) if ellipsoid_name == SPHERE_NAME: error_checking.assert_is_greater(earth_radius_metres, 0.) return Proj(proj='lcc', lat_1=standard_latitudes_deg[0], lat_2=standard_latitudes_deg[1], lon_0=central_longitude_deg, rsphere=earth_radius_metres, ellps=ellipsoid_name) return Proj(proj='lcc', lat_1=standard_latitudes_deg[0], lat_2=standard_latitudes_deg[1], lon_0=central_longitude_deg, ellps=ellipsoid_name)
def _check_boundary(latitudes_deg, longitudes_deg): """Error-checks boundary. V = number of vertices in boundary :param latitudes_deg: length-V numpy array of latitudes (deg N). :param longitudes_deg: length-V numpy array of longitudes (deg E). :return: longitudes_deg: Same as input but positive in western hemisphere. """ longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg=longitudes_deg, allow_nan=False) error_checking.assert_is_valid_lat_numpy_array(latitudes_deg=latitudes_deg, allow_nan=False) num_vertices = len(latitudes_deg) expected_dim = numpy.array([num_vertices], dtype=int) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=expected_dim) return longitudes_deg
def get_latlng_centroid(latitudes_deg, longitudes_deg, allow_nan=True): """Finds centroid of lat-long points. P = number of points :param latitudes_deg: length-P numpy array of latitudes (deg N). :param longitudes_deg: length-P numpy array of longitudes (deg E). :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). :return: centroid_lat_deg: Centroid latitude (deg N). :return: centroid_lng_deg: Centroid longitude (deg E). :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) error_checking.assert_is_valid_lat_numpy_array(latitudes_deg, allow_nan) error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1) num_points = len(latitudes_deg) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg, allow_nan) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=numpy.array( [num_points])) nan_latitude_indices = numpy.where(numpy.isnan(latitudes_deg))[0] nan_longitude_indices = numpy.where(numpy.isnan(longitudes_deg))[0] if not numpy.array_equal(nan_latitude_indices, nan_longitude_indices): error_string = ( '\nNaN' 's occur at the following positions in `latitudes_deg`:\n' + str(nan_latitude_indices) + '\nand the following positions in `longitudes_deg`:\n' + str(nan_longitude_indices) + '\nNaN' 's should occur at the same positions in the two arrays.') raise ValueError(error_string) return numpy.nanmean(latitudes_deg), numpy.nanmean(longitudes_deg)
def get_wind_rotation_angles(latitudes_deg, longitudes_deg, model_name): """Computes wind-rotation angle for each lat-long point. These angles may be used in `rotate_winds_to_earth_relative` or `rotate_winds_to_grid_relative`. :param latitudes_deg: numpy array of latitudes (deg N). :param longitudes_deg: equivalent-shape numpy array of longitudes (deg E). :param model_name: Model name (string). This model must use a Lambert conformal grid. :return: rotation_angle_cosines: equivalent-shape numpy array with cosines of rotation angles. :return: rotation_angle_sines: equivalent-shape numpy array with sines of rotation angles. """ # TODO(thunderhoser): ensure that the model uses a Lambert conformal grid. # For now the models allowed in GewitterGefahr are the NARR, RUC, and RAP -- # all of which use a Lambert conformal grid. But this may change. error_checking.assert_is_valid_lat_numpy_array(latitudes_deg, allow_nan=False) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg, allow_nan=False) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=numpy.asarray( latitudes_deg.shape)) standard_latitudes_deg, central_longitude_deg = get_projection_params( model_name=model_name) rotation_angles = ( numpy.sin(standard_latitudes_deg[0] * DEGREES_TO_RADIANS) * (longitudes_deg - central_longitude_deg) * DEGREES_TO_RADIANS) return numpy.cos(rotation_angles), numpy.sin(rotation_angles)
def plot_storm_track(basemap_object=None, axes_object=None, latitudes_deg=None, longitudes_deg=None, line_colour=DEFAULT_TRACK_COLOUR, line_width=DEFAULT_TRACK_WIDTH, line_style=DEFAULT_TRACK_STYLE, start_marker=DEFAULT_TRACK_START_MARKER, end_marker=DEFAULT_TRACK_END_MARKER, start_marker_size=DEFAULT_TRACK_START_MARKER_SIZE, end_marker_size=DEFAULT_TRACK_END_MARKER_SIZE): """Plots storm track (path of storm centroid). P = number of points in track :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param latitudes_deg: length-P numpy array of latitudes (deg N). :param longitudes_deg: length-P numpy array of longitudes (deg E). :param line_colour: Colour (in any format accepted by `matplotlib.colors`). :param line_width: Line width (real positive number). :param line_style: Line style (in any format accepted by `matplotlib.lines`). :param start_marker: Marker type for beginning of track (in any format accepted by `matplotlib.lines`). This may also be None. :param end_marker: Marker type for end of track (in any format accepted by `matplotlib.lines`). This may also be None. :param start_marker_size: Size of marker at beginning of track. :param end_marker_size: Size of marker at end of track. """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg) error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1) num_points = len(latitudes_deg) longitudes_deg = lng_conversion.convert_lng_positive_in_west(longitudes_deg) error_checking.assert_is_numpy_array( longitudes_deg, exact_dimensions=numpy.array([num_points])) x_coords_metres, y_coords_metres = basemap_object( longitudes_deg, latitudes_deg) axes_object.plot( x_coords_metres, y_coords_metres, color=line_colour, linestyle=line_style, linewidth=line_width) if start_marker is not None: if start_marker == 'x': start_marker_edge_width = 2 else: start_marker_edge_width = 1 axes_object.plot( x_coords_metres[0], y_coords_metres[0], linestyle='None', marker=start_marker, markerfacecolor=line_colour, markeredgecolor=line_colour, markersize=start_marker_size, markeredgewidth=start_marker_edge_width) if end_marker is not None: if end_marker == 'x': end_marker_edge_width = 2 else: end_marker_edge_width = 1 axes_object.plot( x_coords_metres[-1], y_coords_metres[-1], linestyle='None', marker=end_marker, markerfacecolor=line_colour, markeredgecolor=line_colour, markersize=end_marker_size, markeredgewidth=end_marker_edge_width)
def create_map_with_nwp_proj(model_name, grid_name=None, latlng_limit_dict=None, xy_limit_dict=None, figure_width_inches=DEFAULT_FIGURE_WIDTH_INCHES, figure_height_inches=DEFAULT_FIGURE_HEIGHT_INCHES, resolution_string=DEFAULT_RESOLUTION_STRING): """Initializes map with same projection as NWP model. However, this map will have false easting = false northing = 0 metres. If `latlng_limit_dict is not None`, corners of the map will be determined by lat-long coords. If `xy_limit_dict is not None`, corners of the map will be determined by x-y coords. If both are None, corners of the map will be x-y corners of model grid. :param model_name: See doc for `nwp_model_utils.check_grid_name`. :param grid_name: See doc for `nwp_model_utils.check_grid_name`. :param latlng_limit_dict: Dictionary with the following keys: latlng_limit_dict['min_latitude_deg']: Minimum latitude (deg N) in map. latlng_limit_dict['max_latitude_deg']: Max latitude (deg N) in map. latlng_limit_dict['min_longitude_deg']: Minimum longitude (deg E) in map. latlng_limit_dict['max_longitude_deg']: Max longitude (deg E) in map. :param xy_limit_dict: Dictionary with the following keys: xy_limit_dict['x_min_metres']: Minimum x-coord in map. xy_limit_dict['x_max_metres']: Max x-coord in map. xy_limit_dict['y_min_metres']: Minimum y-coord in map. xy_limit_dict['y_max_metres']: Max y-coord in map. :param figure_width_inches: Figure width. :param figure_height_inches: Figure height. :param resolution_string: See doc for `create_lambert_conformal_map`. :return: figure_object: Same. :return: axes_object: Same. :return: basemap_object: Same. """ nwp_model_utils.check_grid_name(model_name=model_name, grid_name=grid_name) standard_latitudes_deg, central_longitude_deg = ( nwp_model_utils.get_projection_params(model_name)) if latlng_limit_dict is None and xy_limit_dict is None: all_x_coords_metres, all_y_coords_metres = ( nwp_model_utils.get_xy_grid_cell_edges(model_name=model_name, grid_name=grid_name)) false_easting_metres, false_northing_metres = ( nwp_model_utils.get_false_easting_and_northing( model_name=model_name, grid_name=grid_name)) all_x_coords_metres -= false_easting_metres all_y_coords_metres -= false_northing_metres xy_limit_dict = { X_MIN_KEY: numpy.min(all_x_coords_metres), X_MAX_KEY: numpy.max(all_x_coords_metres), Y_MIN_KEY: numpy.min(all_y_coords_metres), Y_MAX_KEY: numpy.max(all_y_coords_metres) } figure_object, axes_object = pyplot.subplots( 1, 1, figsize=(figure_width_inches, figure_height_inches)) if latlng_limit_dict is not None: min_latitude_deg = latlng_limit_dict[MIN_LATITUDE_KEY] max_latitude_deg = latlng_limit_dict[MAX_LATITUDE_KEY] error_checking.assert_is_valid_lat_numpy_array( numpy.array([min_latitude_deg, max_latitude_deg])) min_longitude_deg = lng_conversion.convert_lng_positive_in_west( latlng_limit_dict[MIN_LONGITUDE_KEY]) max_longitude_deg = lng_conversion.convert_lng_positive_in_west( latlng_limit_dict[MAX_LONGITUDE_KEY]) error_checking.assert_is_greater(max_latitude_deg, min_latitude_deg) error_checking.assert_is_greater(max_longitude_deg, min_longitude_deg) basemap_object = Basemap(projection='lcc', lat_1=standard_latitudes_deg[0], lat_2=standard_latitudes_deg[1], lon_0=central_longitude_deg, rsphere=EARTH_RADIUS_METRES, ellps=ELLIPSOID_NAME, resolution=resolution_string, llcrnrlat=min_latitude_deg, llcrnrlon=min_longitude_deg, urcrnrlat=max_latitude_deg, urcrnrlon=max_longitude_deg) else: x_min_metres = xy_limit_dict[X_MIN_KEY] x_max_metres = xy_limit_dict[X_MAX_KEY] y_min_metres = xy_limit_dict[Y_MIN_KEY] y_max_metres = xy_limit_dict[Y_MAX_KEY] error_checking.assert_is_greater(x_max_metres, x_min_metres) error_checking.assert_is_greater(y_max_metres, y_min_metres) basemap_object = Basemap(projection='lcc', lat_1=standard_latitudes_deg[0], lat_2=standard_latitudes_deg[1], lon_0=central_longitude_deg, rsphere=EARTH_RADIUS_METRES, ellps=ELLIPSOID_NAME, resolution=resolution_string, llcrnrx=x_min_metres, urcrnrx=x_max_metres, llcrnry=y_min_metres, urcrnry=y_max_metres) return figure_object, axes_object, basemap_object
def plot_wind_barbs(basemap_object, axes_object, latitudes_deg, longitudes_deg, u_winds_m_s01, v_winds_m_s01, barb_length=DEFAULT_BARB_LENGTH, barb_width=DEFAULT_BARB_WIDTH, empty_barb_radius=DEFAULT_EMPTY_BARB_RADIUS, fill_empty_barb=FILL_EMPTY_BARB_DEFAULT, colour_map=DEFAULT_COLOUR_MAP, colour_minimum_kt=DEFAULT_COLOUR_MINIMUM_KT, colour_maximum_kt=DEFAULT_COLOUR_MAXIMUM_KT): """Plots wind barbs. N = number of wind barbs :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param latitudes_deg: length-N numpy array with latitudes (deg N) of wind- observation points. :param longitudes_deg: length-N numpy array with longitudes (deg E) of wind- observation points. :param u_winds_m_s01: length-N numpy array with zonal wind components ("u-winds") at observation points (metres per second). :param v_winds_m_s01: length-N numpy array with meridional wind components ("v-winds") at observation points (metres per second). :param barb_length: Length of wind barb. :param barb_width: Width of wind barb. :param empty_barb_radius: Radius of "empty" wind barb (which is actually a circle, denoting 0 metres per second). :param fill_empty_barb: Boolean flag. If True, "empty" wind barbs (circles) will be coloured in. :param colour_map: Instance of `matplotlib.pyplot.cm`. :param colour_minimum_kt: Minimum wind speed (nautical miles per hour) in colour map. :param colour_maximum_kt: Max wind speed (nautical miles per hour) in colour map. """ error_checking.assert_is_valid_lat_numpy_array(latitudes_deg) error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1) num_points = len(latitudes_deg) longitudes_deg = lng_conversion.convert_lng_positive_in_west( longitudes_deg) error_checking.assert_is_numpy_array(longitudes_deg, exact_dimensions=numpy.array( [num_points])) error_checking.assert_is_numpy_array_without_nan(u_winds_m_s01) error_checking.assert_is_numpy_array(u_winds_m_s01, exact_dimensions=numpy.array( [num_points])) error_checking.assert_is_numpy_array_without_nan(v_winds_m_s01) error_checking.assert_is_numpy_array(v_winds_m_s01, exact_dimensions=numpy.array( [num_points])) # error_checking.assert_is_geq(colour_minimum_kt, 0.) error_checking.assert_is_greater(colour_maximum_kt, colour_minimum_kt) x_coords_metres, y_coords_metres = basemap_object(longitudes_deg, latitudes_deg) size_dict = {'emptybarb': empty_barb_radius} colour_limits_kt = numpy.array([colour_minimum_kt, colour_maximum_kt]) wind_speeds_m_s01 = numpy.sqrt(u_winds_m_s01**2 + v_winds_m_s01**2) axes_object.barbs(x_coords_metres, y_coords_metres, u_winds_m_s01 * METRES_PER_SECOND_TO_KT, v_winds_m_s01 * METRES_PER_SECOND_TO_KT, wind_speeds_m_s01 * METRES_PER_SECOND_TO_KT, length=barb_length, sizes=size_dict, fill_empty=fill_empty_barb, rounding=False, cmap=colour_map, clim=colour_limits_kt, linewidth=barb_width)
def plot_front_with_markers( line_latitudes_deg, line_longitudes_deg, axes_object, basemap_object, marker_spacing_metres=DEFAULT_MARKER_SPACING_METRES, marker_type=None, front_type_string=None, marker_colour=DEFAULT_MARKER_COLOUR, marker_size=DEFAULT_MARKER_SIZE): """Plots front with markers (instead of a line). P = number of points in line :param line_latitudes_deg: length-P numpy array of latitudes (deg N). :param line_longitudes_deg: length-P numpy array of longitudes (deg E). :param axes_object: Front will be plotted on these axes (instance of `matplotlib.axes._subplots.AxesSubplot`). :param basemap_object: Basemap used to convert lat-long coordinates to x-y (instance of `mpl_toolkits.basemap.Basemap`). :param marker_spacing_metres: Spacing between successive markers. :param marker_type: Marker type (any format accepted by matplotlib). :param front_type_string: [used only if `marker_type is None`] Front type (determines marker type). :param marker_colour: Marker colour (any format accepted by matplotlib). :param marker_size: Marker size (any format accepted by matplotlib). """ error_checking.assert_is_valid_lat_numpy_array(line_latitudes_deg) error_checking.assert_is_numpy_array(line_latitudes_deg, num_dimensions=1) num_points = len(line_latitudes_deg) these_expected_dim = numpy.array([num_points], dtype=int) error_checking.assert_is_numpy_array(line_longitudes_deg, exact_dimensions=these_expected_dim) line_longitudes_deg = lng_conversion.convert_lng_positive_in_west( line_longitudes_deg) error_checking.assert_is_greater(marker_spacing_metres, 0.) if marker_type is None: front_utils.check_front_type(front_type_string) if front_type_string == front_utils.WARM_FRONT_STRING_ID: marker_type = DEFAULT_WF_MARKER_TYPE else: marker_type = DEFAULT_CF_MARKER_TYPE x_coords_metres, y_coords_metres = basemap_object(line_longitudes_deg, line_latitudes_deg) for i in range(num_points - 1): this_x_diff_metres = x_coords_metres[i + 1] - x_coords_metres[i] this_y_diff_metres = y_coords_metres[i + 1] - y_coords_metres[i] this_distance_metres = numpy.sqrt(this_x_diff_metres**2 + this_y_diff_metres**2) this_num_points = 1 + int( numpy.ceil(this_distance_metres / marker_spacing_metres)) these_x_coords_metres = numpy.linspace(x_coords_metres[i], x_coords_metres[i + 1], num=this_num_points) these_y_coords_metres = numpy.linspace(y_coords_metres[i], y_coords_metres[i + 1], num=this_num_points) axes_object.plot(these_x_coords_metres, these_y_coords_metres, linestyle='None', marker=marker_type, markerfacecolor=marker_colour, markeredgecolor=marker_colour, markersize=marker_size, markeredgewidth=0.1)
def test_assert_is_valid_lat_numpy_array_all_invalid(self): """Checks assert_is_valid_lat_numpy_array; all latitudes invalid.""" with self.assertRaises(ValueError): error_checking.assert_is_valid_lat_numpy_array( LAT_NUMPY_ARRAY_INVALID_DEG)
def test_assert_is_valid_lat_numpy_array_true(self): """Checks assert_is_valid_lat_numpy_array; all latitudes valid.""" error_checking.assert_is_valid_lat_numpy_array(LAT_NUMPY_ARRAY_DEG)
def plot_storm_track(basemap_object, axes_object, centroid_latitudes_deg, centroid_longitudes_deg, line_colour=DEFAULT_TRACK_COLOUR, line_width=DEFAULT_TRACK_WIDTH, line_style=DEFAULT_TRACK_STYLE, start_marker=DEFAULT_START_MARKER_TYPE, end_marker=DEFAULT_END_MARKER_TYPE, start_marker_size=DEFAULT_START_MARKER_SIZE, end_marker_size=DEFAULT_END_MARKER_SIZE): """Plots storm track (path of centroid). P = number of points in track :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param centroid_latitudes_deg: length-P numpy array with latitudes (deg N) of storm centroid. :param centroid_longitudes_deg: length-P numpy array with longitudes (deg E) of storm centroid. :param line_colour: Colour (in any format accepted by `matplotlib.colors`). :param line_width: Line width (real positive number). :param line_style: Line style (in any format accepted by `matplotlib.lines`). :param start_marker: Marker type for beginning of track (in any format accepted by `matplotlib.lines`). This may also be None. :param end_marker: Marker type for end of track (in any format accepted by `matplotlib.lines`). This may also be None. :param start_marker_size: Size of marker at beginning of track. :param end_marker_size: Size of marker at end of track. """ # TODO(thunderhoser): Get rid of this method (or clean it up a lot). error_checking.assert_is_valid_lat_numpy_array(centroid_latitudes_deg) error_checking.assert_is_numpy_array(centroid_latitudes_deg, num_dimensions=1) centroid_longitudes_deg = lng_conversion.convert_lng_positive_in_west( centroid_longitudes_deg) num_points = len(centroid_latitudes_deg) these_expected_dim = numpy.array([num_points], dtype=int) error_checking.assert_is_numpy_array(centroid_longitudes_deg, exact_dimensions=these_expected_dim) centroid_x_coords_metres, centroid_y_coords_metres = basemap_object( centroid_longitudes_deg, centroid_latitudes_deg) line_colour_tuple = plotting_utils.colour_from_numpy_to_tuple(line_colour) axes_object.plot(centroid_x_coords_metres, centroid_y_coords_metres, color=line_colour_tuple, linestyle=line_style, linewidth=line_width) if start_marker is not None: if start_marker == 'x': this_edge_width = 2 else: this_edge_width = 1 axes_object.plot(centroid_x_coords_metres[0], centroid_y_coords_metres[0], linestyle='None', marker=start_marker, markerfacecolor=line_colour_tuple, markeredgecolor=line_colour_tuple, markersize=start_marker_size, markeredgewidth=this_edge_width) if end_marker is not None: if end_marker == 'x': this_edge_width = 2 else: this_edge_width = 1 axes_object.plot(centroid_x_coords_metres[-1], centroid_y_coords_metres[-1], linestyle='None', marker=end_marker, markerfacecolor=line_colour_tuple, markeredgecolor=line_colour_tuple, markersize=end_marker_size, markeredgewidth=this_edge_width)
def create_lambert_conformal_map( min_latitude_deg, max_latitude_deg, min_longitude_deg, max_longitude_deg, standard_latitudes_deg=numpy.full(2, 25.), central_longitude_deg=265., figure_width_inches=DEFAULT_FIGURE_WIDTH_INCHES, figure_height_inches=DEFAULT_FIGURE_HEIGHT_INCHES, resolution_string=DEFAULT_RESOLUTION_STRING): """Creates Lambert conformal map. This method only initializes a map with the Lambert conformal projection. It does not plot anything. Latitudes must be in deg N, and longitudes must be in deg E. :param min_latitude_deg: See doc for `_check_basemap_args`. :param max_latitude_deg: Same. :param min_longitude_deg: Same. :param max_longitude_deg: Same. :param standard_latitudes_deg: length-2 numpy array of standard latitudes for projection. :param central_longitude_deg: Central longitude for projection. :param figure_width_inches: Figure width. :param figure_height_inches: Figure height. :param resolution_string: See doc for `_check_basemap_args`. :return: figure_object: Figure handle (instance of `matplotlib.figure.Figure`). :return: axes_object: Axes handle (instance of `matplotlib.axes._subplots.AxesSubplot`). :return: basemap_object: Basemap handle (instance of `mpl_toolkits.basemap.Basemap`). """ min_longitude_deg, max_longitude_deg = _check_basemap_args( min_latitude_deg=min_latitude_deg, max_latitude_deg=max_latitude_deg, min_longitude_deg=min_longitude_deg, max_longitude_deg=max_longitude_deg, resolution_string=resolution_string) error_checking.assert_is_valid_lat_numpy_array(standard_latitudes_deg) error_checking.assert_is_numpy_array(standard_latitudes_deg, exact_dimensions=numpy.array( [2], dtype=int)) error_checking.assert_is_non_array(central_longitude_deg) central_longitude_deg = lng_conversion.convert_lng_positive_in_west( central_longitude_deg) figure_object, axes_object = pyplot.subplots( 1, 1, figsize=(figure_width_inches, figure_height_inches)) basemap_object = Basemap(projection='lcc', lat_1=standard_latitudes_deg[0], lat_2=standard_latitudes_deg[1], lon_0=central_longitude_deg, rsphere=EARTH_RADIUS_METRES, ellps=ELLIPSOID_NAME, resolution=resolution_string, llcrnrlat=min_latitude_deg, llcrnrlon=min_longitude_deg, urcrnrlat=max_latitude_deg, urcrnrlon=max_longitude_deg) return figure_object, axes_object, basemap_object
def read_highs_and_lows(text_file_name): """Reads locations of high- and low-pressure centers. :param text_file_name: Path to input file (text file in WPC format). :return: high_low_table: pandas DataFrame with the following columns. Each row is one high- or low-pressure center. high_low_table.system_type_string: Type of system (either "high" or "low"). high_low_table.unix_time_sec: Valid time. high_low_table.latitude_deg: Latitude (deg N). high_low_table.longitude_deg: Longitude (deg E). """ error_checking.assert_file_exists(text_file_name) valid_time_unix_sec = _file_name_to_valid_time(text_file_name) system_type_strings = [] latitudes_deg = numpy.array([], dtype=float) longitudes_deg = numpy.array([], dtype=float) for this_line in open(text_file_name, 'r').readlines(): these_words = this_line.split() if len(these_words) == 0: continue this_system_type_string = these_words[0].lower() if this_system_type_string not in VALID_SYSTEM_TYPE_STRINGS: continue these_words = these_words[1:] these_latitudes_deg = [] these_longitudes_deg = [] for this_word in these_words: if len(this_word) < 5: continue this_latitude_deg, this_longitude_deg = _string_to_latlng( latlng_string=this_word, raise_error_if_fails=True) these_latitudes_deg.append(this_latitude_deg) these_longitudes_deg.append(this_longitude_deg) these_latitudes_deg = numpy.array(these_latitudes_deg) these_longitudes_deg = numpy.array(these_longitudes_deg) if numpy.any(numpy.isnan(these_latitudes_deg)): continue error_checking.assert_is_valid_lat_numpy_array(these_latitudes_deg) these_longitudes_deg = lng_conversion.convert_lng_positive_in_west( these_longitudes_deg, allow_nan=False) system_type_strings += ([this_system_type_string] * len(these_latitudes_deg)) latitudes_deg = numpy.concatenate((latitudes_deg, these_latitudes_deg)) longitudes_deg = numpy.concatenate( (longitudes_deg, these_longitudes_deg)) valid_times_unix_sec = numpy.full(len(system_type_strings), valid_time_unix_sec, dtype=int) high_low_dict = { SYSTEM_TYPE_COLUMN: system_type_strings, front_utils.TIME_COLUMN: valid_times_unix_sec, LATITUDE_COLUMN: latitudes_deg, LONGITUDE_COLUMN: longitudes_deg } return pandas.DataFrame.from_dict(high_low_dict)
def read_fronts_from_file(text_file_name): """Reads locations of warm and cold fronts from WPC bulletin. Input file should contain positions of cyclones, anticyclones, fronts, etc. for a single valid time. :param text_file_name: Path to input file (text file in WPC format). :return: front_table: pandas DataFrame with the following columns. Each row is one front. front_table.front_type: Type of front (examples: "warm", "cold"). front_table.unix_time_sec: Valid time. front_table.latitudes_deg: 1-D numpy array of latitudes (deg N) along front. front_table.longitudes_deg: 1-D numpy array of longitudes (deg E) along front. """ error_checking.assert_file_exists(text_file_name) valid_time_unix_sec = _file_name_to_valid_time(text_file_name) front_types = [] latitudes_2d_list_deg = [] longitudes_2d_list_deg = [] for this_line in open(text_file_name, 'r').readlines(): these_words = this_line.split() # Need to skip empty lines. if not these_words: continue this_front_type = these_words[0].lower() if this_front_type not in VALID_FRONT_TYPES: continue these_words = these_words[1:] this_num_points = len(these_words) these_latitudes_deg = numpy.full(this_num_points, numpy.nan) these_longitudes_deg = numpy.full(this_num_points, numpy.nan) for i in range(this_num_points): these_latitudes_deg[i], these_longitudes_deg[ i] = _string_to_latlng(these_words[i], False) if numpy.any(numpy.isnan(these_latitudes_deg)): continue error_checking.assert_is_valid_lat_numpy_array(these_latitudes_deg) these_longitudes_deg = lng_conversion.convert_lng_positive_in_west( these_longitudes_deg, allow_nan=False) front_types.append(this_front_type) latitudes_2d_list_deg.append(these_latitudes_deg) longitudes_2d_list_deg.append(these_longitudes_deg) num_fronts = len(front_types) valid_times_unix_sec = numpy.full(num_fronts, valid_time_unix_sec, dtype=int) front_dict = { front_utils.FRONT_TYPE_COLUMN: front_types, front_utils.TIME_COLUMN: valid_times_unix_sec, front_utils.LATITUDES_COLUMN: latitudes_2d_list_deg, front_utils.LONGITUDES_COLUMN: longitudes_2d_list_deg } return pandas.DataFrame.from_dict(front_dict)
def interp_temperature_surface_from_nwp( radar_grid_point_latitudes_deg, radar_grid_point_longitudes_deg, radar_time_unix_sec, critical_temperature_kelvins, model_name, top_grib_directory_name, use_all_grids=True, grid_id=None, wgrib_exe_name=grib_io.WGRIB_EXE_NAME_DEFAULT, wgrib2_exe_name=grib_io.WGRIB2_EXE_NAME_DEFAULT): """Interpolates temperature (isothermal) surface from NWP model. M = number of rows (unique grid-point latitudes) in radar grid N = number of columns (unique grid-point longitudes) in radar grid :param radar_grid_point_latitudes_deg: length-M numpy array of grid-point latitudes (deg N). :param radar_grid_point_longitudes_deg: length-N numpy array of grid-point longitudes (deg E). :param radar_time_unix_sec: Radar time. :param critical_temperature_kelvins: Temperature of isosurface. :param model_name: See doc for `interp.interp_temperature_surface_from_nwp`. :param top_grib_directory_name: Same. :param use_all_grids: Same. :param grid_id: Same. :param wgrib_exe_name: Same. :param wgrib2_exe_name: Same. :return: isosurface_height_matrix_m_asl: M-by-N numpy array with heights of temperature isosurface (metres above sea level). """ error_checking.assert_is_numpy_array(radar_grid_point_latitudes_deg, num_dimensions=1) error_checking.assert_is_valid_lat_numpy_array( radar_grid_point_latitudes_deg) error_checking.assert_is_numpy_array(radar_grid_point_longitudes_deg, num_dimensions=1) lng_conversion.convert_lng_positive_in_west( radar_grid_point_longitudes_deg, allow_nan=False) (radar_latitude_matrix_deg, radar_longitude_matrix_deg) = grids.latlng_vectors_to_matrices( unique_latitudes_deg=radar_grid_point_latitudes_deg, unique_longitudes_deg=radar_grid_point_longitudes_deg) num_grid_rows = len(radar_grid_point_latitudes_deg) num_grid_columns = len(radar_grid_point_longitudes_deg) radar_latitude_vector_deg = numpy.reshape(radar_latitude_matrix_deg, num_grid_rows * num_grid_columns) radar_longitude_vector_deg = numpy.reshape( radar_longitude_matrix_deg, num_grid_rows * num_grid_columns) query_point_dict = { interp.QUERY_LAT_COLUMN: radar_latitude_vector_deg, interp.QUERY_LNG_COLUMN: radar_longitude_vector_deg } query_point_table = pandas.DataFrame.from_dict(query_point_dict) isosurface_height_vector_m_asl = interp.interp_temperature_surface_from_nwp( query_point_table=query_point_table, query_time_unix_sec=radar_time_unix_sec, critical_temperature_kelvins=critical_temperature_kelvins, model_name=model_name, top_grib_directory_name=top_grib_directory_name, use_all_grids=use_all_grids, grid_id=grid_id, wgrib_exe_name=wgrib_exe_name, wgrib2_exe_name=wgrib2_exe_name, raise_error_if_missing=True) return numpy.reshape(isosurface_height_vector_m_asl, (num_grid_rows, num_grid_columns))