def test_remove_short_tracks_min_length3(self):
        """Ensures correct output from remove_short_tracks.

        In this case, minimum track length is 3 storm objects.
        """

        this_storm_object_table = best_tracks.remove_short_tracks(
            MAIN_STORM_OBJECT_TABLE, min_objects_in_track=3)

        self.assertTrue(
            numpy.array_equal(
                this_storm_object_table[tracking_io.STORM_ID_COLUMN].values,
                STORM_OBJECT_TABLE_TRACK_LENGTH_GEQ3[
                    tracking_io.STORM_ID_COLUMN].values))
        self.assertTrue(
            numpy.array_equal(
                this_storm_object_table[tracking_io.TIME_COLUMN].values,
                STORM_OBJECT_TABLE_TRACK_LENGTH_GEQ3[
                    tracking_io.TIME_COLUMN].values))
def run_best_track(
        smart_file_dict=None,
        max_extrap_time_for_breakup_sec=best_tracks.
    DEFAULT_MAX_EXTRAP_TIME_SEC,
        max_prediction_error_for_breakup_metres=best_tracks.
    DEFAULT_MAX_PREDICTION_ERROR_METRES,
        max_join_time_sec=best_tracks.DEFAULT_MAX_JOIN_TIME_SEC,
        max_join_distance_metres=best_tracks.DEFAULT_MAX_JOIN_DISTANCE_METRES,
        max_mean_join_error_metres=best_tracks.
    DEFAULT_MAX_MEAN_JOIN_ERROR_METRES,
        max_velocity_diff_for_join_m_s01=None,
        num_main_iters=best_tracks.DEFAULT_NUM_MAIN_ITERS,
        num_breakup_iters=best_tracks.DEFAULT_NUM_BREAKUP_ITERS,
        min_objects_in_track=best_tracks.DEFAULT_MIN_OBJECTS_IN_TRACK):
    """Runs the full w2besttrack algorithm with smart IO.

    :param smart_file_dict: Dictionary created by find_files_for_smart_io.
    :param max_extrap_time_for_breakup_sec: See documentation for
        `best_tracks.run_best_track`.
    :param max_prediction_error_for_breakup_metres: See doc for
        `best_tracks.run_best_track`.
    :param max_join_time_sec: See doc for `best_tracks.run_best_track`.
    :param max_join_distance_metres: See doc for `best_tracks.run_best_track`.
    :param max_mean_join_error_metres: See doc for `best_tracks.run_best_track`.
    :param max_velocity_diff_for_join_m_s01: See doc for `best_tracks.run_best_track`.
    :param num_main_iters: See doc for `best_tracks.run_best_track`.
    :param num_breakup_iters: See doc for `best_tracks.run_best_track`.
    :param min_objects_in_track: See doc for
        `best_tracks.run_best_track`.
    """

    best_tracks.check_best_track_params(
        max_extrap_time_for_breakup_sec=max_extrap_time_for_breakup_sec,
        max_prediction_error_for_breakup_metres=
        max_prediction_error_for_breakup_metres,
        max_join_time_sec=max_join_time_sec,
        max_join_distance_metres=max_join_distance_metres,
        max_mean_join_error_metres=max_mean_join_error_metres,
        max_velocity_diff_for_join_m_s01=max_velocity_diff_for_join_m_s01,
        num_main_iters=num_main_iters,
        num_breakup_iters=num_breakup_iters,
        min_objects_in_track=min_objects_in_track)

    spc_dates_unix_sec = smart_file_dict[SPC_DATES_KEY]
    num_spc_dates = len(spc_dates_unix_sec)
    storm_object_table = None

    for i in range(num_main_iters):
        print('Starting main iteration ' + str(i + 1) + '/' +
              str(num_main_iters) + '...\n\n')

        for j in range(num_breakup_iters):
            print('Starting break-up iteration ' + str(j + 1) + '/' +
                  str(num_breakup_iters) + '...\n\n')

            for k in range(num_spc_dates):
                storm_object_table = _shuffle_data_with_smart_io(
                    storm_object_table=storm_object_table,
                    file_dict=smart_file_dict,
                    working_spc_date_unix_sec=spc_dates_unix_sec[k],
                    read_from_intermediate=i > 0 or j > 0)

                if k == 0:
                    best_track_start_time_unix_sec = numpy.min(
                        storm_object_table[tracking_io.TIME_COLUMN].values)
                if k == num_spc_dates - 1:
                    best_track_end_time_unix_sec = numpy.max(
                        storm_object_table[tracking_io.TIME_COLUMN].values)

                storm_track_table = best_tracks.storm_objects_to_tracks(
                    storm_object_table)
                storm_track_table = best_tracks.theil_sen_fit_for_each_track(
                    storm_track_table)
                these_working_indices = numpy.where(
                    storm_object_table[tracking_io.SPC_DATE_COLUMN].values ==
                    spc_dates_unix_sec[k])[0]

                storm_object_table, storm_track_table = (
                    best_tracks.break_storm_tracks(
                        storm_object_table=storm_object_table,
                        storm_track_table=storm_track_table,
                        working_object_indices=these_working_indices,
                        max_extrapolation_time_sec=
                        max_extrap_time_for_breakup_sec,
                        max_prediction_error_metres=
                        max_prediction_error_for_breakup_metres))

        for k in range(num_spc_dates):
            storm_object_table = _shuffle_data_with_smart_io(
                storm_object_table=storm_object_table,
                file_dict=smart_file_dict,
                working_spc_date_unix_sec=spc_dates_unix_sec[k],
                read_from_intermediate=True)

            storm_track_table = best_tracks.storm_objects_to_tracks(
                storm_object_table)
            storm_track_table = best_tracks.theil_sen_fit_for_each_track(
                storm_track_table)
            these_working_indices = _find_tracks_with_spc_date(
                storm_object_table,
                storm_track_table,
                spc_date_unix_sec=spc_dates_unix_sec[k])

            storm_object_table, storm_track_table = (
                best_tracks.merge_storm_tracks(
                    storm_object_table=storm_object_table,
                    storm_track_table=storm_track_table,
                    working_track_indices=these_working_indices,
                    max_join_time_sec=max_join_time_sec,
                    max_join_distance_metres=max_join_distance_metres,
                    max_mean_prediction_error_metres=max_mean_join_error_metres,
                    max_velocity_diff_m_s01=max_velocity_diff_for_join_m_s01))

        for k in range(num_spc_dates):
            storm_object_table = _shuffle_data_with_smart_io(
                storm_object_table=storm_object_table,
                file_dict=smart_file_dict,
                working_spc_date_unix_sec=spc_dates_unix_sec[k],
                read_from_intermediate=True)

            storm_track_table = best_tracks.storm_objects_to_tracks(
                storm_object_table)
            storm_track_table = best_tracks.theil_sen_fit_for_each_track(
                storm_track_table)
            these_working_indices = _find_tracks_with_spc_date(
                storm_object_table,
                storm_track_table,
                spc_date_unix_sec=spc_dates_unix_sec[k])

            storm_object_table, storm_track_table = (
                best_tracks.break_ties_among_storm_objects(
                    storm_object_table,
                    storm_track_table,
                    working_track_indices=these_working_indices))

    for k in range(num_spc_dates):
        storm_object_table = _shuffle_data_with_smart_io(
            storm_object_table=storm_object_table,
            file_dict=smart_file_dict,
            working_spc_date_unix_sec=spc_dates_unix_sec[k],
            read_from_intermediate=True)

        print('Removing storm tracks with < ' + str(min_objects_in_track) +
              ' objects...')
        storm_object_table = best_tracks.remove_short_tracks(
            storm_object_table, min_objects_in_track=min_objects_in_track)

        print 'Recomputing storm attributes...'
        storm_object_table = best_tracks.recompute_attributes(
            storm_object_table,
            best_track_start_time_unix_sec=best_track_start_time_unix_sec,
            best_track_end_time_unix_sec=best_track_end_time_unix_sec)

        this_spc_date_indices = numpy.where(storm_object_table[
            tracking_io.SPC_DATE_COLUMN].values == spc_dates_unix_sec[k])[0]
        best_tracks.write_output_storm_objects(
            storm_object_table.iloc[this_spc_date_indices],
            input_file_names=smart_file_dict[INPUT_FILE_NAMES_KEY][k],
            output_file_names=smart_file_dict[OUTPUT_FILE_NAMES_KEY][k])

    for k in range(num_spc_dates):
        print 'Deleting temp files...'
        os.remove(smart_file_dict[TEMP_FILE_NAMES_KEY][k])