Skip to content

Commit e2af632

Browse files
authored
Merge pull request #375 from OpenGeoscience/uncertainty-task-2
Uncertainty quantification task
2 parents ff0765c + b1b3574 commit e2af632

3 files changed

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

uvdat/settings/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@
173173
UVDAT_ENABLE_CREATE_ROAD_NETWORK: bool = env.bool(
174174
"DJANGO_UVDAT_ENABLE_CREATE_ROAD_NETWORK", default=True
175175
)
176+
UVDAT_ENABLE_UNCERTAINTY_QUANTIFICATION: bool = env.bool(
177+
"DJANGO_UVDAT_ENABLE_UNCERTAINTY_QUANTIFICATION", default=True
178+
)
176179

177180
logging.getLogger("pyvips").setLevel(logging.ERROR)
178181
logging.getLogger("rasterio").setLevel(logging.ERROR)

0 commit comments

Comments
 (0)