|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +Created on Fri Jan 4 10:05:58 2019 |
| 4 | +
|
| 5 | +@author: imhof002 |
| 6 | +
|
| 7 | +RainyMotion script to run all four modules and to use the sliced outputs per |
| 8 | +catchment. |
| 9 | +In addition, this script manages to loop through a main directory and opens |
| 10 | +all folders in order to make nowcasts per event for 'n' selected events. |
| 11 | +
|
| 12 | +For simplicity, normally only the initial data has to be changed. |
| 13 | +""" |
| 14 | + |
| 15 | +########### |
| 16 | +# Import package |
| 17 | +########### |
| 18 | + |
| 19 | +# import rainymotion library |
| 20 | +from rainymotion import models, metrics, utils, Catchment_slice_RM |
| 21 | + |
| 22 | +# import accompanying libraries |
| 23 | +from collections import OrderedDict |
| 24 | +import numpy as np |
| 25 | +import h5py |
| 26 | +import matplotlib.pyplot as plt |
| 27 | +import os |
| 28 | +from os import listdir |
| 29 | +from os.path import isfile, join |
| 30 | +import time |
| 31 | + |
| 32 | +############################################################################### |
| 33 | +############ |
| 34 | +# Initial data - Basically only this has to be changed |
| 35 | +############ |
| 36 | + |
| 37 | +# Set the directory with the input radar files (Note that this is the top directory, |
| 38 | +# which contains multiple directories with all the cases). |
| 39 | +Dir_in = "c:\\Users\\imhof_rn\\Documents\\Nowcasting\\Input\\Processor_1" |
| 40 | + |
| 41 | +# Set number of rows and number of cols in the full radar image. |
| 42 | +num_rows = 765 |
| 43 | +num_cols = 700 |
| 44 | + |
| 45 | +# Catchment filenames and directories |
| 46 | +catchments = True # Put on false when you don't want any slicing for catchments (i.e. you will use the full output) |
| 47 | +# If catchments = 'False', uncomment the next two lines. |
| 48 | +catchment_filenames = ["c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\Hupsel.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\stroomgebied_Regge.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\GroteWaterleiding.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\Aa.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\Reusel.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\het_molentje.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\Luntersebeek.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\Dwarsdiep.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\AfwaterendgebiedBoezemsysteem.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\HHRijnland.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\Beemster.shp", "c:\\Users\\imhof_rn\\Documents\\GIS\\Catchments_for1H\\DeLinde.shp"] # Put here the locations of the shapefiles |
| 49 | +catchment_names = ['Hupsel', 'Regge', 'GroteWaterleiding', 'Aa', 'Reusel', 'Molentje', 'Luntersebeek', 'Dwarsdiep', 'Delfland', 'Rijnland', 'Beemster', 'Linde'] # A list of catchment names. |
| 50 | + |
| 51 | +# Set the output file directory. The names will later be added based on the catchment names. |
| 52 | +File_out_dir = "c:\\Users\\imhof_rn\\Documents\\Nowcasting\\Results\\1hours" |
| 53 | + |
| 54 | +# Set the number of lead times |
| 55 | +leadtime = 72 |
| 56 | +############################################################################### |
| 57 | + |
| 58 | +Start_loop = time.time() |
| 59 | + |
| 60 | +########## |
| 61 | +# We start with defining the functions itself |
| 62 | +########## |
| 63 | + |
| 64 | +# Model run setups |
| 65 | + |
| 66 | +def persistence(data_instance, eval_instance, results_instance): |
| 67 | + |
| 68 | + for i in range(0,len(catchment_names)): |
| 69 | + results_instance[i].create_group("/Persistence/") |
| 70 | + |
| 71 | + for key in sorted(list(eval_instance.keys())): |
| 72 | + |
| 73 | + inputs = np.array([ data_instance[key] for key in eval_instance[key][0][-1:] ]) / 100.0 |
| 74 | + |
| 75 | + model = models.Persistence() |
| 76 | + |
| 77 | + model.input_data = inputs |
| 78 | + |
| 79 | + nowcast = model.run() |
| 80 | + |
| 81 | + nowcast_slice, chunks_slice, maxshape_slice = Catchment_slice_RM.catchment_slice(nowcast, catchment_filenames, leadtime) |
| 82 | + |
| 83 | + inputs = None |
| 84 | + nowcast = None |
| 85 | + |
| 86 | + for i in range(0,len(catchment_names)): |
| 87 | + results_instance[i]["/Persistence/"].create_dataset(key, |
| 88 | + data=nowcast_slice[i], |
| 89 | + dtype="float16", |
| 90 | + maxshape=maxshape_slice[i], |
| 91 | + compression="gzip") |
| 92 | + nowcast_slice = None |
| 93 | + chunks_slice = None |
| 94 | + maxshape_slice = None |
| 95 | + |
| 96 | + |
| 97 | +# create ground truth predictions |
| 98 | +def ground_truth(data_instance, eval_instance, results_instance): |
| 99 | + |
| 100 | + for i in range(0,len(catchment_names)): |
| 101 | + results_instance[i].create_group("/GT/") |
| 102 | + |
| 103 | + for key in sorted(list(eval_instance.keys())): |
| 104 | + |
| 105 | + ground_truth = np.array([ data_instance[key] for key in eval_instance[key][1] ]) / 100.0 |
| 106 | + |
| 107 | + GT_slice, chunks_slice, maxshape_slice = Catchment_slice_RM.catchment_slice(ground_truth, catchment_filenames, leadtime) |
| 108 | + |
| 109 | + ground_truth = None |
| 110 | + |
| 111 | + for i in range(0, len(catchment_names)): |
| 112 | + results_instance[i]["/GT/"].create_dataset(key, |
| 113 | + data=GT_slice[i], |
| 114 | + dtype="float16", |
| 115 | + maxshape=maxshape_slice[i], compression="gzip") |
| 116 | + |
| 117 | + GT_slice = None |
| 118 | + chunks_slice = None |
| 119 | + maxshape_slice = None |
| 120 | + |
| 121 | +def optical_flow(data_instance, eval_instance, results_instance, model_name): |
| 122 | + |
| 123 | + if model_name == "Sparse": |
| 124 | + model = models.Sparse() |
| 125 | + |
| 126 | + elif model_name == "SparseSD": |
| 127 | + model = models.SparseSD() |
| 128 | + |
| 129 | + elif model_name == "Dense": |
| 130 | + model = models.Dense() |
| 131 | + |
| 132 | + elif model_name == "DenseRotation": |
| 133 | + model = models.DenseRotation() |
| 134 | + |
| 135 | + for i in range(0,len(catchment_names)): |
| 136 | + results_instance[i].create_group("/{}/".format(model_name)) |
| 137 | + |
| 138 | + for key in sorted(list(eval_instance.keys())): |
| 139 | + |
| 140 | + inputs = np.array([ data_instance[key] for key in eval_instance[key][0] ]) / 100.0 |
| 141 | + |
| 142 | + model.input_data = inputs |
| 143 | + |
| 144 | + nowcast = model.run() |
| 145 | + |
| 146 | + nowcast_slice, chunks_slice, maxshape_slice = Catchment_slice_RM.catchment_slice(nowcast, catchment_filenames, leadtime) |
| 147 | + |
| 148 | + inputs = None |
| 149 | + nowcast = None |
| 150 | + |
| 151 | + for i in range(0, len(catchment_names)): |
| 152 | + results_instance[i]["/{}/".format(model_name)].create_dataset(key, |
| 153 | + data=nowcast_slice[i], |
| 154 | + dtype="float16", |
| 155 | + maxshape=maxshape_slice[i], |
| 156 | + compression="gzip") |
| 157 | + |
| 158 | + nowcast_slice = None |
| 159 | + chunks_slice = None |
| 160 | + maxshape_slice = None |
| 161 | + |
| 162 | +################## |
| 163 | +# Also the definition of some metrics |
| 164 | +################## |
| 165 | + |
| 166 | +# load a mask which maps RY product coverage |
| 167 | +mask = [ [1] * num_cols for _ in range(num_rows)] |
| 168 | +mask = np.array([mask for i in range(12)]) |
| 169 | + |
| 170 | +# Verification block |
| 171 | +def calculate_CSI(obs, sim, thresholds=[0.125, 0.250, 0.500, 1.000]): |
| 172 | + |
| 173 | + result = {} |
| 174 | + |
| 175 | + for threshold in thresholds: |
| 176 | + result[str(threshold)] = [metrics.CSI(obs[i], sim[i], threshold=threshold) for i in range(obs.shape[0])] |
| 177 | + |
| 178 | + return result |
| 179 | + |
| 180 | +def calculate_MAE(obs, sim): |
| 181 | + |
| 182 | + return [metrics.MAE(obs[i], sim[i]) for i in range(obs.shape[0])] |
| 183 | + |
| 184 | +def calculate_metrics_dict(eval_instance, results_instance, |
| 185 | + model_names=["Persistence", "Sparse", "SparseSD", "Dense", "DenseRotation"]): |
| 186 | + |
| 187 | + metrics_dict = OrderedDict() |
| 188 | + |
| 189 | + for model_name in model_names: |
| 190 | + |
| 191 | + metrics_dict[model_name] = OrderedDict() |
| 192 | + |
| 193 | + for key in sorted(list(eval_instance.keys())): |
| 194 | + |
| 195 | + metrics_dict[model_name][key] = {model_name: {"CSI": None, "MAE": None}} |
| 196 | + |
| 197 | + # observed ground-truth |
| 198 | + o = results_instance["GT"][key][()] |
| 199 | + |
| 200 | + # results of nowcasting |
| 201 | + s = results_instance[model_name][key][()] |
| 202 | + |
| 203 | + # convert values from depth (mm) to intensity (mm/h) |
| 204 | + o = utils.depth2intensity(o) |
| 205 | + s = utils.depth2intensity(s) |
| 206 | + |
| 207 | + # mask arrays |
| 208 | + o = np.ma.array(o, mask=mask) |
| 209 | + s = np.ma.array(s, mask=mask) |
| 210 | + |
| 211 | + metrics_dict[model_name][key][model_name]["CSI"] = calculate_CSI(o, s) |
| 212 | + metrics_dict[model_name][key][model_name]["MAE"] = calculate_MAE(o, s) |
| 213 | + |
| 214 | + return metrics_dict |
| 215 | + |
| 216 | +########## |
| 217 | +# The loop and actual work |
| 218 | +########## |
| 219 | + |
| 220 | +# We loop through every folder and make the nowcast per folder |
| 221 | +for n in range(0, len(os.listdir(Dir_in))): |
| 222 | + Start = time.time() |
| 223 | + |
| 224 | + # Get the directory name of the case of this loop |
| 225 | + Case_name = os.listdir(Dir_in)[n] |
| 226 | + Case_dir = os.path.join(Dir_in, Case_name) |
| 227 | + # Make the output directory |
| 228 | + try: |
| 229 | + if not os.path.exists(os.path.join(File_out_dir, Case_name)): |
| 230 | + os.makedirs(os.path.join(File_out_dir, Case_name)) # Make this directory in the output folder |
| 231 | + except OSError: |
| 232 | + print('Error: Creating directory', Case_name) |
| 233 | + |
| 234 | + print('Loop starts for case', Case_name) |
| 235 | + print('State so far:', float(n) / float(len(os.listdir(Dir_in))), '% of the total procedure completed.') |
| 236 | + |
| 237 | + ############ |
| 238 | + # Set output filenames |
| 239 | + ############ |
| 240 | + File_out = [] |
| 241 | + for i in range(0,len(catchment_names)): |
| 242 | + File_out.append(os.path.join(File_out_dir, Case_name, catchment_names[i]+'.h5')) |
| 243 | + |
| 244 | + ############ |
| 245 | + # Import data |
| 246 | + ############ |
| 247 | + |
| 248 | + # First make a list of all h5-files |
| 249 | + # Then import them and combine them in one h5-file. |
| 250 | + combined = [] |
| 251 | + dates = [] |
| 252 | + |
| 253 | + print('Reading all files in directory') |
| 254 | + |
| 255 | + for filename in os.listdir(Case_dir): |
| 256 | + f=h5py.File(os.path.join(Case_dir, filename), 'r') |
| 257 | + dset=f['image1']['image_data'] |
| 258 | + f_copy=np.copy(dset) #copy the content |
| 259 | + # f_copy = np.where(f_copy == 65535, 0, f_copy) |
| 260 | + combined.append(f_copy) |
| 261 | + dates.append(filename.split("_")[4].split(".")[0]) |
| 262 | + f.close() |
| 263 | + |
| 264 | + print(len(dates), 'files in this directory.') |
| 265 | + |
| 266 | + # create dictionary with timestep indexes |
| 267 | + # dictionary structure: {"t": [ [t-24, t-23,..., t-1], [t+1,...,t+12] ]} |
| 268 | + #eval_idx = np.load("M:\My Documents\RainyMotion\data\eval_dict.npy").item() |
| 269 | + eval_idx = {} |
| 270 | + for i in range(23, (len(dates) - 71)): |
| 271 | + date = dates[i] |
| 272 | + old_date = [] |
| 273 | + new_date = [] |
| 274 | + for old_num in range(0,24): |
| 275 | + old_date.append(dates[i-(24-old_num)]) |
| 276 | + for new_num in range(0,72): |
| 277 | + new_date.append(dates[i+new_num]) |
| 278 | + eval_idx[date] = [old_date,new_date] |
| 279 | + |
| 280 | + old_date = None |
| 281 | + new_date = None |
| 282 | + |
| 283 | + data = {} |
| 284 | + for j in range(0,len(dates)): |
| 285 | + date = dates[j] |
| 286 | + data[date] = combined[j] |
| 287 | + |
| 288 | + ############ |
| 289 | + # Storage of results |
| 290 | + ############ |
| 291 | + |
| 292 | + # create placeholder (or load previously calculated) results |
| 293 | + results = [] |
| 294 | + |
| 295 | + for i in range(0,len(catchment_names)): |
| 296 | + results.append(h5py.File(File_out[i])) |
| 297 | + |
| 298 | + ################# |
| 299 | + # Run the model |
| 300 | + ################# |
| 301 | + |
| 302 | + print('Start with the model - this will take some time') |
| 303 | + |
| 304 | + ground_truth(data, eval_idx, results) |
| 305 | + |
| 306 | + print("Ground truth is calculated") |
| 307 | + gt_time = time.time() |
| 308 | + print('Process took', (gt_time-Start)/3600.0, 'hours') |
| 309 | + |
| 310 | +# persistence(data, eval_idx, results) |
| 311 | +# |
| 312 | +# print("Persistence is calculated") |
| 313 | +# per_time = time.time() |
| 314 | +# print('Process took', (per_time - gt_time)/3600.0, 'hours') |
| 315 | + |
| 316 | + optical_flow(data, eval_idx, results, "Sparse") |
| 317 | + |
| 318 | + print("Sparse model is calculated") |
| 319 | + sparse_time = time.time() |
| 320 | + print('Process took', (sparse_time - gt_time)/3600.0, 'hours') |
| 321 | + |
| 322 | +# optical_flow(data, eval_idx, results, "SparseSD") |
| 323 | +# |
| 324 | +# print("Sparse SD model is calculated") |
| 325 | +# |
| 326 | +# sparseSD_time = time.time() |
| 327 | +# print('Process took', (sparseSD_time - sparse_time)/3600.0, 'hours') |
| 328 | +# |
| 329 | +# optical_flow(data, eval_idx, results, "Dense") |
| 330 | +# |
| 331 | +# print("Dense model is calculated") |
| 332 | +# dense_time = time.time() |
| 333 | +# print('Process took', (dense_time - sparseSD_time)/3600.0, 'hours') |
| 334 | + |
| 335 | + optical_flow(data, eval_idx, results, "DenseRotation") |
| 336 | + |
| 337 | + print("Dense Rotation model is calculated") |
| 338 | + denseRot_time = time.time() |
| 339 | + print('Process took', (denseRot_time - sparse_time)/3600.0, 'hours') |
| 340 | + |
| 341 | + for i in range(0, len(results)): |
| 342 | + results[i].close() |
| 343 | + |
| 344 | + End = time.time() |
| 345 | + print('This case took in total', (End - Start)/3600.0, 'hours') |
| 346 | + |
| 347 | + # Finally and for certainty, delete all variables |
| 348 | + Case_name = None |
| 349 | + Case_dir = None |
| 350 | + File_out = None |
| 351 | + combined = None |
| 352 | + dates = None |
| 353 | + eval_idx = None |
| 354 | + data = None |
| 355 | + results = None |
| 356 | + |
| 357 | +# And we're done! |
| 358 | +End_loop = time.time() |
| 359 | +print('Total process took', (End_loop - Start_loop)/3600.0, 'hours') |
| 360 | + |
| 361 | +print("Done!") |
| 362 | + |
| 363 | + |
0 commit comments