Changeset 9219


Ignore:
Timestamp:
Jun 25, 2014, 4:55:20 PM (10 years ago)
Author:
davies
Message:

Changes + enhanced testing for spatialInputUtil + quantity_setting_functions

Location:
trunk/anuga_core/source/anuga/utilities
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/anuga_core/source/anuga/utilities/quantity_setting_functions.py

    r9202 r9219  
    7878        Make a 'composite function' to set quantities -- applies different functions inside different polygon regions.
    7979             
    80         fun_poly_pairs = [ [f0, p0], [f1, p1], ...] where fi is a function and pi is a polygon, or None, or 'All'
     80        fun_poly_pairs = [ [f0, p0], [f1, p1], ...]
     81                    where fi is a function, or a constant, or the name of a gdal-compatible rasterFile;
     82                    and pi is a polygon, or None, or 'All' (or it can be 'Extent' in the case that fi is a rasterFile name)
    8183             
    8284        IMPORTANT: When polygons overlap, the first elements of the list are given priority.
     
    9092              fun_poly_pairs = [ [f0, p0], [f1, p1], ...]
    9193
    92                   where fi(x,y) are functions returning quantity values at points, and
    93                   pi are polygons where we want to use fi inside
     94                  where fi(x,y) are functions returning quantity values at
     95                  points, or constants in which case points in the polygon are set to that
     96                  value, or (string) rasterFile names which can be passed to quantityRasterFun to make a function
     97
     98                  and pi are polygons where we want to use fi inside
    9499               
    95100                  If any pi = 'All', then we assume that ALL unset points are set
    96                     using the function. This CAN ONLY happen in the last [fi,pi] pair where pi is
    97                     not None (since fi will be applied to all remaining points -- so anything else is probably an input mistake)
     101                  using the function. This CAN ONLY happen in the last [fi,pi] pair where pi is
     102                  not None (since fi will be applied to all remaining points -- so anything else is probably an input mistake)
    98103   
    99104                  If any pi = None, then that [fi,pi] pair is skipped
    100105
     106                  if pi='Extent' and fi is the name of a raster file, then the
     107                    extent of the raster file is used to define the polygon
     108
    101109              domain = ANUGA domain object
    102110
     
    105113                domain.set_quantity('elevation', F)
    106114    """
     115    import os
    107116    import scipy
    108117    from matplotlib import path
     
    136145            fi = fun_poly_pairs[i][0] # The function
    137146            pi = fun_poly_pairs[i][1] # The polygon
     147
     148            # Quick exit
     149            if(pi is None):
     150                continue
     151
    138152            # Get a 'true/false' flag for whether the point is in pi, and not set
    139153            if(pi is 'All'):
    140154                fInside=(1-isSet)
    141             elif(pi is None):
    142                 continue
    143155            else:
    144                 # Try matplotlib -- make the path a matplotlib path object
    145                 pi_path=path.Path(scipy.array(pi))
     156                if(pi is 'Extent' and type(fi) is str and os.path.exists(fi)):
     157                    # Here fi MUST be a gdal-compatible raster
     158                    # Then we get the extent from the raster itself
     159                    import anuga.utilities.spatialInputUtil as su
     160                    newpi=su.getRasterExtent(fi,asPolygon=True)
     161                    pi_path=path.Path(scipy.array(newpi))
     162                else:
     163                    # Try matplotlib -- make the path a matplotlib path object
     164                    pi_path=path.Path(scipy.array(pi))
     165
    146166                fInside=xy_array_trans[:,0]*0.
    147167                for j in range(len(fInside)):
     
    153173            fInds=(fInside==1.).nonzero()[0]
    154174            if(len(fInds)>0):
    155                 quantityVal[fInds] = fi(x[fInds], y[fInds])
     175                if(hasattr(fi,'__call__')):
     176                    # fi is a function
     177                    quantityVal[fInds] = fi(x[fInds], y[fInds])
     178                elif isinstance(fi, (int, long, float)):
     179                    # fi is a numerical constant
     180                    quantityVal[fInds]=fi*1.0
     181                elif ( type(fi) is str and os.path.exists(fi)):
     182                    # fi is a file which is assumed to be
     183                    # a gdal-compatible raster
     184                    newfi = quantityRasterFun(domain, fi)
     185                    quantityVal[fInds] = newfi(x[fInds], y[fInds])
     186               
    156187                isSet[fInds]=1
    157188
     
    191222#################################################################################
    192223
    193 def elevation_from_Pt_Pol_Data_and_Raster(Pt_Pol_Data, elevation_raster, domain):
    194     """
    195         Function to make a function F(x,y) which returns the elevation on elevation_raster,
    196             except if x,y is inside the polygon associated with any element of Pt_Pol_Data,
    197             in which case a Pt_Pol_-specific nearest neighbour interpolator is used.
     224def quantity_from_Pt_Pol_Data_and_Raster(Pt_Pol_Data, quantity_raster, domain):
     225    """
     226        Function to make a function F(x,y) which returns the corresponding
     227        values on quantity_raster, except if x,y is inside the polygon associated with
     228        any element of Pt_Pol_Data, in which case a Pt_Pol_-specific nearest neighbour
     229        interpolator is used.
    198230
    199231        INPUT:
     
    201233                                        [ Polygon_1, Pt_XYZ_1],
    202234                                        ... ]
    203             elevation_raster = A GDAL-compatible elevation raster
     235                    Here Polygon_i is a polygon in ANUGA format,
     236                    and Pt_XYZ_i is a 3 column array of x,y,Value points
     237            quantity_raster = A GDAL-compatible quantity raster
    204238            domain = ANUGA domain
    205239    """
    206240
    207     # Function to set elevation from raster
    208     elevFun1=quantityRasterFun(domain, rasterFile=elevation_raster)
    209 
    210     # List of function/polygon pairs defining the Pt_Pol_ elevation data
    211     elevFunChanList=[]
     241    # Function to set quantity from raster
     242    qFun1=quantityRasterFun(domain, rasterFile=quantity_raster)
     243
     244    # List of function/polygon pairs defining the Pt_Pol_ quantity data
     245    qFunChanList=[]
    212246    for i in range(len(Pt_Pol_Data)):
    213         elevFunChanList.append([
     247        qFunChanList.append([
    214248             make_nearestNeighbour_quantity_function(Pt_Pol_Data[i][1], domain),
    215249             Pt_Pol_Data[i][0]
     
    217251
    218252    #
    219     elevFun=composite_quantity_setting_function(elevFunChanList+[[elevFun1, 'All']], domain)
    220 
    221     return elevFun
     253    qFun=composite_quantity_setting_function(qFunChanList+[[qFun1, 'All']], domain)
     254
     255    return qFun
  • trunk/anuga_core/source/anuga/utilities/spatialInputUtil.py

    r9212 r9219  
    502502        else:
    503503            return [L1, L2]
    504    
     504   
     505    ###########################################################
     506    def getRasterExtent(rasterFile, asPolygon=False):
     507        """
     508            Sometimes we need to know the extent of a raster
     509            i.e. the minimum x, maximum x, minimum y, and maximum y values
     510           
     511            INPUT:
     512                rasterFile -- a gdal compatible rasterfile
     513                asPolygon -- if False, return [xmin,xmax,ymin,ymax].
     514                             If True, return [ [xmin,ymin],[xmax,ymin],[xmax,ymax],[xmin,ymax]]
     515            OUTPUT
     516                The extent as defined above
     517
     518        """
     519        raster = gdal.Open(rasterFile)
     520        transform=raster.GetGeoTransform()
     521        xOrigin = transform[0]
     522        yOrigin = transform[3]
     523        xPixels=raster.RasterXSize
     524        yPixels=raster.RasterYSize
     525
     526        # Compute the other extreme corner
     527        x2=xOrigin + xPixels*transform[1]+yPixels*transform[2]
     528        y2=yOrigin + xPixels*transform[4]+yPixels*transform[5]
     529       
     530        xmin=min(xOrigin,x2)
     531        xmax=max(xOrigin,x2)
     532
     533        ymin=min(yOrigin,y2)
     534        ymax=max(yOrigin,y2)
     535
     536        if(asPolygon):
     537            return [ [xmin,ymin], [xmax,ymin], [xmax,ymax], [xmin,ymax]]
     538        else:
     539            return [xmin,xmax,ymin,ymax]
     540
     541 
    505542    ###########################################################
    506543    def rasterValuesAtPoints(xy, rasterFile, band=1):
     
    548585            print 'You might need to edit this code to read the data type'
    549586            raise Exception, 'Stopping'
    550    
     587 
     588        # Upper bounds for pixel values, so we can fail gracefully
     589        xMax=raster.RasterXSize
     590        yMax=raster.RasterYSize
     591        if(px.max()<xMax and px.min()>=0 and py.max()<yMax and py.min()>=0):
     592            pass
     593        else:
     594            raise Exception, 'Trying to extract point values that exceed the raster extent'
     595
    551596        # Get values -- seems we have to loop, but it is efficient enough
    552597        for i in range(len(px)):
  • trunk/anuga_core/source/anuga/utilities/test_quantity_setting_functions.py

    r9202 r9219  
    140140        return
    141141
    142     def test_elevation_from_Pt_Pol_Data_and_Raster(self):
    143         #
    144         #
    145         #
     142    def test_composite_quantity_setting_function(self):
     143        # Test the composite_quantity_setting_function
     144       
    146145        domain=self.create_domain(1.0, 0.0)
    147 
    148         # Evolve the model
    149         #for t in domain.evolve(yieldstep=0.2, finaltime=1.0):
    150         #    pass
    151 
     146       
    152147        # Make a raster from the elevation data
    153148        from anuga.utilities import plot_utils as util
     
    162157        # Make a polygon-point pair which we use to set elevation in a 'channel'
    163158        trenchPoly=[[minX+40., minY], [minX+40., minY+100.], [minX+60., minY+100.], [minX+60., minY]]
     159
     160        #################################################################
     161 
     162        # This example uses a constant, and a raster, to set the quantity           
     163        F=qs.composite_quantity_setting_function([[-1000., trenchPoly], ['PointData_ElevTest.tif', 'Extent']],\
     164                                                domain)
     165
     166        # Points where we test the function
     167        testPts_X=numpy.array([50., 3.])
     168        testPts_Y=numpy.array([1., 20.])
     169        fitted=F(testPts_X,testPts_Y)
     170
     171        # The fitted value in the trench should be -1000.
     172        assert(fitted[0]==-1000.)
     173
     174        # Find the nearest domain point to the second test point
     175        # This will have been used in constructing the elevation raster
     176        nearest=((domain.centroid_coordinates[:,0]-3.)**2 + (domain.centroid_coordinates[:,1]-20.)**2).argmin()
     177        nearest_x=domain.centroid_coordinates[nearest,0]
     178        assert(numpy.allclose(fitted[1],-nearest_x/150.))
     179
     180        #########################################################################
     181
     182        # This example uses a function, and a raster, to set the quantity           
     183        def f0(x,y):
     184            return x/10.
     185        F=qs.composite_quantity_setting_function([[f0, trenchPoly], ['PointData_ElevTest.tif', 'Extent']],\
     186                                                domain)
     187        fitted=F(testPts_X,testPts_Y)
     188        # Now the fitted value in the trench should be determined by f0
     189        assert(numpy.allclose(fitted[0],50./10.))
     190        # The second test point should be as before
     191        nearest=((domain.centroid_coordinates[:,0]-3.)**2 + (domain.centroid_coordinates[:,1]-20.)**2).argmin()
     192        nearest_x=domain.centroid_coordinates[nearest,0]
     193        assert(numpy.allclose(fitted[1],-nearest_x/150.))
     194
     195        ##########################################################################
     196
     197        # This example uses 'All' as a polygon
     198        F=qs.composite_quantity_setting_function([[f0, 'All'], ['PointData_ElevTest.tif', None]],\
     199                                                domain)
     200        fitted=F(testPts_X,testPts_Y)
     201        # Now the fitted value in the trench should be determined by f0
     202        assert(numpy.allclose(fitted[0],50./10.))
     203        assert(numpy.allclose(fitted[1],3./10.))
     204
     205        ###########################################################################
     206        # This example should fail
     207        try:
     208            F=qs.composite_quantity_setting_function([[f0, 'All'], ['PointData_ElevTest.tif', 'All']],\
     209                                                    domain)
     210            raise Exception, 'The last command should fail'
     211        except:
     212            assert True
     213
     214        return
     215
     216    def test_quantity_from_Pt_Pol_Data_and_Raster(self):
     217        #
     218        #
     219        #
     220        domain=self.create_domain(1.0, 0.0)
     221
     222        # Evolve the model
     223        #for t in domain.evolve(yieldstep=0.2, finaltime=1.0):
     224        #    pass
     225
     226        # Make a raster from the elevation data
     227        from anuga.utilities import plot_utils as util
     228        xs=domain.centroid_coordinates[:,0]+domain.geo_reference.xllcorner
     229        ys=domain.centroid_coordinates[:,1]+domain.geo_reference.yllcorner
     230        elev=domain.quantities['elevation'].centroid_values
     231
     232        allDat=numpy.vstack([xs,ys,elev]).transpose()
     233        util.Make_Geotif(allDat, output_quantities=['ElevTest'], EPSG_CODE=32756,
     234                        output_dir='.', CellSize=1.)
     235
     236        # Make a polygon-point pair which we use to set elevation in a 'channel'
     237        trenchPoly=[[minX+40., minY], [minX+40., minY+100.], [minX+60., minY+100.], [minX+60., minY]]
    164238        trenchPts=numpy.array([minX+50., minY+50., -1000.])
    165239        #
    166240        PtPolData=[[trenchPoly, trenchPts]]
    167         F=qs.elevation_from_Pt_Pol_Data_and_Raster(PtPolData, 'PointData_ElevTest.tif', domain)
     241        F=qs.quantity_from_Pt_Pol_Data_and_Raster(PtPolData, 'PointData_ElevTest.tif', domain)
    168242
    169243        testPts_X=numpy.array([50., 3.])
  • trunk/anuga_core/source/anuga/utilities/test_spatialInputUtil.py

    r9212 r9219  
    2929    def tearDown(self):
    3030        pass
     31
     32    def make_me_a_tif(self):
     33        # We need to make a .tif to test some functions
     34        # This does the job
     35        #
     36        from anuga.utilities import plot_utils as util
     37        #
     38        # Do it with Make_Geotif
     39        # Pick a domain that makes sense in EPSG:32756
     40        x=numpy.linspace(307000., 307100., 101)     
     41        y=numpy.linspace(6193000., 6193100., 101)
     42        xG,yG=numpy.meshgrid(x, y)
     43        xG=xG.flatten()
     44        yG=yG.flatten()
     45        # Surface is z=x+y
     46        fakeZ=xG-min(xG)+yG -min(yG)
     47        dataToGrid=numpy.vstack([xG,yG,fakeZ]).transpose()
     48        #   
     49        util.Make_Geotif(dataToGrid, output_quantities=['TestData'],
     50                         EPSG_CODE=32756, output_dir='.',CellSize=1.0)
    3151   
    3252    def test_compute_square_distance_to_segment(self):
     
    281301        assert(all(pip[:,0]+pip[:,1]>=10.))
    282302
     303
     304    def test_getRasterExtent(self):
     305        self.make_me_a_tif()
     306
     307        extentOut=su.getRasterExtent('PointData_TestData.tif')
     308        assert(numpy.allclose(extentOut[0], 307000.-0.5))
     309        assert(numpy.allclose(extentOut[1], 307100.+0.5))
     310        assert(numpy.allclose(extentOut[2], 6193000.-0.5))
     311        assert(numpy.allclose(extentOut[3], 6193100.+0.5))
     312       
     313        extentOut=su.getRasterExtent('PointData_TestData.tif',asPolygon=True)
     314        assert(numpy.allclose(extentOut[0][0], 307000.-0.5))
     315        assert(numpy.allclose(extentOut[3][0], 307000.-0.5))
     316        assert(numpy.allclose(extentOut[1][0], 307100.+0.5))
     317        assert(numpy.allclose(extentOut[2][0], 307100.+0.5))
     318        assert(numpy.allclose(extentOut[0][1], 6193000.-0.5))
     319        assert(numpy.allclose(extentOut[1][1], 6193000.-0.5))
     320        assert(numpy.allclose(extentOut[2][1], 6193100.+0.5))
     321        assert(numpy.allclose(extentOut[3][1], 6193100.+0.5))
     322
    283323    def test_rasterValuesAtPoints(self):
    284324        # We need to make a .tif to test this function.
    285         from anuga.utilities import plot_utils as util
    286         # Do it with Make_Geotif
    287         # Pick a domain that makes sense in EPSG:32756
    288         x=numpy.linspace(307000., 307100., 101)     
    289         y=numpy.linspace(6193000., 6193100., 101)
    290         xG,yG=numpy.meshgrid(x, y)
    291         xG=xG.flatten()
    292         yG=yG.flatten()
    293         # Surface is z=x+y
    294         fakeZ=xG-min(xG)+yG -min(yG)
    295         dataToGrid=numpy.vstack([xG,yG,fakeZ]).transpose()
    296 
    297         util.Make_Geotif(dataToGrid, output_quantities=['TestData'],
    298                          EPSG_CODE=32756, output_dir='.',CellSize=1.0)
    299 
     325        self.make_me_a_tif()
     326
     327        # Get the range of the tif
     328        tifRange=su.getRasterExtent('PointData_TestData.tif')
    300329
    301330        # Now try to get some point values -- note they will be rounded to the
    302331        # nearest cell
    303         xA=numpy.array([0., 10.3, 50.9, 100.])+x.min()
    304         yA=numpy.array([0., 20.1, 75.1, 100.])+y.min()
    305         z_predicted=numpy.round(xA)+numpy.round(yA)-x.min()-y.min()
     332        xA=numpy.array([0., 10.3, 50.9, 100.])+tifRange[0]+0.5
     333        yA=numpy.array([0., 20.1, 75.1, 100.])+tifRange[2]+0.5
     334        z_predicted=numpy.round(xA)+numpy.round(yA)-tifRange[0]-tifRange[2]-1.0
    306335        InDat=numpy.vstack([xA,yA]).transpose()
    307336        z_fitted=su.rasterValuesAtPoints(InDat, rasterFile='PointData_TestData.tif')
Note: See TracChangeset for help on using the changeset viewer.