예제 #1
0
    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')
예제 #2
0
    def error_map(self, x, y, clim, plotname):
        import matplotlib.pyplot as plt

        err = self.GT.flatten() - self.P.flatten()
        levels = np.linspace(clim[0], clim[1], 11)
        n, m = self.GT.shape

        plt.figure("Error Map - " + str(plotname))
        err = common.to_grid(err, n, m)
        Gx = common.to_grid(x, n, m)
        Gy = common.to_grid(y, n, m)

        #If more than half the points are unknown, the dataset to plot logically must be a testing dataset
        if np.sum(np.isnan(err)) > err.shape[0] * err.shape[1] / 2.0:
            print "-> Assuming plot of Testing Dataset."
            cs = plt.scatter(Gx,
                             Gy,
                             s=10,
                             c=err,
                             cmap=plt.cm.bwr,
                             vmin=clim[0],
                             vmax=clim[1],
                             edgecolors='none')
        else:
            cs = plt.contourf(Gx,
                              Gy,
                              err,
                              levels,
                              cmap=plt.cm.bwr,
                              extend='both')

        cs.cmap.set_over('deeppink')
        cs.cmap.set_under('k')
        cs.set_clim(np.floor(levels[0]), np.ceil(levels[-1]))
        cbar = plt.colorbar(cs)
        cbar.set_label('Bed Level Difference (m)',
                       labelpad=15,
                       weight='bold',
                       size='14')
        plt.axis('equal')
        plt.ion()
        plt.show()
예제 #3
0
    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()))
예제 #4
0
    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')
예제 #5
0
 def gridify_samples(self, branch):
     """
     Use to set the sample data on the grid, if it is known that the samples
     respond to the specified grid.
     """
     if self.samples:
         try:
             data = zip(*self.samples)[2]  #retrive only z values
             b = str(branch)
             s = self.gr.grid[b]['x'].shape
             self.griddeddata[b] = common.to_grid(data, s[0], s[1])
             print "Success: Sample data set to grid notation (matrix).\n"
         except:
             print "ERROR: Could not transform samples onto gridded data."
     else:
         print "No data samples loaded."
예제 #6
0
    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')
예제 #7
0
    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')
예제 #8
0
    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')
예제 #9
0
    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
예제 #10
0
    def plot(self, fignum, clim='auto', classes=100, system='xy', hold=False):

        #append nan values
        Gz = deepcopy(self.z_interpol)
        Gz[Gz == -999.0] = np.nan

        if system == 'xy':
            Gx = self.x
            Gy = self.y
        elif system == 'sn':
            Gx = common.to_grid(self.s, self.rows, self.cols)
            Gy = common.to_grid(self.n, self.rows, self.cols)
        elif system == 'mn':
            Gx, Gy = np.meshgrid(self.cols, self.rows)
        else:
            print "Wrong coordinate system chosen. Please specify input system as \'xy\', \'sn\' or \'mn\'."

        #plt.close(fignum)
        plt.figure(fignum)
        #plt.clf()

        # set colorlimits
        minn = np.nanmin(Gz)
        maxx = np.nanmax(Gz)
        if clim == 'auto':
            mean = np.mean(np.ma.masked_array(Gz, np.isnan(Gz)))
            classes = int(classes)
            if classes % 2 == 1:
                classes += 1
            dl = np.linspace(minn, mean, classes / 2)
            dr = np.linspace(mean, maxx, classes / 2)
            d = 10.0
            flag = True
            c = 0
            while flag:
                levels = np.round(np.append(dl, dr[1:]) / d) * d
                if c % 2 == 0:
                    d = d / 2.0
                else:
                    d = d - 4 * d / 5.0
                c += 1
                flag = len(levels) != len(set(levels))
        elif clim == 'minmax':
            levels = np.linspace(minn, maxx, classes)
        else:
            levels = np.linspace(clim[0], clim[1], classes)

        #If more than half the points are unknown, the dataset to plot logically must be a testing dataset
        if np.sum(np.isnan(Gz)) > Gz.shape[0] * Gz.shape[1] / 2.0:
            print "-> Assuming plot of Testing Dataset."
            cs = plt.scatter(Gx,
                             Gy,
                             s=10,
                             c=Gz,
                             cmap=plt.cm.jet,
                             vmin=clim[0],
                             vmax=clim[1],
                             edgecolors='none')
        else:
            cs = plt.contourf(Gx,
                              Gy,
                              Gz,
                              levels,
                              cmap=plt.cm.jet,
                              extend="both")
        cs.cmap.set_under('k')
        cs.set_clim(np.floor(levels[0]), np.ceil(levels[-1]))
        cbar = plt.colorbar(cs)
        cbar.set_label('Bed Level (m)', labelpad=15, weight='bold', size='14')
        plt.axis('equal')
        plt.hold(hold)  #used when the data needs to be "on top" of other data
        plt.ion()
        plt.show()
예제 #11
0
    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')
예제 #12
0
    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')
예제 #13
0
    def hw_slope(self, widths, lengths, plotname=False):
        import matplotlib.pyplot as plt
        #take half-width:
        k = int(self.GT.shape[0] / 4.0)
        CDhw = self.P[k:-k, :]  #computed dataset half-width
        GThw = self.GT[k:-k, :]  #ground-truth dataset half-width
        numlines = CDhw.shape[0]

        #TODO: find a better way to fill this
        #filling of ground-truth half-widths // by nearest grid neighbour
        z = GThw.flatten()
        m = range(CDhw.shape[1]) * CDhw.shape[0]
        n = sorted(m)
        gpnts = np.vstack((m, n)).T
        znear = griddata(gpnts[~np.isnan(z)],
                         z[~np.isnan(z)],
                         gpnts[np.isnan(z)],
                         method='nearest')
        z[np.isnan(z)] = znear
        GThw = common.to_grid(z, CDhw.shape[0], CDhw.shape[1])

        #real half-width
        w = (float(numlines - 1) / (self.P.shape[0] - 1)) * np.array(widths)

        slopeDiff = []
        a = []
        gt_a = []
        testNHWS = []
        gtNHWS = []
        for j in range(CDhw.shape[1]):  #for each cross-section
            excl = ~np.isnan(GThw[:, j]) * ~np.isnan(
                CDhw[:, j])  #mutual exclusion
            cs_x = np.linspace(0.0, 1.0, numlines) * w[j]
            #test
            cs_y = CDhw[:, j]
            testslope = np.polyfit(cs_x[excl], cs_y[excl], 1)  #f(x) = ax+b
            #ground-truth
            cs_y = GThw[:, j]
            gtslope = np.polyfit(cs_x[excl], cs_y[excl], 1)  #f(x) = ax+b
            if np.isnan(gtslope[0]):
                #print gtslope
                #print cs_x[excl],cs_y[excl]
                print "CHECK"

            #slope difference
            a.append(testslope[0])
            gt_a.append(gtslope[0])
            slopeDiff.append(abs(a[-1] - gt_a[-1]))

            #Normalized Half-Width Slope
            H = testslope[0] * cs_x[numlines / 2] + testslope[1]
            Hgt = gtslope[0] * cs_x[numlines / 2] + gtslope[1]
            testNHWS.append(testslope[0] * 1. / H)
            gtNHWS.append(gtslope[0] * 1. / Hgt)
        #//end for-loop

        #slope's mae (not necessary):
        print "SLOPE metrics:"
        slopeDiff = np.array(slopeDiff)
        sub = np.sum(np.isnan(slopeDiff))
        Csum = np.nansum(slopeDiff)
        Dim = len(slopeDiff) - sub
        slope_mae = Csum / Dim
        print "mae:", slope_mae
        slopeDiff = np.array(slopeDiff)**2
        sub = np.sum(np.isnan(slopeDiff))
        Csum = np.nansum(slopeDiff)
        Dim = len(slopeDiff) - sub
        slope_rmse = np.sqrt(Csum / Dim)
        print "rmse:", slope_rmse
        nsd = np.sum(
            np.abs(np.array(gtNHWS) - np.array(testNHWS))) / len(gtNHWS)
        print "nsdiff:", nsd

        #PLOTS:
        if plotname:
            #alpha "normalized"
            plt.close(plotname + ' NHWS')
            plt.figure(plotname + ' NHWS')
            plt.xlabel('River span (m)', weight='bold', size='14')
            plt.ylabel('Normalized Half-Width Slope (1/m)',
                       weight='bold',
                       size='14')
            plt.hold(True)
            plt.plot(lengths, testNHWS, 'r.-')
            plt.plot(lengths, gtNHWS, 'b.-')
            plt.hold(False)

        #return calculations; in order of output:
        #[slope of dataset to be tested, slope of ground-truth data, MAE of slope for dataset to be tested,
        # RMSE of slope for dataset to be tested, absolute slope difference]
        return [testNHWS, gtNHWS, slope_mae, slope_rmse, nsd]