Exemple #1
0
    def _direct_path(
        self,
        instance,
        mode,
        pt_object_origin,
        pt_object_destination,
        fallback_extremity,
        request,
        direct_path_type,
        request_id,
    ):
        # if the crowfly distance between origin and destination is too large, there is no need to call asgard
        crowfly_distance = crowfly_distance_between(
            get_pt_object_coord(pt_object_origin),
            get_pt_object_coord(pt_object_destination))

        # if the crowfly distance between origin and destination is
        # bigger than max_{mode}_direct_path_distance don't compute direct_path
        if crowfly_distance > int(
                request['max_{mode}_direct_path_distance'.format(mode=mode)]):
            return response_pb2.Response()

        if (crowfly_distance / float(request['{mode}_speed'.format(mode=mode)])
                >
                request['max_{mode}_direct_path_duration'.format(mode=mode)]):
            return response_pb2.Response()

        language = self.get_language_parameter(request)

        req = self._create_direct_path_request(
            mode,
            pt_object_origin,
            pt_object_destination,
            fallback_extremity,
            request,
            direct_path_type,
            language,
        )

        response = self._call_asgard(req)

        # car_no_park is interpreted as car for Asgard, we need to overwrite the streetnetwork mode here
        if mode == "car_no_park":
            try:
                response.journeys[0].sections[
                    0].street_network.mode = response_pb2.CarNoPark
            except AttributeError:
                pass
            except Exception as e:
                raise e

        if response and mode in (FallbackModes.bike.name,
                                 FallbackModes.bss.name):
            response = self._add_cycle_lane_length(response)

        return response
Exemple #2
0
def _create_crowfly(pt_journey, crowfly_origin, crowfly_destination, begin, end, mode):
    section = response_pb2.Section()
    section.type = response_pb2.CROW_FLY
    section.origin.CopyFrom(crowfly_origin)
    section.destination.CopyFrom(crowfly_destination)
    section.duration = end - begin
    pt_journey.durations.total += section.duration
    pt_journey.duration += section.duration
    section.begin_date_time = begin
    section.end_date_time = end
    if section.duration > 0:
        section.street_network.mode = FallbackModes[mode].value
    # mode is always walking for a teleportation crow_fly
    else:
        section.street_network.mode = response_pb2.Walking

    # Calculate section length
    from_coord = get_pt_object_coord(section.origin)
    to_coord = get_pt_object_coord(section.destination)
    section.length = int(crowfly_distance_between(from_coord, to_coord))

    section.id = six.text_type(generate_id())
    return section
Exemple #3
0
def build_ridesharing_journeys(from_pt_obj, to_pt_obj, period_extremity,
                               instance):
    from_coord = get_pt_object_coord(from_pt_obj)
    to_coord = get_pt_object_coord(to_pt_obj)
    from_str = "{},{}".format(from_coord.lat, from_coord.lon)
    to_str = "{},{}".format(to_coord.lat, to_coord.lon)
    try:
        rsjs, fps = instance.get_ridesharing_journeys_with_feed_publishers(
            from_str, to_str, period_extremity)
    except Exception as e:
        logging.exception(
            'Error while retrieving ridesharing ads and feed_publishers from %s to %s: {}',
            from_str, to_str)
        new_relic.record_custom_event('ridesharing_internal_failure',
                                      {'message': str(e)})
        rsjs = []
        fps = []

    pb_rsjs = []
    pb_tickets = []
    pb_feed_publishers = [_make_pb_fp(fp) for fp in fps if fp is not None]

    for rsj in rsjs:
        pb_rsj = response_pb2.Journey()
        pb_rsj_pickup = instance.georef.place("{};{}".format(
            rsj.pickup_place.lon, rsj.pickup_place.lat))
        pb_rsj_dropoff = instance.georef.place("{};{}".format(
            rsj.dropoff_place.lon, rsj.dropoff_place.lat))
        pickup_coord = get_pt_object_coord(pb_rsj_pickup)
        dropoff_coord = get_pt_object_coord(pb_rsj_dropoff)

        pb_rsj.requested_date_time = period_extremity.datetime
        pb_rsj.departure_date_time = rsj.pickup_date_time
        pb_rsj.arrival_date_time = rsj.dropoff_date_time
        pb_rsj.tags.append('ridesharing')

        # start teleport section
        start_teleport_section = pb_rsj.sections.add()
        start_teleport_section.id = "section_{}".format(
            six.text_type(generate_id()))
        start_teleport_section.type = response_pb2.CROW_FLY
        start_teleport_section.street_network.mode = response_pb2.Walking
        start_teleport_section.origin.CopyFrom(from_pt_obj)
        start_teleport_section.destination.CopyFrom(pb_rsj_pickup)
        start_teleport_section.length = int(
            crowfly_distance_between(from_coord, pickup_coord))
        start_teleport_section.duration = 0
        start_teleport_section.shape.extend([from_coord, pickup_coord])
        start_teleport_section.begin_date_time = rsj.pickup_date_time
        start_teleport_section.end_date_time = rsj.pickup_date_time
        # report value to journey
        pb_rsj.distances.walking += start_teleport_section.length

        # real ridesharing section
        rs_section = pb_rsj.sections.add()
        rs_section.id = "section_{}".format(six.text_type(generate_id()))
        rs_section.type = response_pb2.RIDESHARING
        rs_section.origin.CopyFrom(pb_rsj_pickup)
        rs_section.destination.CopyFrom(pb_rsj_dropoff)
        rs_section.additional_informations.append(
            response_pb2.HAS_DATETIME_ESTIMATED)

        rs_section.ridesharing_information.operator = rsj.metadata.system_id
        rs_section.ridesharing_information.network = rsj.metadata.network
        if rsj.available_seats is not None:
            rs_section.ridesharing_information.seats.available = rsj.available_seats
        if rsj.total_seats is not None:
            rs_section.ridesharing_information.seats.total = rsj.total_seats
        if rsj.driver.alias:
            rs_section.ridesharing_information.driver.alias = rsj.driver.alias
        if rsj.driver.image:
            rs_section.ridesharing_information.driver.image = rsj.driver.image
        if rsj.driver.gender is not None:
            if rsj.driver.gender == Gender.MALE:
                rs_section.ridesharing_information.driver.gender = response_pb2.MALE
            elif rsj.driver.gender == Gender.FEMALE:
                rs_section.ridesharing_information.driver.gender = response_pb2.FEMALE
        if rsj.driver.rate is not None and rsj.driver.rate_count:
            rs_section.ridesharing_information.driver.rating.value = rsj.driver.rate
        if rsj.driver.rate_count:
            rs_section.ridesharing_information.driver.rating.count = rsj.driver.rate_count
        if rsj.metadata.rating_scale_min is not None and rsj.metadata.rating_scale_max is not None:
            rs_section.ridesharing_information.driver.rating.scale_min = rsj.metadata.rating_scale_min
            rs_section.ridesharing_information.driver.rating.scale_max = rsj.metadata.rating_scale_max

        if rsj.ridesharing_ad:
            l = rs_section.ridesharing_information.links.add()
            l.key = "ridesharing_ad"
            l.href = rsj.ridesharing_ad

        # TODO CO2 = length * coeffCar / (totalSeats  + 1)
        rs_section.length = rsj.distance

        rs_section.shape.extend(rsj.shape)

        rs_section.duration = rsj.dropoff_date_time - rsj.pickup_date_time
        rs_section.begin_date_time = rsj.pickup_date_time
        rs_section.end_date_time = rsj.dropoff_date_time
        # report values to journey
        pb_rsj.distances.ridesharing += rs_section.length
        pb_rsj.duration += rs_section.duration
        pb_rsj.durations.total += rs_section.duration
        pb_rsj.durations.ridesharing += rs_section.duration

        # end teleport section
        end_teleport_section = pb_rsj.sections.add()
        end_teleport_section.id = "section_{}".format(
            six.text_type(generate_id()))
        end_teleport_section.type = response_pb2.CROW_FLY
        end_teleport_section.street_network.mode = response_pb2.Walking
        end_teleport_section.origin.CopyFrom(pb_rsj_dropoff)
        end_teleport_section.destination.CopyFrom(to_pt_obj)
        end_teleport_section.length = int(
            crowfly_distance_between(dropoff_coord, to_coord))
        end_teleport_section.duration = 0
        end_teleport_section.shape.extend([dropoff_coord, to_coord])
        end_teleport_section.begin_date_time = rsj.dropoff_date_time
        end_teleport_section.end_date_time = rsj.dropoff_date_time
        # report value to journey
        pb_rsj.distances.walking += end_teleport_section.length

        # create ticket associated
        ticket = response_pb2.Ticket()
        ticket.id = "ticket_{}".format(six.text_type(generate_id()))
        ticket.name = "ridesharing_price_{}".format(ticket.id)
        ticket.found = True
        ticket.comment = "Ridesharing price for section {}".format(
            rs_section.id)
        ticket.section_id.extend([rs_section.id])
        # also add fare to journey
        ticket.cost.value = rsj.price
        pb_rsj.fare.total.value = ticket.cost.value
        ticket.cost.currency = rsj.currency
        pb_rsj.fare.total.currency = rsj.currency
        pb_rsj.fare.found = True
        pb_rsj.fare.ticket_id.extend([ticket.id])

        pb_tickets.append(ticket)
        pb_rsjs.append(pb_rsj)

    return pb_rsjs, pb_tickets, pb_feed_publishers
Exemple #4
0
    def _direct_path(
        self,
        instance,
        mode,
        pt_object_origin,
        pt_object_destination,
        fallback_extremity,
        request,
        direct_path_type,
        request_id,
    ):
        """
        :param direct_path_type: we need to "invert" a direct path when it's a ending fallback by car if and only if
                                 it's returned by kraken. In other case, it's ignored
        """
        should_invert_journey = mode == 'car' and direct_path_type == StreetNetworkPathType.ENDING_FALLBACK
        if should_invert_journey:
            pt_object_origin, pt_object_destination = pt_object_destination, pt_object_origin

        direct_path_request = {}
        for attr in [
                'walking_speed',
                'max_walking_duration_to_pt',
                'bike_speed',
                'max_bike_duration_to_pt',
                'bss_speed',
                'max_bss_duration_to_pt',
                'car_speed',
                'max_car_duration_to_pt',
                'car_no_park_speed',
                'max_car_no_park_duration_to_pt',
                'taxi_speed',
                'max_taxi_duration_to_pt',
                'ridesharing_speed',
                'max_ridesharing_duration_to_pt',
        ]:
            direct_path_request[attr] = request[attr]

        if direct_path_type == StreetNetworkPathType.DIRECT:
            # in distributed scenario, we allow the street network calculator to compute a very long direct path
            # in case of Kraken, the stop condition of direct path in Kraken is defined as
            # max_{mode}_duration_to_pt * 2.
            # When it comes to a direct path request, we override this parameter with
            # max_{mode}_direct_path_duration / 2.0
            from jormungandr.fallback_modes import FallbackModes as fm

            direct_path_request['max_{mode}_duration_to_pt'.format(
                mode=mode)] = int(
                    request['max_{mode}_direct_path_duration'.format(
                        mode=mode)] / 2)
            # if the crowfly distance between origin and destination is too large, there is no need to call kraken
            crowfly_distance = crowfly_distance_between(
                utils.get_pt_object_coord(pt_object_origin),
                utils.get_pt_object_coord(pt_object_destination))

            if (crowfly_distance / float(
                    direct_path_request['{mode}_speed'.format(mode=mode)]) >
                    request['max_{mode}_direct_path_duration'.format(
                        mode=mode)]):
                return response_pb2.Response()

        req = self._create_direct_path_request(mode, pt_object_origin,
                                               pt_object_destination,
                                               fallback_extremity,
                                               direct_path_request)

        response = instance.send_and_receive(req, request_id=request_id)
        if should_invert_journey:
            return self._reverse_journeys(response)

        return response
Exemple #5
0
    def _direct_path(
        self,
        instance,
        mode,
        pt_object_origin,
        pt_object_destination,
        fallback_extremity,
        request,
        direct_path_type,
        request_id,
    ):
        """
        :param direct_path_type: we need to "invert" a direct path when it's a ending fallback by car if and only if
                                 it's returned by kraken. In other case, it's ignored
        """
        should_invert_journey = mode == 'car' and direct_path_type == StreetNetworkPathType.ENDING_FALLBACK
        if should_invert_journey:
            pt_object_origin, pt_object_destination = pt_object_destination, pt_object_origin

        direct_path_request = {}
        for attr in [
                'walking_speed',
                'max_walking_duration_to_pt',
                'bike_speed',
                'max_bike_duration_to_pt',
                'bss_speed',
                'max_bss_duration_to_pt',
                'car_speed',
                'max_car_duration_to_pt',
                'car_no_park_speed',
                'max_car_no_park_duration_to_pt',
                'taxi_speed',
                'max_taxi_duration_to_pt',
                'ridesharing_speed',
                'max_ridesharing_duration_to_pt',
                '_enable_instructions',
        ]:
            direct_path_request[attr] = request[attr]

        if direct_path_type == StreetNetworkPathType.DIRECT:
            # in distributed scenario, we allow the street network calculator to compute a very long direct path
            # in case of Kraken, the stop condition of direct path in Kraken is defined as
            # max_{mode}_duration_to_pt * 2.
            # When it comes to a direct path request, we override this parameter with
            # max_{mode}_direct_path_duration / 2.0
            from jormungandr.fallback_modes import FallbackModes as fm

            direct_path_request['max_{mode}_duration_to_pt'.format(
                mode=mode)] = int(
                    request['max_{mode}_direct_path_duration'.format(
                        mode=mode)] / 2)
            # if the crowfly distance between origin and destination is too large, there is no need to call kraken
            crowfly_distance = crowfly_distance_between(
                utils.get_pt_object_coord(pt_object_origin),
                utils.get_pt_object_coord(pt_object_destination))

            if (crowfly_distance / float(
                    direct_path_request['{mode}_speed'.format(mode=mode)]) >
                    request['max_{mode}_direct_path_duration'.format(
                        mode=mode)]):
                return response_pb2.Response()

        req = self._create_direct_path_request(mode, pt_object_origin,
                                               pt_object_destination,
                                               fallback_extremity,
                                               direct_path_request)

        response = instance.send_and_receive(req, request_id=request_id)
        if should_invert_journey:
            response = self._reverse_journeys(response)

        def has_bss_rent_before_put_back_section(journey):
            # Here is a little trick with python's generator
            # the next 3 lines check not only the existences of BSS_RENT and BSS_PUT_BACK, but also check the fact that
            # BSS_RENT must be located Before BSS_PUT_BACK
            sections = (s for s in journey.sections)
            bss_rent = next(
                (True for s in sections if s.type == response_pb2.BSS_RENT),
                False)
            bss_put_back = next(
                (True
                 for s in sections if s.type == response_pb2.BSS_PUT_BACK),
                False)
            return bss_rent and bss_put_back

        if response.journeys:
            # Note that: the journey returned by Kraken is a direct path. A direct path of walking/bike/car/car_no_park/
            # contains only one section. But for bss, there may be one or three sections.
            # For bss,we only need attribute the mode to the first section. The most significant mode will be chosen
            # later
            if has_bss_rent_before_put_back_section(response.journeys[0]):
                return response

            if mode == FallbackModes.bss.name and (
                    not has_bss_rent_before_put_back_section(
                        response.journeys[0])):
                response.journeys[0].sections[
                    0].street_network.mode = FallbackModes.walking.value
            else:
                response.journeys[0].sections[
                    0].street_network.mode = FallbackModes[mode].value
        return response
Exemple #6
0
    def _compute_journeys(self, future_manager, request, instance,
                          krakens_call, context, request_type):
        """
        For all krakens_call, call the kraken and aggregate the responses

        Note: the responses will only attach a crowfly section as a fallback. Street network will be
        done when calling finalise_journeys

        return the list of all responses
        """

        logger = logging.getLogger(__name__)
        logger.debug('request datetime: %s', request['datetime'])
        request_id = request["request_id"]
        logger.debug("request_id : {}".format(request_id))

        requested_dep_modes_with_pt = {
            mode
            for mode, _, direct_path_type in krakens_call
            if direct_path_type != "only"
        }
        requested_arr_modes_with_pt = {
            mode
            for _, mode, direct_path_type in krakens_call
            if direct_path_type != "only"
        }

        # These are the modes in first_section_modes[] and direct_path_modes[]
        # We need to compute direct_paths for them either because we requested it with direct_path_modes[]
        # Or because we need them to optimize the pt_journey computation
        requested_direct_path_modes = {
            mode
            for mode, _, direct_path_type in krakens_call
            if direct_path_type == "only"
        }
        requested_direct_path_modes.update(requested_dep_modes_with_pt)

        if context.partial_response_is_empty:
            logger.debug('requesting places by uri orig: %s dest %s',
                         request['origin'], request['destination'])

            context.requested_orig = PlaceByUri(
                future_manager=future_manager,
                instance=instance,
                uri=request['origin'],
                request_id="{}_place_origin".format(request_id),
            )
            context.requested_dest = PlaceByUri(
                future_manager=future_manager,
                instance=instance,
                uri=request['destination'],
                request_id="{}_place_dest".format(request_id),
            )

            context.requested_orig_obj = get_entry_point_or_raise(
                context.requested_orig, request['origin'])
            context.requested_dest_obj = get_entry_point_or_raise(
                context.requested_dest, request['destination'])

            context.streetnetwork_path_pool = StreetNetworkPathPool(
                future_manager=future_manager, instance=instance)

            period_extremity = PeriodExtremity(request['datetime'],
                                               request['clockwise'])

            for mode in requested_direct_path_modes:
                context.streetnetwork_path_pool.add_async_request(
                    requested_orig_obj=context.requested_orig_obj,
                    requested_dest_obj=context.requested_dest_obj,
                    mode=mode,
                    period_extremity=period_extremity,
                    request=request,
                    streetnetwork_path_type=StreetNetworkPathType.DIRECT,
                    request_id="{}_direct_path_mode_{}".format(
                        request_id, mode),
                )

            # if max_duration(time to pass in pt) is zero, there is no need to continue,
            # we return all direct path without pt
            if request['max_duration'] == 0:
                res = [
                    context.streetnetwork_path_pool.wait_and_get(
                        requested_orig_obj=context.requested_orig_obj,
                        requested_dest_obj=context.requested_dest_obj,
                        mode=mode,
                        request=request,
                        period_extremity=period_extremity,
                        streetnetwork_path_type=StreetNetworkPathType.DIRECT,
                    ) for mode in requested_direct_path_modes
                ]
                # add SN feed publishers
                context.streetnetwork_path_pool.add_feed_publishers(
                    request, requested_direct_path_modes, res)
                return res

            # We'd like to get the duration of a direct path to do some optimizations in ProximitiesByCrowflyPool and
            # FallbackDurationsPool.
            # Note :direct_paths_by_mode is a dict of mode vs future of a direct paths, this line is not blocking
            context.direct_paths_by_mode = context.streetnetwork_path_pool.get_all_direct_paths(
            )

            crowfly_distance = crowfly_distance_between(
                get_pt_object_coord(context.requested_orig_obj),
                get_pt_object_coord(context.requested_dest_obj))
            context.orig_proximities_by_crowfly = ProximitiesByCrowflyPool(
                future_manager=future_manager,
                instance=instance,
                requested_place_obj=context.requested_orig_obj,
                modes=requested_dep_modes_with_pt,
                request=request,
                direct_paths_by_mode=context.direct_paths_by_mode,
                max_nb_crowfly_by_mode=request['max_nb_crowfly_by_mode'],
                request_id="{}_crowfly_orig".format(request_id),
                o_d_crowfly_distance=crowfly_distance,
            )

            context.dest_proximities_by_crowfly = ProximitiesByCrowflyPool(
                future_manager=future_manager,
                instance=instance,
                requested_place_obj=context.requested_dest_obj,
                modes=requested_arr_modes_with_pt,
                request=request,
                direct_paths_by_mode=context.direct_paths_by_mode,
                max_nb_crowfly_by_mode=request['max_nb_crowfly_by_mode'],
                request_id="{}_crowfly_dest".format(request_id),
                o_d_crowfly_distance=crowfly_distance,
            )

            context.orig_places_free_access = PlacesFreeAccess(
                future_manager=future_manager,
                instance=instance,
                requested_place_obj=context.requested_orig_obj,
                request_id="{}_places_free_access_orig".format(request_id),
            )
            context.dest_places_free_access = PlacesFreeAccess(
                future_manager=future_manager,
                instance=instance,
                requested_place_obj=context.requested_dest_obj,
                request_id="{}_places_free_access_dest".format(request_id),
            )

            context.orig_fallback_durations_pool = FallbackDurationsPool(
                future_manager=future_manager,
                instance=instance,
                requested_place_obj=context.requested_orig_obj,
                modes=requested_dep_modes_with_pt,
                proximities_by_crowfly_pool=context.
                orig_proximities_by_crowfly,
                places_free_access=context.orig_places_free_access,
                direct_paths_by_mode=context.direct_paths_by_mode,
                request=request,
                direct_path_type=StreetNetworkPathType.BEGINNING_FALLBACK,
                request_id="{}_fallback_orig".format(request_id),
            )

            context.dest_fallback_durations_pool = FallbackDurationsPool(
                future_manager=future_manager,
                instance=instance,
                requested_place_obj=context.requested_dest_obj,
                modes=requested_arr_modes_with_pt,
                proximities_by_crowfly_pool=context.
                dest_proximities_by_crowfly,
                places_free_access=context.dest_places_free_access,
                direct_paths_by_mode=context.direct_paths_by_mode,
                request=request,
                direct_path_type=StreetNetworkPathType.ENDING_FALLBACK,
                request_id="{}_fallback_dest".format(request_id),
            )

        pt_journey_pool = PtJourneyPool(
            future_manager=future_manager,
            instance=instance,
            requested_orig_obj=context.requested_orig_obj,
            requested_dest_obj=context.requested_dest_obj,
            streetnetwork_path_pool=context.streetnetwork_path_pool,
            krakens_call=krakens_call,
            orig_fallback_durations_pool=context.orig_fallback_durations_pool,
            dest_fallback_durations_pool=context.dest_fallback_durations_pool,
            request=request,
            request_type=request_type,
            request_id="{}_ptjourney".format(request_id),
        )

        pt_journey_elements = wait_and_build_crowflies(
            requested_orig_obj=context.requested_orig_obj,
            requested_dest_obj=context.requested_dest_obj,
            pt_journey_pool=pt_journey_pool,
            has_valid_direct_paths=context.streetnetwork_path_pool.
            has_valid_direct_paths(),
            orig_places_free_access=context.orig_places_free_access,
            dest_places_free_acces=context.dest_places_free_access,
            orig_fallback_durations_pool=context.orig_fallback_durations_pool,
            dest_fallback_durations_pool=context.dest_fallback_durations_pool,
        )

        context.journeys_to_modes.update(
            self._map_journeys_to_modes(pt_journey_elements))

        # At the stage, all types of journeys have been computed thus we build the final result here
        res = []
        if context.partial_response_is_empty:
            for mode in requested_direct_path_modes:
                dp = context.direct_paths_by_mode.get(mode).wait_and_get()
                if getattr(dp, "journeys", None):
                    res.append(dp)

        # pt_journeys may contain None and res must be a list of protobuf journey
        res.extend(
            (j.pt_journeys for j in pt_journey_elements if j.pt_journeys))

        check_final_results_or_raise(res, context.orig_fallback_durations_pool,
                                     context.dest_fallback_durations_pool)

        for r in res:
            fill_uris(r)

        context.partial_response_is_empty = False

        # add SN feed publishers
        context.streetnetwork_path_pool.add_feed_publishers(
            request, requested_direct_path_modes, res)

        return res