def _smooth_widths(self, branch, degree): ''' 1D Gaussian smoothing of Grid width values. ''' try: self.widths[branch] = common.smooth(self.widths[branch], degree) except: print "ERROR: Cannot smooth grid widths! [Key Error]."
def eidw(self, power=2.0, anisotropy=5.0, smoothie=0, plane='sn', plot=False): """ Performs Elliptical Inverse Distance Weighting (EIDW) interpolation to the instance's data Kwargs: power <float> : power parameter, should be above 2.0 anisotropy <float> : anisotropy parameter: if >1.0, it brings points closer in the longitudinal (s) direction, if <1.0 it brings points closer in the transverse (n) direction smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented plot <boolean> : decides to plot or not the resulting EIDW values """ gc.enable() print "Calculating: Elliptical Inverse Distance Weighting [EIDW]" #check if power < 2.0: print "Warning: Power parameter too small; set to 2.0." power = 2.0 eidw = deepcopy(self.z) #avoid overwrite #calculate EIDW (radius='None' executes global EIDW) if plane == 'sn': eidw[self.nodata] = self.eidw_interpol(self.s[self.isdata], self.n[self.isdata], eidw[self.isdata], self.s[self.nodata], self.n[self.nodata], power, anisotropy, 'None') elif plane == 'xy': x = self.x.flatten() y = self.y.flatten() eidw[self.nodata] = self.eidw_interpol( x[self.isdata], y[self.isdata], eidw[self.isdata], x[self.nodata], y[self.nodata], power, anisotropy, 'None') else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return #grid (matrix) notation eidw = common.to_grid(eidw, self.rows, self.cols) #add pre-defined banks eidw = self.__add_banks(eidw) #smoothen for i in range(self.rows): eidw[i, :] = common.smooth(eidw[i, :], smoothie) print "Finished [EIDW]." self.z_interpol = eidw del eidw #plot if plot: self.plot(fignum='EIDW-GLOBAL')
def rbf(self, method='linear', anisotropy=5.0, smoothie=0, plane='sn', plot=False): """ Performs Radial Basis Interpolation using the defined method (linear or thin plate spline) Kwargs: method <str> : choice of RBF interpolation ['linear' or 'tps'] anisotropy <float> : anisotropy parameter: if >1.0, it brings points closer in the longitudinal (s) direction, if <1.0 it brings points closer in the transverse (n) direction smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented plot <boolean> : decides to plot or not the resulting RBF values """ gc.enable() print "Calculating: Radial Basis Function (RBF) with {0} method".format( method) rbf = deepcopy(self.z) #avoid overwrite #choice of plane and rbf interpolation if plane == 'sn': rbf[self.nodata] = self.rbf_solver( self.s[self.isdata], self.n[self.isdata], rbf[self.isdata], self.s[self.nodata], self.n[self.nodata], anisotropy, method) elif plane == 'xy': x = self.x.flatten() y = self.y.flatten() rbf[self.nodata] = self.rbf_solver(x[self.isdata], y[self.isdata], rbf[self.isdata], x[self.nodata], y[self.nodata], anisotropy, method) else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return rbf = common.to_grid(rbf, self.rows, self.cols) #griddify #add pre-defined banks rbf = self.__add_banks(rbf) #smoothen for i in range(self.rows): rbf[i, :] = common.smooth(rbf[i, :], smoothie) print "Finished [RBF]." self.z_interpol = rbf del rbf #plot if plot: self.plot(fignum='RADIAL-BASIS[{0}]'.format(method.upper()))
def idw(self, power=2.0, smoothie=0, plane='sn', plot=False): """ Performs Inverse Distance Weighting (IDW) interpolation to the instance's data Kwargs: power <float> : power parameter, should be above 2.0 smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented plot <boolean> : decides to plot or not the resulting IDW values """ gc.enable() print "Calculating: Inverse Distance Weighting" #check if power < 2.0: print "Warning: Power parameter too small; set to 2.0." power = 2.0 idw = deepcopy(self.z) #avoid overwrite #calculate IDW (when anisotropy ratio is 1, we have IDW; radius='None' executes global IDW) if plane == 'sn': idw[self.nodata] = self.eidw_interpol( self.s[self.isdata], self.n[self.isdata], idw[self.isdata], self.s[self.nodata], self.n[self.nodata], power, 1.0, 'None') elif plane == 'xy': x = self.x.flatten() y = self.y.flatten() idw[self.nodata] = self.eidw_interpol( x[self.isdata], y[self.isdata], idw[self.isdata], x[self.nodata], y[self.nodata], power, 1.0, 'None') else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return #grid (matrix) notation idw = common.to_grid(idw, self.rows, self.cols) #add pre-defined banks idw = self.__add_banks(idw) #smoothen for i in range(self.rows): idw[i, :] = common.smooth(idw[i, :], smoothie) print "Finished [IDW]." self.z_interpol = idw del idw #plot if plot: self.plot(fignum='IDW-GLOBAL')
def cubic(self, smoothie=0, plane='sn', fill_nans=True, plot=False): """ Performs Cubic interpolation to the instance's data (piecewise cubic, continuously differentiable and approximately curvature-minimizing polynomial surface). WARNING: High memory usage, usually in \'xy\' plane Kwargs: smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented fill_nans <str> : decides to fill NaN values in a linear manner or keep NaN values plot <boolean> : decides to plot or not the resulting CUBIC values """ gc.enable() print "Calculating: Cubic Interpolation" cubic = deepcopy(self.z) #avoid overwrite #choice of plane if plane == 'sn': pnts = np.array(zip(self.s, self.n)) elif plane == 'xy': pnts = np.array(zip(self.x.flatten(), self.y.flatten())) else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return #cubic interpolation cubic[self.nodata] = griddata(pnts[self.isdata], cubic[self.isdata], pnts[self.nodata], method='cubic', fill_value=np.nan) cubic = common.to_grid(cubic, self.rows, self.cols) #griddify if fill_nans: cubic = self.__fill_nans(cubic) #linear fill of nan values #add pre-defined banks cubic = self.__add_banks(cubic) #smoothen for i in range(self.rows): cubic[i, :] = common.smooth(cubic[i, :], smoothie) print "Finished [CUBIC]." self.z_interpol = cubic del cubic #plot if plot: self.plot(fignum='CUBIC')
def linear(self, smoothie=0, plane='sn', fill_nans=True, plot=False): """ Performs Linear Barycentric interpolation to the instance's data Kwargs: smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented fill_nans <str> : decides to fill NaN values in a linear manner or keep NaN values plot <boolean> : decides to plot or not the resulting LINEAR values """ gc.enable() print "Calculating: Linear Barycentric Interpolation" linear = deepcopy(self.z) #avoid overwrite #choice of plane if plane == 'sn': pnts = np.array(zip(self.s, self.n)) elif plane == 'xy': pnts = np.array(zip(self.x.flatten(), self.y.flatten())) else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return #linear interpolation linear[self.nodata] = griddata(pnts[self.isdata], linear[self.isdata], pnts[self.nodata], method='linear', fill_value=np.nan) linear = common.to_grid(linear, self.rows, self.cols) #griddify if fill_nans: linear = self.__fill_nans(linear) #linear fill of nan values #add pre-defined banks linear = self.__add_banks(linear) #smoothen for i in range(self.rows): linear[i, :] = common.smooth(linear[i, :], smoothie) print "Finished [LINEAR]." self.z_interpol = linear del linear #plot if plot: self.plot(fignum='LINEAR-BARYCENTRIC')
def near(self, smoothie=0, plane='sn', plot=False): """ Fills values of unsampled data points with the values of the closest sampled data point of the instance's data. Kwargs: smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented plot <boolean> : decides to plot or not the result NEAREST values """ gc.enable() print "Calculating: Nearest-Neighbour \"Interpolation\"" near = deepcopy(self.z) #avoid overwrite #choice of plane if plane == 'sn': pnts = np.array(zip(self.s, self.n)) elif plane == 'xy': pnts = np.array(zip(self.x.flatten(), self.y.flatten())) else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return #find nearest values near[self.nodata] = griddata(pnts[self.isdata], near[self.isdata], pnts[self.nodata], method='nearest') near = common.to_grid(near, self.rows, self.cols) #griddify #add pre-defined banks near = self.__add_banks(near) #smoothen for i in range(self.rows): near[i, :] = common.smooth(near[i, :], smoothie) print "Finished [NEAR]." self.z_interpol = near del near #plot if plot: self.plot(fignum='NEAREST')
def fuse(self, ftype='free-form', dthres=0.0, anisotropy=1.0, smoothie=0): gc.enable() print "Calculating: Fusion method (" + ftype + ")" if ftype not in ['free-form', 'cross-sections']: print "Warning: Please specify testing dataset type as: \'free-form\' for trackline or free-form data, or \'cross-sections\' for cross-sectional data." print "Assuming free-form data." ftype = 'free-form' s, n = self.s.flatten(), self.n.flatten() isdata = self.isdata.flatten() nodata = self.nodata.flatten() #if samples in free-form (ie tracklines) if ftype == 'free-form': #check dthres = abs(float(dthres)) #distance matrix: s0, n0 = s[isdata], n[isdata] #sampled s1, n1 = s[nodata], n[nodata] #unsampled dm = common.distance_matrix(s0, n0, s1, n1, anisotropy) #matrix #if no threshold is defined, calculate the furthest possible point # = this is where bathymetry has the most impact dmins = dm.min(axis=0) if dthres <= 0: dthres = dmins.max() print "Threshold Distance:", dthres #weights w_bth = dmins / dthres #weights for model dataset w_bth[w_bth > 1.0] = 1.0 #adjust to range of [0,1] w_int = 1.0 - w_bth #weights for interpolation dataset del dm, dmins, s0, n0, s1, n1 #clear #if samples in cross-sections else: #find cross-sections and the points where there is data (clustering of data): cs_where = [] for j in range(self.cols): if np.nansum(self.isdata[:, j]) != 0: cs_where.append(j) print "Cross-section at: ", j #Find minimum distances from 2 different cross-sections ratios = np.ones((self.rows * self.cols, 2)) * np.inf for j in cs_where: dist_from_cs = common.distance_matrix( self.s[:, j][self.isdata[:, j]], self.n[:, j][self.isdata[:, j]], s, n, anisotropy) cs_mindist = np.min(dist_from_cs, axis=0) change = cs_mindist < ratios[:, 1] ratios[:, 1][change] = cs_mindist[change] ratios = np.sort(ratios, axis=1) #holds min distances from 2 cs del dist_from_cs #weights w_int = [] w_bth = [] for i in range(len(ratios)): #real distances d1 = ratios[i, 0] #distance from one cs d2 = ratios[i, 1] #distance from another cs if d1 == 0.0: d1 = 1e-20 #avoid division by 0 if d2 == 0.0: d2 = 1e-20 #avoid division by 0 hd = (d1 + d2) / 2.0 #half-distance if d1 < hd: d2 -= hd r1 = 1. / (1. + (d2 / d1)**2) else: d1 -= hd r1 = 1. / (1. + (d1 / d2)**2) if r1 > 1.0: r1 = 1.0 r2 = 1.0 - r1 w_bth.append(r1) w_int.append(r2) w_int = np.array(w_int)[nodata] w_bth = np.array(w_bth)[nodata] #In both cases, fused dataset is the sum of the weighted datasets I = self.inter.flatten() M = self.model.flatten() fusion = self.z.flatten() #initialize, so to keep measured data values fusion[nodata] = I[nodata] * w_int + M[nodata] * w_bth fusion = common.to_grid(fusion, self.rows, self.cols) #grid (matrix) notation del w_bth, w_int #clear #smoothen the longitudinals, if required if smoothie > 0: for i in range(self.rows): fusion[i, :] = common.smooth(fusion[i, :], smoothie) if smoothie > int(fusion.shape[0] / 4): smoothie = int(fusion.shape[0] / 4) for i in range(self.cols): fusion[:, i] = common.smooth(fusion[:, i], smoothie) print "Finished [FUSION]." self.fused = fusion del fusion
def natneigh(self, anisotropy=1.0, smoothie=0, plane='sn', plot=False): """ Performs Natural Neighbor (NN) interpolation with defined anisotropy to the instance's data. The algorithm assumes a brute-force way of calculating the Voronoi cells every time an unsampled point's value is computed. Kwargs: anisotropy <float> : anisotropy parameter: if >1.0, it brings points closer in the longitudinal (s) direction, if <1.0 it brings points closer in the transverse (n) direction smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented plot <boolean> : decides to plot or not the resulting NN values """ from scipy.spatial import voronoi_plot_2d import matplotlib.pyplot as plt gc.enable() print "Calculating: Natural Neighbour [NN]" nn = deepcopy(self.z) #avoid overwrite #choose plane if plane == 'sn': x = self.s * 1. / anisotropy #already flattened y = self.n #already flattened elif plane == 'xy': x = self.x.flatten() * 1. / anisotropy y = self.y.flatten() else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return #DEFINE BOUNDARY FOR INTERPOLATION #griddify points to choose boundary easier: Gx = common.to_grid(x, self.rows, self.cols) Gy = common.to_grid(y, self.rows, self.cols) bx = np.hstack((Gx[0, :], Gx[1:-1, -1], Gx[-1, :][::-1], Gx[1:-1, 0][::-1])) by = np.hstack((Gy[0, :], Gy[1:-1, -1], Gy[-1, :][::-1], Gy[1:-1, 0][::-1])) #define boundary: boundary = np.array(zip(bx, by)) #VORONOI OF SAMPLED DATA POINTS: vorpoints = np.array(zip(x[self.isdata], y[self.isdata])) #shift points around central point of the dataset (for precision purposes) center = vorpoints.mean(axis=0) vorpoints -= center #construct Voronoi diagram from (centered) sampled data points vor = Voronoi(vorpoints) vor.close() """ #TODO: delete: voronoi_plot_2d(vor) plt.ion() plt.axis('equal') plt.show() """ #calculate areas of sampled dataset Voronoi cells original_areas, vor = self.__find_areas(vor, boundary - center) """ #TODO: delete: # colorize for region in vor.regions[1:]: polygon = vor.vertices[region] plt.fill(*zip(*polygon), alpha=0.4) plt.plot(vorpoints[:,0], vorpoints[:,1], 'ko') plt.xlim(vor.min_bound[0] - 0.1, vor.max_bound[0] + 0.1) plt.ylim(vor.min_bound[1] - 0.1, vor.max_bound[1] + 0.1) plt.axis('equal') plt.ion() plt.show() """ #ITERATE THROUGH UNSAMPLED DATA POINTS: # ~ For each unsampled point, construct the new Voronoi diagram consisting of the # ~ sampled data and the current unsampled point. Then calculate the new areas and # ~ find the normalized weights based on how much of each area is "stolen away" from # ~ each sampled dataset Voronoi cell (https://en.wikipedia.org/wiki/Natural_neighbor). # ~ The areas are always bounded by the river polygon (based on the grid defined). unknown = [] for i in range(len(x[self.nodata])): if i % 1000 == 0: print i, "out of ", len(x[self.nodata]) #add new point shifted around central point varys = np.vstack((vorpoints, [ x[self.nodata][i] - center[0], y[self.nodata][i] - center[1] ])) #calculate new Voronoi pntvor = Voronoi(varys) pntvor.close() #calculate areas new_areas, pntvor = self.__find_areas(pntvor, boundary - center) new_areas = new_areas[:-1] #exclude new point's area w = new_areas / original_areas w[w > 1.0] = 1.0 #make sure that no area is larger than initial areas areaweight = 1.0 - w normalize = np.nansum(areaweight) if normalize == 0.0: #to avoid division by 0 normalize = 1e-12 areaweight /= normalize unknown.append(np.nansum(areaweight * self.z[self.isdata])) nn[self.nodata] = np.array(unknown) #grid (matrix) notation nn = common.to_grid(nn, self.rows, self.cols) #add pre-defined banks nn = self.__add_banks(nn) #smoothen for i in range(self.rows): nn[i, :] = common.smooth(nn[i, :], smoothie) print "Finished [NN]." self.z_interpol = nn del nn #plot if plot: self.plot(fignum='NN')
def uk(self, sill, vmodel='spherical', anisotropy=1.0, smoothie=0, plane='sn', plot=False): """ Performs Universal Kriging (UK) interpolation with defined anisotropy to the instance's data using the specified model for its semivariogram. The sill for the semivariogram needs to be defined. The range used is equal to the sill times the anisotropy defined. Args: sill <float> : Sill value for semivariogram in UK Kwargs: vmodel <str> : Semivariogram model (default: 'spherical') anisotropy <float> : anisotropy parameter: if >1.0, it brings points closer in the longitudinal (s) direction, if <1.0 it brings points closer in the transverse (n) direction smoothie <int> : smoothing degree (Gaussian window) plane <str> : chooses plane for interpolation; 'xy' for Cartesian, 'sn' for flow-oriented plot <boolean> : decides to plot or not the resulting UK values """ gc.enable() print "Calculating: Universal Kriging [UK]" uk = deepcopy(self.z) #avoid overwrite #calculate UK with anisotropy defined if plane == 'sn': UK = UniversalKriging( self.s[self.isdata], self.n[self.isdata], uk[self.isdata], anisotropy_scaling=anisotropy, anisotropy_angle=0.0, nlags=self.cols, variogram_model=vmodel, variogram_parameters=[sill, sill * anisotropy, 0.0], drift_terms=['functional'], functional_drift=[self.uk_funct], verbose=True, enable_plotting=True) uk[self.nodata], sigmas = UK.execute('points', self.s[self.nodata], self.n[self.nodata]) elif plane == 'xy': x = self.x.flatten() y = self.y.flatten() UK = UniversalKriging( x[self.isdata], y[self.isdata], uk[self.isdata], anisotropy_scaling=anisotropy, anisotropy_angle=0.0, nlags=self.cols, variogram_model=vmodel, variogram_parameters=[sill, sill * anisotropy, 0.0], drift_terms=['regional_linear'], functional_drift=[self.uk_funct], verbose=False, enable_plotting=False) uk[self.nodata], sigmas = UK.execute('points', x[self.nodata], y[self.nodata]) else: print "Error: Plane for interpolation not correctly specified. No interpolation performed." return #grid (matrix) notation uk = common.to_grid(uk, self.rows, self.cols) #add pre-defined banks uk = self.__add_banks(uk) #smoothen for i in range(self.rows): uk[i, :] = common.smooth(uk[i, :], smoothie) print "Finished [UK]." self.z_interpol = uk del uk #plot if plot: self.plot(fignum='UK')
def create_dep(self, branches='all', Q = 500, C = 45, i_slope = 9e-5, D50 = 300e-6, a = 10, WL = 0, deg = 20, system = 'm', banks_profile ='linear', curvature = 'global', fix_CbyH = False, fix_CbyB = False, fix_abyB = False, lonsmooth = False, transmooth = True, confined_width = True, adjust_byArea = False, remove_shallow_banks = False): if branches=='all': branches = self.gr.grid.keys() elif type(branches) != type([]): print "Please provide names of branches in a list.\n" return for branch in branches: print "Calculating bed levels for branch {0}".format(branch) try: #In order to extract the local curvature, it must be calculated on each point of the grid self.bath[branch] = {} Gx = self.gr.grid[branch]['x'] Gy = self.gr.grid[branch]['y'] k = self.__get_curvature(Gx,Gy,deg,which=curvature) widths = self.gr.widths[branch] #TODO: Experimenting with further smoothing: S-Golay smoothing on curvature (per longitudinal): if deg>=3: if deg%2 != 1: smoothfactor = int(deg - deg%2 + 1) else: smoothfactor = int(deg) for q in range(k.shape[0]): k[q,:] = common.savitzky_golay(k[q,:], smoothfactor, 1) #TODO: delete! s = np.array(self.gr._get_s_coordinates('1')) w = np.array(widths) if system=='ft': s*=0.3048 w*=0.3048 curv = k[k.shape[0]/2,:] """ #TODO: LAG???? curv_s = s + w/2.0 #ASSUMPTION!!!! curv_ls = LineString([(0,curv[0])]+zip(curv_s,curv)) curv_new = [] for i in s: curv_new.append(curv_ls.interpolate(i).coords[:][0][1]) curv_new = np.array(curv_new) for i in range(k.shape[0]): k[i,:] = curv_new """ plt.figure('WIDTH VS CURVATURE') plt.subplot(2,1,1) plt.plot(s,w) plt.ylabel('widths (m)') plt.subplot(2,1,2) plt.plot(s,curv) plt.ylabel('curvature [-]') plt.xlabel('Longitudinal distance (m)') plt.ion() plt.show() norow, nocon = self.gr.grid[branch]['x'].shape except KeyError: print 'invalid key or parameter value' return #If the data are in feet, change widths into meters for equations to work if system=='ft': B = np.array(widths) * 0.3048 if self.banks: self.banks = [j*0.3048 for j in self.banks] else: B = np.array(widths) #TODO: DELETE!! if fix_CbyB: C *= B/np.average(B) #TODO: ??? #k *= np.average(B)/B #a += (np.average(B)/B) if fix_abyB: a *= np.average(B)/B ### FIND BANKS AND ORIGINAL AREAS ### hc_ref = ( float(Q) / ( B * C * i_slope**0.5 ) ) ** (2.0/3.0) if fix_CbyH: href = np.average(hc_ref) p = 1./6 hc_original = hc_ref**(3./(2*p+3.)) * href**(2*p/(2*p+3.)) Cp = (hc_original/href)**p * C #fix Chezy #hc = hc_ref**(3./(3.-2*p)) * href**(-2*p/(3.-2*p)) #Cp = (href/hc)**p * C #fix Chezy #TODO: delete plt.figure('WIDTH VS Chezy') plt.subplot(2,1,1) plt.plot(s,w) plt.ylabel('widths (m)') plt.subplot(2,1,2) plt.plot(s,Cp) plt.ylabel('Chezy coeff') plt.xlabel('Longitudinal distance (m)') plt.ion() plt.show() else: hc_original = hc_ref Cp = C * np.ones(hc_original.shape) E = 0.0944 * ((hc_original/D50)**0.3) delta = (self.rhos-self.rhow)/self.rhow theta = 1.0 / (Cp**2 * delta * D50) ft = (0.85/E) * (theta**0.5) Rcinv = -k karman = 0.44 g = 9.80665 A = (2.0*a)/(karman**2) * (1.0 - np.sqrt(g)/(karman*Cp) ) hf = np.ones((norow, nocon)) * np.nan #initialize bankslope_width_r = [] bankslope_width_l = [] original_areas = [] #for each cross-section: for j in range(nocon): n = np.linspace(-B[j]/2.0,B[j]/2.0,norow) power = A[j] * ft[j] * n * Rcinv[:,j] hf[:,j] = hc_original[j] * np.exp(power) #areas of original theory calculations xy = [(-B[j]/2.0,0.0)] + zip(n,hf[:,j]) + [(B[j]/2.0,0.0)] #close polygon p = Polygon(xy) original_areas.append(p.area) #TODO: DELETE! if j==300: store1 = np.array(hf[:,j][::]) #TODO: DELETE! if j==350: store2 = np.array(hf[:,j][::]) #compute banks widths: if self.banks: if self.banks[0] > B[j]/3.0: #TODO: delete next line's print! print j, self.banks[0], B[j], self.banks[0]/B[j] bankslope_width_r.append(B[j]/3.0) else: bankslope_width_r.append(self.banks[0]) if self.banks[1] > B[j]/3.0: #TODO: delete next line's print! print j, self.banks[1], B[j], self.banks[1]/B[j] bankslope_width_l.append(B[j]/3.0) else: bankslope_width_l.append(self.banks[1]) else: add = max(hf[:,j]) #find maximum depth calculated #check that banks do not exceed computable size if add > B[j]/3.0: #TODO: delete print! print j, add, B[j], add/B[j] add = B[j]/3.0 bankslope_width_r.append(add) bankslope_width_l.append(add) bankslope_width_r = np.array(bankslope_width_r) bankslope_width_l = np.array(bankslope_width_l) #If chosen, the banks on the shallow side of the river bend can be excluded if remove_shallow_banks: sign = np.sign(Rcinv[int(norow/2),:]) bankslope_width_r[sign>0] = 0.0 bankslope_width_l[sign<0] = 0.0 """ #TODO: delete! shallowest_points = [] for j in range(nocon): shallowest_points.append(min(hf[:,j])) plt.figure('Shallows') plt.plot(s,shallowest_points) plt.ion() plt.show() """ ### ZERO-ORDER #################################################### if confined_width: B_model = B - (bankslope_width_r + bankslope_width_l) else: B_model = B hc_ref = ( float(Q) / ( B_model * C * i_slope**0.5 ) ) ** (2.0/3.0) if fix_CbyH: href = np.average(hc_ref) p = 1./6 hc = hc_ref**(3./(2*p+3.)) * href**(2*p/(2*p+3.)) Cp = (hc/href)**p * C #fix Chezy #hc = hc_ref**(3./(3.-2*p)) * href**(-2*p/(3.-2*p)) #Cp = (href/hc)**p * C #fix Chezy else: hc = hc_ref Cp = C * np.ones(hc.shape) ################################################################### ### AXI-SYMMETRIC: ################################################ E = 0.0944 * ((hc/D50)**0.3) delta = (self.rhos-self.rhow)/self.rhow theta = 1.0 / (Cp**2 * delta * D50) ft = (0.85/E) * (theta**0.5) Rcinv = -k karman = 0.44 g = 9.80665 A = 2.0*a/karman**2 * (1.0 - np.sqrt(g)/(karman*Cp) ) hf = np.ones((norow, nocon)) * np.nan #initialize new_areas = [] for j in range(nocon): #for each cross-section n = np.linspace(-B[j]/2.0,B[j]/2.0,norow) #calculate for whole area; excess will be "cut down" by the bank profiles power = A[j] * ft[j] * n * Rcinv[:,j] hf[:,j] = hc[j] * np.exp(power) #if there are banks described: discrete_chunks = B[j] / (norow-1.0) #right bank: if (bankslope_width_r[j]>0.0): mr = int(np.round(bankslope_width_r[j]/discrete_chunks)) if mr == 0: mr = 1 #at least 1 if banks_profile == 'linear': sloppy_r = np.linspace( 0.0, hf[mr,j], mr+1 ) #right elif banks_profile == 'hyper': spread = np.linspace( -np.sinh(1.0), np.sinh(1.0), mr+1 ) sloppy_r = (np.arcsinh(spread)+1.0) * hf[mr,j]/2.0 #right hf[:mr+1,j] = sloppy_r #attach right bank bankslope_width_r[j] = mr*discrete_chunks #left bank: if (bankslope_width_l[j]>0.0): ml = int(np.round(bankslope_width_l[j]/discrete_chunks)) if ml == 0: ml = 1 #at least 1 if banks_profile == 'linear': sloppy_l = np.linspace( 0.0, hf[norow-ml-1,j], ml+1 ) #left elif banks_profile == 'hyper': spread = np.linspace( -np.sinh(1.0), np.sinh(1.0), ml+1) sloppy_l = (np.arcsinh(spread)+1.0) * hf[norow-ml-1,j]/2.0 #left hf[norow-ml-1:,j] = sloppy_l[::-1] #attach left bank bankslope_width_l[j] = ml*discrete_chunks #areas xy = zip(n,hf[:,j]) if hf[-1,j] != 0: xy = xy + [(B[j]/2.0,0.0)] if hf[0,j] != 0: xy = [(-B[j]/2.0,0.0)] + xy new_areas.append(Polygon(xy).area) #if an adjustment to initially computed areas is chosen: if adjust_byArea: Adiff = original_areas[j] - new_areas[j] h_plus = Adiff / ( B[j] - (bankslope_width_l[j]+bankslope_width_r[j])/2.0 ) hf[:,j] += h_plus hc[j] += h_plus #FIX banks: if (bankslope_width_r[j]>0.0): if banks_profile == 'linear': sloppy_r = np.linspace( 0.0, hf[mr,j], mr+1 ) #right elif banks_profile == 'hyper': spread = np.linspace( -np.sinh(1.0), np.sinh(1.0), mr+1 ) sloppy_r = (np.arcsinh(spread)+1.0) * hf[mr,j]/2.0 #right hf[:mr+1,j] = sloppy_r #attach right bank #left bank: if (bankslope_width_l[j]>0.0): if banks_profile == 'linear': sloppy_l = np.linspace( 0.0, hf[norow-ml-1,j], ml+1 ) #left elif banks_profile == 'hyper': spread = np.linspace( -np.sinh(1.0), np.sinh(1.0), ml+1) sloppy_l = (np.arcsinh(spread)+1.0) * hf[norow-ml-1,j]/2.0 #left hf[norow-ml-1:,j] = sloppy_l[::-1] #attach left bank #AREAS #recalculate final areas for comparison purposes xy = zip(n,hf[:,j]) if hf[-1,j] != 0: xy = xy + [(B[j]/2.0,0.0)] if hf[0,j] != 0: xy = [(-B[j]/2.0,0.0)] + xy new_areas[j] = Polygon(xy).area #store finalized 0-order: if system == 'ft': #if specified system is in feet self.bath[branch]['hc'] = hc / 0.3048 #return notation back to feet else: self.bath[branch]['hc'] = hc #TODO: delete graph plt.figure("MODEL_AREAS") plt.hold(True) plt.plot(s,original_areas) plt.plot(s,new_areas) plt.hold(False) plt.ion() plt.show() ##TODO: Inspect: 2D EXPERIMENTAL SMOOTHING: # hf = common.smooth2D(hf, 0.0, deg/2, 3.0, 1.0, 5.0) #OR: # hf[bankslope_width:norow-bankslope_width+1,:] = \ # common.smooth2D(hf[bankslope_width:norow-bankslope_width+1,:], 0.0, deg/2, 5.0, 1.0, 5.0) # ### SMOOTHING ### #transverse if transmooth: for j in range(nocon): #smoothen each cross-section hf[:,j] = common.smooth(hf[:,j], int(0.2*norow)) #Smoothing window: 20% of cross-section width #TODO: Should the side banks be returned to expected 0-water level after smoothing? #hf[0,:] = 0.0 #hf[-1,:] = 0.0 #longitudinal if lonsmooth and deg>0: for i in range(norow): #smoothen each row on grid hf[i,:] = common.smooth(hf[i,:], deg) #TODO: delete - creates a few cross-sectional profiles for representation reasons ## all based on water level = 0 plt.figure("a cross-section")#, figsize=(10,10)) plt.hold(True) for j in range(hf.shape[1]): #smoothen each cross-section if j==300: #in range(0,1500,120): bbb = np.linspace(-B[j]/2.0, B[j]/2.0, norow) plt.plot(bbb,-hf[:,j],'.-',label=str(j)) plt.plot(bbb,-store1,'.-',label=str(j)) if j==350: #in range(0,1500,120): bbb = np.linspace(-B[j]/2.0, B[j]/2.0, norow) plt.plot(bbb,-hf[:,j],'.-',label=str(j)) plt.plot(bbb,-store2,'.-',label=str(j)) plt.hold(False) axes = plt.gca() axes.set_ylim([-60,40]) plt.axis('equal') plt.show() if system == 'ft': #if specified system is in feet hf /= 0.3048 #return notation back to feet if self.banks: self.banks = [j/0.3048 for j in self.banks] self.bath[branch]['h'] = hf #water levels Salong = self.gr._get_s_coordinates(branch) #Adjust to bed levels (assuming WL = Water Level at start of river section, following the water flow) WLdecrease = ( Salong * i_slope ) / ( (i_slope**2 + 1.0)**0.5 ) self.bath[branch]['bedlvl'] = (WL-WLdecrease) - hf #returns feet if feet, or meters if meters print "Model bed levels calculated for branch: {0}!".format(branch)