def RunLumpedRRP(ConceptualModel, Raster, sp_prec, sp_et, sp_temp, sp_pars, p2, snow, init_st=None, ll_temp=None, q_init=None): """ ======================================================================== RunLumpedRRP(Raster,sp_prec,sp_et,sp_temp,sp_pars,p2,init_st,ll_temp,q_init) ======================================================================== this function runs the rainfall runoff lumped model (HBV, GR4,...) separately for each cell and return a time series of arrays Inputs: ---------- 1-ConceptualModel: [function] conceptual model function 2-Raster: [gdal.dataset] raster to get the spatial information (nodata cells) raster input could be dem, flow accumulation or flow direction raster of the catchment but the nodata value stored in the raster should be far from the range of values that could result from the calculation 3-sp_prec: [numpy array] 3d array of the precipitation data, sp_prec should have the same 2d dimension of raster input 4-sp_et: [numpy array] 3d array of the evapotranspiration data, sp_et should have the same 2d dimension of raster input 5-sp_temp: [numpy array] 3d array of the temperature data, sp_temp should have the same 2d dimension of raster input 6-sp_pars: [numpy array] number of 2d arrays of the catchment properties spatially distributed in 2d and the third dimension is the number of parameters, sp_pars should have the same 2d dimension of raster input 7-p2: [List] list of unoptimized parameters p2[0] = tfac, 1 for hourly, 0.25 for 15 min time step and 24 for daily time step p2[1] = catchment area in km2 8-init_st: [list] initial state variables values [sp, sm, uz, lz, wc]. default=None 9-ll_temp: [numpy array] 3d array of the long term average temperature data 10-q_init: [float] initial discharge m3/s Outputs: ---------- 1-st: [numpy ndarray] 4D array (rows,cols,time,states) states are [sp,wc,sm,uz,lv] 2-q_lz: [numpy ndarray] 3D array of the lower zone discharge 3-q_uz: [numpy ndarray] 3D array of the upper zone discharge Example: ---------- ### meteorological data prec=GIS.ReadRastersFolder(PrecPath) evap=GIS.ReadRastersFolder(Evap_Path) temp=GIS.ReadRastersFolder(TempPath) sp_pars=GIS.ReadRastersFolder(parPath) #### GIS data dem= gdal.Open(DemPath) p2=[1, 227.31] init_st=[0,5,5,5,0] st, q_lz, q_uz = DistRRM.RunLumpedRRP(DEM,sp_prec=sp_prec, sp_et=sp_et, sp_temp=sp_temp, sp_pars=sp_par, p2=p2, init_st=init_st) """ ### input data validation # data type assert isinstance( ConceptualModel, ModuleType ), "ConceptualModel should be a module or a python file contains functions " assert type( Raster ) == gdal.Dataset, "Raster should be read using gdal (gdal dataset please read it using gdal library) " assert type(sp_prec) == np.ndarray, "array should be of type numpy array" assert type(sp_et) == np.ndarray, "array should be of type numpy array" assert type(sp_temp) == np.ndarray, "array should be of type numpy array" assert type(sp_pars) == np.ndarray, "array should be of type numpy array" assert type(p2) == list, "p2 should be of type list" if init_st != None: assert type(init_st) == list, "init_st should be of type list" if ll_temp != None: assert type(ll_temp) == np.ndarray, "init_st should be of type list" if q_init != None: assert type(q_init) == float, "init_st should be of type list" # input dimensions [rows, cols] = Raster.ReadAsArray().shape assert np.shape(sp_prec)[0] == rows and np.shape( sp_et)[0] == rows and np.shape(sp_temp)[0] == rows and np.shape( sp_pars )[0] == rows, "all input data should have the same number of rows" assert np.shape(sp_prec)[1] == cols and np.shape( sp_et)[1] == cols and np.shape(sp_temp)[1] == cols and np.shape( sp_pars )[1] == cols, "all input data should have the same number of columns" assert np.shape(sp_prec)[2] == np.shape(sp_et)[2] and np.shape( sp_temp)[2] == np.shape(sp_prec)[ 2], "all meteorological input data should have the same length" n_steps = sp_prec.shape[2] + 1 # no of time steps =length of time series +1 # intiialise vector of nans to fill states dummy_states = np.empty([n_steps, 5]) # [sp,sm,uz,lz,wc] dummy_states[:] = np.nan dummy_states = np.float32(dummy_states) # Get the mask no_val = np.float32(Raster.GetRasterBand(1).GetNoDataValue()) raster = Raster.ReadAsArray() # calculate area covered by cells geo_trans = Raster.GetGeoTransform( ) # get the coordinates of the top left corner and cell size [x,dx,y,dy] dx = np.abs(geo_trans[1]) / 1000.0 # dx in Km dy = np.abs(geo_trans[-1]) / 1000.0 # dy in Km px_area = dx * dy # area of the cell no_cells = np.size(raster[:, :]) - np.count_nonzero( raster[raster == no_val]) px_tot_area = no_cells * px_area # total area of pixels st = [] # Spatially distributed states q_lz = [] q_uz = [] for x in range(rows): # no of rows st_row = [] q_lz_row = [] q_uz_row = [] for y in range(cols): # no of columns if raster[x, y] != no_val: # only for cells in the domain # Calculate the states per cell try: uzg, lzg, stvar = ConceptualModel.Simulate( prec=sp_prec[x, y, :], temp=sp_temp[x, y, :], et=sp_et[x, y, :], par=sp_pars[x, y, :], p2=p2, init_st=init_st, ll_temp=None, q_init=q_init, snow=0) except: print("conceptual model argument are not correct") # append column after column in the same row # st_i.append(np.array(_st)) st_row.append(stvar) # calculate upper zone Q = k*(UZ_int_3)**(1+alpha) # q_uz_temp = np.array(sp_pars[x, y, 5])*(np.power(_uzg, (1.0 + sp_pars[x, y, 7]))) # q_uzi.append(q_uz_temp) q_uz_row.append(uzg) #calculate lower zone Q = K1*(LZ_int_1) # q_lz_temp=np.array(sp_pars[x, y, 6])*_lzg # q_lzi.append(q_lz_temp) q_lz_row.append(lzg) # print("total = "+str(fff)+"/"+str(tot_elem)+" cell, row= "+str(x+1)+" column= "+str(y+1) ) else: # if the cell is novalue------------------------------------- # Fill the empty cells with a nan vector st_row.append( dummy_states ) # fill all states(5 states) for all time steps = nan q_lz_row.append( dummy_states[:, 0] ) # q lower zone =nan for all time steps = nan q_uz_row.append( dummy_states[:, 0] ) # q upper zone =nan for all time steps = nan # store row by row-------- ---------------------------------------------------- # st.append(st_i) # state variables st.append(st_row) # state variables q_lz.append(q_lz_row) # lower zone discharge mm/timestep q_uz.append(q_uz_row) # upper zone routed discharge mm/timestep #------------------------------------------------------------------------------ # convert to arrays st = np.array(st) q_lz = np.array(q_lz) q_uz = np.array(q_uz) # convert quz from mm/time step to m3/sec area_coef = p2[1] / px_tot_area q_uz = q_uz * px_area * area_coef / (p2[0] * 3.6) # # convert QLZ to 1D time series # q_lz = np.array([np.nanmean(q_lz[:,:,i]) for i in range(n_steps)]) # average of all cells (not routed mm/timestep) # # convert Qlz to m3/sec # q_lz = q_lz* p2[1]/ (p2[0]*3.6) # generation q_lz = q_lz * px_area * area_coef / (p2[0] * 3.6) # convert all to float32 to save storage q_lz = np.float32(q_lz) q_uz = np.float32(q_uz) st = np.float32(st) return st, q_lz, q_uz
def NearestCell(Raster, StCoord): """ ====================================================== NearestCell(Raster,StCoord) ====================================================== this function calculates the the indices (row, col) of nearest cell in a given raster to a station coordinate system of the raster has to be projected to be able to calculate the distance Inputs: ---------- 1-Raster: [gdal.dataset] raster to get the spatial information (coordinates of each cell) 2-StCoord: [Dataframe] dataframe with two columns "x", "y" contains the coordinates of each station Output: ---------- 1-StCoord:the same input dataframe with two extra columns "cellx","celly" Examples: soil_type=gdal.Open("DEM.tif") coordinates=stations[['id','x','y']][:] coordinates.loc[:,["cell_row","cell_col"]]=NearestCell(Raster,StCoord) """ # input data validation # data type assert type( Raster ) == gdal.Dataset, "raster should be read using gdal (gdal dataset please read it using gdal library) " assert type( StCoord ) == pd.core.frame.DataFrame, "please check StCoord input it should be pandas dataframe " # check if the user has stored the coordinates in the dataframe with the right names or not assert "x" in StCoord.columns, "please check the StCoord x coordinates of the stations should be stored in a column name 'x'" assert "y" in StCoord.columns, "please check the StCoord y coordinates of the stations should be stored in a column name 'y'" StCoord['cell_row'] = np.nan StCoord['cell_col'] = np.nan rows = Raster.RasterYSize cols = Raster.RasterXSize geo_trans = Raster.GetGeoTransform( ) # get the coordinates of the top left corner and cell size [x,dx,y,dy] # X_coordinate= upperleft corner x+ index* cell size+celsize/2 coox = np.ones((rows, cols)) cooy = np.ones((rows, cols)) for i in range(rows): # iteration by row for j in range(cols): # iteration by column coox[i, j] = geo_trans[0] + geo_trans[1] / 2 + j * geo_trans[ 1] # calculate x cooy[i, j] = geo_trans[3] + geo_trans[5] / 2 + i * geo_trans[ 5] # calculate y Dist = np.ones((rows, cols)) for no in range(len(StCoord['x'])): # calculate the distance from the station to all cells for i in range(rows): # iteration by row for j in range(cols): # iteration by column Dist[i, j] = np.sqrt( np.power((StCoord.loc[StCoord.index[no], 'x'] - coox[i, j]), 2) + np.power((StCoord.loc[StCoord.index[no], 'y'] - cooy[i, j]), 2)) StCoord.loc[no, 'cell_row'], StCoord.loc[no, 'cell_col'] = np.where( Dist == np.min(Dist)) return StCoord.loc[:, ["cell_row", "cell_col"]]