Skip to content
Open
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
56 changes: 35 additions & 21 deletions sample_data/boston_floods.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,62 +211,76 @@
},
{
"type": "Chart",
"name": "Parabolic Hyetograph",
"description": "Rainfall intensity over 24 hours following a parabolic model",
"name": "Charles River Hydrograph (Long Flow Length)",
"description": "Hourly hydrograph for Charles River, using a longer flow length measurement coming from Chester Brook. Uses the following units. Timestep is one hour. Values are volume without units - volume is a proportion of total flood volume. Since these are hourly timesteps, each value can also be thought of as a per-hour rate (volume/hour = discharge).",
"project": "Boston Transportation",
"files": [
{
"url": "https://data.kitware.com/api/v1/item/67d9a34e429cb34d95af01c5/download",
"hash": "0af8013362c94a3d043c88a277abcbf8e2c44999812f7b8da33dd18e4b22686e",
"path": "boston/parabolic_hyetograph.csv"
"url": "https://data.kitware.com/api/v1/item/68d950f73ba8f1c07a875e68/download",
"hash": "c2c7164b0b9ad8272c225c496e2f17a40a84d0712b00fe6e5aa3f677910cef1f",
"path": "boston/hydrograph_charles_long.csv"
}
],
"metadata": {
"precipitation_model": "Parabolic"
"method": "NRCS lag equation",
"watershed_slope_percent": 3,
"curve_number": 85,
"flow_length_ft": 124080,
"time_of_concentration_hours": 12.3,
"peak_rate_factor": 484,
"time_to_peak_hours": 7.2,
"attribution": "Calculated by August Posch, September 2025, Northeastern University."
},
"chart_options": {
"chart_title": "Rainfall Intensity over 24 hours",
"chart_title": "Proportional Discharge over 24 hours",
"x_title": "Hour",
"y_title": "Precipitation rate (mm/hr)"
"y_title": "Proportional discharge rate (volume/hour)"
},
"conversion_options": {
"labels": "hour",
"datasets": [
"precipitation"
"discharge"
],
"palette": {
"precipitation": "blue"
"discharge": "blue"
}
}
},
{
"type": "Chart",
"name": "NCRS Type II Hyetograph",
"description": "Rainfall intensity over 24 hours following the NCRS Type II model",
"name": "Charles River Hydrograph (Short Flow Length)",
"description": "Hourly hydrograph for Charles River, using a shorter flow length measurement directly from Waltham gage to mouth. Uses the following units. Timestep is one hour. Values are volume without units - volume is a proportion of total flood volume. Since these are hourly timesteps, each value can also be thought of as a per-hour rate (volume/hour = discharge).",
"project": "Boston Transportation",
"files": [
{
"url": "https://data.kitware.com/api/v1/item/67d9a34e429cb34d95af01c2/download",
"hash": "aa83acf52af4dcc8e384fda18bcbba5d85d84ffdd30314950e8aacce772111e7",
"path": "boston/ncrs_type_2_hyetograph.csv"
"url": "https://data.kitware.com/api/v1/item/68d950f63ba8f1c07a875e65/download",
"hash": "d0ce5335c53bc2ee80b8762b5c458d06f0cdce8e03cfce935964d365da118c4d",
"path": "boston/hydrograph_charles_short.csv"
}
],
"metadata": {
"precipitation_model": "NCRS Type II"
"method": "NRCS lag equation",
"watershed_slope_percent": 3,
"curve_number": 85,
"flow_length_ft": 81840,
"time_of_concentration_hours": 8.8,
"peak_rate_factor": 484,
"time_to_peak_hours": 5.2,
"attribution": "Calculated by August Posch, September 2025, Northeastern University."
},
"chart_options": {
"chart_title": "Rainfall Intensity over 24 hours",
"chart_title": "Proportional Discharge over 24 hours",
"x_title": "Hour",
"y_title": "Precipitation rate (mm/hr)"
"y_title": "Proportional discharge rate (volume/hour)"
},
"conversion_options": {
"labels": "hour",
"datasets": [
"precipitation"
"discharge"
],
"palette": {
"precipitation": "blue"
"discharge": "blue"
}
}
}
]
]
29 changes: 18 additions & 11 deletions sample_data/tests/analytics.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,39 @@
},
{
"type": "Chart",
"name": "Parabolic Hyetograph",
"description": "Rainfall intensity over 24 hours following a parabolic model",
"name": "Charles River Hydrograph (Short Flow Length)",
"description": "Hourly hydrograph for Charles River, using a shorter flow length measurement directly from Waltham gage to mouth. Uses the following units. Timestep is one hour. Values are volume without units - volume is a proportion of total flood volume. Since these are hourly timesteps, each value can also be thought of as a per-hour rate (volume/hour = discharge).",
"project": "Boston Transportation",
"files": [
{
"url": "https://data.kitware.com/api/v1/item/67d9a34e429cb34d95af01c5/download",
"hash": "0af8013362c94a3d043c88a277abcbf8e2c44999812f7b8da33dd18e4b22686e",
"path": "boston/parabolic_hyetograph.csv"
"url": "https://data.kitware.com/api/v1/item/68d950f63ba8f1c07a875e65/download",
"hash": "d0ce5335c53bc2ee80b8762b5c458d06f0cdce8e03cfce935964d365da118c4d",
"path": "boston/hydrograph_charles_short.csv"
}
],
"metadata": {
"precipitation_model": "Parabolic"
"method": "NRCS lag equation",
"watershed_slope_percent": 3,
"curve_number": 85,
"flow_length_ft": 81840,
"time_of_concentration_hours": 8.8,
"peak_rate_factor": 484,
"time_to_peak_hours": 5.2,
"attribution": "Calculated by August Posch, September 2025, Northeastern University."
},
"chart_options": {
"chart_title": "Rainfall Intensity over 24 hours",
"chart_title": "Proportional Discharge over 24 hours",
"x_title": "Hour",
"y_title": "Precipitation rate (mm/hr)"
"y_title": "Proportional discharge rate (volume/hour)"
},
"conversion_options": {
"labels": "hour",
"datasets": [
"precipitation"
"discharge"
],
"palette": {
"precipitation": "blue"
"discharge": "blue"
}
}
}
]
]
18 changes: 2 additions & 16 deletions uvdat/core/rest/analytics.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import inspect

from django.db.models import QuerySet
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ReadOnlyModelViewSet

from uvdat.core.models import Project, TaskResult
Expand Down Expand Up @@ -38,19 +35,8 @@ def list_types(self, request, project_id: int, **kwargs):
filtered_queryset = filter_queryset_by_projects(
v, Project.objects.filter(id=project_id)
)
queryset_serializer = next(
iter(
s
for name, s in inspect.getmembers(uvdat_serializers, inspect.isclass)
if issubclass(s, ModelSerializer) and s.Meta.model is v.model
),
None,
)
if queryset_serializer is None:
v = None
else:
v = [queryset_serializer(o).data for o in filtered_queryset]
else:
v = [dict(id=o.id, name=o.name) for o in filtered_queryset]
elif not all(isinstance(o, dict) for o in v):
v = [dict(id=o, name=o) for o in v]
filtered_input_options[k] = v
serializer = uvdat_serializers.AnalysisTypeSerializer(
Expand Down
40 changes: 24 additions & 16 deletions uvdat/core/tasks/analytics/flood_network_failure.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def flood_network_failure(result_id):
result.save()

node_failures = {}
n_nodes = network.nodes.count()
flood_dataset_id = flood_sim.outputs.get('flood')
flood_layer = Layer.objects.get(dataset__id=flood_dataset_id)

Expand All @@ -128,24 +129,31 @@ def get_station_region(point):
units='EPSG:4326',
)

for frame in flood_layer.frames.all():
n_nodes = network.nodes.count()
result.write_status(
f'Evaluating flood levels at {n_nodes} nodes for frame {frame.index}...'
)
raster_path = utilities.field_file_to_local_path(
frame.raster.cloud_optimized_geotiff
)
source = tilesource.get_tilesource_from_path(raster_path)
# Precompute node regions
node_regions = {
node.id: get_station_region(node.location) for node in network.nodes.all()
}

node_failures[frame.index] = []
for node in network.nodes.all():
region = get_station_region(node.location)
region_data, _ = source.getRegion(region=region, format='numpy')
water_heights = numpy.take(region_data, 0, axis=2)
if numpy.any(numpy.where(water_heights > tolerance)):
node_failures[frame.index].append(node.id)
# Assume that all frames in flood_layer refer to frames of the same RasterData
raster = flood_layer.frames.first().raster
raster_path = utilities.field_file_to_local_path(raster.cloud_optimized_geotiff)
source = tilesource.get_tilesource_from_path(raster_path)
metadata = source.getMetadata()

for frame in metadata.get('frames', []):
frame_index = frame.get('Index')
result.write_status(
f'Evaluating flood levels at {n_nodes} nodes for frame {frame_index}...'
)
node_failures[frame_index] = []
for node_id, node_region in node_regions.items():
region_data, _ = source.getRegion(
region=node_region,
frame=frame_index,
format='numpy',
)
if numpy.any(numpy.where(region_data > tolerance)):
node_failures[frame_index].append(node_id)
result.outputs = dict(failures=node_failures)
except Exception as e:
result.error = str(e)
Expand Down
Loading