Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What to do when no variance in weight bounds #218

Merged
merged 5 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions swmmanywhere/graph_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -1007,11 +1007,13 @@ def __call__(self, G: nx.Graph,
# Calculate bounds to normalise between
bounds: Dict[Any, List[float]] = defaultdict(lambda: [np.Inf, -np.Inf])

for (u, v, d), w in product(G.edges(data=True),
topology_derivation.weights):
bounds[w][0] = min(bounds[w][0], d.get(w, np.Inf))
bounds[w][1] = max(bounds[w][1], d.get(w, -np.Inf))
for w in topology_derivation.weights:
bounds[w][0] = min(nx.get_edge_attributes(G, w).values()) # lower bound
bounds[w][1] = max(nx.get_edge_attributes(G, w).values()) # upper bound

# Avoid division by zero
bounds = {w : [b[0], b[1]] for w, b in bounds.items() if b[0] != b[1]}

G = G.copy()
eps = np.finfo(float).eps
for u, v, d in G.edges(data=True):
Expand Down
35 changes: 17 additions & 18 deletions tests/test_geospatial_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import geopandas as gpd
import networkx as nx
import numpy as np
import pytest
import rasterio as rst
from scipy.interpolate import RegularGridInterpolator
from shapely import geometry as sgeom
Expand All @@ -17,7 +18,8 @@
from swmmanywhere.misc.debug_derive_rc import derive_rc_alt


def load_street_network():
@pytest.fixture
def street_network():
"""Load a street network."""
G = ge.load_graph(Path(__file__).parent / 'test_data' / 'street_graph.json')
return G
Expand Down Expand Up @@ -217,19 +219,18 @@ def test_burn_shape_in_raster():
raster_fid.unlink(missing_ok=True)
new_raster_fid.unlink(missing_ok=True)

def test_derive_subcatchments():
def test_derive_subcatchments(street_network):
"""Test the derive_subcatchments function."""
G = load_street_network()
elev_fid = Path(__file__).parent / 'test_data' / 'elevation.tif'
for method in ['pysheds', 'pyflwdir']:
polys = go.derive_subcatchments(G, elev_fid,method=method)
polys = go.derive_subcatchments(street_network, elev_fid,method=method)
assert 'slope' in polys.columns
assert 'area' in polys.columns
assert 'geometry' in polys.columns
assert 'id' in polys.columns
assert polys.shape[0] > 0
assert polys.dropna().shape == polys.shape
assert polys.crs == G.graph['crs']
assert polys.crs == street_network.graph['crs']

# Pyflwdir and pysheds catchment derivation aren't absolutely identical
assert almost_equal(polys.set_index('id').loc[2623975694, 'area'],
Expand All @@ -239,10 +240,9 @@ def test_derive_subcatchments():
assert almost_equal(polys.set_index('id').loc[2623975694, 'width'],
21.845, tol = 0.001)

def test_derive_rc():
def test_derive_rc(street_network):
"""Test the derive_rc function."""
G = load_street_network()
crs = G.graph['crs']
crs = street_network.graph['crs']
eg_bldg = sgeom.Polygon([(700291,5709928),
(700331,5709927),
(700321,5709896),
Expand Down Expand Up @@ -276,7 +276,7 @@ def test_derive_rc():
(700329, 5709883),
(700351, 5709883)])]

streetcover = [d['geometry'].buffer(5) for u,v,d in G.edges(data=True)]
streetcover = [d['geometry'].buffer(5) for u,v,d in street_network.edges(data=True)]
streetcover = gpd.GeoDataFrame(geometry = streetcover, crs = crs)

subs = gpd.GeoDataFrame(data = {'id' : [107733,
Expand Down Expand Up @@ -410,27 +410,26 @@ def test_remove_intersections():
assert polys_.set_index('id')[['area']].equals(
targets.set_index('id')[['area']])

def test_graph_to_geojson():
def test_graph_to_geojson(street_network):
"""Test the graph_to_geojson function."""
G = load_street_network()
crs = G.graph['crs']
crs = street_network.graph['crs']
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
go.graph_to_geojson(G,
go.graph_to_geojson(street_network,
temp_path / 'graph_nodes.geojson',
temp_path / 'graph_edges.geojson',
crs)
gdf = gpd.read_file(temp_path / 'graph_nodes.geojson')
assert gdf.crs == crs
assert gdf.shape[0] == len(G.nodes)
assert gdf.shape[0] == len(street_network.nodes)

gdf = gpd.read_file(temp_path / 'graph_edges.geojson')
assert gdf.shape[0] == len(G.edges)
assert gdf.shape[0] == len(street_network.edges)

def test_merge_points():
def test_merge_points(street_network):
"""Test the merge_points function."""
G = load_street_network()
mapping = go.merge_points([(d['x'], d['y']) for u,d in G.nodes(data=True)],
mapping = go.merge_points([(d['x'], d['y'])
for u,d in street_network.nodes(data=True)],
20)
assert set(mapping.keys()) == set([2,3,5,15,16,18,22])
assert set([x['maps_to'] for x in mapping.values()]) == set([2,5,15])
Expand Down
78 changes: 46 additions & 32 deletions tests/test_graph_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,17 @@
from swmmanywhere.graph_utilities import graphfcns as gu


def load_street_network():
@pytest.fixture
def street_network():
"""Load a street network."""
bbox = (-0.11643,51.50309,-0.11169,51.50549)
G = load_graph(Path(__file__).parent / 'test_data' / 'street_graph.json')
return G, bbox

def test_save_load():
def test_save_load(street_network):
"""Test the save_graph and load_graph functions."""
G, _ = street_network
# Load a street network
G,_ = load_street_network()
with tempfile.TemporaryDirectory() as temp_dir:
# Save the graph
save_graph(G, Path(temp_dir) / 'test_graph.json')
Expand All @@ -43,25 +44,25 @@ def test_save_load():
# Check if the loaded graph is the same as the original graph
assert nx.is_isomorphic(G, G_new)

def test_assign_id():
def test_assign_id(street_network):
"""Test the assign_id function."""
G, _ = load_street_network()
G, _ = street_network
G = gu.assign_id(G)
for u, v, data in G.edges(data=True):
assert 'id' in data.keys()
assert isinstance(data['id'], str)

def test_double_directed():
def test_double_directed(street_network):
"""Test the double_directed function."""
G, _ = load_street_network()
G, _ = street_network
G = gu.assign_id(G)
G = gu.double_directed(G)
for u, v in G.edges():
assert (v,u) in G.edges

def test_calculate_streetcover():
def test_calculate_streetcover(street_network):
"""Test the calculate_streetcover function."""
G, _ = load_street_network()
G, _ = street_network
params = parameters.SubcatchmentDerivation()
addresses = parameters.FilePaths(base_dir = None,
project_name = None,
Expand All @@ -77,17 +78,17 @@ def test_calculate_streetcover():
assert len(gdf) == len(G.edges)
assert gdf.geometry.area.sum() > 0

def test_split_long_edges():
def test_split_long_edges(street_network):
"""Test the split_long_edges function."""
G, _ = load_street_network()
G, _ = street_network
G = gu.assign_id(G)
max_length = 40
params = parameters.SubcatchmentDerivation(max_street_length = max_length)
G = gu.split_long_edges(G, params)
for u, v, data in G.edges(data=True):
assert data['length'] <= (max_length * 2)

def test_derive_subcatchments():
def test_derive_subcatchments(street_network):
"""Test the derive_subcatchments function."""
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
Expand All @@ -101,7 +102,7 @@ def test_derive_subcatchments():
addresses.streetcover = temp_path / 'building.geojson'
addresses.subcatchments = temp_path / 'subcatchments.geojson'
params = parameters.SubcatchmentDerivation()
G, bbox = load_street_network()
G, _ = street_network

# mock up buildings
eg_bldg = sgeom.Polygon([(700291.346,5709928.922),
Expand All @@ -122,9 +123,9 @@ def test_derive_subcatchments():
assert 'contributing_area' in data.keys()
assert isinstance(data['contributing_area'], float)

def test_set_elevation_and_slope():
def test_set_elevation_and_slope(street_network):
"""Test the set_elevation, set_surface_slope, chahinian_slope function."""
G, _ = load_street_network()
G, _ = street_network
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
addresses = parameters.FilePaths(base_dir = temp_path,
Expand Down Expand Up @@ -162,19 +163,19 @@ def test_set_elevation_and_slope():



def test_chahinian_angle():
def test_chahinian_angle(street_network):
"""Test the chahinian_angle function."""
G, _ = load_street_network()
G, _ = street_network
G = gu.set_chahinian_angle(G)
for u, v, data in G.edges(data=True):
assert 'chahinian_angle' in data.keys()
assert math.isfinite(data['chahinian_angle'])



def test_calculate_weights():
def test_calculate_weights(street_network):
"""Test the calculate_weights function."""
G, _ = load_street_network()
G, _ = street_network
params = parameters.TopologyDerivation()
for weight in params.weights:
for ix, (u,v,data) in enumerate(G.edges(data=True)):
Expand All @@ -184,10 +185,23 @@ def test_calculate_weights():
for u, v, data in G.edges(data=True):
assert 'weight' in data.keys()
assert math.isfinite(data['weight'])

def test_identify_outlets_no_river():

def test_calculate_weights_novar(street_network):
"""Test the calculate_weights function with no variance."""
G, _ = street_network
params = parameters.TopologyDerivation()
for weight in params.weights:
for ix, (u,v,data) in enumerate(G.edges(data=True)):
data[weight] = 1.5

G = gu.calculate_weights(G, params)
for u, v, data in G.edges(data=True):
assert 'weight' in data.keys()
assert math.isfinite(data['weight'])

def test_identify_outlets_no_river(street_network):
"""Test the identify_outlets in the no river case."""
G, _ = load_street_network()
G, _ = street_network
G = gu.assign_id(G)
G = gu.double_directed(G)
elev_fid = Path(__file__).parent / 'test_data' / 'elevation.tif'
Expand All @@ -205,9 +219,9 @@ def test_identify_outlets_no_river():
outlets = [(u,v,d) for u,v,d in G.edges(data=True) if d['edge_type'] == 'outlet']
assert len(outlets) == 1

def test_identify_outlets_sg():
def test_identify_outlets_sg(street_network):
"""Test the identify_outlets with subgraphs."""
G, _ = load_street_network()
G, _ = street_network

G = gu.assign_id(G)
G = gu.double_directed(G)
Expand Down Expand Up @@ -277,9 +291,9 @@ def test_identify_outlets_sg():
outlets = [(u,v,d) for u,v,d in G_.edges(data=True) if d['edge_type'] == 'outlet']
assert len(outlets) == 3

def test_identify_outlets_and_derive_topology():
def test_identify_outlets_and_derive_topology(street_network):
"""Test the identify_outlets and derive_topology functions."""
G, _ = load_street_network()
G, _ = street_network
G = gu.assign_id(G)
G = gu.double_directed(G)
for ix, (u,v,d) in enumerate(G.edges(data=True)):
Expand Down Expand Up @@ -342,9 +356,9 @@ def test_identify_outlets_and_derive_topology():
outlets = [(u,v,d) for u,v,d in G_.edges(data=True) if d['edge_type'] == 'outlet']
assert len(outlets) == 1

def test_identify_outlets_and_derive_topology_withtopo():
def test_identify_outlets_and_derive_topology_withtopo(street_network):
"""Test the identify_outlets and derive_topology functions."""
G, _ = load_street_network()
G, _ = street_network
G = gu.assign_id(G)
G = gu.double_directed(G)
for ix, (u,v,d) in enumerate(G.edges(data=True)):
Expand Down Expand Up @@ -499,18 +513,18 @@ def almost_equal(a, b, tol=1e-6):
"""Check if two numbers are almost equal."""
return abs(a-b) < tol

def test_merge_street_nodes():
def test_merge_street_nodes(street_network):
"""Test the merge_street_nodes function."""
G, _ = load_street_network()
G, _ = street_network
subcatchment_derivation = parameters.SubcatchmentDerivation(
node_merge_distance = 20)
G_ = gu.merge_street_nodes(G, subcatchment_derivation)
assert not set([107736,266325461,2623975694,32925453]).intersection(G_.nodes)
assert almost_equal(G_.nodes[25510321]['x'], 700445.0112082)

def test_clip_to_catchments():
def test_clip_to_catchments(street_network):
"""Test the clip_to_catchments function."""
G, _ = load_street_network()
G, _ = street_network

with tempfile.TemporaryDirectory() as temp_dir:

Expand Down
Loading