Exemple #1
0
def runTool(FCs, SQLDbase, dayString, start_time, end_time, DepOrArrChoice):

    def RetrieveStatsForStop(stop_id, rtdirtuple):
        '''For a given stop, query the stoptimedict {stop_id: [[trip_id, stop_time]]}
        and return the NumTrips, NumTripsPerHr, MaxWaitTime, and AvgHeadway given a
        specific route_id and direction'''

        try:
            stoptimedict = stoptimedict_rtdirpair[rtdirtuple]
        except KeyError:
            # We will get a KeyError if there were no trips found for the route/direction
            # pair, which usually happens if the wrong SQL database was selected.
            stoptimedict = {}

        # Make a list of stop_times
        StopTimesAtThisPoint = []
        try:
            for trip in stoptimedict[stop_id]:
                StopTimesAtThisPoint.append(trip[1])
        except KeyError:
            pass
        StopTimesAtThisPoint.sort()

        # Calculate the number of trips
        NumTrips = len(StopTimesAtThisPoint)
        NumTripsPerHr = float(NumTrips) / TimeWindowLength

        # Get the max wait time and the average headway
        MaxWaitTime = BBB_SharedFunctions.CalculateMaxWaitTime(StopTimesAtThisPoint, start_sec, end_sec)
        AvgHeadway = BBB_SharedFunctions.CalculateAvgHeadway(StopTimesAtThisPoint)

        return NumTrips, NumTripsPerHr, MaxWaitTime, AvgHeadway

    try:
        # ------ Get input parameters and set things up. -----
        try:
            OverwriteOutput = arcpy.env.overwriteOutput # Get the orignal value so we can reset it.
            arcpy.env.overwriteOutput = True

            BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2")

            # Stops and Polygons from Step 1 (any number and route combo)
            FCList = FCs.split(";")
            # Remove single quotes ArcGIS puts in if there are spaces in the filename.
            for d in FCList:
                if d[0] == "'" and d[-1] == "'":
                    loc = FCList.index(d)
                    FCList[loc] = d[1:-1]

            # Get list of field names from the input data and check that the required ones are there
            FieldNames = {}
            RequiredFields = ["stop_id", "route_id", "direction_id"]
            for FC in FCList:
                Fields = arcpy.ListFields(FC)
                FieldNames[FC] = [f.name for f in Fields]
                for field in RequiredFields:
                    if not field in FieldNames[FC]:
                        arcpy.AddError("Feature class %s does not have the required \
fields %s. Please choose a valid feature class." % (FC, str(RequiredFields)))
                        raise BBB_SharedFunctions.CustomError

            # SQL database of preprocessed GTFS from Step 1
            conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase)
            c = BBB_SharedFunctions.c = conn.cursor()

            Specific, day = BBB_SharedFunctions.CheckSpecificDate(dayString)
            # For field names in the output file
            if Specific:
                dayshort = BBB_SharedFunctions.days[day.weekday()][0:3] 
            else:
                dayshort = dayString[0:3]
            
            if start_time == "":
                start_time = "00:00"
            start_time_pretty = start_time.replace(":", "") # For field names in the output file
            if end_time == "":
                end_time = "23:59"
            end_time_pretty = end_time.replace(":", "") # For field names in the output file
            start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds(start_time, end_time)
            TimeWindowLength = (end_sec - start_sec) / 3600

            # Does the user want to count arrivals or departures at the stops?
            DepOrArr = BBB_SharedFunctions.CleanUpDepOrArr(DepOrArrChoice)

        except:
            arcpy.AddError("Error getting inputs.")
            raise


        # ----- Get list of route_ids and direction_ids to analyze from input files -----
        try:
            # We just check the first line in each file for this information.
            FC_route_dir_dict = {} # {FC: [route_id, direction_id]}
            route_dir_list = [] # [[route_id, direction_id], ...]
            for FC in FCList:
                with arcpy.da.SearchCursor(FC, ["route_id", "direction_id"]) as cur:
                    rt_dir = cur.next()
                route_dir_pair = [rt_dir[0], rt_dir[1]]
                FC_route_dir_dict[FC] = route_dir_pair
                if not route_dir_pair in route_dir_list:
                    route_dir_list.append(route_dir_pair)

        except:
            arcpy.AddError("Error getting route_id and direction_id values from input feature classes.")
            raise


        # ----- Get trips associated with route and direction -----

        try:
            arcpy.AddMessage("Getting list of trips...")

            # Get the service_ids serving the correct days
            serviceidlist, serviceidlist_yest, serviceidlist_tom = \
                BBB_SharedFunctions.GetServiceIDListsAndNonOverlaps(day, start_sec, end_sec, DepOrArr, Specific)

            trip_route_dict = {} #{(route_id, direction_id): [trip_id, trip_id,..]}
            trip_route_dict_yest = {}
            trip_route_dict_tom = {}
            for rtpair in route_dir_list:
                key = tuple(rtpair)
                route_id = rtpair[0]
                direction_id = rtpair[1]

                # Get list of trips
                # Ignore direction if this route doesn't have a direction
                if direction_id:
                    triproutefetch = '''
                        SELECT trip_id, service_id FROM trips
                        WHERE route_id='%s'
                        AND direction_id=%s
                        ;''' % (route_id, direction_id)
                else:
                    triproutefetch = '''
                        SELECT trip_id, service_id FROM trips
                        WHERE route_id='%s'
                        ;''' % route_id
                c.execute(triproutefetch)
                triproutelist = c.fetchall()

                if not triproutelist:
                    arcpy.AddWarning("Your GTFS dataset does not contain any trips \
corresponding to Route %s and Direction %s. Please ensure that \
you have selected the correct GTFS SQL file for this input file or that your \
GTFS data is good. Output fields will be generated, but \
the values will be 0 or <Null>." % (route_id, str(direction_id)))

                for triproute in triproutelist:
                    # Only keep trips running on the correct day
                    if triproute[1] in serviceidlist:
                        trip_route_dict.setdefault(key, []).append(triproute[0])
                    if triproute[1] in serviceidlist_tom:
                        trip_route_dict_tom.setdefault(key, []).append(triproute[0])
                    if triproute[1] in serviceidlist_yest:
                        trip_route_dict_yest.setdefault(key, []).append(triproute[0])

                if not trip_route_dict and not trip_route_dict_tom and not trip_route_dict_yest:
                    arcpy.AddWarning("There is no service for route %s in direction %s \
on %s during the time window you selected. Output fields will be generated, but \
the values will be 0 or <Null>." % (route_id, str(direction_id), str(day)))

        except:
            arcpy.AddError("Error getting trips associated with route.")
            raise


        #----- Query the GTFS data to count the trips at each stop -----
        try:
            arcpy.AddMessage("Calculating the number of transit trips available during the time window...")

            frequencies_dict = BBB_SharedFunctions.MakeFrequenciesDict()

            stoptimedict_rtdirpair = {}
            for rtdirpair in list(set([rt for rt in list(trip_route_dict.keys()) + list(trip_route_dict_yest.keys()) + list(trip_route_dict_tom.keys())])):

                # Get the stop_times that occur during this time window
                stoptimedict = {}
                stoptimedict_yest = {}
                stoptimedict_tom = {}
                try:
                    triplist = trip_route_dict[rtdirpair]
                    stoptimedict = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(start_sec, end_sec, DepOrArr, triplist, "today", frequencies_dict)
                except KeyError: # No trips
                    pass
                try:
                    triplist_yest = trip_route_dict_yest[rtdirpair]
                    stoptimedict_yest = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(start_sec, end_sec, DepOrArr, triplist_yest, "yesterday", frequencies_dict)
                except KeyError: # No trips
                    pass
                try:
                    triplist_tom = trip_route_dict_tom[rtdirpair]
                    stoptimedict_tom = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(start_sec, end_sec, DepOrArr, triplist_tom, "tomorrow", frequencies_dict)
                except KeyError: # No trips
                    pass

                # Combine the three dictionaries into one master
                for stop in stoptimedict_yest:
                    stoptimedict[stop] = stoptimedict.setdefault(stop, []) + stoptimedict_yest[stop]
                for stop in stoptimedict_tom:
                    stoptimedict[stop] = stoptimedict.setdefault(stop, []) + stoptimedict_tom[stop]

                stoptimedict_rtdirpair[rtdirpair] = stoptimedict

                # Add a warning if there is no service.
                if not stoptimedict:
                    arcpy.AddWarning("There is no service for route %s in direction %s \
on %s during the time window you selected. Output fields will be generated, but \
the values will be 0 or <Null>." % (rtdirpair[0], str(rtdirpair[1]), dayString))

        except:
            arcpy.AddError("Error counting arrivals or departures at stop during time window.")
            raise


        #----- Write to output -----

        arcpy.AddMessage("Writing output...")

        try:
            # Prepare the fields we're going to add to the feature classes
            ending = "_" + dayshort + "_" + start_time_pretty + "_" + end_time_pretty
            fields_to_fill = ["NumTrips" + ending, "NumTripsPerHr" + ending, "MaxWaitTime" + ending, "AvgHeadway" + ending]
            fields_to_read = ["stop_id", "route_id", "direction_id"] + fields_to_fill
            field_type_dict = {"NumTrips" + ending: "Short", "NumTripsPerHr" + ending: "Double", "MaxWaitTime" + ending: "Short", "AvgHeadway" + ending: "Short"}

            for FC in FCList:
                # We probably need to add new fields for our calculations, but if the field
                # is already there, don't add it because we'll overwrite it.
                for field in fields_to_fill:
                    if field not in FieldNames[FC]:
                        arcpy.management.AddField(FC, field, field_type_dict[field])
                with arcpy.da.UpdateCursor(FC, fields_to_read) as cur2:
                    for row in cur2:
                        rtpairtuple = (row[1], row[2]) # (route_id, direction_id)
                        stop = row[0]
                        NumTrips, NumTripsPerHr, MaxWaitTime, AvgHeadway = RetrieveStatsForStop(stop, rtpairtuple)
                        row[3] = NumTrips
                        row[4] = NumTripsPerHr
                        row[5] = MaxWaitTime
                        row[6] = AvgHeadway
                        cur2.updateRow(row)

        except:
            arcpy.AddError("Error writing output to feature class(es).")
            raise

        arcpy.AddMessage("Finished!")
        arcpy.AddMessage("Calculated trip counts, frequency, max wait time, and \
headway were written to the following fields in your input feature class(es):")
        for field in fields_to_fill:
            arcpy.AddMessage("- " + field)

        # Tell the tool that this is output. This will add the output to the map.
        arcpy.SetParameterAsText(6, FCs)

    except BBB_SharedFunctions.CustomError:
        arcpy.AddError("Failed to calculate transit statistics for this route and time window.")
        pass

    except:
        arcpy.AddError("Failed to calculate transit statistics for this route and time window.")
        raise

    finally:
        arcpy.env.overwriteOutput = OverwriteOutput
Exemple #2
0
def runTool(output_stop_file, SQLDbase, time_window_value_table,
            snap_to_nearest_5_minutes):
    def RetrieveFrequencyStatsForStop(stop_id, stoptimedict, start_sec,
                                      end_sec):
        '''For a given stop, query the dictionary
        and return the NumTrips, NumTripsPerHr, MaxWaitTime, and AvgHeadway given a
        specific route_id and direction. If snap to nearest five minutes is true, then
        this function will return headways snapped to the closest 5 minute interval.'''
        # Make a list of stop_times
        StopTimesAtThisPoint = []
        try:
            for trip in stoptimedict[stop_id]:
                StopTimesAtThisPoint.append(trip[1])
        except KeyError:
            pass
        StopTimesAtThisPoint.sort()

        # Calculate the number of trips
        NumTrips = len(StopTimesAtThisPoint)
        NumTripsPerHr = round(
            float(NumTrips) / ((end_sec - start_sec) / 3600), 2)
        # Get the max wait time and the average headway
        MaxWaitTime = BBB_SharedFunctions.CalculateMaxWaitTime(
            StopTimesAtThisPoint, start_sec, end_sec)
        if snap_to_nearest_5_minutes:
            round_to = 5
        else:
            round_to = None
        AvgHeadway = BBB_SharedFunctions.CalculateAvgHeadway(
            StopTimesAtThisPoint, round_to)
        return NumTrips, NumTripsPerHr, MaxWaitTime, AvgHeadway

    # ----- Get input parameters and set things up. -----
    # Check software version and fail out quickly if it's not sufficient.
    BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2")

    arcpy.AddMessage("Reading data...")

    # Connect to SQL database of preprocessed GTFS from Step 1
    conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase)
    c = BBB_SharedFunctions.c = conn.cursor()

    # Store frequencies if relevant
    frequencies_dict = BBB_SharedFunctions.MakeFrequenciesDict()

    # Get unique route_id/direction_id pairs and calculate the trips used in each
    # Some GTFS datasets use the same route_id to identify trips traveling in
    # either direction along a route. Others identify it as a different route.
    # We will consider each direction separately if there is more than one.
    trip_route_dict = {
    }  # {(route_id, direction_id): [(trip_id, service_id),..]}
    triproutefetch = '''SELECT DISTINCT route_id,direction_id FROM trips;'''
    c.execute(triproutefetch)
    for rtpair in c.fetchall():
        key = tuple(rtpair)
        route_id = rtpair[0]
        direction_id = rtpair[1]
        # Get list of trips
        # Ignore direction if this route doesn't have a direction
        if direction_id is not None and str(direction_id).strip():
            triproutefetch = '''
                    SELECT trip_id, service_id FROM trips
                    WHERE route_id = '{0}' AND direction_id = {1};'''.format(
                route_id, direction_id)
        else:
            triproutefetch = '''
                    SELECT trip_id, service_id FROM trips
                    WHERE route_id = '{0}';'''.format(route_id)
        c.execute(triproutefetch)
        triproutelist = c.fetchall()
        trip_route_dict[key] = triproutelist

    # ----- For each time window, calculate the stop frequency -----
    final_stop_freq_dict = {
    }  # {(stop_id, route_id, direction_id): {prefix: (NumTrips, NumTripsPerHour, MaxWaitTimeSec, AvgHeadwayMin)}}
    # The time_window_value_table will be a list of nested lists of strings like:
    # [[Weekday name or YYYYMMDD date, HH: MM, HH: MM, Departures / Arrivals, Prefix], [], ...]
    for time_window in time_window_value_table:
        # Prefix/identifier associated with this time window
        prefix = time_window[4]
        arcpy.AddMessage("Calculating statistics for time window %s..." %
                         prefix)
        # Clean up date and determine whether it's a date or a weekday
        Specific, day = BBB_SharedFunctions.CheckSpecificDate(time_window[0])
        # Convert times to seconds
        start_time = time_window[1]
        end_time = time_window[2]
        if not start_time:
            start_time = "00:00"
        if not end_time:
            end_time = "23:59"
        start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds(
            start_time, end_time)
        # Clean up arrival/departure time choice
        DepOrArr = BBB_SharedFunctions.CleanUpDepOrArr(time_window[3])

        # Get the trips running in this time window for each route/direction pair
        # Get the service_ids serving the correct days
        serviceidlist, serviceidlist_yest, serviceidlist_tom = \
            BBB_SharedFunctions.GetServiceIDListsAndNonOverlaps(day, start_sec, end_sec, DepOrArr, Specific)

        # Retrieve the stop_times for the time window broken out by route/direction
        stoproutedir_dict = {
        }  # {(stop_id, route_id, direction_id): [NumTrips, NumTripsPerHour, MaxWaitTimeSec, AvgHeadwayMin]}
        for rtdirpair in trip_route_dict:
            # Get trips running with these service_ids
            trip_serv_list = trip_route_dict[rtdirpair]
            triplist = []
            for tripserv in trip_serv_list:
                # Only keep trips running on the correct day
                if tripserv[1] in serviceidlist or tripserv[1] in serviceidlist_tom or \
                    tripserv[1] in serviceidlist_yest:
                    triplist.append(tripserv[0])

            # Get the stop_times that occur during this time window for these trips
            try:
                stoptimedict = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(
                    start_sec, end_sec, DepOrArr, triplist, "today",
                    frequencies_dict)
            except KeyError:  # No trips
                pass
            try:
                stoptimedict_yest = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(
                    start_sec, end_sec, DepOrArr, triplist, "yesterday",
                    frequencies_dict)
            except KeyError:  # No trips
                pass
            try:
                stoptimedict_tom = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(
                    start_sec, end_sec, DepOrArr, triplist, "tomorrow",
                    frequencies_dict)
            except KeyError:  # No trips
                pass

            # Combine the three dictionaries into one master
            for stop in stoptimedict_yest:
                stoptimedict[stop] = stoptimedict.setdefault(
                    stop, []) + stoptimedict_yest[stop]
            for stop in stoptimedict_tom:
                stoptimedict[stop] = stoptimedict.setdefault(
                    stop, []) + stoptimedict_tom[stop]

            for stop in stoptimedict.keys():
                # Get Stop-Route-Dir Frequencies by time period
                vals = RetrieveFrequencyStatsForStop(stop, stoptimedict,
                                                     start_sec, end_sec)
                key = (
                    stop,
                    rtdirpair[0],
                    rtdirpair[1],
                )
                if key not in final_stop_freq_dict:
                    final_stop_freq_dict[key] = {prefix: vals}
                else:
                    final_stop_freq_dict[key][prefix] = vals

    # ----- Write the stops and stats to the output feature class -----
    arcpy.AddMessage("Writing outputs...")
    # Make the basic feature class for stops with correct gtfs fields
    with arcpy.EnvManager(overwriteOutput=True):
        output_coords = BBB_SharedFunctions.CreateStopsFeatureClass(
            output_stop_file)

    # Add fields specific to this tool's outputs
    arcpy.management.AddField(output_stop_file, 'route_id', "TEXT")
    arcpy.management.AddField(output_stop_file, 'direction_id', "SHORT")
    # Create fields for stats for each time window using prefix
    base_field_names = [
        '_NumTrips', '_NumTripsPerHr', '_MaxWaitTime', '_AvgHeadway'
    ]
    new_fields = []
    for time_window in time_window_value_table:
        for base_field in base_field_names:
            new_field = time_window[4] + base_field
            new_fields.append(new_field)
            arcpy.management.AddField(output_stop_file, new_field, "DOUBLE")

    # Get the stop info from the GTFS SQL file
    StopTable = BBB_SharedFunctions.GetStopsData()
    stop_dict = {stop[0]: stop for stop in StopTable}

    # Make a dictionary to track whether we have inserted all stops at least once into the output
    used_stops = {stop[0]: False for stop in StopTable}
    # Store stop geometries in dictionary so they can be inserted multiple times without recalculating
    stop_geoms = {
        stop[0]: BBB_SharedFunctions.MakeStopGeometry(stop[4], stop[5],
                                                      output_coords)
        for stop in StopTable
    }

    # Add the stops with stats to the feature class
    fields = [
        "SHAPE@", "stop_id", "stop_code", "stop_name", "stop_desc", "zone_id",
        "stop_url", "location_type", "parent_station", "route_id",
        "direction_id"
    ] + new_fields
    with arcpy.da.InsertCursor(output_stop_file, fields) as cur3:
        # Iterate over all unique stop, route_id, direction_id groups and insert values
        for key in sorted(final_stop_freq_dict.keys()):
            stop_id = key[0]
            used_stops[stop_id] = True
            route_id = key[1]
            direction_id = key[2]
            stop_data = stop_dict[stop_id]
            # Schema of StopTable
            ##   0 - stop_id
            ##   1 - stop_code
            ##   2 - stop_name
            ##   3 - stop_desc
            ##   4 - stop_lat
            ##   5 - stop_lon
            ##   6 - zone_id
            ##   7 - stop_url
            ##   8 - location_type
            ##   9 - parent_station
            row = [
                stop_geoms[stop_id],  # Geometry
                stop_data[0],
                stop_data[1],
                stop_data[2],
                stop_data[3],
                stop_data[6],
                stop_data[7],
                stop_data[8],
                stop_data[9],  # GTFS data
                route_id,
                direction_id  # route and direction IDs
            ]
            # Populate stats fields for each prefix
            for time_window in time_window_value_table:
                prefix = time_window[4]
                try:
                    vals = final_stop_freq_dict[key][prefix]
                except KeyError:
                    # This stop/route/direction group had no service for this time window
                    vals = [0, 0, None, None]
                row += vals

            # Insert the row
            cur3.insertRow(row)

        # Insert row for any remaining stops that were not used at all
        for stop_id in used_stops:
            if used_stops[stop_id]:
                # This one was already inserted
                continue
            stop_data = stop_dict[stop_id]
            row = [
                stop_geoms[stop_id],  # Geometry
                stop_data[0],
                stop_data[1],
                stop_data[2],
                stop_data[3],
                stop_data[6],
                stop_data[7],
                stop_data[8],
                stop_data[9],  # GTFS data
                None,
                None  # route and direction IDs - None because not used
            ]
            # Populate stats fields for each prefix
            for time_window in time_window_value_table:
                row += [0, 0, None, None]
            # Insert the row
            cur3.insertRow(row)

    # Close Connection
    conn.close()
    arcpy.AddMessage("Finished!")
    arcpy.AddMessage("Calculated trip counts, frequency, max wait time, and \
headway were written to an output stops file by route-direction pairs.")
Exemple #3
0
def runTool(outStops, SQLDbase, day, start_time, end_time, DepOrArrChoice,
            FrequencyThreshold, SnapToNearest5MinuteBool):
    def RetrieveFrequencyStatsForStop(stop_id,
                                      rtdirtuple,
                                      snap_to_nearest_5_minutes=False):
        '''For a given stop, query the stop_time_dictionaries {stop_id: [[trip_id, stop_time]]}
        and return the NumTrips, NumTripsPerHr, MaxWaitTime, and AvgHeadway given a
        specific route_id and direction. If snap to nearest five minutes is true, then
        this function will return headways snapped to the closest 5 minute interval.'''
        try:
            stop_time_dictionaries = stoptimedict_rtedirpair[rtdirtuple]
        except KeyError:
            # We will get a KeyError if there were no trips found for the route/direction
            # pair, which usually happens if the wrong SQL database was selected.
            stop_time_dictionaries = {}

        # Make a list of stop_times
        StopTimesAtThisPoint = []
        try:
            for trip in stop_time_dictionaries[stop_id]:
                StopTimesAtThisPoint.append(trip[1])
        except KeyError:
            pass
        StopTimesAtThisPoint.sort()

        # Calculate the number of trips
        NumTrips = len(StopTimesAtThisPoint)
        NumTripsPerHr = float(NumTrips) / TimeWindowLength
        # Get the max wait time and the average headway
        MaxWaitTime = BBB_SharedFunctions.CalculateMaxWaitTime(
            StopTimesAtThisPoint, start_sec, end_sec)
        AvgHeadway = None
        if NumTrips > 1:
            AvgHeadway = max(
                1,
                int(
                    round(
                        float(
                            sum(
                                abs(x - y)
                                for (x, y) in zip(StopTimesAtThisPoint[1:],
                                                  StopTimesAtThisPoint[:-1])) /
                            (len(StopTimesAtThisPoint) - 1)) / 60,
                        0)))  # minutes
            if snap_to_nearest_5_minutes:
                AvgHeadway = round(AvgHeadway / 5.0) * 5
        return NumTrips, NumTripsPerHr, MaxWaitTime, AvgHeadway

    try:
        # ------ Get input parameters and set things up. -----
        try:
            arcpy.env.overwriteOutput = True

            BBB_SharedFunctions.CheckArcVersion(min_version_pro="1.2",
                                                min_version_10x="10.4")

            try:
                import pandas as pd
            except:
                # Pandas is shipped with ArcGIS Pro and ArcGIS 10.4 and higher.  The previous logic should hopefully prevent users from ever hitting this error.
                arcpy.AddError(
                    "This BetterBusBuffers tool requires the python library pandas, but the tool was unable to import the library."
                )
                raise BBB_SharedFunctions.CustomError

            # GTFS SQL dbase - must be created ahead of time.
            conn = BBB_SharedFunctions.conn = sqlite3.connect(SQLDbase)
            c = BBB_SharedFunctions.c = conn.cursor()

            Specific, day = BBB_SharedFunctions.CheckSpecificDate(day)
            start_sec, end_sec = BBB_SharedFunctions.ConvertTimeWindowToSeconds(
                start_time, end_time)
            # Window of Time In Hours
            TimeWindowLength = (end_sec - start_sec) / 3600

            # threshold for headways to be counted
            FrequencyThreshold = float(FrequencyThreshold)
            # boolean will snap headways to nearest 5 minute increment (ie 11.5 minutes snaps to 10, but 13 snaps to 15)
            SnapToNearest5MinuteBool = bool(SnapToNearest5MinuteBool)
            # Does the user want to count arrivals or departures at the stops?
            DepOrArr = BBB_SharedFunctions.CleanUpDepOrArr(DepOrArrChoice)
            time_period = start_time + ":" + end_time

        except:
            arcpy.AddError("Error getting user inputs.")
            raise

        # ----- Create a feature class of stops and add fields for transit trip counts ------
        try:
            arcpy.AddMessage("Creating feature class of GTFS stops...")
            # Create a feature class of transit stops
            outStops, StopIDList = BBB_SharedFunctions.MakeStopsFeatureClass(
                outStops)
        except:
            arcpy.AddError("Error creating feature class of GTFS stops.")
            raise

        # ----- Query the GTFS data to count the trips at each stop -----
        try:
            arcpy.AddMessage(
                "Calculating the determining trips for route-direction pairs..."
            )

            # Get the service_ids serving the correct days
            serviceidlist, serviceidlist_yest, serviceidlist_tom = \
                BBB_SharedFunctions.GetServiceIDListsAndNonOverlaps(day, start_sec, end_sec, DepOrArr, Specific)

            # Assemble Route and Direction IDS
            triproutefetch = '''SELECT DISTINCT route_id,direction_id FROM trips;'''
            c.execute(triproutefetch)
            #route_dir_list = c.fetchall()

            # Some GTFS datasets use the same route_id to identify trips traveling in
            # either direction along a route. Others identify it as a different route.
            # We will consider each direction separately if there is more than one.
            trip_route_warning_counter = 0
            trip_route_dict = {
            }  # {(route_id, direction_id): [trip_id, trip_id,..]}
            trip_route_dict_yest = {}
            trip_route_dict_tom = {}
            triproutelist = []
            c2 = conn.cursor()
            for rtpair in c:
                key = tuple(rtpair)
                route_id = rtpair[0]
                direction_id = rtpair[1]
                # Get list of trips
                # Ignore direction if this route doesn't have a direction
                if direction_id not in [
                        None, ""
                ]:  # GTFS can have direction IDs of zero
                    triproutefetch = '''
                            SELECT trip_id, service_id FROM trips
                            WHERE route_id='%s'
                            AND direction_id=%s
                            ;''' % (route_id, direction_id)
                else:
                    triproutefetch = '''
                            SELECT trip_id, service_id FROM trips
                            WHERE route_id='%s'
                            ;''' % route_id
                c2.execute(triproutefetch)
                triproutelist = c2.fetchall()
                if not triproutelist:
                    arcpy.AddWarning(
                        "Your GTFS dataset does not contain any trips \
corresponding to Route %s and Direction %s. Please ensure that \
you have selected the correct GTFS SQL file for this input file or that your \
GTFS data is good. Output fields will be generated, but \
the values will be 0 or <Null>." % (route_id, str(direction_id)))

                for triproute in triproutelist:
                    # Only keep trips running on the correct day
                    if triproute[1] in serviceidlist:
                        trip_route_dict.setdefault(key,
                                                   []).append(triproute[0])
                    if triproute[1] in serviceidlist_tom:
                        trip_route_dict_tom.setdefault(key,
                                                       []).append(triproute[0])
                    if triproute[1] in serviceidlist_yest:
                        trip_route_dict_yest.setdefault(key, []).append(
                            triproute[0])

                if not trip_route_dict and not trip_route_dict_tom and not trip_route_dict_yest:
                    arcpy.AddWarning(
                        "There is no service for route %s in direction %s \
on %s during the time window you selected. Output fields will be generated, but \
the values will be 0 or <Null>." % (route_id, str(direction_id), str(day)))

        except:
            arcpy.AddError("Error getting trips associated with route.")
            raise

        # ----- Query the GTFS data to count the trips at each stop for this time period -----
        try:
            arcpy.AddMessage(
                "Calculating the number of transit trips available during the time window of time period ID {0}..."
                .format(str(time_period)))

            frequencies_dict = BBB_SharedFunctions.MakeFrequenciesDict()

            stoptimedict_rtedirpair = {}  # #{rtdir tuple:stoptimedict}}
            stoptimedict_service_check_counter = 0
            for rtdirpair in list(
                    set([
                        rt for rt in list(trip_route_dict.keys()) +
                        list(trip_route_dict_yest.keys()) +
                        list(trip_route_dict_tom.keys())
                    ])):

                # Get the stop_times that occur during this time window
                stoptimedict = {}
                stoptimedict_yest = {}
                stoptimedict_tom = {}
                try:
                    triplist = trip_route_dict[rtdirpair]
                    stoptimedict = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(
                        start_sec, end_sec, DepOrArr, triplist, "today",
                        frequencies_dict)
                except KeyError:  # No trips
                    pass
                try:
                    triplist_yest = trip_route_dict_yest[rtdirpair]
                    stoptimedict_yest = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(
                        start_sec, end_sec, DepOrArr, triplist_yest,
                        "yesterday", frequencies_dict)
                except KeyError:  # No trips
                    pass
                try:
                    triplist_tom = trip_route_dict_tom[rtdirpair]
                    stoptimedict_tom = BBB_SharedFunctions.GetStopTimesForStopsInTimeWindow(
                        start_sec, end_sec, DepOrArr, triplist_tom, "tomorrow",
                        frequencies_dict)
                except KeyError:  # No trips
                    pass

                # Combine the three dictionaries into one master
                for stop in stoptimedict_yest:  # Update Dictionaries based on setdefault returns values.
                    stoptimedict[stop] = stoptimedict.setdefault(
                        stop, []) + stoptimedict_yest[stop]
                for stop in stoptimedict_tom:
                    stoptimedict[stop] = stoptimedict.setdefault(
                        stop, []) + stoptimedict_tom[stop]
                # PD here
                stoptimedict_rtedirpair[
                    rtdirpair] = stoptimedict  # {rtdir tuple:{stoptimedict}}
                # Add a minor warning if there is no service for at least one route-direction combination.
                if not stoptimedict:
                    stoptimedict_service_check_counter += 1
            if stoptimedict_service_check_counter > 0:
                arcpy.AddWarning(
                    "There is no service for %s route-direction pair(s) \
on %s during the time window you selected. Output fields will be generated, but \
the values will be 0 or <Null>." %
                    (str(stoptimedict_service_check_counter), str(day)))

        except:
            arcpy.AddError(
                "Error counting arrivals or departures at stop during time window."
            )
            raise

        # ----- Write to output -----

        try:
            arcpy.AddMessage(
                "Calculating frequency statistics from route direction pairs..."
            )
            frequency_record_table = [
            ]  #[(rtedirpair_id,route_id,direction_id,stop_id,NumTripsPerHr,MaxWaitTime,AvgHeadway)]
            labels = [
                "rtedir_id", "rte_count", "stop_id", "NumTrips",
                "NumTripsPerHr", "MaxWaitTime", "AvgHeadway"
            ]
            for rtedirpair in stoptimedict_rtedirpair:
                route_id = rtedirpair[0]
                stops = stoptimedict_rtedirpair[rtedirpair].keys()
                for stop_id in stops:
                    NumTrips, NumTripsPerHr, MaxWaitTime, AvgHeadway = RetrieveFrequencyStatsForStop(
                        stop_id,
                        rtedirpair,
                        snap_to_nearest_5_minutes=SnapToNearest5MinuteBool)
                    AvgHeadway = post_process_headways(AvgHeadway,
                                                       NumTripsPerHr)
                    frequency_record_table.append(
                        (rtedirpair, route_id, stop_id, NumTrips,
                         NumTripsPerHr, MaxWaitTime, AvgHeadway))
            frequency_dataframe = pd.DataFrame.from_records(
                frequency_record_table, columns=labels)
            #Count the number of routes that meet threshold
            frequency_dataframe["MetHdWyLim"] = 1
            frequency_dataframe["MetHdWyLim"].where(
                frequency_dataframe["AvgHeadway"] <= FrequencyThreshold,
                np.nan,
                inplace=True)
            #Add Fields for frequency aggregation
            frequency_dataframe["MinHeadway"] = frequency_dataframe[
                "AvgHeadway"]
            frequency_dataframe["MaxHeadway"] = frequency_dataframe[
                "AvgHeadway"]
            output_stats = collections.OrderedDict([("NumTrips", ("sum")),
                                                    ("NumTripsPerHr", ("sum")),
                                                    ("MaxWaitTime", ("max")),
                                                    ("rte_count", ("count")),
                                                    ("AvgHeadway", ("mean")),
                                                    ("MinHeadway", ("min")),
                                                    ("MaxHeadway", ("max")),
                                                    ("MetHdWyLim", ("sum"))])
            stop_groups = frequency_dataframe.groupby("stop_id")
            stop_frequency_statistics = stop_groups.agg(output_stats)
            if ".shp" in outStops:
                # Set up shapefile accommodations for long fields (>10 chars) & null values
                stop_frequency_statistics.rename(columns={
                    "NumTripsPerHr": "TripsPerHr",
                    "MaxWaitTime": "MxWtTime"
                },
                                                 inplace=True)
                stop_frequency_statistics = stop_frequency_statistics.fillna(
                    value=-1)

        except:
            arcpy.AddError("Error calculating frequency statistics...")
            raise
        try:
            arcpy.AddMessage("Writing output data...")
            # Create an update cursor to add numtrips, trips/hr, maxwaittime, and headway stats to stops
            frequency_records = stop_frequency_statistics.to_records()
            arcpy.da.ExtendTable(outStops,
                                 "stop_id",
                                 frequency_records,
                                 "stop_id",
                                 append_only=False)
            arcpy.AddMessage("Script complete!")
        except:
            arcpy.AddError("Error writing to output.")
            raise

        arcpy.AddMessage("Finished!")
        arcpy.AddMessage("Your output is located at " + outStops)

    except BBB_SharedFunctions.CustomError:
        arcpy.AddError("Failed to count high frequency routes at stops.")
        pass

    except:
        arcpy.AddError("Failed to count high frequency routes at stops.")
        raise