Use CustomBroadcastArea to estimate phones in bleed area

Our current assumption is that the bleed area has the same population
density as the broadcast area.

This is particularly naïve when:
- the bleed area overlaps the sea – no-one lives in the sea
- the broadcast area is a village and the bleed area is the surrounding
  countryside
- the broadcast area is adjacent to a densely populated area like a city

We can be smarter about this now that we have a way of determining the
number of phones in an arbitrary area, based on the known areas that we
have population data about.

Calculating the population in an overlap is a slightly more intensive
calculation. So we only doing it for areas which are smaller enough that
it doesn’t slow things down too much. For larger areas we still use the
more naïve algorithm.
This commit is contained in:
Chris Hill-Scott
2021-06-24 08:43:35 +01:00
parent 256c840b46
commit 5a378fe51f
3 changed files with 43 additions and 9 deletions

View File

@@ -144,6 +144,10 @@ class CustomBroadcastArea(BaseBroadcastArea):
self.name = name
self._polygons = polygons or []
@classmethod
def from_polygon_objects(cls, polygon_objects):
return cls(name=None, polygons=polygon_objects.as_coordinate_pairs_lat_long)
@property
def polygons(self):
return Polygons(

View File

@@ -7,6 +7,7 @@ from orderedset import OrderedSet
from werkzeug.utils import cached_property
from app.broadcast_areas.models import (
CustomBroadcastArea,
CustomBroadcastAreas,
broadcast_area_libraries,
)
@@ -17,6 +18,10 @@ from app.notify_client.broadcast_message_api_client import (
broadcast_message_api_client,
)
ESTIMATED_AREA_OF_LARGEST_UK_COUNTY = broadcast_area_libraries.get_areas(
'ctyua19-E10000023' # North Yorkshire
)[0].polygons.estimated_area
class BroadcastMessage(JSONModel):
@@ -176,12 +181,18 @@ class BroadcastMessage(JSONModel):
@property
def count_of_phones_likely(self):
area_estimate = self.simple_polygons.estimated_area
bleed_area_estimate = self.simple_polygons_with_bleed.estimated_area - area_estimate
return round_to_significant_figures(
self.count_of_phones + (self.count_of_phones * bleed_area_estimate / area_estimate),
1
)
estimated_area = self.simple_polygons.estimated_area
if estimated_area > ESTIMATED_AREA_OF_LARGEST_UK_COUNTY:
count = self.count_of_phones * (
self.simple_polygons_with_bleed.estimated_area / estimated_area
)
else:
count = CustomBroadcastArea.from_polygon_objects(
self.simple_polygons_with_bleed
).count_of_phones
return round_to_significant_figures(count, 1)
def get_areas(self, areas):
return broadcast_area_libraries.get_areas(

View File

@@ -830,7 +830,7 @@ def test_broadcast_page(
], [
'An area of 6.3 square miles Will get the alert',
'An extra area of 22.6 square miles is Likely to get the alert',
'9,000 to 40,000 phones',
'9,000 to 10,000 phones',
]),
([
'lad20-E09000019',
@@ -839,7 +839,26 @@ def test_broadcast_page(
], [
'An area of 9.7 square miles Will get the alert',
'An extra area of 4.7 square miles is Likely to get the alert',
'200,000 to 300,000 phones',
'200,000 to 500,000 phones',
]),
([
'ctyua19-E10000019',
], [
'Lincolnshire remove',
], [
'An area of 3,986.6 square miles Will get the alert',
'An extra area of 599.4 square miles is Likely to get the alert',
'500,000 to 600,000 phones',
]),
([
'ctyua19-E10000019',
'ctyua19-E10000023'
], [
'Lincolnshire remove', 'North Yorkshire remove',
], [
'An area of 9,776.2 square miles Will get the alert',
'An extra area of 1,654.6 square miles is Likely to get the alert',
'1,000,000 phones estimated',
]),
))
def test_preview_broadcast_areas_page(
@@ -907,7 +926,7 @@ def test_preview_broadcast_areas_page(
[
'An area of 3,205.0 square miles Will get the alert',
'An extra area of 763.4 square miles is Likely to get the alert',
'4,000 to 5,000 phones',
'4,000 phones estimated',
]
),
))