Exemple #1
0
def _compute_shape_stats(spc_date_string, top_tracking_dir_name,
                         tracking_scale_metres2, output_dir_name):
    """Computes shape statistics for each storm object.

    :param spc_date_string: SPC (Storm Prediction Center) date in format
        "yyyymmdd".  Shape statistics will be computed for all storm objects on
        this date.
    :param top_tracking_dir_name: Name of top-level directory with storm-
        tracking data.
    :param tracking_scale_metres2: Tracking scale (minimum storm area).  Will be
        used to find input data.
    :param output_dir_name: Name of output directory.  A single Pickle file,
        with shape statistics for each storm object, will be written here.
    """

    tracking_file_names, _ = tracking_io.find_processed_files_one_spc_date(
        spc_date_string=spc_date_string,
        data_source=tracking_utils.SEGMOTION_SOURCE_ID,
        top_processed_dir_name=top_tracking_dir_name,
        tracking_scale_metres2=tracking_scale_metres2)

    storm_object_table = tracking_io.read_many_processed_files(
        tracking_file_names)
    print SEPARATOR_STRING

    shape_statistic_table = shape_stats.get_stats_for_storm_objects(
        storm_object_table)
    print SEPARATOR_STRING

    shape_statistic_file_name = '{0:s}/shape_statistics_{1:s}.p'.format(
        output_dir_name, spc_date_string)
    print 'Writing shape statistics to: "{0:s}"...'.format(
        shape_statistic_file_name)
    shape_stats.write_stats_for_storm_objects(shape_statistic_table,
                                              shape_statistic_file_name)
Exemple #2
0
def _run(spc_date_string, top_wind_dir_name, top_tracking_dir_name,
         tracking_scale_metres2, top_output_dir_name):
    """Runs `linkage.link_winds_to_storms`.

    This is effectively the main method.

    :param spc_date_string: See documentation at top of file.
    :param top_wind_dir_name: Same.
    :param top_tracking_dir_name: Same.
    :param tracking_scale_metres2: Same.
    :param top_output_dir_name: Same.
    """

    tracking_file_names, _ = tracking_io.find_processed_files_one_spc_date(
        spc_date_string=spc_date_string,
        data_source=tracking_utils.SEGMOTION_SOURCE_ID,
        top_processed_dir_name=top_tracking_dir_name,
        tracking_scale_metres2=tracking_scale_metres2,
        raise_error_if_missing=True)

    storm_to_winds_table = linkage.link_storms_to_winds(
        tracking_file_names=tracking_file_names,
        top_wind_directory_name=top_wind_dir_name)
    print SEPARATOR_STRING

    output_file_name = linkage.find_linkage_file(
        top_directory_name=top_output_dir_name,
        event_type_string=linkage.WIND_EVENT_STRING,
        spc_date_string=spc_date_string, raise_error_if_missing=False)

    print 'Writing linkages to: "{0:s}"...'.format(output_file_name)
    linkage.write_linkage_file(storm_to_events_table=storm_to_winds_table,
                               pickle_file_name=output_file_name)
Exemple #3
0
    def test_find_processed_files_one_spc_date(self):
        """Ensures correct output from find_processed_files_one_spc_date."""

        _, this_glob_pattern = tracking_io.find_processed_files_one_spc_date(
            top_processed_dir_name=TOP_SEGMOTION_DIR_NAME,
            tracking_scale_metres2=TRACKING_SCALE_METRES2,
            data_source=tracking_utils.SEGMOTION_SOURCE_ID,
            spc_date_string=VALID_SPC_DATE_STRING,
            raise_error_if_missing=False)

        self.assertTrue(this_glob_pattern == GLOB_PATTERN_FOR_SPC_DATE)
def _write_csv_file_for_thea(
        first_spc_date_string, last_spc_date_string, top_tracking_dir_name,
        tracking_scale_metres2, output_file_name):
    """Converts storm tracks to a single CSV file for Thea.

    :param first_spc_date_string: See documentation at top of file.
    :param last_spc_date_string: Same.
    :param top_tracking_dir_name: Same.
    :param tracking_scale_metres2: Same.
    :param output_file_name: Same.
    """

    spc_date_strings = time_conversion.get_spc_dates_in_range(
        first_spc_date_string=first_spc_date_string,
        last_spc_date_string=last_spc_date_string)

    tracking_file_names = []
    for this_spc_date_string in spc_date_strings:
        (these_tracking_file_names, _
        ) = tracking_io.find_processed_files_one_spc_date(
            spc_date_string=this_spc_date_string,
            data_source=tracking_utils.SEGMOTION_SOURCE_ID,
            top_processed_dir_name=top_tracking_dir_name,
            tracking_scale_metres2=tracking_scale_metres2)
        tracking_file_names += these_tracking_file_names

    num_files = len(tracking_file_names)
    list_of_storm_object_tables = [None] * num_files

    for i in range(num_files):
        print 'Reading {0:d}th of {1:d} input files: "{2:s}"...'.format(
            i + 1, num_files, tracking_file_names[i])

        list_of_storm_object_tables[i] = tracking_io.read_processed_file(
            tracking_file_names[i])
        if i == 0:
            continue

        list_of_storm_object_tables[i], _ = (
            list_of_storm_object_tables[i].align(
                list_of_storm_object_tables[0], axis=1))

    storm_object_table = pandas.concat(
        list_of_storm_object_tables, axis=0, ignore_index=True)

    print 'Writing all storm tracks to "{0:s}"...'.format(output_file_name)
    best_tracks.write_simple_output_for_thea(
        storm_object_table, output_file_name)
def _compute_radar_stats_from_gridrad(spc_date_string, top_tracking_dir_name,
                                      tracking_scale_metres2,
                                      top_gridrad_dir_name, output_dir_name):
    """Uses GridRad data to compute radar statistics for each storm object.

    :param spc_date_string: SPC (Storm Prediction Center) date in format
        "yyyymmdd".  Radar stats will be computed for all storm objects on this
        date.
    :param top_tracking_dir_name: Name of top-level directory with storm-
        tracking files.  Storm objects will be read from here.
    :param tracking_scale_metres2: Tracking scale (minimum storm area).  Will be
        used to find tracking files.
    :param top_gridrad_dir_name: Name of top-level directory with GridRad files.
    :param output_dir_name: Name of output directory.  A single Pickle file,
        with radar stats for each storm object, will be written here.
    """

    file_system_utils.mkdir_recursive_if_necessary(
        directory_name=output_dir_name)

    tracking_file_names, _ = tracking_io.find_processed_files_one_spc_date(
        spc_date_string=spc_date_string,
        data_source=tracking_utils.SEGMOTION_SOURCE_ID,
        top_processed_dir_name=top_tracking_dir_name,
        tracking_scale_metres2=tracking_scale_metres2)

    storm_object_table = tracking_io.read_many_processed_files(
        tracking_file_names)
    print SEPARATOR_STRING

    storm_object_statistic_table = (
        radar_statistics.get_storm_based_radar_stats_gridrad(
            storm_object_table=storm_object_table,
            top_radar_dir_name=top_gridrad_dir_name))
    print SEPARATOR_STRING

    output_file_name = '{0:s}/radar_stats_for_storm_objects_{1:s}.p'.format(
        output_dir_name, spc_date_string)
    print 'Writing radar statistics to file: "{0:s}"...'.format(
        output_file_name)
    radar_statistics.write_stats_for_storm_objects(
        storm_object_statistic_table, output_file_name)
def get_storm_object_table(num_spc_dates, climatology_type, working_date_index):
    date_in_memory_indices = _get_dates_needed(working_date_index, num_spc_dates, climatology_type)
    for i in range(num_spc_dates):
        if i in date_in_memory_indices:
            if storm_object_table_by_spc_date[i] is None:
                these_tracking_file_names = (tracking_io.find_processed_files_one_spc_date(
                                                spc_date_string=spc_date_strings[i],
                                                data_source='segmotion',
                                                top_processed_dir_name=TOP_PROCESSED_DIR_NAME,
                                                tracking_scale_metres2=TRACKING_SCALE_METRES2))
                storm_object_table_by_spc_date[i] = (tracking_io.read_many_processed_files(
                                                    these_tracking_file_names))

        else:
            print 'Clearing data for SPC date "{0:s}"...'.format(spc_date_strings[i])
            storm_object_table_by_spc_date[i] = None

    for j in date_in_memory_indices[1:]:
        storm_object_table_by_spc_date[j], _ = (storm_object_table_by_spc_date[j].align(
                                                storm_object_table_by_spc_date[date_in_memory_indices[0]], axis=1))
    storm_object_tables_to_concat = [storm_object_table_by_spc_date[j] for j in date_in_memory_indices]
    multiday_storm_object_table = pandas.concat(storm_object_tables_to_concat, axis=0, ignore_index=True)
    multiday_storm_object_table = multiday_storm_object_table[multiday_storm_object_table['age_sec']>= 900]
    return multiday_storm_object_table
def find_files_for_smart_io(start_time_unix_sec=None,
                            start_spc_date_string=None,
                            end_time_unix_sec=None,
                            end_spc_date_string=None,
                            data_source=None,
                            tracking_scale_metres2=None,
                            top_input_dir_name=None,
                            top_output_dir_name=None):
    """Finds input, output, and temporary working files for smart IO.

    N = number of SPC dates in period
    T_i = number of time steps in the [i]th SPC date

    :param start_time_unix_sec: Beginning of time period.
    :param start_spc_date_string: SPC date at beginning of time period (format
        "yyyymmdd").
    :param end_time_unix_sec: End of time period.
    :param end_spc_date_string: SPC date at end of time period (format
        "yyyymmdd").
    :param data_source: Source for input data (examples: "segmotion",
        "probSevere").
    :param tracking_scale_metres2: Tracking scale.
    :param top_input_dir_name: Name of top-level directory for input files.
    :param top_output_dir_name: Name of top-level directory for output files.
    :return: file_dict: Dictionary with the following keys.
    file_dict.spc_dates_unix_sec: length-N numpy array of SPC dates.
    file_dict.temp_file_names: 1-D list of paths to temp files (will be used for
        intermediate IO).
    file_dict.input_file_names_by_spc_date: length-N list, where the [i]th
        element is a 1-D list (length T_i) of paths to input files.
    file_dict.output_file_names_by_spc_date: Same but for output files.

    :raises: ValueError: if start_time_unix_sec is not part of the first SPC
        date (determined by start_spc_date_unix_sec).
    :raises: ValueError: if end_time_unix_sec is not part of the last SPC date
        (determined by end_spc_date_unix_sec).
    """

    if not time_conversion.is_time_in_spc_date(start_time_unix_sec,
                                               start_spc_date_string):
        start_time_string = time_conversion.unix_sec_to_string(
            start_time_unix_sec, TIME_FORMAT_FOR_MESSAGES)
        raise ValueError('Start time (' + start_time_string +
                         ') is not in first SPC date (' +
                         start_spc_date_string + ').')

    if not time_conversion.is_time_in_spc_date(end_time_unix_sec,
                                               end_spc_date_string):
        end_time_string = time_conversion.unix_sec_to_string(
            end_time_unix_sec, TIME_FORMAT_FOR_MESSAGES)
        raise ValueError('End time (' + end_time_string +
                         ') is not in last SPC date (' + end_spc_date_string +
                         ').')

    error_checking.assert_is_greater(end_time_unix_sec, start_time_unix_sec)

    start_spc_date_unix_sec = time_conversion.spc_date_string_to_unix_sec(
        start_spc_date_string)
    end_spc_date_unix_sec = time_conversion.spc_date_string_to_unix_sec(
        end_spc_date_string)

    num_spc_dates = int(1 + (end_spc_date_unix_sec - start_spc_date_unix_sec) /
                        DAYS_TO_SECONDS)
    spc_dates_unix_sec = numpy.linspace(start_spc_date_unix_sec,
                                        end_spc_date_unix_sec,
                                        num=num_spc_dates,
                                        dtype=int)

    temp_file_names = [''] * num_spc_dates
    input_file_names_by_spc_date = [['']] * num_spc_dates
    output_file_names_by_spc_date = [['']] * num_spc_dates

    for i in range(num_spc_dates):
        spc_dates_unix_sec[i] = time_conversion.time_to_spc_date_unix_sec(
            spc_dates_unix_sec[i])
        temp_file_names[i] = tempfile.NamedTemporaryFile(delete=False).name

        input_file_names_by_spc_date[i] = (
            tracking_io.find_processed_files_one_spc_date(
                spc_dates_unix_sec[i],
                data_source=data_source,
                top_processed_dir_name=top_input_dir_name,
                tracking_scale_metres2=tracking_scale_metres2,
                raise_error_if_missing=True))

        this_num_files = len(input_file_names_by_spc_date[i])
        these_times_unix_sec = numpy.full(this_num_files, -1, dtype=int)
        output_file_names_by_spc_date[i] = [''] * this_num_files

        for j in range(this_num_files):
            these_times_unix_sec[j] = tracking_io.processed_file_name_to_time(
                input_file_names_by_spc_date[i][j])
            output_file_names_by_spc_date[i][j] = (
                tracking_io.find_processed_file(
                    unix_time_sec=these_times_unix_sec[j],
                    data_source=data_source,
                    spc_date_unix_sec=spc_dates_unix_sec[i],
                    top_processed_dir_name=top_output_dir_name,
                    tracking_scale_metres2=tracking_scale_metres2,
                    raise_error_if_missing=False))

        if i == 0:
            keep_time_indices = numpy.where(
                these_times_unix_sec >= start_time_unix_sec)[0]

            these_times_unix_sec = these_times_unix_sec[keep_time_indices]
            input_file_names_by_spc_date[i] = [
                input_file_names_by_spc_date[i][j] for j in keep_time_indices
            ]
            output_file_names_by_spc_date[i] = [
                output_file_names_by_spc_date[i][j] for j in keep_time_indices
            ]

        if i == num_spc_dates - 1:
            keep_time_indices = numpy.where(
                these_times_unix_sec <= end_time_unix_sec)[0]
            input_file_names_by_spc_date[i] = [
                input_file_names_by_spc_date[i][j] for j in keep_time_indices
            ]
            output_file_names_by_spc_date[i] = [
                output_file_names_by_spc_date[i][j] for j in keep_time_indices
            ]

    return {
        SPC_DATES_KEY: spc_dates_unix_sec,
        TEMP_FILE_NAMES_KEY: temp_file_names,
        INPUT_FILE_NAMES_KEY: input_file_names_by_spc_date,
        OUTPUT_FILE_NAMES_KEY: output_file_names_by_spc_date
    }
Exemple #8
0
    speeds = []
    for working_date_index in range(num_spc_dates):
        date_in_memory_indices = utils._get_dates_needed(
            working_date_index=working_date_index,
            num_dates=num_spc_dates,
            climatology_type=PASSAGE_CLIMATOLOGY_TYPE)

        for i in range(num_spc_dates):
            if i in date_in_memory_indices:
                if storm_object_table_by_spc_date[i] is None:

                    # Find tracking files for [i]th date.
                    these_tracking_file_names = (
                        tracking_io.find_processed_files_one_spc_date(
                            spc_date_string=spc_date_strings[i],
                            data_source='segmotion',
                            top_processed_dir_name=TOP_PROCESSED_DIR_NAME,
                            tracking_scale_metres2=TRACKING_SCALE_METRES2))

                    # Read tracking files for [i]th date.
                    storm_object_table_by_spc_date[i] = (
                        tracking_io.read_many_processed_files(
                            these_tracking_file_names))

                else:
                    print 'Clearing data for SPC date "{0:s}"...'.format(
                        spc_date_strings[i])
                    storm_object_table_by_spc_date[i] = None

        print SEPARATOR_STRING
Exemple #9
0
def _extract_storm_images(num_image_rows, num_image_columns, rotate_grids,
                          rotated_grid_spacing_metres, radar_field_names,
                          radar_heights_m_agl, spc_date_string,
                          top_radar_dir_name, top_tracking_dir_name,
                          tracking_scale_metres2, target_name,
                          top_target_dir_name, top_output_dir_name):
    """Extracts storm-centered radar images from GridRad data.

    :param num_image_rows: See documentation at top of file.
    :param num_image_columns: Same.
    :param rotate_grids: Same.
    :param rotated_grid_spacing_metres: Same.
    :param radar_field_names: Same.
    :param radar_heights_m_agl: Same.
    :param spc_date_string: Same.
    :param top_radar_dir_name: Same.
    :param top_tracking_dir_name: Same.
    :param tracking_scale_metres2: Same.
    :param target_name: Same.
    :param top_target_dir_name: Same.
    :param top_output_dir_name: Same.
    """

    if target_name in ['', 'None']:
        target_name = None

    if target_name is not None:
        target_param_dict = target_val_utils.target_name_to_params(target_name)
        target_file_name = target_val_utils.find_target_file(
            top_directory_name=top_target_dir_name,
            event_type_string=target_param_dict[
                target_val_utils.EVENT_TYPE_KEY],
            spc_date_string=spc_date_string)

        print 'Reading data from: "{0:s}"...'.format(target_file_name)
        target_dict = target_val_utils.read_target_values(
            netcdf_file_name=target_file_name, target_name=target_name)
        print '\n'

    # Find storm objects on the given SPC date.
    tracking_file_names = tracking_io.find_processed_files_one_spc_date(
        spc_date_string=spc_date_string,
        data_source=tracking_utils.SEGMOTION_SOURCE_ID,
        top_processed_dir_name=top_tracking_dir_name,
        tracking_scale_metres2=tracking_scale_metres2)[0]

    # Read storm objects on the given SPC date.
    storm_object_table = tracking_io.read_many_processed_files(
        tracking_file_names)[storm_images.STORM_COLUMNS_NEEDED]
    print SEPARATOR_STRING

    if target_name is not None:
        print(
            'Removing storm objects without target values (variable = '
            '"{0:s}")...').format(target_name)

        these_indices = tracking_utils.find_storm_objects(
            all_storm_ids=storm_object_table[
                tracking_utils.STORM_ID_COLUMN].values.tolist(),
            all_times_unix_sec=storm_object_table[
                tracking_utils.TIME_COLUMN].values.astype(int),
            storm_ids_to_keep=target_dict[target_val_utils.STORM_IDS_KEY],
            times_to_keep_unix_sec=target_dict[
                target_val_utils.VALID_TIMES_KEY],
            allow_missing=False)

        num_storm_objects_orig = len(storm_object_table.index)
        storm_object_table = storm_object_table.iloc[these_indices]
        num_storm_objects = len(storm_object_table.index)

        print 'Removed {0:d} of {1:d} storm objects!\n'.format(
            num_storm_objects_orig - num_storm_objects, num_storm_objects_orig)

    # Extract storm-centered radar images.
    storm_images.extract_storm_images_gridrad(
        storm_object_table=storm_object_table,
        top_radar_dir_name=top_radar_dir_name,
        top_output_dir_name=top_output_dir_name,
        num_storm_image_rows=num_image_rows,
        num_storm_image_columns=num_image_columns,
        rotate_grids=rotate_grids,
        rotated_grid_spacing_metres=rotated_grid_spacing_metres,
        radar_field_names=radar_field_names,
        radar_heights_m_agl=radar_heights_m_agl)
def _find_io_files_for_renaming(top_input_dir_name, first_date_unix_sec,
                                last_date_unix_sec, top_output_dir_name):
    """Finds input and output files for renaming storms.

    N = number of dates

    :param top_input_dir_name: See documentation for `rename_storms.`
    :param first_date_unix_sec: Same.
    :param last_date_unix_sec: Same.
    :param top_output_dir_name: Same.
    :return: input_file_names_by_date: length-N list, where the [i]th item is a
        numpy array of paths to input files for the [i]th date.
    :return: output_file_names_by_date: Same as above, but for output files.
    :return: valid_times_by_date_unix_sec: Same as above, but for valid times.
        All 3 arrays for the [i]th date have the same length.
    """

    dates_unix_sec = time_periods.range_and_interval_to_list(
        start_time_unix_sec=first_date_unix_sec,
        end_time_unix_sec=last_date_unix_sec,
        time_interval_sec=DAYS_TO_SECONDS,
        include_endpoint=True)
    date_strings = [
        time_conversion.unix_sec_to_string(t, DATE_FORMAT)
        for t in dates_unix_sec
    ]

    num_dates = len(date_strings)
    input_file_names_by_date = [numpy.array([], dtype=object)] * num_dates
    output_file_names_by_date = [numpy.array([], dtype=object)] * num_dates
    valid_times_by_date_unix_sec = [numpy.array([], dtype=int)] * num_dates

    for i in range(num_dates):
        print 'Finding input files for date {0:s}...'.format(date_strings[i])

        (these_input_file_names,
         _) = tracking_io.find_processed_files_one_spc_date(
             spc_date_string=date_strings[i],
             data_source=tracking_utils.PROBSEVERE_SOURCE_ID,
             top_processed_dir_name=top_input_dir_name,
             tracking_scale_metres2=DUMMY_TRACKING_SCALE_METRES2,
             raise_error_if_missing=True)

        these_input_file_names.sort()
        these_valid_times_unix_sec = numpy.array([
            tracking_io.processed_file_name_to_time(f)
            for f in these_input_file_names
        ],
                                                 dtype=int)

        these_output_file_names = []
        for t in these_valid_times_unix_sec:
            these_output_file_names.append(
                tracking_io.find_processed_file(
                    unix_time_sec=t,
                    data_source=tracking_utils.PROBSEVERE_SOURCE_ID,
                    top_processed_dir_name=top_output_dir_name,
                    tracking_scale_metres2=DUMMY_TRACKING_SCALE_METRES2,
                    raise_error_if_missing=False))

        input_file_names_by_date[i] = numpy.array(these_input_file_names,
                                                  dtype=object)
        output_file_names_by_date[i] = numpy.array(these_output_file_names,
                                                   dtype=object)
        valid_times_by_date_unix_sec[i] = these_valid_times_unix_sec

    print SEPARATOR_STRING
    return (input_file_names_by_date, output_file_names_by_date,
            valid_times_by_date_unix_sec)
def _interp_soundings(spc_date_string, lead_times_seconds,
                      lag_time_for_convective_contamination_sec,
                      top_ruc_directory_name, top_rap_directory_name,
                      top_tracking_dir_name, tracking_scale_metres2,
                      top_output_dir_name):
    """Interpolates NWP sounding to each storm object at each lead time.

    :param spc_date_string: See documentation at top of file.
    :param lead_times_seconds: Same.
    :param lag_time_for_convective_contamination_sec: Same.
    :param top_ruc_directory_name: Same.
    :param top_rap_directory_name: Same.
    :param top_tracking_dir_name: Same.
    :param tracking_scale_metres2: Same.
    :param top_output_dir_name: Same.
    :raises: ValueError: if model-initialization times needed are on opposite
        sides of 0000 UTC 1 May 2012 (the cutoff between RUC and RAP models).
    """

    lead_times_seconds = numpy.array(lead_times_seconds, dtype=int)

    tracking_file_names, _ = tracking_io.find_processed_files_one_spc_date(
        spc_date_string=spc_date_string,
        data_source=tracking_utils.SEGMOTION_SOURCE_ID,
        top_processed_dir_name=top_tracking_dir_name,
        tracking_scale_metres2=tracking_scale_metres2)

    storm_object_table = tracking_io.read_many_processed_files(
        tracking_file_names)
    print SEPARATOR_STRING

    first_storm_time_unix_sec = numpy.min(
        storm_object_table[tracking_utils.TIME_COLUMN].values)
    last_storm_time_unix_sec = numpy.max(
        storm_object_table[tracking_utils.TIME_COLUMN].values)

    first_init_time_unix_sec = number_rounding.floor_to_nearest(
        (first_storm_time_unix_sec + numpy.min(lead_times_seconds) -
         lag_time_for_convective_contamination_sec), HOURS_TO_SECONDS)
    last_init_time_unix_sec = number_rounding.floor_to_nearest(
        (last_storm_time_unix_sec + numpy.max(lead_times_seconds) -
         lag_time_for_convective_contamination_sec), HOURS_TO_SECONDS)

    extreme_init_times_unix_sec = numpy.array(
        [first_init_time_unix_sec, last_init_time_unix_sec], dtype=int)

    if numpy.all(extreme_init_times_unix_sec < FIRST_RAP_TIME_UNIX_SEC):
        top_grib_directory_name = top_ruc_directory_name
        model_name = nwp_model_utils.RUC_MODEL_NAME
    elif numpy.all(extreme_init_times_unix_sec >= FIRST_RAP_TIME_UNIX_SEC):
        top_grib_directory_name = top_rap_directory_name
        model_name = nwp_model_utils.RAP_MODEL_NAME
    else:
        first_storm_time_string = time_conversion.unix_sec_to_string(
            first_storm_time_unix_sec, STORM_TIME_FORMAT)
        last_storm_time_string = time_conversion.unix_sec_to_string(
            last_storm_time_unix_sec, STORM_TIME_FORMAT)
        first_init_time_string = time_conversion.unix_sec_to_string(
            first_init_time_unix_sec, MODEL_INIT_TIME_FORMAT)
        last_init_time_string = time_conversion.unix_sec_to_string(
            last_init_time_unix_sec, MODEL_INIT_TIME_FORMAT)

        error_string = (
            'First and last storm times are {0:s} and {1:s}.  Thus, first and '
            'last model-initialization times needed are {2:s} and {3:s}, which '
            'are on opposite sides of {4:s} (the cutoff between RUC and RAP '
            'models).  The code is not generalized enough to interp data from '
            'two different models.  Sorry, eh?').format(
                first_storm_time_string, last_storm_time_string,
                first_init_time_string, last_init_time_string,
                FIRST_RAP_TIME_STRING)
        raise ValueError(error_string)

    sounding_dict_by_lead_time = soundings.interp_soundings_to_storm_objects(
        storm_object_table=storm_object_table,
        top_grib_directory_name=top_grib_directory_name,
        model_name=model_name,
        use_all_grids=True,
        height_levels_m_agl=soundings.DEFAULT_HEIGHT_LEVELS_M_AGL,
        lead_times_seconds=lead_times_seconds,
        lag_time_for_convective_contamination_sec=
        lag_time_for_convective_contamination_sec,
        wgrib_exe_name=WGRIB_EXE_NAME,
        wgrib2_exe_name=WGRIB2_EXE_NAME,
        raise_error_if_missing=False)
    print SEPARATOR_STRING

    num_lead_times = len(lead_times_seconds)
    for k in range(num_lead_times):
        this_sounding_file_name = soundings.find_sounding_file(
            top_directory_name=top_output_dir_name,
            spc_date_string=spc_date_string,
            lead_time_seconds=lead_times_seconds[k],
            lag_time_for_convective_contamination_sec=
            lag_time_for_convective_contamination_sec,
            raise_error_if_missing=False)

        print 'Writing soundings to: "{0:s}"...'.format(
            this_sounding_file_name)
        soundings.write_soundings(
            netcdf_file_name=this_sounding_file_name,
            sounding_dict_height_coords=sounding_dict_by_lead_time[k],
            lead_time_seconds=lead_times_seconds[k],
            lag_time_for_convective_contamination_sec=
            lag_time_for_convective_contamination_sec)
def _extract_storm_images(num_image_rows, num_image_columns, rotate_grids,
                          rotated_grid_spacing_metres, radar_field_names,
                          refl_heights_m_agl, spc_date_string,
                          tarred_myrorss_dir_name, untarred_myrorss_dir_name,
                          top_tracking_dir_name, tracking_scale_metres2,
                          target_name, top_target_dir_name,
                          top_output_dir_name):
    """Extracts storm-centered img for each field/height pair and storm object.

    :param num_image_rows: See documentation at top of file.
    :param num_image_columns: Same.
    :param rotate_grids: Same.
    :param rotated_grid_spacing_metres: Same.
    :param radar_field_names: Same.
    :param refl_heights_m_agl: Same.
    :param spc_date_string: Same.
    :param tarred_myrorss_dir_name: Same.
    :param untarred_myrorss_dir_name: Same.
    :param top_tracking_dir_name: Same.
    :param tracking_scale_metres2: Same.
    :param target_name: Same.
    :param top_target_dir_name: Same.
    :param top_output_dir_name: Same.
    """

    if target_name in ['', 'None']:
        target_name = None

    if target_name is not None:
        target_param_dict = target_val_utils.target_name_to_params(target_name)
        target_file_name = target_val_utils.find_target_file(
            top_directory_name=top_target_dir_name,
            event_type_string=target_param_dict[
                target_val_utils.EVENT_TYPE_KEY],
            spc_date_string=spc_date_string)

        print 'Reading data from: "{0:s}"...'.format(target_file_name)
        target_dict = target_val_utils.read_target_values(
            netcdf_file_name=target_file_name, target_name=target_name)
        print '\n'

    refl_heights_m_asl = radar_utils.get_valid_heights(
        data_source=radar_utils.MYRORSS_SOURCE_ID,
        field_name=radar_utils.REFL_NAME)

    # Untar files with azimuthal shear.
    az_shear_field_names = list(
        set(radar_field_names) & set(ALL_AZ_SHEAR_FIELD_NAMES))

    if len(az_shear_field_names):
        az_shear_tar_file_name = (
            '{0:s}/{1:s}/azimuthal_shear_only/{2:s}.tar'.format(
                tarred_myrorss_dir_name, spc_date_string[:4], spc_date_string))

        myrorss_io.unzip_1day_tar_file(
            tar_file_name=az_shear_tar_file_name,
            field_names=az_shear_field_names,
            spc_date_string=spc_date_string,
            top_target_directory_name=untarred_myrorss_dir_name)
        print SEPARATOR_STRING

    # Untar files with other radar fields.
    non_shear_field_names = list(
        set(radar_field_names) - set(ALL_AZ_SHEAR_FIELD_NAMES))

    if len(non_shear_field_names):
        non_shear_tar_file_name = '{0:s}/{1:s}/{2:s}.tar'.format(
            tarred_myrorss_dir_name, spc_date_string[:4], spc_date_string)

        myrorss_io.unzip_1day_tar_file(
            tar_file_name=non_shear_tar_file_name,
            field_names=non_shear_field_names,
            spc_date_string=spc_date_string,
            top_target_directory_name=untarred_myrorss_dir_name,
            refl_heights_m_asl=refl_heights_m_asl)
        print SEPARATOR_STRING

    # Read storm tracks for the given SPC date.
    tracking_file_names = tracking_io.find_processed_files_one_spc_date(
        spc_date_string=spc_date_string,
        data_source=tracking_utils.SEGMOTION_SOURCE_ID,
        top_processed_dir_name=top_tracking_dir_name,
        tracking_scale_metres2=tracking_scale_metres2)[0]

    storm_object_table = tracking_io.read_many_processed_files(
        tracking_file_names)[storm_images.STORM_COLUMNS_NEEDED]
    print SEPARATOR_STRING

    if target_name is not None:
        print(
            'Removing storm objects without target values (variable = '
            '"{0:s}")...').format(target_name)

        these_indices = tracking_utils.find_storm_objects(
            all_storm_ids=storm_object_table[
                tracking_utils.STORM_ID_COLUMN].values.tolist(),
            all_times_unix_sec=storm_object_table[
                tracking_utils.TIME_COLUMN].values.astype(int),
            storm_ids_to_keep=target_dict[target_val_utils.STORM_IDS_KEY],
            times_to_keep_unix_sec=target_dict[
                target_val_utils.VALID_TIMES_KEY],
            allow_missing=False)

        num_storm_objects_orig = len(storm_object_table.index)
        storm_object_table = storm_object_table.iloc[these_indices]
        num_storm_objects = len(storm_object_table.index)

        print 'Removed {0:d} of {1:d} storm objects!\n'.format(
            num_storm_objects_orig - num_storm_objects, num_storm_objects_orig)

    # Extract storm-centered radar images.
    storm_images.extract_storm_images_myrorss_or_mrms(
        storm_object_table=storm_object_table,
        radar_source=radar_utils.MYRORSS_SOURCE_ID,
        top_radar_dir_name=untarred_myrorss_dir_name,
        top_output_dir_name=top_output_dir_name,
        num_storm_image_rows=num_image_rows,
        num_storm_image_columns=num_image_columns,
        rotate_grids=rotate_grids,
        rotated_grid_spacing_metres=rotated_grid_spacing_metres,
        radar_field_names=radar_field_names,
        reflectivity_heights_m_agl=refl_heights_m_agl)
    print SEPARATOR_STRING

    # Remove untarred MYRORSS files.
    myrorss_io.remove_unzipped_data_1day(
        spc_date_string=spc_date_string,
        top_directory_name=untarred_myrorss_dir_name,
        field_names=radar_field_names,
        refl_heights_m_asl=refl_heights_m_asl)
    print SEPARATOR_STRING
def _find_tracking_gaps(first_spc_date_string, last_spc_date_string,
                        top_tracking_dir_name, tracking_scale_metres2,
                        data_source, min_time_diff_seconds):
    """Finds gaps (temporal discontinuities) between storm-tracking files.

    :param first_spc_date_string: See documentation at top of file.
    :param last_spc_date_string: Same.
    :param top_tracking_dir_name: Same.
    :param tracking_scale_metres2: Same.
    :param data_source: Same.
    :param min_time_diff_seconds: Same.
    """

    spc_date_strings = time_conversion.get_spc_dates_in_range(
        first_spc_date_string=first_spc_date_string,
        last_spc_date_string=last_spc_date_string)

    tracking_file_names = []
    unix_times_sec = numpy.array([], dtype=int)
    num_spc_dates = len(spc_date_strings)

    for i in range(num_spc_dates):
        print 'Finding tracking files for SPC date "{0:s}"...'.format(
            spc_date_strings[i])

        these_file_names, _ = tracking_io.find_processed_files_one_spc_date(
            spc_date_string=spc_date_strings[i],
            data_source=data_source,
            top_processed_dir_name=top_tracking_dir_name,
            tracking_scale_metres2=tracking_scale_metres2,
            raise_error_if_missing=False)
        print len(these_file_names)

        if not len(these_file_names):
            continue

        these_file_sizes_bytes = numpy.array(
            [os.path.getsize(f) for f in these_file_names], dtype=int)
        these_valid_indices = numpy.where(
            these_file_sizes_bytes > FILE_SIZE_WITHOUT_STORMS_BYTES)[0]
        these_file_names = [these_file_names[k] for k in these_valid_indices]

        these_unix_times_sec = numpy.array([
            tracking_io.processed_file_name_to_time(f)
            for f in these_file_names
        ],
                                           dtype=int)

        these_sort_indices = numpy.argsort(these_unix_times_sec)
        these_unix_times_sec = these_unix_times_sec[these_sort_indices]
        these_file_names = [these_file_names[k] for k in these_sort_indices]

        tracking_file_names += these_file_names
        unix_times_sec = numpy.concatenate(
            (unix_times_sec, these_unix_times_sec))

    time_diffs_seconds = numpy.diff(unix_times_sec)
    time_gap_indices = numpy.where(
        time_diffs_seconds >= min_time_diff_seconds)[0]
    num_time_gaps = len(time_gap_indices)

    print(
        '\nThere are {0:d} time gaps (successive files >= {1:d} seconds apart),'
        ' listed below:\n').format(num_time_gaps, min_time_diff_seconds)

    for i in time_gap_indices:
        this_start_time_string = time_conversion.unix_sec_to_string(
            unix_times_sec[i], TIME_FORMAT)
        this_end_time_string = time_conversion.unix_sec_to_string(
            unix_times_sec[i + 1], TIME_FORMAT)

        print 'Gap between {0:s} and {1:s} = {2:d} seconds'.format(
            this_start_time_string, this_end_time_string,
            time_diffs_seconds[i])