예제 #1
0
def test_get_locations_to_check_by_service_area():
    locations = [
        Point(**{'latitude': 33.77500830300005, 'longitude': -118.11176916399995}),
        Point(**{'latitude': 85.00000000000000, 'longitude': -100.00000000000000})
    ]
    output = adequacy._get_locations_to_check_by_service_area(
        service_area_ids=['ca_los_angeles_county_00000'],
        locations=locations,
        radius_in_meters=10**4,
        engine=engine,
    )['ca_los_angeles_county_00000']
    assert output == [locations[0]]
예제 #2
0
def _find_closest_location(point,
                           locations,
                           measurer,
                           exit_distance_in_meters=None,
                           index=None):
    """Find closest provider to a representative point."""
    if index and index % 100 == 0:
        logger.info('Processing point #{}'.format(index))
    point_coords = Point(latitude=point['latitude'],
                         longitude=point['longitude'])
    if not exit_distance_in_meters:
        closest_distance, closest_provider = measurer.closest(
            origin=point_coords,
            point_list=locations,
        )
    else:
        closest_distance, closest_provider = measurer.closest_with_early_exit(
            origin=point_coords,
            point_list=locations,
            exit_distance=exit_distance_in_meters)
    provider = {
        'id': point['id'],
        'closest_point': closest_provider,
        'to_closest_provider': closest_distance
    }
    return provider
예제 #3
0
def _measure_one_to_many(point, locations, measurer):
    """Measure the distance from the input point to all locations."""
    point_coords = Point(latitude=point['latitude'], longitude=point['longitude'])
    supply_locations = [
        Point(latitude=location['latitude'], longitude=location['longitude'])
        for location in locations
    ]
    distance_matrix = measurer._get_matrix(
        source_points=[point_coords],
        destination_points=supply_locations
    )
    # TODO: Determine exactly which keys are needed in the response.
    return {
        'id': point['id'],
        'locations': locations,
        'location_ids': [location['id'] for location in locations],
        'measurements': distance_matrix[0],
    }
예제 #4
0
def _measure_one_to_many(point, locations, measurer):
    """Measure the distance from the input point to all locations."""
    point_coords = Point(latitude=point['latitude'],
                         longitude=point['longitude'])
    distance_matrix = measurer._get_matrix(source_points=[point_coords],
                                           destination_points=locations)
    return {
        'id': point['id'],
        'locations': locations,
        'measurements': distance_matrix[0],
    }
예제 #5
0
def calculate_measurement_matrix(
        service_area_ids,
        locations,
        measurer_name,
        engine=connect.create_db_engine(),
):
    """
    Calculate a measurement matrix for the given service area IDs.

    The measurement between point i and location j in the cell with row i, column j.
    """
    # TODO: Share introduction of this function with calculate.adequacy.
    location_to_id_map = collections.defaultdict(list)
    for j, location in enumerate(locations):
        # TODO - Permanently fix this on the frontend side.
        location.pop('id')
        location_to_id_map[Point(**location)].append(j)

    locations = list(location_to_id_map.keys())
    points = representative_points.minimal_fetch_representative_points(
        service_area_ids=service_area_ids, engine=engine)

    logger.debug('{} pairwise distances to calculate.'.format(
        len(locations) * len(points)))

    measurer = get_measurer(measurer_name)
    measurer_config = config.get('measurer_config')[measurer_name]
    executor_type = measurer_config['adequacy_executor_type']
    n_processors = measurer_config['n_adequacy_processors']

    logger.debug('Starting {} executors for gravity calculations...'.format(
        n_processors))
    with executor_type(processes=n_processors) as executor:
        measurements_by_point = executor.starmap(
            func=_measure_one_to_many,
            iterable=zip(
                points,
                itertools.repeat(locations),
                itertools.repeat(measurer),
            ))

    measurements_by_point = _add_provider_ids(
        measurements_by_point=measurements_by_point,
        location_to_id_map=location_to_id_map)

    measurement_matrix = np.full(shape=(len(points), len(locations)),
                                 fill_value=float('inf'))
    for i, response in enumerate(measurements_by_point):
        for j, distance in zip(response['location_ids'],
                               response['measurements']):
            measurement_matrix[i][j] = distance

    return measurement_matrix
예제 #6
0
def test_find_closest_location():
    point = {
        'id': 0,
        'latitude': 37.74753421600008,
        'longitude': -122.2316317029999,
    }
    locations = [
        Point(**{'latitude': 37.74753421600008, 'longitude': -122.2316317029999}),
        Point(**{'latitude': 32.74753421600008, 'longitude': -122.2316317029999}),
    ]
    output = adequacy._find_closest_location(
        point=point,
        measurer=get_measurer('haversine'),
        locations=locations,
    )

    expected = {
        'id': point['id'],
        'closest_point': Point(latitude=37.74753421600008, longitude=-122.2316317029999),
        'to_closest_provider': 0
    }

    assert output == expected
 def test_measure_one_to_many(self):
     """Test measure_one_to_many."""
     point = {
         'id': 0,
         'latitude': 32.74753421600008,
         'longitude': -122.2316317029999
     }
     locations = [
         Point(latitude=location['latitude'],
               longitude=location['longitude'])
         for location in self.locations
     ]
     output = gravity._measure_one_to_many(point, locations,
                                           get_measurer('haversine'))
     expected = {
         'id': 0,
         'locations': locations,
         'measurements': [399476.6135406669, 0],
     }
     assert output == expected
예제 #8
0
def _find_closest_location(point,
                           locations,
                           measurer,
                           exit_distance_in_meters=None):
    """Find closest provider from to a representative point."""
    point_coords = Point(latitude=point['latitude'],
                         longitude=point['longitude'])
    if not exit_distance_in_meters:
        closest_distance, closest_provider = measurer.closest(
            origin=point_coords,
            point_list=locations,
        )
    else:
        closest_distance, closest_provider = measurer.closest_with_early_exit(
            origin=point_coords,
            point_list=locations,
            exit_distance=exit_distance_in_meters)
    provider = {
        'id': point['id'],
        'closest_point': closest_provider,
        'to_closest_provider': closest_distance
    }
    return provider
예제 #9
0
def calculate_adequacies(service_area_ids,
                         locations,
                         engine,
                         measurer_name,
                         radius_in_meters=RELEVANCY_RADIUS_IN_METERS):
    """
    Calculate adequacies.

    The calculation proceeds as follows:
        - Determine nearby providers for each service area using the radius_in_meters.
        - If no nearby providers are found, use the full provider list.
        - Fetch representative points.
        - Compare each representative point to the subset of nearby providers to determine
            the closest provider.
        - Aggregate the information for each point and return.
    """
    # TODO - Split analyis by specialty.
    location_mapping = collections.defaultdict(list)
    for i, location in enumerate(locations):
        # TODO - Permanently fix this on the frontend side.
        point_id = location.pop('id', i)
        location_mapping[Point(**location)].append(point_id)

    locations = list(location_mapping.keys())

    logger.debug(
        'Calculating adequacies for {} locations ({} unique) and {} service areas using {}.'
        .format(len(locations), len(location_mapping), len(service_area_ids),
                measurer_name))

    points = representative_points.minimal_fetch_representative_points(
        service_area_ids=service_area_ids, engine=engine)

    locations_to_check_by_service_area = _get_locations_to_check_by_service_area(
        service_area_ids=service_area_ids,
        locations=locations,
        engine=engine,
        radius_in_meters=radius_in_meters)

    locations_to_check_by_point = [
        locations_to_check_by_service_area[point['service_area_id']]
        for point in points
    ]

    logger.debug('{} pairwise distances to calculate.'.format(
        str(sum(len(locations) for locations in locations_to_check_by_point))))

    measurer = get_measurer(measurer_name)
    measurer_config = config.get('measurer_config')[measurer_name]
    executor_type = measurer_config['adequacy_executor_type']
    n_processors = measurer_config['n_adequacy_processors']
    exit_distance = measurer_config[
        'exit_distance_in_miles'] * ONE_MILE_IN_METERS

    logger.debug('Starting {} executors for adequacy calculations...'.format(
        n_processors))
    with executor_type(processes=n_processors) as executor:
        adequacies = executor.starmap(func=_find_closest_location,
                                      iterable=zip(
                                          points, locations_to_check_by_point,
                                          itertools.repeat(measurer),
                                          itertools.repeat(exit_distance)))

    adequacies_response = _add_closest_provider_id(adequacies,
                                                   location_mapping)
    logger.debug('Returning adequacy results.')
    return list(adequacies_response)
예제 #10
0
"""Test MapBox API."""
import os

from backend.lib.utils.datatypes import Point
from backend.models import time

import mock

import requests

NEWPORT_RI = Point(**{'longitude': -71.312796, 'latitude': 41.49008})
CLEVELAND_OH = Point(**{'longitude': -81.695391, 'latitude': 41.499498})


class MockResponse:
    """Mock HTTP responses."""
    def __init__(self, json_data, status_code):
        self.json_data = json_data
        self.status_code = status_code

    def json(self):
        return self.json_data

    def raise_for_status(self):
        if self.status_code != 200:
            raise requests.exceptions.HTTPError('{}'.format(self.status_code),
                                                response=self)


class TestMapBoxAPIDriving():
    """Test methods related to the MapBox API."""
예제 #11
0
"""Tests for methods measuring distance between two series of points."""
from backend.lib.utils.datatypes import Point
from backend.models import base
from backend.models import distance

import pytest

NEWPORT_RI = Point(**{'longitude': -71.312796, 'latitude': 41.49008})
CLEVELAND_OH = Point(**{'longitude': -81.695391, 'latitude': 41.499498})
EUCLID_OH = Point(**{'longitude': -81.526787, 'latitude': 41.593105})
NASSAU = Point(**{'longitude': -77.3554, 'latitude': 25.0480})
MIAMI_FL = Point(**{'longitude': -80.1918, 'latitude': 25.7617})


class TestMetrics():
    """Test base metrics in the distance module."""
    def setup(self):
        """Initialize a measurer for use in the test cases."""
        self.measurer = distance.HaversineDistance()

    def test_haversine_distance_class(self):
        """Check that the haversine distance matches expectations."""
        d = self.measurer.measure_between_two_points(NEWPORT_RI, CLEVELAND_OH)
        assert abs(d - 863.731 * 10**3) < 10**-2

    def test_haversine_distance_returns_none_when_a_point_is_missing(self):
        """Check that the haversine distance matches expectations."""
        d1 = self.measurer.measure_between_two_points(NEWPORT_RI, None)
        d2 = self.measurer.measure_between_two_points(None, CLEVELAND_OH)
        assert d1 is None
        assert d2 is None