Skip to content

Commit e5cd87e

Browse files
committed
Added uncertainty quantification task
1 parent 127312d commit e5cd87e

3 files changed

Lines changed: 127 additions & 0 deletions

File tree

uvdat/core/tasks/analytics/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from .flood_simulation import FloodSimulation
88
from .geoai_segmentation import GeoAISegmentation
99
from .network_recovery import NetworkRecovery
10+
from .uncertainty_quantification import UncertaintyQuantification
1011

1112
if TYPE_CHECKING:
1213
from .analysis_type import AnalysisType
@@ -15,6 +16,7 @@
1516
FloodSimulation,
1617
FloodNetworkFailure,
1718
NetworkRecovery,
19+
UncertaintyQuantification,
1820
GeoAISegmentation,
1921
CreateRoadNetwork,
2022
]
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
from __future__ import annotations
2+
3+
import numpy as np
4+
import tempfile
5+
6+
from celery import shared_task
7+
from django.conf import settings
8+
9+
from uvdat.core.models import TaskResult
10+
11+
from .analysis_type import AnalysisType, AnalysisTask
12+
from .flood_simulation import FloodSimulation
13+
14+
15+
class UncertaintyQuantification(AnalysisType):
16+
def __init__(self):
17+
super().__init__()
18+
self.name = "Uncertainty Quantification"
19+
self.description = "Select simulated floods and calculate their standard error."
20+
self.db_value = "uncertainty_quant"
21+
self.input_types = {
22+
"flood_simulation_1": "TaskResult",
23+
"flood_simulation_2": "TaskResult",
24+
"flood_simulation_3": "TaskResult",
25+
}
26+
self.output_types = {
27+
"mean_precipitation_level_mm": "number",
28+
"standard_error_precipitation_level_mm": "number",
29+
"min_precipitation_level_mm": "number",
30+
"max_precipitation_level_mm": "number",
31+
"range_precipitation_level_mm": "number",
32+
"mean_discharge_ft3_per_second": "number",
33+
"standard_error_discharge_ft3_per_second": "number",
34+
"min_discharge_ft3_per_second": "number",
35+
"max_discharge_ft3_per_second": "number",
36+
"range_discharge_ft3_per_second": "number",
37+
}
38+
self.attribution = "Northeastern University"
39+
40+
@classmethod
41+
def is_enabled(cls):
42+
return settings.UVDAT_ENABLE_UNCERTAINTY_QUANTIFICATION
43+
44+
def get_input_options(self):
45+
return {
46+
"flood_simulation_1": TaskResult.objects.filter(task_type=FloodSimulation().db_value),
47+
"flood_simulation_2": TaskResult.objects.filter(task_type=FloodSimulation().db_value),
48+
"flood_simulation_3": TaskResult.objects.filter(task_type=FloodSimulation().db_value),
49+
}
50+
51+
def run_task(self, *, project, **inputs):
52+
result = TaskResult.objects.create(
53+
name="Uncertainty Quantification",
54+
task_type=self.db_value,
55+
inputs=inputs,
56+
project=project,
57+
status="Initializing task...",
58+
)
59+
uncertainty_quantification.delay(result.id)
60+
return result
61+
62+
def finalize(self, result):
63+
pass
64+
65+
66+
67+
68+
@shared_task(base=AnalysisTask)
69+
def uncertainty_quantification(result_id):
70+
result = TaskResult.objects.get(id=result_id)
71+
flood_sim_1_id = result.inputs.get("flood_simulation_1")
72+
flood_sim_1 = TaskResult.objects.get(id=flood_sim_1_id)
73+
flood_sim_2_id = result.inputs.get("flood_simulation_2")
74+
flood_sim_2 = TaskResult.objects.get(id=flood_sim_2_id)
75+
flood_sim_3_id = result.inputs.get("flood_simulation_3")
76+
flood_sim_3 = TaskResult.objects.get(id=flood_sim_3_id)
77+
78+
# Update name
79+
result.name = (
80+
f"Uncertainty Quantification for Flood Results {flood_sim_1.id}, {flood_sim_2.id}, {flood_sim_3.id}"
81+
)
82+
result.save()
83+
84+
85+
precip1 = flood_sim_1.outputs.get("precipitation_level_mm")
86+
discharge1 = flood_sim_1.outputs.get("discharge_ft3_per_second")
87+
precip2 = flood_sim_2.outputs.get("precipitation_level_mm")
88+
discharge2 = flood_sim_2.outputs.get("discharge_ft3_per_second")
89+
precip3 = flood_sim_3.outputs.get("precipitation_level_mm")
90+
discharge3 = flood_sim_3.outputs.get("discharge_ft3_per_second")
91+
92+
93+
result.write_status(
94+
f"Calculating uncertainty..."
95+
)
96+
97+
precip_mean = np.mean([precip1, precip2, precip3])
98+
precip_stde = np.std([precip1, precip2, precip3])
99+
precip_max = np.max([precip1, precip2, precip3])
100+
precip_min = np.min([precip1, precip2, precip3])
101+
precip_range = precip_max - precip_min
102+
discharge_mean = np.mean([discharge1, discharge2, discharge3])
103+
discharge_stde = np.std([discharge1, discharge2, discharge3])
104+
discharge_max = np.max([discharge1, discharge2, discharge3])
105+
discharge_min = np.min([discharge1, discharge2, discharge3])
106+
discharge_range = discharge_max - discharge_min
107+
108+
109+
result.write_status("Saving result to database")
110+
111+
result.write_outputs = {
112+
"mean_precipitation_level_mm": precip_mean,
113+
"standard_error_precipitation_level_mm": precip_stde,
114+
"min_precipitation_level_mm": precip_min,
115+
"max_precipitation_level_mm": precip_max,
116+
"range_precipitation_level_mm": precip_range,
117+
"mean_discharge_ft3_per_second": discharge_mean,
118+
"standard_error_discharge_ft3_per_second": discharge_stde,
119+
"min_discharge_ft3_per_second": discharge_min,
120+
"max_discharge_ft3_per_second": discharge_max,
121+
"range_discharge_ft3_per_second": discharge_range,
122+
}

uvdat/settings/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@
169169
UVDAT_ENABLE_CREATE_ROAD_NETWORK: bool = env.bool(
170170
"DJANGO_UVDAT_ENABLE_CREATE_ROAD_NETWORK", default=True
171171
)
172+
UVDAT_ENABLE_UNCERTAINTY_QUANTIFICATION: bool = env.bool(
173+
"DJANGO_UVDAT_ENABLE_UNCERTAINTY_QUANTIFICATION", default=True
174+
)
172175

173176
logging.getLogger("pyvips").setLevel(logging.ERROR)
174177
logging.getLogger("rasterio").setLevel(logging.ERROR)

0 commit comments

Comments
 (0)