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]]
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
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], }
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], }
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
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
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
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)
"""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."""
"""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