Skip to content

Commit d95349b

Browse files
committed
added ensemble percentage table
1 parent 2363fbd commit d95349b

File tree

7 files changed

+292
-169
lines changed

7 files changed

+292
-169
lines changed

tethysapp/streamflow_prediction_tool/app.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ def url_maps(self):
4949
'get-ecmwf-hydrograph-plot',
5050
controller='streamflow_prediction_tool.controllers_ajax'
5151
'.get_ecmwf_hydrograph_plot'),
52+
url_map(name='get_ecmwf_forecast_probabilities',
53+
url='streamflow-prediction-tool/map/'
54+
'get-ecmwf-forecast-probabilities',
55+
controller='streamflow_prediction_tool.controllers_ajax'
56+
'.get_ecmwf_forecast_probabilities'),
5257
url_map(name='get_return_periods_ajax',
5358
url='streamflow-prediction-tool/map/'
5459
'get-return-periods',
@@ -226,10 +231,6 @@ def url_maps(self):
226231
url='streamflow-prediction-tool/api/GetForecast',
227232
controller='streamflow_prediction_tool.controllers_api'
228233
'.get_ecmwf_forecast'),
229-
url_map(name='waterml',
230-
url='streamflow-prediction-tool/api/GetEnsemble',
231-
controller='streamflow_prediction_tool.controllers_api'
232-
'.get_ecmwf_ensemble_csv'),
233234
url_map(name='era_interim',
234235
url='streamflow-prediction-tool/api/GetHistoricData',
235236
controller='streamflow_prediction_tool.controllers_api'

tethysapp/streamflow_prediction_tool/controllers_ajax.py

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# -*- coding: utf-8 -*-
22
"""controllers_ajax.py
3-
43
Created by Alan D. Snow, Curtis Rae, Shawn Crawley 2015.
54
License: BSD 3-Clause
65
"""
@@ -18,6 +17,8 @@
1817
from sqlalchemy.orm.exc import ObjectDeletedError
1918
import xarray
2019

20+
from .functions import ecmwf_find_most_current_files
21+
2122
# django imports
2223
from django.contrib.auth.decorators import user_passes_test, login_required
2324
from django.core.exceptions import PermissionDenied
@@ -45,7 +46,8 @@
4546
get_return_period_dict,
4647
get_return_period_ploty_info)
4748
from .controllers_validators import (validate_historical_data,
48-
validate_watershed_info)
49+
validate_watershed_info,
50+
validate_rivid_info)
4951
from .functions import (delete_from_database,
5052
format_name,
5153
get_units_title,
@@ -408,6 +410,7 @@ def get_ecmwf_hydrograph_plot(request):
408410
forecast_statistics, watershed_name, subbasin_name, river_id, units = \
409411
get_ecmwf_forecast_statistics(request)
410412

413+
411414
# ensure lower std dev values limited by the min
412415
std_dev_lower_df = \
413416
forecast_statistics['std_dev_range_lower']
@@ -953,7 +956,6 @@ def get_monthly_seasonal_streamflow_chart(request):
953956
def get_flow_duration_curve(request):
954957
"""
955958
Generate flow duration curve for hydrologic time series data
956-
957959
Based on: http://earthpy.org/flow.html
958960
"""
959961
historical_data_file, river_id, watershed_name, subbasin_name = \
@@ -1800,3 +1802,89 @@ def watershed_group_update(request):
18001802
return JsonResponse({
18011803
'success': "Watershed group successfully updated."
18021804
})
1805+
1806+
1807+
@require_GET
1808+
@login_required
1809+
@exceptions_to_http_status
1810+
def get_ecmwf_forecast_probabilities(request):
1811+
"""
1812+
Returns the statistics for the 52 member forecast
1813+
"""
1814+
1815+
path_to_rapid_output = app.get_custom_setting('ecmwf_forecast_folder')
1816+
if not os.path.exists(path_to_rapid_output):
1817+
raise SettingsError('Location of ECMWF forecast files faulty. '
1818+
'Please check settings.')
1819+
1820+
# get/check information from AJAX request
1821+
get_info = request.GET
1822+
watershed_name, subbasin_name = validate_watershed_info(get_info)
1823+
river_id = validate_rivid_info(get_info)
1824+
1825+
forecast_folder = get_info.get('forecast_folder')
1826+
if not forecast_folder:
1827+
forecast_folder = 'most_recent'
1828+
1829+
# find/check current output datasets
1830+
path_to_output_files = \
1831+
os.path.join(path_to_rapid_output,
1832+
"{0}-{1}".format(watershed_name, subbasin_name))
1833+
forecast_nc_list, start_date = \
1834+
ecmwf_find_most_current_files(path_to_output_files, forecast_folder)
1835+
if not forecast_nc_list or not start_date:
1836+
raise NotFoundError('ECMWF forecast for %s (%s).'
1837+
% (watershed_name, subbasin_name))
1838+
1839+
# combine 52 ensembles
1840+
qout_datasets = []
1841+
ensemble_index_list = []
1842+
with rivid_exception_handler("ECMWF Forecast", river_id):
1843+
for forecast_nc in forecast_nc_list:
1844+
if forecast_nc.endswith("52.nc"):
1845+
continue
1846+
else:
1847+
ensemble_index_list.append(
1848+
int(os.path.basename(forecast_nc)[:-3].split("_")[-1])
1849+
)
1850+
qout_datasets.append(
1851+
xarray.open_dataset(forecast_nc, autoclose=True)
1852+
.sel(rivid=river_id).Qout
1853+
)
1854+
1855+
merged_ds = xarray.concat(qout_datasets,
1856+
pd.Index(ensemble_index_list, name='ensemble'))
1857+
1858+
returnperiods = {}
1859+
1860+
return_period_data = get_return_period_dict(request)
1861+
1862+
returnperiods['two'] = float(return_period_data["two"])
1863+
returnperiods['ten'] = float(return_period_data["ten"])
1864+
returnperiods['twenty'] = float(return_period_data["twenty"])
1865+
1866+
timelist = merged_ds.time.values
1867+
datelist = []
1868+
shortdate = []
1869+
problist = {'two':[],'ten':[],'twenty':[]}
1870+
1871+
for timestep in timelist:
1872+
x = pd.to_datetime(timestep)
1873+
if str(x.date()) not in datelist:
1874+
datelist.append(str(x.date()))
1875+
shortdate.append(str(x.date())[-5:])
1876+
1877+
for date in datelist:
1878+
mergedtime = merged_ds.sel(time=date)
1879+
for period in returnperiods:
1880+
retperflow = float(returnperiods[period])
1881+
probabilities = xarray.where(mergedtime > retperflow, 1, 0).sum(dim='ensemble').astype(float)/51.0*100.
1882+
probability = probabilities.max().round(2).values
1883+
problist[period].append((date,np.asscalar(probability)))
1884+
1885+
problist['dates'] = shortdate
1886+
1887+
for entries in problist:
1888+
problist[entries] = problist[entries][:-5 or None]
1889+
1890+
return JsonResponse({'success':True, 'percentages':problist})

tethysapp/streamflow_prediction_tool/controllers_api.py

Lines changed: 8 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
Author: Michael Suffront & Alan D. Snow, 2017
55
License: BSD 3-Clause
66
"""
7-
from django.http import JsonResponse, HttpResponse
7+
from django.http import JsonResponse
88
from django.shortcuts import render_to_response
9-
from rest_framework.authentication import TokenAuthentication, SessionAuthentication
9+
from rest_framework.authentication import TokenAuthentication
1010
from rest_framework.decorators import api_view, authentication_classes
1111

1212
from .app import StreamflowPredictionTool as app
@@ -15,20 +15,16 @@
1515
generate_warning_points)
1616
from .controllers_functions import (get_ecmwf_avaialable_dates,
1717
get_ecmwf_forecast_statistics,
18-
get_ecmwf_ensemble,
1918
get_historic_streamflow_series,
2019
get_return_period_dict)
2120
from .controllers_validators import validate_historical_data
2221
from .exception_handling import InvalidData, exceptions_to_http_status
2322
from .functions import get_units_title
2423
from .model import Watershed
2524

26-
import pandas as pd
27-
from csv import writer as csv_writer
28-
2925

3026
@api_view(['GET'])
31-
@authentication_classes((TokenAuthentication, SessionAuthentication,))
27+
@authentication_classes((TokenAuthentication,))
3228
@exceptions_to_http_status
3329
def get_ecmwf_forecast(request):
3430
"""
@@ -101,40 +97,7 @@ def get_ecmwf_forecast(request):
10197

10298

10399
@api_view(['GET'])
104-
@authentication_classes((TokenAuthentication, SessionAuthentication,))
105-
@exceptions_to_http_status
106-
def get_ecmwf_ensemble_csv(request):
107-
"""
108-
Retrieve the forecasted streamflow as CSV
109-
"""
110-
# retrieve statistics
111-
forecast_statistics, watershed_name, subbasin_name, river_id, units = \
112-
get_ecmwf_ensemble(request)
113-
114-
# prepare to write response for CSV
115-
response = HttpResponse(content_type='text/csv')
116-
response['Content-Disposition'] = \
117-
'attachment; filename=forecasted_ensembles_{0}_{1}_{2}.csv' \
118-
.format(watershed_name,
119-
subbasin_name,
120-
river_id)
121-
122-
writer = csv_writer(response)
123-
forecast_df = pd.DataFrame(forecast_statistics)
124-
column_names = (forecast_df.columns.values +
125-
[' ({}3/s)'.format(get_units_title(units))]
126-
).tolist()
127-
128-
writer.writerow(['datetime'] + column_names)
129-
130-
for row_data in forecast_df.itertuples():
131-
writer.writerow(row_data)
132-
133-
return response
134-
135-
136-
@api_view(['GET'])
137-
@authentication_classes((TokenAuthentication, SessionAuthentication,))
100+
@authentication_classes((TokenAuthentication,))
138101
@exceptions_to_http_status
139102
def get_historic_data(request):
140103
"""
@@ -190,7 +153,7 @@ def get_historic_data(request):
190153

191154

192155
@api_view(['GET'])
193-
@authentication_classes((TokenAuthentication, SessionAuthentication,))
156+
@authentication_classes((TokenAuthentication,))
194157
@exceptions_to_http_status
195158
def get_return_periods_api(request):
196159
"""
@@ -200,7 +163,7 @@ def get_return_periods_api(request):
200163

201164

202165
@api_view(['GET'])
203-
@authentication_classes((TokenAuthentication, SessionAuthentication,))
166+
@authentication_classes((TokenAuthentication,))
204167
@exceptions_to_http_status
205168
def get_available_dates(request):
206169
"""
@@ -217,7 +180,7 @@ def get_available_dates(request):
217180

218181

219182
@api_view(['GET'])
220-
@authentication_classes((TokenAuthentication, SessionAuthentication,))
183+
@authentication_classes((TokenAuthentication,))
221184
@exceptions_to_http_status
222185
def get_watershed_list(request): # pylint: disable=unused-argument
223186
"""
@@ -248,7 +211,7 @@ def get_watershed_list(request): # pylint: disable=unused-argument
248211

249212

250213
@api_view(['GET'])
251-
@authentication_classes((TokenAuthentication, SessionAuthentication,))
214+
@authentication_classes((TokenAuthentication,))
252215
@exceptions_to_http_status
253216
def get_warning_points(request):
254217
"""

0 commit comments

Comments
 (0)