Inspire a community of professionals skilled in spatiotemporal analysis for community health and safety.

Prototype an algorithm that places batteries near service drop poles.

Roy Hyunjin Han

A battery must be close enough to its discharge point to minimize distribution loss.

20171108-2000 - 20171108-2100: 60 minutes estimated

- Draft algorithm.
- Prototype tool.

20171108-2000 - 20171108-2030: 30 minutes

This seems to be identical to the problem of placing service drop poles near customers. The difference is that there is no limit to the number of poles per battery.

In [1]:

```
from shapely.geometry import MultiPoint, Point
drop_poles = [
Point(1, 1),
Point(3, 2),
Point(7, 0),
]
MultiPoint(drop_poles)
```

Out[1]:

In [2]:

```
from shapely.geometry import GeometryCollection, Polygon
obstacle_geometries = [
Polygon([(1.5, 0), (1.5, 3), (2.5, 3), (2.5, 0)])
]
GeometryCollection(drop_poles + obstacle_geometries)
```

Out[2]:

```
+ Create a sample dataset of service drop poles
+ Create example obstacles
```

20171110-1330 - 20171110-1400: 30 minutes

Remember that the first implementation only considers the case of no roads and no obstacles.

In [3]:

```
from copy import copy
from shapely.geometry import LineString
from shapely.ops import polygonize, unary_union
def get_source_geometries(target_geometries, maximum_distance):
# Convert target_geometries into target_polygons using maximum_distance
target_polygons = [x.buffer(maximum_distance) for x in target_geometries]
lonely_polygons = copy(target_polygons)
# Identify areas of intersection
social_polygons = []
for polygon in get_disjoint_polygons(target_polygons):
connected_polygons = []
for target_polygon in target_polygons:
if target_polygon.contains(polygon.centroid):
connected_polygons.append(target_polygon)
if len(connected_polygons) > 1:
for target_polygon in connected_polygons:
try:
lonely_polygons.remove(target_polygon)
except ValueError:
pass
social_polygons.append(polygon)
polygon.connected_polygons = connected_polygons
# Define connected_polygons for each lonely_polygon
for polygon in lonely_polygons:
polygon.connected_polygons = []
return social_polygons + lonely_polygons
def get_disjoint_polygons(overlapping_polygons):
'Split overlapping polygons into disjoint polygons'
rings = [LineString(list(
x.exterior.coords)) for x in overlapping_polygons]
return list(polygonize(unary_union(rings)))
```

In [4]:

```
GeometryCollection(drop_poles + get_source_geometries(drop_poles, 1))
```

Out[4]:

In [5]:

```
GeometryCollection(drop_poles + get_source_geometries(drop_poles, 1.5))
```

Out[5]:

```
+ Minimize the distance of a battery to each service drop pole
+ Minimize the number of batteries
+ Limit the maximum distance of a battery to a service drop pole
```

We'll save obstacles for the 3rd implementation.

20171117-1845 - 20171117-1900: 15 minutes

It seems that each of the batteries are supposed to be placed on a distribution line and distances to each service drop are computed as measured along the distribution line. We'll save that for the 2nd implementation.