def test_2(self):
        #end_point0=[307138.813,6193474]
        #end_point1=[307150.563,6193469]
        end_point0=[10., 5.]
        end_point1=[10., 10.]     
        width = 1
        height = 3.5 
        number_of_barrels=1

        P = create_culvert_polygons(end_point0,
                                    end_point1,
                                    width=width,   
                                    height=height,
                                    number_of_barrels=number_of_barrels)
        
        # Compute area and check that it is greater than 0
        for key1 in ['exchange_polygon0',
                    'exchange_polygon1']:
            polygon = P[key1]
            area = polygon_area(polygon)
            
            msg = 'Polygon %s ' % (polygon)
            msg += ' has area = %f' % area
            assert area > 0.0, msg

            for key2 in ['enquiry_point0', 'enquiry_point1']:
                point = P[key2]
                assert not inside_polygon(point, polygon)                        
Exemplo n.º 2
0
    def test_2(self):
        #end_point0=[307138.813,6193474]
        #end_point1=[307150.563,6193469]
        end_point0 = [10., 5.]
        end_point1 = [10., 10.]
        width = 1
        height = 3.5
        number_of_barrels = 1

        P = create_culvert_polygons(end_point0,
                                    end_point1,
                                    width=width,
                                    height=height,
                                    number_of_barrels=number_of_barrels)

        # Compute area and check that it is greater than 0
        for key1 in ['exchange_polygon0', 'exchange_polygon1']:
            polygon = P[key1]
            area = polygon_area(polygon)

            msg = 'Polygon %s ' % (polygon)
            msg += ' has area = %f' % area
            assert area > 0.0, msg

            for key2 in ['enquiry_point0', 'enquiry_point1']:
                point = P[key2]
                assert not inside_polygon(point, polygon)
Exemplo n.º 3
0
    def setup_indices_polygon(self):

        # Determine indices for polygonal region
        points = self.domain.get_centroid_coordinates(absolute=True)
        vertex_coordinates = self.domain.get_vertex_coordinates(absolute=True)
        
        indices = inside_polygon(points, self.polygon)

        if self.expand_polygon :
            n = len(self.polygon)
            for j in range(n):
                tris_0 = line_intersect(vertex_coordinates,
                                        [self.polygon[j],self.polygon[(j+1)%n]])
                indices = num.union1d(tris_0, indices)            

        if len(indices) is 0:
            self.indices = indices
        else:
            self.indices = num.asarray(indices)

        
        if not self.domain.parallel:
            # only warn if not parallel as we should get lots of subdomains without indices
            if len(indices) is 0:
                msg = 'No centroids found for polygon %s '% str(self.polygon)
                import warnings
                warnings.warn(msg)
Exemplo n.º 4
0
    def setup_indices_polygon(self):

        # Determine indices for polygonal region
        points = self.domain.get_centroid_coordinates(absolute=True)
        vertex_coordinates = self.domain.get_vertex_coordinates(absolute=True)

        indices = inside_polygon(points, self.polygon)

        if self.expand_polygon:
            n = len(self.polygon)
            for j in range(n):
                tris_0 = line_intersect(
                    vertex_coordinates,
                    [self.polygon[j], self.polygon[(j + 1) % n]])
                indices = num.union1d(tris_0, indices)

        if len(indices) == 0:
            self.indices = indices
        else:
            self.indices = num.asarray(indices)

        if not self.domain.parallel:
            # only warn if not parallel as we should get lots of subdomains without indices
            if len(indices) == 0:
                msg = 'No centroids found for polygon %s ' % str(self.polygon)
                import warnings
                warnings.warn(msg)
    def __init__(self, domain, threshold=0.0, polygon=None, verbose=False):

        # Determine indices in update region
        N = domain.get_number_of_triangles()
        points = domain.get_centroid_coordinates(absolute=True)

        indices = inside_polygon(points, polygon)
        self.polygon = polygon

        # It is possible that circle doesn't intersect with mesh (as can happen
        # for parallel runs

        Erosion_operator.__init__(self,
                                  domain,
                                  threshold=threshold,
                                  indices=indices,
                                  verbose=verbose)
Exemplo n.º 6
0
    def compute_triangle_indices(self):


        domain_centroids = self.domain.get_centroid_coordinates(absolute=True)
        vertex_coordinates = self.domain.get_full_vertex_coordinates(absolute=True)


        if self.line: # poly is a line
            self.triangle_indices = line_intersect(vertex_coordinates, self.poly)

        else: # poly is a polygon

            tris_0 = line_intersect(vertex_coordinates, [self.poly[0],self.poly[1]])
            tris_1 = inside_polygon(domain_centroids, self.poly)
            self.triangle_indices = num.union1d(tris_0, tris_1)
            #print self.triangle_indices

        for i in self.triangle_indices:
            assert self.domain.tri_full_flag[i] == 1
Exemplo n.º 7
0
    def compute_triangle_indices(self):

        domain_centroids = self.domain.get_centroid_coordinates(absolute=True)
        vertex_coordinates = self.domain.get_full_vertex_coordinates(
            absolute=True)

        if self.line:  # poly is a line
            self.triangle_indices = line_intersect(vertex_coordinates,
                                                   self.poly)

        else:  # poly is a polygon

            tris_0 = line_intersect(vertex_coordinates,
                                    [self.poly[0], self.poly[1]])
            tris_1 = inside_polygon(domain_centroids, self.poly)
            self.triangle_indices = num.union1d(tris_0, tris_1)
            #print self.triangle_indices

        for i in self.triangle_indices:
            assert self.domain.tri_full_flag[i] == 1
    def __init__(self, domain,
                 threshold=0.0,
                 polygon=None,
                 verbose=False):


        # Determine indices in update region
        N = domain.get_number_of_triangles()
        points = domain.get_centroid_coordinates(absolute=True)


        indices = inside_polygon(points, polygon)
        self.polygon = polygon

        # It is possible that circle doesn't intersect with mesh (as can happen
        # for parallel runs


        Erosion_operator.__init__(self,
                                  domain,
                                  threshold=threshold,
                                  indices=indices,
                                  verbose=verbose)
Exemplo n.º 9
0
    def elevation_setter(xc, yc):

        # Return scipy array of values
        out = xc * 0.

        # Get multiple elevation values in each triangle.
        # Process triangles in chunks to reduce function call overhead
        lx = len(xc)
        lx_div_cs = scipy.ceil(lx * 1. / (1. * chunk_size)).astype(int)

        # Crude check that xc/yc are the centroid values
        #
        erMess = ' Result of make_meanFun can ONLY be applied to a vector' +\
            ' of ALL centroid coordinates\n' +\
            ' (since mesh triangles are used to spatially average)'
        assert scipy.all(xc == domain.centroid_coordinates[:, 0]), erMess
        assert scipy.all(yc == domain.centroid_coordinates[:, 1]), erMess

        # Find triangles in which we want to average
        if polygons_for_averaging is not None:

            averaging_flag = 0 * xc

            # Need georeferenced centroid coordinates to find which
            # are in the polygon
            xll = domain.geo_reference.xllcorner
            yll = domain.geo_reference.yllcorner
            centroid_coordinates_georef = scipy.vstack([xc + xll,
                                                        yc + yll]).transpose()

            for j in range(len(polygons_for_averaging)):
                poly_j = polygons_for_averaging[j]
                # poly_j can either be a polygon, or a filename
                if type(poly_j) is str:
                    poly_j = su.read_polygon(poly_j)

                points_in_poly_j = inside_polygon(centroid_coordinates_georef,
                                                  poly_j)

                averaging_flag[points_in_poly_j] = 1

        else:
            averaging_flag = 1 + 0 * xc

        for i in range(lx_div_cs):
            # Evaluate in triangles lb:ub
            lb = i * chunk_size
            ub = min((i + 1) * chunk_size, lx)

            if verbose:
                print 'Averaging in triangles ', lb, '-', ub - 1

            # Store x,y,triangleIndex
            px = scipy.array([])
            py = scipy.array([])
            p_indices = scipy.array([])

            for j in range(lb, ub):
                # If we average this cell, then get a grid
                # of points in it. Otherwise just get the centroid
                # coordinates.
                if averaging_flag[j] == 1:
                    mesh_tri = \
                        domain.mesh.vertex_coordinates[
                            range(3 * j, 3 * j + 3), :].tolist()

                    pts = su.gridPointsInPolygon(
                        mesh_tri, approx_grid_spacing=approx_grid_spacing)
                else:
                    # Careful to keep this a 2D array
                    pts = domain.centroid_coordinates[j, :, None].transpose()

                px = scipy.hstack([px, pts[:, 0]])

                py = scipy.hstack([py, pts[:, 1]])

                p_indices = scipy.hstack(
                    [p_indices, scipy.repeat(j, len(pts[:, 0]))])

            # Get function values at all px,py
            if verbose:
                print '  Evaluating function at ', len(px), ' points'

            allTopo = q_function(px, py)

            # Set output values in lb:ub
            for j in range(lb, ub):
                out_indices = (p_indices == j).nonzero()[0]
                assert len(out_indices) > 0
                if (averaging == 'mean'):
                    out[j] = allTopo[out_indices].mean()
                elif (averaging == 'min'):
                    out[j] = allTopo[out_indices].min()
                elif (averaging == 'max'):
                    out[j] = allTopo[out_indices].max()
                else:
                    raise Exception('Unknown value of averaging')
        return (out)
Exemplo n.º 10
0
def create_culvert_polygons(end_point0,
                            end_point1, 
                            width, height=None,
                            enquiry_gap_factor=0.2,
                            number_of_barrels=1):
    """Create polygons at the end of a culvert inlet and outlet.
    At either end two polygons will be created; one for the actual flow to pass through and one a little further away
    for enquiring the total energy at both ends of the culvert and transferring flow.

    Input (mandatory):
        end_point0 - one end of the culvert (x,y)
        end_point1 - other end of the culvert (x,y)        
        width - culvert width

    Input (optional):        
        height - culvert height, defaults to width making a square culvert
        enquiry_gap_factor - sets the distance to the enquiry point as fraction of the height
        number_of_barrels - number of identical pipes.
        
    Output:

        Dictionary of four polygons. The dictionary keys are:
            'exchange_polygon0' - polygon defining the flow area at end_point0
            'exchange_polygon1' - polygon defining the flow area at end_point1
            'enquiry_point0' - point beyond exchange_polygon0
            'enquiry_point1' - point beyond exchange_polygon1            
            'vector'
            'length'
            'normal'
    """    


    # Input check
    if height is None:
        height = width

    # Dictionary for calculated polygons
    culvert_polygons = {}
    

    # Calculate geometry
    x0, y0 = end_point0
    x1, y1 = end_point1

    dx = x1-x0
    dy = y1-y0

    vector = num.array([dx, dy])
    length = sqrt(num.sum(vector**2))

    # Adjust polygon width to number of barrels in this culvert
    width *= number_of_barrels
    
    
    # Unit direction vector and normal 
    vector /= length                 # Unit vector in culvert direction
    normal = num.array([-dy, dx])/length # Normal vector
    
    culvert_polygons['vector'] = vector
    culvert_polygons['length'] = length
    culvert_polygons['normal'] = normal    

    # Short hands
    w = 0.5*width*normal # Perpendicular vector of 1/2 width 
    h = height*vector    # Vector of length=height in the
                         # direction of the culvert
    gap = (1 + enquiry_gap_factor)*h 
                         

    # Build exchange polygon and enquiry point for opening 0
    p0 = end_point0 + w
    p1 = end_point0 - w
    p2 = p1 - h
    p3 = p0 - h
    culvert_polygons['exchange_polygon0'] = num.array([p0,p1,p2,p3])
    culvert_polygons['enquiry_point0'] = end_point0 - gap
    

    # Build exchange polygon and enquiry point for opening 1
    p0 = end_point1 + w
    p1 = end_point1 - w
    p2 = p1 + h
    p3 = p0 + h
    culvert_polygons['exchange_polygon1'] = num.array([p0,p1,p2,p3])
    culvert_polygons['enquiry_point1'] = end_point1 + gap  

    # Check that enquiry polygons are outside exchange polygons
    for key1 in ['exchange_polygon0',
                 'exchange_polygon1']:
        polygon = culvert_polygons[key1]
        area = polygon_area(polygon)
        
        msg = 'Polygon %s ' %(polygon)
        msg += ' has area = %f' % area
        assert area > 0.0, msg

        for key2 in ['enquiry_point0', 'enquiry_point1']:
            point = culvert_polygons[key2]
            msg = 'Enquiry point falls inside an enquiry point.'
            msg += 'Email [email protected]'
            assert not inside_polygon(point, polygon), msg

    # Return results
    return culvert_polygons
Exemplo n.º 11
0
def _create_mesh_from_regions(bounding_polygon,
                              boundary_tags,
                              maximum_triangle_area=None,
                              filename=None,                              
                              interior_regions=None,
                              interior_holes=None,
                              hole_tags=None,
                              poly_geo_reference=None,
                              mesh_geo_reference=None,
                              minimum_triangle_angle=28.0,
                              fail_if_polygons_outside=True,
                              breaklines=None,
                              verbose=True,
                              regionPtArea=None):
    """_create_mesh_from_regions - internal function.

    See create_mesh_from_regions for documentation.
    """

    # check the segment indexes - throw an error if they are out of bounds
    if boundary_tags is not None:
        max_points = len(bounding_polygon)
        for key in boundary_tags.keys():
            if len([x for x in boundary_tags[key] if x > max_points-1]) >= 1:
                msg = 'Boundary tag %s has segment out of bounds. '\
                      %(str(key))
                msg += 'Number of points in bounding polygon = %d' % max_points
                raise SegmentError(msg)

        for i in range(max_points):
            found = False
            for tag in boundary_tags:
                if i in boundary_tags[tag]:
                    found = True
            if found is False:
                msg = 'Segment %d was not assigned a boundary_tag.' % i
                msg +=  'Default tag "exterior" will be assigned to missing segment'
                #raise Exception(msg)
                # Fixme: Use proper Python warning
                if verbose: log.critical('WARNING: %s' % msg)
                

    
    #In addition I reckon the polygons could be of class Geospatial_data 
    #(DSG) If polygons were classes caching would break in places.

    # Simple check
    bounding_polygon = ensure_numeric(bounding_polygon, num.float)
    msg = 'Bounding polygon must be a list of points or an Nx2 array'
    assert len(bounding_polygon.shape) == 2, msg
    assert bounding_polygon.shape[1] == 2, msg    

    # 
    if interior_regions is not None:
        
        # Test that all the interior polygons are inside the
        # bounding_poly and throw out those that aren't fully
        # included.  #Note, Both poly's have the same geo_ref,
        # therefore don't take into account # geo_ref


        polygons_inside_boundary = []
        for interior_polygon, res in interior_regions:
            indices = inside_polygon(interior_polygon, bounding_polygon,
                                     closed = True, verbose = False)
    
            if len(indices) <> len(interior_polygon): 
                msg = 'Interior polygon %s is not fully inside'\
                      %(str(interior_polygon))
                msg += ' bounding polygon: %s.' %(str(bounding_polygon))

                if fail_if_polygons_outside is True:
                    raise PolygonError(msg)
                else:
                    msg += ' I will ignore it.'
                    log.critical(msg)

            else:
                polygons_inside_boundary.append([interior_polygon, res])
                
        # Record only those that were fully contained        
        interior_regions = polygons_inside_boundary

            
    
# the following segment of code could be used to Test that all the 
# interior polygons are inside the bounding_poly... however it might need 
# to be change a bit   
#
#count = 0
#for i in range(len(interior_regions)):
#    region = interior_regions[i]
#    interior_polygon = region[0]
#    if len(inside_polygon(interior_polygon, bounding_polygon,
#                   closed = True, verbose = False)) <> len(interior_polygon):
#        print 'WARNING: interior polygon %d is outside bounding polygon' %(i)
#        count += 1

#if count == 0:
#    print 'interior regions OK'
#else:
#    print 'check out your interior polygons'
#    print 'check %s in production directory' %figname
#    import sys; sys.exit()

    if interior_holes is not None:        
        # Test that all the interior polygons are inside the bounding_poly
        for interior_polygon in interior_holes:

            # Test that we have a polygon
            if len(num.array(interior_polygon).flat) < 6:
                msg = 'Interior hole polygon %s has too few (<3) points.\n' \
                    %(str(interior_polygon))
                msg = msg + '(Insure that you have specified a LIST of interior hole polygons)'
                raise PolygonError(msg)
                    
            indices = inside_polygon(interior_polygon, bounding_polygon,
                                     closed = True, verbose = False)

    
            if len(indices) <> len(interior_polygon): 
                msg = 'Interior polygon %s is outside bounding polygon: %s'\
                      %(str(interior_polygon), str(bounding_polygon))
                raise PolygonError(msg)

    # Resolve geo referencing        
    if mesh_geo_reference is None:
        xllcorner = min(bounding_polygon[:,0])
        yllcorner = min(bounding_polygon[:,1])    
        #
        if poly_geo_reference is None:
            zone = DEFAULT_ZONE
        else:
            zone = poly_geo_reference.get_zone()
            [(xllcorner,yllcorner)] = poly_geo_reference.get_absolute( \
            [(xllcorner,yllcorner)])
        # create a geo_ref, based on the llc of the bounding_polygon
        mesh_geo_reference = Geo_reference(xllcorner = xllcorner,
                                           yllcorner = yllcorner,
                                           zone = zone)

    m = Mesh(geo_reference=mesh_geo_reference)

    # build a list of discrete segments from the breakline polygons
    if breaklines is not None:
        points, verts = polylist2points_verts(breaklines)
        m.add_points_and_segments(points, verts)

    # Do bounding polygon
    m.add_region_from_polygon(bounding_polygon,
                              segment_tags=boundary_tags,
                              geo_reference=poly_geo_reference)

    # Find one point inside region automatically
    if interior_regions is not None:
        excluded_polygons = []        
        for polygon, res in interior_regions:
            excluded_polygons.append( polygon )
    else:
        excluded_polygons = None

    # Convert bounding poly to absolute values
    # this sort of thing can be fixed with the geo_points class
    if poly_geo_reference is not None:
        bounding_polygon_absolute = \
            poly_geo_reference.get_absolute(bounding_polygon)
    else:
        bounding_polygon_absolute = bounding_polygon
   
    inner_point = point_in_polygon(bounding_polygon_absolute)
    inner = m.add_region(inner_point[0], inner_point[1])
    inner.setMaxArea(maximum_triangle_area)

    # Do interior regions
#    if interior_regions is not None:    
#        for polygon, res in interior_regions:
#            m.add_region_from_polygon(polygon,
#                                      geo_reference=poly_geo_reference)
#            # convert bounding poly to absolute values
#            if poly_geo_reference is not None:
#                polygon_absolute = \
#                    poly_geo_reference.get_absolute(polygon)
#            else:
#                polygon_absolute = polygon
#            inner_point = point_in_polygon(polygon_absolute)
#            region = m.add_region(inner_point[0], inner_point[1])
#            region.setMaxArea(res)
            
            
    if interior_regions is not None:    
        for polygon, res in interior_regions:
            m.add_region_from_polygon(polygon,
                                      max_triangle_area=res,
                                      geo_reference=poly_geo_reference)
    
            
    # Do interior holes
    if interior_holes is not None:    
        for n, polygon in enumerate(interior_holes):
            try:
                tags = hole_tags[n]
            except:
                tags = {}
            m.add_hole_from_polygon(polygon,
                                    segment_tags=tags,
                                    geo_reference=poly_geo_reference)


    # 22/04/2014
    # Add user-specified point-based regions with max area
    if(regionPtArea is not None):
        for i in range(len(regionPtArea)):
            inner = m.add_region(regionPtArea[i][0], regionPtArea[i][1])
            inner.setMaxArea(regionPtArea[i][2])
        
               


    # NOTE (Ole): This was moved here as it is annoying if mesh is always
    # stored irrespective of whether the computation
    # was cached or not. This caused Domain to
    # recompute as it has meshfile as a dependency

    # Decide whether to store this mesh or return it 
    
    
    if filename is None:
        return m
    else:
        if verbose: log.critical("Generating mesh to file '%s'" % filename)
      
        m.generate_mesh(minimum_triangle_angle=minimum_triangle_angle,
                        verbose=verbose)
        m.export_mesh_file(filename)

        return m
Exemplo n.º 12
0
def get_maximum_inundation_data(filename, polygon=None, time_interval=None,
                                use_centroid_values=True,
                                verbose=False):
    """Compute maximum run up height from sww file.

    filename             path to SWW file to read
    polygon              if specified resrict to points inside this polygon
                         assumed absolute coordinates and in same zone as
                         domain
    time_interval        if specified resrict to within the period specified
    use_centroid_values 
    verbose              True if this function is to be verbose

    Returns (maximal_runup, maximal_runup_location).

    Usage:
    runup, location = get_maximum_inundation_data(filename,
                                                  polygon=None,
                                                  time_interval=None,
                                                  verbose=False)

    Algorithm is as in get_maximum_inundation_elevation from
    shallow_water_domain except that this function works with the SWW file and
    computes the maximal runup height over multiple timesteps.

    If no inundation is found within polygon and time_interval the return value
    is None signifying "No Runup" or "Everything is dry".
    """

    # We are using nodal values here as that is what is stored in sww files.

    # Water depth below which it is considered to be 0 in the model
    # FIXME (Ole): Allow this to be specified as a keyword argument as well

    from anuga.geometry.polygon import inside_polygon
    from anuga.config import minimum_allowed_height
    from anuga.file.netcdf import NetCDFFile

    dir, base = os.path.split(filename)

    iterate_over = get_all_swwfiles(dir, base)

    if verbose:
        print iterate_over
        
    # Read sww file
    if verbose: log.critical('Reading from %s' % filename)
    # FIXME: Use general swwstats (when done)

    maximal_runup = None
    maximal_runup_location = None

    for _, swwfile in enumerate (iterate_over):
        # Read sww file
        filename = os.path.join(dir, swwfile+'.sww')

        if verbose: log.critical('Reading from %s' % filename)
        # FIXME: Use general swwstats (when done)

        fid = NetCDFFile(filename)

        # Get geo_reference
        # sww files don't have to have a geo_ref
        try:
            geo_reference = Geo_reference(NetCDFObject=fid)
        except AttributeError:
            geo_reference = Geo_reference() # Default georef object

        xllcorner = geo_reference.get_xllcorner()
        yllcorner = geo_reference.get_yllcorner()

        # Get extent
        volumes = fid.variables['volumes'][:]
        x = fid.variables['x'][:] + xllcorner
        y = fid.variables['y'][:] + yllcorner

        # Get the relevant quantities (Convert from single precison)
        elevation = num.array(fid.variables['elevation'][:], num.float)
        stage = num.array(fid.variables['stage'][:], num.float)

        if verbose:
            print 'stage.shape ',stage.shape
            print 'elevation.shape ',elevation.shape
            
        # Here's where one could convert nodal information to centroid
        # information but is probably something we need to write in C.
        # Here's a Python thought which is NOT finished!!!
        if use_centroid_values is True:
            vols0=volumes[:,0]
            vols1=volumes[:,1]
            vols2=volumes[:,2]
            # Then use these to compute centroid averages 
            x=(x[vols0]+x[vols1]+x[vols2])/3.0
            y=(y[vols0]+y[vols1]+y[vols2])/3.0

            elevation=(elevation[vols0]+elevation[vols1]+elevation[vols2])/3.0
            stage=(stage[:,vols0]+stage[:,vols1]+stage[:,vols2])/3.0

        # Spatial restriction
        if polygon is not None:
            msg = 'polygon must be a sequence of points.'
            assert len(polygon[0]) == 2, msg
            # FIXME (Ole): Make a generic polygon input check in polygon.py
            # and call it here
            points = num.ascontiguousarray(num.concatenate((x[:, num.newaxis],
                                                            y[:, num.newaxis]),
                                                            axis=1))
            point_indices = inside_polygon(points, polygon)

            # Restrict quantities to polygon
            elevation = num.take(elevation, point_indices, axis=0)
            stage = num.take(stage, point_indices, axis=1)

            # Get info for location of maximal runup
            points_in_polygon = num.take(points, point_indices, axis=0)

            x = points_in_polygon[:,0]
            y = points_in_polygon[:,1]
        else:
            # Take all points
            point_indices = num.arange(len(x))

        # Temporal restriction
        time = fid.variables['time'][:]
        if verbose:
            print time
        all_timeindices = num.arange(len(time))
        if time_interval is not None:
            msg = 'time_interval must be a sequence of length 2.'
            assert len(time_interval) == 2, msg
            msg = 'time_interval %s must not be decreasing.' % time_interval
            assert time_interval[1] >= time_interval[0], msg
            msg = 'Specified time interval [%.8f:%.8f] ' % tuple(time_interval)
            msg += 'must does not match model time interval: [%.8f, %.8f]\n' \
                   % (time[0], time[-1])
            if time_interval[1] < time[0]:
                fid.close()
                raise ValueError(msg)
            if time_interval[0] > time[-1]:
                fid.close()
                raise ValueError(msg)

            # Take time indices corresponding to interval (& is bitwise AND)
            timesteps = num.compress((time_interval[0] <= time) \
                                     & (time <= time_interval[1]),
                                     all_timeindices)

            msg = 'time_interval %s did not include any model timesteps.' \
                  % time_interval
            assert not num.alltrue(timesteps == 0), msg
        else:
            # Take them all
            timesteps = all_timeindices

        fid.close()

        # Compute maximal runup for each timestep
        #maximal_runup = None
        #maximal_runup_location = None
        #maximal_runups = [None]
        #maximal_runup_locations = [None]



            
        for i in timesteps:
            ## if use_centroid_values is True:
            ##     stage_i  = stage[i,:]
            ## else:
            ##     stage_i = stage[i,:]

            stage_i = stage[i,:]
            depth = stage_i - elevation

            if verbose:
                print '++++++++'
            # Get wet nodes i.e. nodes with depth>0 within given region
            # and timesteps
            wet_nodes = num.where(depth > 0.0)[0]


            if verbose:
                print stage_i.shape
                print num.max(stage_i)
                #print max(wet_elevation)


            if num.alltrue(wet_nodes == 0):
                runup = None
            else:
                # Find maximum elevation among wet nodes
                wet_elevation = num.take(elevation, wet_nodes, axis=0)


                if verbose:
                    pass
                    #print wet_elevation
                    
                runup_index = num.argmax(wet_elevation)
                runup = max(wet_elevation)
                if verbose:
                    print 'max(wet_elevation) ',max(wet_elevation)
                assert wet_elevation[runup_index] == runup       # Must be True

            if runup > maximal_runup:
                maximal_runup = runup      # works even if maximal_runup is None

                # Record location
                wet_x = num.take(x, wet_nodes, axis=0)
                wet_y = num.take(y, wet_nodes, axis=0)
                maximal_runup_location =    [wet_x[runup_index], \
                                            wet_y[runup_index]]
            if verbose:
                print i, runup

    return maximal_runup, maximal_runup_location
Exemplo n.º 13
0
    def __init__(self,
                 domain,
                 quantity_name,
                 rate=0.0,
                 center=None,
                 radius=None,
                 polygon=None,
                 default_rate=None,
                 verbose=False):

        from math import pi, cos, sin

        if domain.numproc > 1:
            msg = 'Not implemented to run in parallel'
            assert self.parallel_safe(), msg

        if center is None:
            msg = 'I got radius but no center.'
            assert radius is None, msg

        if radius is None:
            msg += 'I got center but no radius.'
            assert center is None, msg

        self.domain = domain
        self.quantity_name = quantity_name
        self.rate = rate
        self.center = ensure_numeric(center)
        self.radius = radius
        self.polygon = polygon
        self.verbose = verbose
        self.value = 0.0    # Can be used to remember value at
                            # previous timestep in order to obtain rate

        # Get boundary (in absolute coordinates)
        bounding_polygon = domain.get_boundary_polygon()

        # Update area if applicable
        if center is not None and radius is not None:
            assert len(center) == 2
            msg = 'Polygon cannot be specified when center and radius are'
            assert polygon is None, msg

            # Check that circle center lies within the mesh.
            msg = 'Center %s specified for forcing term did not' % str(center)
            msg += 'fall within the domain boundary.'
            assert is_inside_polygon(center, bounding_polygon), msg

            # Check that circle periphery lies within the mesh.
            N = 100
            periphery_points = []
            for i in range(N):
                theta = 2*pi*i/100

                x = center[0] + radius*cos(theta)
                y = center[1] + radius*sin(theta)

                periphery_points.append([x,y])

            for point in periphery_points:
                msg = 'Point %s on periphery for forcing term' % str(point)
                msg += ' did not fall within the domain boundary.'
                assert is_inside_polygon(point, bounding_polygon), msg

        if polygon is not None:
            # Check that polygon lies within the mesh.
            for point in self.polygon:
                msg = 'Point %s in polygon for forcing term' % str(point)
                msg += ' did not fall within the domain boundary.'
                assert is_inside_polygon(point, bounding_polygon), msg

        # Pointer to update vector
        self.update = domain.quantities[self.quantity_name].explicit_update

        # Determine indices in flow area
        N = len(domain)
        points = domain.get_centroid_coordinates(absolute=True)

        # Calculate indices in exchange area for this forcing term
        self.exchange_indices = None
        if self.center is not None and self.radius is not None:
            # Inlet is circular
            inlet_region = 'center=%s, radius=%s' % (self.center, self.radius)

            self.exchange_indices = []
            for k in range(N):
                x, y = points[k,:]    # Centroid

                c = self.center
                if ((x-c[0])**2+(y-c[1])**2) < self.radius**2:
                    self.exchange_indices.append(k)

        if self.polygon is not None:
            # Inlet is polygon
            self.exchange_indices = inside_polygon(points, self.polygon)

        if self.exchange_indices is None:
            self.exchange_area = polygon_area(bounding_polygon)
        else:    
            if len(self.exchange_indices) == 0:
                msg = 'No triangles have been identified in '
                msg += 'specified region: %s' % inlet_region
                raise Exception(msg)

            # Compute exchange area as the sum of areas of triangles identified
            # by circle or polygon
            self.exchange_area = 0.0
            for i in self.exchange_indices:
                self.exchange_area += domain.areas[i]
            

        msg = 'Exchange area in forcing term'
        msg += ' has area = %f' %self.exchange_area
        assert self.exchange_area > 0.0            
            
                

            
        # Check and store default_rate
        msg = ('Keyword argument default_rate must be either None '
               'or a function of time.\nI got %s.' % str(default_rate))
        assert (default_rate is None or
                isinstance(default_rate, (int, float)) or
                callable(default_rate)), msg

        if default_rate is not None:
            # If it is a constant, make it a function
            if not callable(default_rate):
                tmp = default_rate
                default_rate = lambda t: tmp

            # Check that default_rate is a function of one argument
            try:
                default_rate(0.0)
            except:
                raise Exception(msg)

        self.default_rate = default_rate
        self.default_rate_invoked = False    # Flag
Exemplo n.º 14
0
def get_maximum_inundation_data(filename,
                                polygon=None,
                                time_interval=None,
                                use_centroid_values=True,
                                return_time=False,
                                verbose=False):
    """Compute maximum run up height from sww file.

    filename             path to SWW file to read
    polygon              if specified resrict to points inside this polygon
                         assumed absolute coordinates and in same zone as
                         domain
    time_interval        if specified resrict to within the period specified
    use_centroid_values 
    verbose              True if this function is to be verbose

    Returns (maximal_runup, maximal_runup_location).

    Usage:
    runup, location = get_maximum_inundation_data(filename,
                                                  polygon=None,
                                                  time_interval=None,
                                                  verbose=False)

    Algorithm is as in get_maximum_inundation_elevation from
    shallow_water_domain except that this function works with the SWW file and
    computes the maximal runup height over multiple timesteps.

    If no inundation is found within polygon and time_interval the return value
    is None signifying "No Runup" or "Everything is dry".
    """

    # We are using nodal values here as that is what is stored in sww files.

    # Water depth below which it is considered to be 0 in the model
    # FIXME (Ole): Allow this to be specified as a keyword argument as well

    from anuga.geometry.polygon import inside_polygon
    from anuga.config import minimum_allowed_height
    from anuga.file.netcdf import NetCDFFile

    # Just find max inundation over one file
    dir, base = os.path.split(filename)
    #iterate_over = get_all_swwfiles(dir, base)
    iterate_over = [filename[:-4]]
    if verbose:
        print iterate_over

    # Read sww file
    if verbose: log.critical('Reading from %s' % filename)
    # FIXME: Use general swwstats (when done)

    maximal_runup = None
    maximal_runup_location = None
    maximal_time = None

    for _, swwfile in enumerate(iterate_over):
        # Read sww file
        filename = os.path.join(dir, swwfile + '.sww')

        if verbose: log.critical('Reading from %s' % filename)
        # FIXME: Use general swwstats (when done)

        fid = NetCDFFile(filename)

        # Get geo_reference
        # sww files don't have to have a geo_ref
        try:
            geo_reference = Geo_reference(NetCDFObject=fid)
        except AttributeError:
            geo_reference = Geo_reference()  # Default georef object

        xllcorner = geo_reference.get_xllcorner()
        yllcorner = geo_reference.get_yllcorner()

        # Get extent
        volumes = fid.variables['volumes'][:]
        x = fid.variables['x'][:] + xllcorner
        y = fid.variables['y'][:] + yllcorner

        # Get the relevant quantities (Convert from single precison)
        try:
            elevation = num.array(fid.variables['elevation_c'][:], num.float)
            stage = num.array(fid.variables['stage_c'][:], num.float)
            found_c_values = True
        except:
            elevation = num.array(fid.variables['elevation'][:], num.float)
            stage = num.array(fid.variables['stage'][:], num.float)
            found_c_values = False

        if verbose:
            print 'found c values ', found_c_values
            print 'stage.shape ', stage.shape
            print 'elevation.shape ', elevation.shape

        # Here's where one could convert nodal information to centroid
        # information but is probably something we need to write in C.
        # Here's a Python thought which is NOT finished!!!
        if use_centroid_values is True:
            vols0 = volumes[:, 0]
            vols1 = volumes[:, 1]
            vols2 = volumes[:, 2]
            # Then use these to compute centroid location
            x = (x[vols0] + x[vols1] + x[vols2]) / 3.0
            y = (y[vols0] + y[vols1] + y[vols2]) / 3.0

            if found_c_values:
                # don't have to do anything as found in sww file
                pass
            else:
                elevation = (elevation[vols0] + elevation[vols1] +
                             elevation[vols2]) / 3.0
                stage = (stage[:, vols0] + stage[:, vols1] +
                         stage[:, vols2]) / 3.0

        # Spatial restriction
        if polygon is not None:
            msg = 'polygon must be a sequence of points.'
            assert len(polygon[0]) == 2, msg
            # FIXME (Ole): Make a generic polygon input check in polygon.py
            # and call it here
            points = num.ascontiguousarray(
                num.concatenate((x[:, num.newaxis], y[:, num.newaxis]),
                                axis=1))
            point_indices = inside_polygon(points, polygon)

            # Restrict quantities to polygon
            elevation = num.take(elevation, point_indices, axis=0)
            stage = num.take(stage, point_indices, axis=1)

            # Get info for location of maximal runup
            points_in_polygon = num.take(points, point_indices, axis=0)
            x = points_in_polygon[:, 0]
            y = points_in_polygon[:, 1]
        else:
            # Take all points
            point_indices = num.arange(len(x))

        # Temporal restriction
        time = fid.variables['time'][:]
        if verbose:
            print time
        all_timeindices = num.arange(len(time))

        if time_interval is not None:
            msg = 'time_interval must be a sequence of length 2.'
            assert len(time_interval) == 2, msg
            msg = 'time_interval %s must not be decreasing.' % time_interval
            assert time_interval[1] >= time_interval[0], msg
            msg = 'Specified time interval [%.8f:%.8f] ' % tuple(time_interval)
            msg += 'must does not match model time interval: [%.8f, %.8f]\n' \
                   % (time[0], time[-1])
            if time_interval[1] < time[0]:
                fid.close()
                raise ValueError(msg)
            if time_interval[0] > time[-1]:
                fid.close()
                raise ValueError(msg)

            # Take time indices corresponding to interval (& is bitwise AND)
            timesteps = num.compress((time_interval[0] <= time) \
                                     & (time <= time_interval[1]),
                                     all_timeindices)

            msg = 'time_interval %s did not include any model timesteps.' \
                  % time_interval
            assert not num.alltrue(timesteps == 0), msg
        else:
            # Take them all
            timesteps = all_timeindices

        #print timesteps

        fid.close()

        # Compute maximal runup for each timestep
        #maximal_runup = None
        #maximal_runup_location = None
        #maximal_runups = [None]
        #maximal_runup_locations = [None]

        for i in timesteps:
            ## if use_centroid_values is True:
            ##     stage_i  = stage[i,:]
            ## else:
            ##     stage_i = stage[i,:]

            stage_i = stage[i, :]
            depth = stage_i - elevation

            if verbose:
                print '++++++++'
            # Get wet nodes i.e. nodes with depth>0 within given region
            # and timesteps
            wet_nodes = num.where(depth > 0.0)[0]

            if verbose:
                print stage_i.shape
                print num.max(stage_i)
                #print max(wet_elevation)

            if num.alltrue(wet_nodes == 0):
                runup = None
            else:
                # Find maximum elevation among wet nodes
                wet_elevation = num.take(elevation, wet_nodes, axis=0)

                if verbose:
                    pass
                    #print wet_elevation

                runup_index = num.argmax(wet_elevation)
                runup = max(wet_elevation)
                if verbose:
                    print 'max(wet_elevation) ', max(wet_elevation)
                assert wet_elevation[runup_index] == runup  # Must be True

            if runup > maximal_runup:
                maximal_runup = runup  # works even if maximal_runup is None
                maximal_time = time[i]

                # Record location
                wet_x = num.take(x, wet_nodes, axis=0)
                wet_y = num.take(y, wet_nodes, axis=0)
                maximal_runup_location =    [wet_x[runup_index], \
                                            wet_y[runup_index]]
            if verbose:
                print i, runup

    if return_time:
        return maximal_runup, maximal_runup_location, maximal_time
    else:
        return maximal_runup, maximal_runup_location
Exemplo n.º 15
0
    def F(x, y):
        """This is the function returned by composite_quantity_setting_function
           It can be passed to set_quantity
        """
        isSet = numpy.zeros(len(x))  # 0/1 - record if each point has been set
        quantityVal = x * 0 + numpy.nan  # Function return value

        # Record points which evaluated to nan on their first preference
        # dataset.
        was_ever_nan = (x * 0).astype(int)

        lpf = len(poly_fun_pairs)
        if (lpf <= 0):
            raise Exception('Must have at least 1 fun-poly-pair')

        # Make an array of 'transformed' spatial coordinates, for checking
        # polygon inclusion
        xll = domain.geo_reference.xllcorner
        yll = domain.geo_reference.yllcorner
        xy_array_trans = numpy.vstack([x + xll, y + yll]).transpose()

        # Check that none of the pi polygons [except perhaps the last] is 'All'
        for i in range(lpf - 1):
            if (poly_fun_pairs[i][0] == 'All'):
                # This is only ok if all the othe poly_fun_pairs are None
                remaining_poly_fun_pairs_are_None = \
                    [poly_fun_pairs[j][0] is None for j in range(i+1,lpf)]
                if (not all(remaining_poly_fun_pairs_are_None)):
                    raise Exception('Can only have the last polygon = All')

        # Main Loop
        # Apply the fi inside the pi
        for i in range(lpf):
            fi = poly_fun_pairs[i][1]  # The function
            pi = poly_fun_pairs[i][0]  # The polygon

            # Quick exit
            if (pi is None):
                continue

            ###################################################################
            # Get indices fInds of points in polygon pi which are not already
            # set
            ###################################################################
            if (pi == 'All'):
                # Get all unset points
                fInside = (1 - isSet)
                fInds = (fInside == 1).nonzero()[0]

            else:

                if (pi == 'Extent'):
                    # Here fi MUST be a gdal-compatible raster
                    if (not (type(fi) == str)):
                        msg = ' pi = "Extent" can only be used when fi is a' +\
                              ' raster file name'
                        raise Exception(msg)

                    if (not os.path.exists(fi)):
                        msg = 'fi ' + str(fi) + ' is supposed to be a ' +\
                              ' raster filename, but it could not be found'
                        raise Exception(msg)

                    # Then we get the extent from the raster itself
                    pi_path = su.getRasterExtent(fi, asPolygon=True)

                    if verbose:
                        print 'Extracting extent from raster: ', fi
                        print 'Extent: ', pi_path

                elif ((type(pi) == str) and os.path.isfile(pi)):
                    # pi is a file
                    pi_path = su.read_polygon(pi)

                else:
                    # pi is the actual polygon data
                    pi_path = pi

                # Get the insides of unset points inside pi_path
                notSet = (isSet == 0.).nonzero()[0]
                fInds = inside_polygon(xy_array_trans[notSet, :], pi_path)
                fInds = notSet[fInds]

            if len(fInds) == 0:
                # No points found, move on
                continue

            ###################################################################
            # Evaluate fi at the points inside pi
            ###################################################################

            # We use various tricks to infer whether fi is a function,
            # a constant, a file (raster or csv), or an array
            if (hasattr(fi, '__call__')):
                # fi is a function
                quantityVal[fInds] = fi(x[fInds], y[fInds])

            elif isinstance(fi, (int, long, float)):
                # fi is a numerical constant
                quantityVal[fInds] = fi * 1.0

            elif (type(fi) is str and os.path.exists(fi)):
                # fi is a file which is assumed to be
                # a gdal-compatible raster OR an x,y,z elevation file
                if os.path.splitext(fi)[1] in ['.txt', '.csv']:
                    fi_array = su.read_csv_optional_header(fi)
                    # Check the results
                    if fi_array.shape[1] is not 3:
                        print 'Treated input file ' + fi +\
                              ' as xyz array with an optional header'
                        msg = 'Array should have 3 columns -- x,y,value'
                        raise Exception(msg)

                    newfi = make_nearestNeighbour_quantity_function(
                        fi_array,
                        domain,
                        k_nearest_neighbours=default_k_nearest_neighbours)
                    quantityVal[fInds] = newfi(x[fInds], y[fInds])

                else:
                    # Treating input file as a raster
                    newfi = quantityRasterFun(
                        domain, fi, interpolation=default_raster_interpolation)
                    quantityVal[fInds] = newfi(x[fInds], y[fInds])

            elif (type(fi) is numpy.ndarray):
                if fi.shape[1] is not 3:
                    msg = 'Array should have 3 columns -- x,y,value'
                    raise Exception(msg)
                newfi = make_nearestNeighbour_quantity_function(
                    fi,
                    domain,
                    k_nearest_neighbours=default_k_nearest_neighbours)
                quantityVal[fInds] = newfi(x[fInds], y[fInds])

            else:
                print 'Error with function from'
                print fi
                msg = 'Cannot make function from type ' + str(type(fi))
                raise Exception, msg

            ###################################################################
            # Check for nan values
            ###################################################################
            #nan_flag = (quantityVal[fInds] != quantityVal[fInds])
            nan_flag = 1 * numpy.isnan(quantityVal[fInds])
            nan_inds = nan_flag.nonzero()[0]
            was_ever_nan[fInds[nan_inds]] = 1

            if len(nan_inds) > 0:
                if nan_treatment == 'exception':
                    msg = 'nan values generated by the poly_fun_pair at '\
                          'index ' + str(i) + ' '\
                          'in composite_quantity_setting_function. ' + \
                          'To allow these values to be set by later ' + \
                          'poly_fun pairs, pass the argument ' + \
                          'nan_treatment="fall_through" ' + \
                          'to composite_quantity_setting_function'
                    raise Exception(msg)

                elif nan_treatment == 'fall_through':
                    msg = 'WARNING: nan values generated by the ' + \
                          'poly_fun_pair at index ' + str(i) + ' '\
                          'in composite_quantity_setting_function. ' + \
                          'They will be passed to later poly_fun_pairs'
                    if verbose: print msg
                    not_nan_inds = (1 - nan_flag).nonzero()[0]

                    if len(not_nan_inds) > 0:
                        fInds = fInds[not_nan_inds]
                    else:
                        # All values are nan
                        msg = '( Actually all the values were nan - ' + \
                              'Are you sure they should be? Possible error?)'
                        if verbose: print msg
                        continue

                else:
                    msg = 'Found nan values in ' + \
                          'composite_quantity_setting_function but ' + \
                          'nan_treatment is not a recognized value'
                    raise Exception(msg)

            # Record that the points have been set
            isSet[fInds] = 1

            # Enforce clip_range
            if clip_range is not None:
                lower_bound = clip_range[i][0]
                upper_bound = clip_range[i][1]
                quantityVal[fInds] = numpy.maximum(quantityVal[fInds],
                                                   lower_bound)
                quantityVal[fInds] = numpy.minimum(quantityVal[fInds],
                                                   upper_bound)

        # End of loop

        # Find points which were nan on their first preference dataset + are
        # inside nan_interpolation_region_polygon. Then reinterpolate their
        # values from the other x,y, quantityVal points.
        if (nan_interpolation_region_polygon is not None) &\
           (was_ever_nan.sum() > 0):
            if nan_interpolation_region_polygon == 'All':
                points_to_reinterpolate = was_ever_nan.nonzero()[0]
            else:
                # nan_interpolation_region_polygon contains information on 1 or
                # more polygons
                # Inside those polygons, we need to re-interpolate points which
                # first evaluted to na
                possible_points_to_reint = was_ever_nan.nonzero()[0]
                points_to_reinterpolate = numpy.array([]).astype(int)

                for i in range(len(nan_interpolation_region_polygon)):
                    nan_pi = nan_interpolation_region_polygon[i]

                    # Ensure nan_pi = list of x,y points making a polygon
                    if (type(nan_pi) == str):
                        nan_pi = su.read_polygon(nan_pi)

                    points_in_nan_pi = inside_polygon(
                        xy_array_trans[possible_points_to_reint, :], nan_pi)

                    if len(points_in_nan_pi) > 0:
                        points_to_reinterpolate = numpy.hstack([
                            points_to_reinterpolate,
                            possible_points_to_reint[points_in_nan_pi]
                        ])

            if verbose:
                print 'Re-interpolating ', len(points_to_reinterpolate),\
                      ' points which were nan under their',\
                      ' first-preference and are inside the',\
                      ' nan_interpolation_region_polygon'

            if len(points_to_reinterpolate) > 0:
                msg = 'WARNING: nan interpolation is being applied. This ',\
                      'should be done in serial prior to distributing the ',\
                      'domain, as there is no parallel communication ',\
                      'implemented yet [so parallel results might depend on ',\
                      'the number of processes]'
                if verbose:
                    print msg

            # Find the interpolation points = points not needing reinterpolation
            ip = x * 0 + 1
            ip[points_to_reinterpolate] = 0
            number_of_ip = ip.sum()
            ip = ip.nonzero()[0]

            # Check that none of the ip points has an nan value
            nan_ip = (quantityVal[ip] != quantityVal[ip]).nonzero()[0]

            if len(nan_ip) > 0:
                print 'There are ', len(nan_ip), ' points outside the ',\
                      'nan_interpolation_region_polygon have nan values.'
                print 'The user should ensure this does not happen.'
                print 'The points have the following coordinates:'
                print xy_array_trans[ip[nan_ip], :]
                msg = "There are nan points outside of " +\
                      "nan_interpolation_region_polygon, even after all " +\
                      "fall-through's"
                raise Exception(msg)

            if (number_of_ip < default_k_nearest_neighbours):
                raise Exception('Too few non-nan points to interpolate from')

            # Make function for re-interpolation. Note this requires
            # x,y,z in georeferenced coordinates, whereas x,y are ANUGA
            # coordinates
            reinterp_F = make_nearestNeighbour_quantity_function(
                numpy.vstack([
                    xy_array_trans[ip, 0], xy_array_trans[ip, 1],
                    quantityVal[ip]
                ]).transpose(),
                domain,
                k_nearest_neighbours=default_k_nearest_neighbours)

            # re-interpolate
            quantityVal[points_to_reinterpolate] = reinterp_F(
                x[points_to_reinterpolate], y[points_to_reinterpolate])

            isSet[points_to_reinterpolate] = 1

        # Check there are no remaining nan values
        if (min(isSet) != 1):
            print 'Some points remain as nan, which is not allowed'
            unset_inds = (isSet != 1).nonzero()[0]
            lui = min(5, len(unset_inds))
            print 'There are ', len(unset_inds), ' such points'
            print 'Here are a few:'
            for i in range(lui):
                print x[unset_inds[i]] + xll, y[unset_inds[i]] + yll
            raise Exception('It seems the input data needs to be fixed')

        return quantityVal
    def elevation_setter(xc, yc):

        # Return scipy array of values
        out = xc * 0.

        # Get multiple elevation values in each triangle.
        # Process triangles in chunks to reduce function call overhead
        lx = len(xc)
        lx_div_cs = scipy.ceil(lx * 1. / (1. * chunk_size)).astype(int)

        # Crude check that xc/yc are the centroid values
        #
        erMess = ' Result of make_meanFun can ONLY be applied to a vector' +\
            ' of ALL centroid coordinates\n' +\
            ' (since mesh triangles are used to spatially average)'
        assert scipy.all(xc == domain.centroid_coordinates[:, 0]), erMess
        assert scipy.all(yc == domain.centroid_coordinates[:, 1]), erMess

        # Find triangles in which we want to average
        if polygons_for_averaging is not None:

            averaging_flag = 0*xc

            # Need georeferenced centroid coordinates to find which
            # are in the polygon
            xll = domain.geo_reference.xllcorner
            yll = domain.geo_reference.yllcorner
            centroid_coordinates_georef = scipy.vstack([xc + xll, yc + yll]).transpose()

            for j in range(len(polygons_for_averaging)):
                poly_j = polygons_for_averaging[j]
                # poly_j can either be a polygon, or a filename
                if type(poly_j) is str:
                    poly_j = su.read_polygon(poly_j)
                
                points_in_poly_j = inside_polygon(centroid_coordinates_georef, 
                    poly_j)
                
                averaging_flag[points_in_poly_j] = 1
                
        else:
            averaging_flag = 1 + 0*xc
        

        for i in range(lx_div_cs):
            # Evaluate in triangles lb:ub
            lb = i * chunk_size
            ub = min((i + 1) * chunk_size, lx)

            if verbose:
                print 'Averaging in triangles ', lb, '-', ub - 1

            # Store x,y,triangleIndex
            px = scipy.array([])
            py = scipy.array([])
            p_indices = scipy.array([])

            for j in range(lb, ub):
                # If we average this cell, then get a grid
                # of points in it. Otherwise just get the centroid
                # coordinates. 
                if averaging_flag[j] == 1:
                    mesh_tri = \
                        domain.mesh.vertex_coordinates[
                            range(3 * j, 3 * j + 3), :].tolist()

                    pts = su.gridPointsInPolygon(
                        mesh_tri,
                        approx_grid_spacing=approx_grid_spacing)
                else:
                    # Careful to keep this a 2D array
                    pts = domain.centroid_coordinates[j,:, None].transpose()

                px = scipy.hstack([px, pts[:, 0]])

                py = scipy.hstack([py, pts[:, 1]])

                p_indices = scipy.hstack([p_indices,
                                          scipy.repeat(j, len(pts[:, 0]))])

            # Get function values at all px,py
            if verbose:
                print '  Evaluating function at ', len(px), ' points'

            allTopo = q_function(px, py)

            # Set output values in lb:ub
            for j in range(lb, ub):
                out_indices = (p_indices == j).nonzero()[0]
                assert len(out_indices) > 0
                if(averaging == 'mean'):
                    out[j] = allTopo[out_indices].mean()
                elif(averaging == 'min'):
                    out[j] = allTopo[out_indices].min()
                elif(averaging == 'max'):
                    out[j] = allTopo[out_indices].max()
                else:
                    raise Exception('Unknown value of averaging')
        return(out)
Exemplo n.º 17
0
def _create_mesh_from_regions(bounding_polygon,
                              boundary_tags,
                              maximum_triangle_area=None,
                              filename=None,
                              interior_regions=None,
                              interior_holes=None,
                              hole_tags=None,
                              poly_geo_reference=None,
                              mesh_geo_reference=None,
                              minimum_triangle_angle=28.0,
                              fail_if_polygons_outside=True,
                              breaklines=None,
                              verbose=True,
                              regionPtArea=None):
    """_create_mesh_from_regions - internal function.

    See create_mesh_from_regions for documentation.
    """

    # check the segment indexes - throw an error if they are out of bounds
    if boundary_tags is not None:
        max_points = len(bounding_polygon)
        for key in boundary_tags.keys():
            if len([x for x in boundary_tags[key] if x > max_points - 1]) >= 1:
                msg = 'Boundary tag %s has segment out of bounds. '\
                      %(str(key))
                msg += 'Number of points in bounding polygon = %d' % max_points
                raise SegmentError(msg)

        for i in range(max_points):
            found = False
            for tag in boundary_tags:
                if i in boundary_tags[tag]:
                    found = True
            if found is False:
                msg = 'Segment %d was not assigned a boundary_tag.' % i
                msg += 'Default tag "exterior" will be assigned to missing segment'
                #raise Exception(msg)
                # Fixme: Use proper Python warning
                if verbose: log.critical('WARNING: %s' % msg)

    #In addition I reckon the polygons could be of class Geospatial_data
    #(DSG) If polygons were classes caching would break in places.

    # Simple check
    bounding_polygon = ensure_numeric(bounding_polygon, num.float)
    msg = 'Bounding polygon must be a list of points or an Nx2 array'
    assert len(bounding_polygon.shape) == 2, msg
    assert bounding_polygon.shape[1] == 2, msg

    #
    if interior_regions is not None:

        # Test that all the interior polygons are inside the
        # bounding_poly and throw out those that aren't fully
        # included.  #Note, Both poly's have the same geo_ref,
        # therefore don't take into account # geo_ref

        polygons_inside_boundary = []
        for interior_polygon, res in interior_regions:
            indices = inside_polygon(interior_polygon,
                                     bounding_polygon,
                                     closed=True,
                                     verbose=False)

            if len(indices) <> len(interior_polygon):
                msg = 'Interior polygon %s is not fully inside'\
                      %(str(interior_polygon))
                msg += ' bounding polygon: %s.' % (str(bounding_polygon))

                if fail_if_polygons_outside is True:
                    raise PolygonError(msg)
                else:
                    msg += ' I will ignore it.'
                    log.critical(msg)

            else:
                polygons_inside_boundary.append([interior_polygon, res])

        # Record only those that were fully contained
        interior_regions = polygons_inside_boundary

# the following segment of code could be used to Test that all the
# interior polygons are inside the bounding_poly... however it might need
# to be change a bit
#
#count = 0
#for i in range(len(interior_regions)):
#    region = interior_regions[i]
#    interior_polygon = region[0]
#    if len(inside_polygon(interior_polygon, bounding_polygon,
#                   closed = True, verbose = False)) <> len(interior_polygon):
#        print 'WARNING: interior polygon %d is outside bounding polygon' %(i)
#        count += 1

#if count == 0:
#    print 'interior regions OK'
#else:
#    print 'check out your interior polygons'
#    print 'check %s in production directory' %figname
#    import sys; sys.exit()

    if interior_holes is not None:
        # Test that all the interior polygons are inside the bounding_poly
        for interior_polygon in interior_holes:

            # Test that we have a polygon
            if len(num.array(interior_polygon).flat) < 6:
                msg = 'Interior hole polygon %s has too few (<3) points.\n' \
                    %(str(interior_polygon))
                msg = msg + '(Insure that you have specified a LIST of interior hole polygons)'
                raise PolygonError(msg)

            indices = inside_polygon(interior_polygon,
                                     bounding_polygon,
                                     closed=True,
                                     verbose=False)

            if len(indices) <> len(interior_polygon):
                msg = 'Interior polygon %s is outside bounding polygon: %s'\
                      %(str(interior_polygon), str(bounding_polygon))
                raise PolygonError(msg)

    # Resolve geo referencing
    if mesh_geo_reference is None:
        xllcorner = min(bounding_polygon[:, 0])
        yllcorner = min(bounding_polygon[:, 1])
        #
        if poly_geo_reference is None:
            zone = DEFAULT_ZONE
        else:
            zone = poly_geo_reference.get_zone()
            [(xllcorner,yllcorner)] = poly_geo_reference.get_absolute( \
            [(xllcorner,yllcorner)])
        # create a geo_ref, based on the llc of the bounding_polygon
        mesh_geo_reference = Geo_reference(xllcorner=xllcorner,
                                           yllcorner=yllcorner,
                                           zone=zone)

    m = Mesh(geo_reference=mesh_geo_reference)

    # build a list of discrete segments from the breakline polygons
    if breaklines is not None:
        points, verts = polylist2points_verts(breaklines)
        m.add_points_and_segments(points, verts)

    # Do bounding polygon
    m.add_region_from_polygon(bounding_polygon,
                              segment_tags=boundary_tags,
                              geo_reference=poly_geo_reference)

    # Find one point inside region automatically
    if interior_regions is not None:
        excluded_polygons = []
        for polygon, res in interior_regions:
            excluded_polygons.append(polygon)
    else:
        excluded_polygons = None

    # Convert bounding poly to absolute values
    # this sort of thing can be fixed with the geo_points class
    if poly_geo_reference is not None:
        bounding_polygon_absolute = \
            poly_geo_reference.get_absolute(bounding_polygon)
    else:
        bounding_polygon_absolute = bounding_polygon

    inner_point = point_in_polygon(bounding_polygon_absolute)
    inner = m.add_region(inner_point[0], inner_point[1])
    inner.setMaxArea(maximum_triangle_area)

    # Do interior regions
    #    if interior_regions is not None:
    #        for polygon, res in interior_regions:
    #            m.add_region_from_polygon(polygon,
    #                                      geo_reference=poly_geo_reference)
    #            # convert bounding poly to absolute values
    #            if poly_geo_reference is not None:
    #                polygon_absolute = \
    #                    poly_geo_reference.get_absolute(polygon)
    #            else:
    #                polygon_absolute = polygon
    #            inner_point = point_in_polygon(polygon_absolute)
    #            region = m.add_region(inner_point[0], inner_point[1])
    #            region.setMaxArea(res)

    if interior_regions is not None:
        for polygon, res in interior_regions:
            m.add_region_from_polygon(polygon,
                                      max_triangle_area=res,
                                      geo_reference=poly_geo_reference)

    # Do interior holes
    if interior_holes is not None:
        for n, polygon in enumerate(interior_holes):
            try:
                tags = hole_tags[n]
            except:
                tags = {}
            m.add_hole_from_polygon(polygon,
                                    segment_tags=tags,
                                    geo_reference=poly_geo_reference)

    # 22/04/2014
    # Add user-specified point-based regions with max area
    if (regionPtArea is not None):
        for i in range(len(regionPtArea)):
            inner = m.add_region(regionPtArea[i][0], regionPtArea[i][1])
            inner.setMaxArea(regionPtArea[i][2])

    # NOTE (Ole): This was moved here as it is annoying if mesh is always
    # stored irrespective of whether the computation
    # was cached or not. This caused Domain to
    # recompute as it has meshfile as a dependency

    # Decide whether to store this mesh or return it

    if filename is None:
        return m
    else:
        if verbose: log.critical("Generating mesh to file '%s'" % filename)

        m.generate_mesh(minimum_triangle_angle=minimum_triangle_angle,
                        verbose=verbose)
        m.export_mesh_file(filename)

        return m
Exemplo n.º 18
0
def allocate_inlet_procs(domain,
                         poly,
                         enquiry_point=None,
                         master_proc=0,
                         procs=None,
                         verbose=False):

    import pypar
    if procs is None:
        procs = range(0, pypar.size())

    myid = pypar.rank()
    vertex_coordinates = domain.get_full_vertex_coordinates(absolute=True)
    domain_centroids = domain.centroid_coordinates
    size = 0
    has_enq_point = False
    numprocs = pypar.size()

    inlet_procs = []
    max_size = -1
    inlet_master_proc = -1
    inlet_enq_proc = -1

    # Calculate the number of points of the line inside full polygon

    #tri_id = line_intersect(vertex_coordinates, poly)

    if len(poly) == 2:  # poly is a line
        if verbose: print "======================"
        tri_id = line_intersect(vertex_coordinates, poly)
    else:  # poly is a polygon
        if verbose: print "+++++++++++++++++++++++"
        tris_0 = line_intersect(vertex_coordinates, [poly[0], poly[1]])
        tris_1 = inside_polygon(domain_centroids, poly)
        tri_id = num.union1d(tris_0, tris_1)

    if verbose:
        print "P%d has %d triangles in poly %s" % (myid, len(tri_id), poly)

    size = len(tri_id)

    if enquiry_point is not None:
        try:
            k = domain.get_triangle_containing_point(enquiry_point)

            if domain.tri_full_flag[k] == 1:
                size = size + 1
                has_enq_point = True
                if verbose:
                    print "P%d has enq point %s" % (myid, enquiry_point)
            else:
                if verbose:
                    print "P%d contains ghost copy of enq point %s" % (
                        myid, enquiry_point)
                has_enq_point = False
        except:
            if verbose:
                print "P%d does not contain enq point %s" % (myid,
                                                             enquiry_point)
            has_enq_point = False

    if myid == master_proc:
        # Recieve size of overlap from each processor
        # Initialize line_master_proc and inlet_procs

        if size > 0:
            inlet_procs = [master_proc]
            max_size = size
            inlet_master_proc = master_proc
            if has_enq_point:
                inlet_enq_proc = master_proc

        # Recieve size of overlap
        for i in procs:
            if i == master_proc: continue
            x = pypar.receive(i)
            y = pypar.receive(i)

            if x > 0:
                inlet_procs.append(i)

                # Choose inlet_master_proc as the one with the most overlap
                if x > max_size:
                    max_size = x
                    inlet_master_proc = i

                if y is True:
                    assert inlet_enq_proc == -1, "Enquiry point correspond to more than one proc"
                    inlet_enq_proc = i

        assert len(inlet_procs) > 0, "Line does not intersect any domain"
        assert inlet_master_proc >= 0, "No master processor assigned"

        if enquiry_point is not None:
            msg = "Enquiry point %s doesn't intersect mesh, maybe inside a building, try reducing enquiry_gap" % str(
                enquiry_point)
            if inlet_enq_proc < 0:
                raise Exception(msg)

        # Send inlet_master_proc and inlet_procs to all processors in inlet_procs
        for i in procs:
            if i != master_proc:
                pypar.send(inlet_master_proc, i)
                pypar.send(inlet_procs, i)
                pypar.send(inlet_enq_proc, i)

    else:
        pypar.send(size, master_proc)
        pypar.send(has_enq_point, master_proc)

        inlet_master_proc = pypar.receive(master_proc)
        inlet_procs = pypar.receive(master_proc)
        inlet_enq_proc = pypar.receive(master_proc)
        if has_enq_point:
            assert inlet_enq_proc == myid, "Enquiry found in proc, but not declared globally"

    if size > 0:
        return True, inlet_master_proc, inlet_procs, inlet_enq_proc
    else:
        return False, inlet_master_proc, inlet_procs, inlet_enq_proc
Exemplo n.º 19
0
            for i in range(k_nearest_neighbours):
                denom += nn_wts[:,i]
                num += quantity[nn_inds[:,i]]*nn_wts[:,i]
            return (num/denom)

    if bounding_polygon is not None:
        # Find points to exclude (i.e. outside the bounding polygon)
        from anuga.geometry.polygon import outside_polygon
        cut_points = outside_polygon(gridXY_array, bounding_polygon)
        
    hole_points_list = []
    if internal_holes is not None:
        # Find points to exclude (i.e. inside the internal_holes)
        from anuga.geometry.polygon import inside_polygon
        for hole in internal_holes:
            cut_holes = inside_polygon(gridXY_array, hole)
            hole_points_list.append(cut_holes)

    # Loop over all output quantities and produce the output
    for myTSindex, myTSi in enumerate(myTimeStep):
        if(verbose):
            print 'Reduction = ', myTSi
        for output_quantity in output_quantities:
            if (verbose): print output_quantity

            if(myTSi is not 'max'):
                myTS = myTSi
            else:
                # We have already extracted the max, and e.g.
                # p2.stage is an array of dimension (1, number_of_pointS).
                myTS = 0
Exemplo n.º 20
0
def allocate_inlet_procs(domain, poly, enquiry_point = None, master_proc = 0, procs = None, verbose = False):


    import pypar
    if procs is None:
        procs = range(0, pypar.size())

    myid = pypar.rank()
    vertex_coordinates = domain.get_full_vertex_coordinates(absolute=True)
    domain_centroids = domain.centroid_coordinates
    size = 0
    has_enq_point = False
    numprocs = pypar.size()

    inlet_procs = []
    max_size = -1
    inlet_master_proc = -1
    inlet_enq_proc = -1

    # Calculate the number of points of the line inside full polygon

    #tri_id = line_intersect(vertex_coordinates, poly)

    if len(poly) == 2: # poly is a line
        if verbose : print "======================"
        tri_id = line_intersect(vertex_coordinates, poly)
    else: # poly is a polygon
        if verbose : print "+++++++++++++++++++++++"
        tris_0 = line_intersect(vertex_coordinates, [poly[0],poly[1]])
        tris_1 = inside_polygon(domain_centroids, poly)
        tri_id = num.union1d(tris_0, tris_1)


    if verbose:
        print "P%d has %d triangles in poly %s" %(myid, len(tri_id), poly)

    size = len(tri_id)

    if enquiry_point is not None:
        try:
            k = domain.get_triangle_containing_point(enquiry_point)

            if domain.tri_full_flag[k] == 1:
                size = size + 1
                has_enq_point = True
                if verbose: print "P%d has enq point %s" %(myid, enquiry_point)
            else:
                if verbose: print "P%d contains ghost copy of enq point %s" %(myid, enquiry_point)
                has_enq_point = False
        except:
            if verbose: print "P%d does not contain enq point %s" %(myid, enquiry_point)
            has_enq_point = False

    if myid == master_proc:
        # Recieve size of overlap from each processor
        # Initialize line_master_proc and inlet_procs

        if size > 0:
            inlet_procs = [master_proc]
            max_size = size
            inlet_master_proc = master_proc
            if has_enq_point:
                inlet_enq_proc = master_proc

        # Recieve size of overlap
        for i in procs:
            if i == master_proc: continue
            x = pypar.receive(i)
            y = pypar.receive(i)

            if x > 0:
                inlet_procs.append(i)

                # Choose inlet_master_proc as the one with the most overlap
                if x > max_size:
                    max_size = x
                    inlet_master_proc = i

                if y is True:
                    assert inlet_enq_proc == -1, "Enquiry point correspond to more than one proc"
                    inlet_enq_proc = i

        assert len(inlet_procs) > 0, "Line does not intersect any domain"
        assert inlet_master_proc >= 0, "No master processor assigned"

        if enquiry_point is not None:
            msg = "Enquiry point %s doesn't intersect mesh, maybe inside a building, try reducing enquiry_gap" % str(enquiry_point)
            if inlet_enq_proc < 0:
                raise Exception(msg)

        # Send inlet_master_proc and inlet_procs to all processors in inlet_procs
        for i in procs:
            if i != master_proc:
                pypar.send(inlet_master_proc, i)
                pypar.send(inlet_procs, i)
                pypar.send(inlet_enq_proc, i)

    else:
        pypar.send(size, master_proc)
        pypar.send(has_enq_point, master_proc)

        inlet_master_proc = pypar.receive(master_proc)
        inlet_procs = pypar.receive(master_proc)
        inlet_enq_proc = pypar.receive(master_proc)
        if has_enq_point: assert inlet_enq_proc == myid, "Enquiry found in proc, but not declared globally"

    if size > 0:
        return True, inlet_master_proc, inlet_procs, inlet_enq_proc
    else:
        return False, inlet_master_proc, inlet_procs, inlet_enq_proc
    def F(x,y):
        """This is the function returned by composite_quantity_setting_function
           It can be passed to set_quantity
        """
        isSet = numpy.zeros(len(x)) # 0/1 - record if each point has been set
        quantityVal = x*0 + numpy.nan # Function return value

        # Record points which evaluated to nan on their first preference
        # dataset.
        was_ever_nan = (x*0).astype(int)

        lpf = len(poly_fun_pairs)
        if(lpf <= 0):
            raise Exception('Must have at least 1 fun-poly-pair')

        # Make an array of 'transformed' spatial coordinates, for checking
        # polygon inclusion
        xll = domain.geo_reference.xllcorner
        yll = domain.geo_reference.yllcorner
        xy_array_trans = numpy.vstack([x+xll,y+yll]).transpose()

        # Check that none of the pi polygons [except perhaps the last] is 'All'
        for i in range(lpf-1):
            if(poly_fun_pairs[i][0]=='All'):
                # This is only ok if all the othe poly_fun_pairs are None
                remaining_poly_fun_pairs_are_None = \
                    [poly_fun_pairs[j][0] is None for j in range(i+1,lpf)]
                if(not all(remaining_poly_fun_pairs_are_None)):
                    raise Exception('Can only have the last polygon = All')

        # Main Loop
        # Apply the fi inside the pi
        for i in range(lpf):
            fi = poly_fun_pairs[i][1] # The function
            pi = poly_fun_pairs[i][0] # The polygon

            # Quick exit
            if(pi is None):
                continue

            ###################################################################
            # Get indices fInds of points in polygon pi which are not already
            # set
            ###################################################################
            if(pi == 'All'):
                # Get all unset points
                fInside = (1-isSet)
                fInds = (fInside==1).nonzero()[0]

            else:

                if(pi == 'Extent'):
                    # Here fi MUST be a gdal-compatible raster
                    if(not (type(fi) == str)):
                        msg = ' pi = "Extent" can only be used when fi is a' +\
                              ' raster file name'
                        raise Exception(msg)

                    if(not os.path.exists(fi)):
                        msg = 'fi ' + str(fi) + ' is supposed to be a ' +\
                              ' raster filename, but it could not be found'
                        raise Exception(msg)

                    # Then we get the extent from the raster itself
                    pi_path = su.getRasterExtent(fi,asPolygon=True)

                    if verbose:
                        print 'Extracting extent from raster: ', fi
                        print 'Extent: ', pi_path

                elif( (type(pi) == str) and os.path.isfile(pi) ): 
                    # pi is a file
                    pi_path = su.read_polygon(pi)

                else:
                    # pi is the actual polygon data
                    pi_path = pi

                # Get the insides of unset points inside pi_path
                notSet = (isSet==0.).nonzero()[0]
                fInds = inside_polygon(xy_array_trans[notSet,:], pi_path)
                fInds = notSet[fInds]

            if len(fInds) == 0:
                # No points found, move on
                continue

            ###################################################################
            # Evaluate fi at the points inside pi
            ###################################################################

            # We use various tricks to infer whether fi is a function,
            # a constant, a file (raster or csv), or an array
            if(hasattr(fi,'__call__')):
                # fi is a function
                quantityVal[fInds] = fi(x[fInds], y[fInds])

            elif isinstance(fi, (int, long, float)):
                # fi is a numerical constant
                quantityVal[fInds] = fi*1.0

            elif ( type(fi) is str and os.path.exists(fi)):
                # fi is a file which is assumed to be 
                # a gdal-compatible raster OR an x,y,z elevation file
                if os.path.splitext(fi)[1] in ['.txt', '.csv']:
                    fi_array = su.read_csv_optional_header(fi)
                    # Check the results
                    if fi_array.shape[1] is not 3:
                        print 'Treated input file ' + fi +\
                              ' as xyz array with an optional header'
                        msg = 'Array should have 3 columns -- x,y,value'
                        raise Exception(msg)

                    newfi = make_nearestNeighbour_quantity_function(
                        fi_array, domain, 
                        k_nearest_neighbours = default_k_nearest_neighbours)
                    quantityVal[fInds] = newfi(x[fInds], y[fInds])

                else:
                    # Treating input file as a raster
                    newfi = quantityRasterFun(domain, fi, 
                        interpolation = default_raster_interpolation)
                    quantityVal[fInds] = newfi(x[fInds], y[fInds])

            elif(type(fi) is numpy.ndarray):
                if fi.shape[1] is not 3:
                    msg = 'Array should have 3 columns -- x,y,value'
                    raise Exception(msg)
                newfi = make_nearestNeighbour_quantity_function(fi, domain, 
                    k_nearest_neighbours = default_k_nearest_neighbours)
                quantityVal[fInds] = newfi(x[fInds], y[fInds])

            else:
                print 'Error with function from'
                print fi
                msg='Cannot make function from type ' + str(type(fi))
                raise Exception, msg 

            ###################################################################
            # Check for nan values
            ###################################################################
            #nan_flag = (quantityVal[fInds] != quantityVal[fInds])
            nan_flag = 1*numpy.isnan(quantityVal[fInds])
            nan_inds = nan_flag.nonzero()[0]
            was_ever_nan[fInds[nan_inds]] = 1

            if len(nan_inds)>0:
                if nan_treatment == 'exception':
                    msg = 'nan values generated by the poly_fun_pair at '\
                          'index ' + str(i) + ' '\
                          'in composite_quantity_setting_function. ' + \
                          'To allow these values to be set by later ' + \
                          'poly_fun pairs, pass the argument ' + \
                          'nan_treatment="fall_through" ' + \
                          'to composite_quantity_setting_function' 
                    raise Exception(msg)

                elif nan_treatment == 'fall_through':
                    msg = 'WARNING: nan values generated by the ' + \
                          'poly_fun_pair at index ' + str(i) + ' '\
                          'in composite_quantity_setting_function. ' + \
                          'They will be passed to later poly_fun_pairs'
                    if verbose: print msg
                    not_nan_inds = (1-nan_flag).nonzero()[0]

                    if len(not_nan_inds)>0:
                        fInds = fInds[not_nan_inds]
                    else:
                        # All values are nan
                        msg = '( Actually all the values were nan - ' + \
                              'Are you sure they should be? Possible error?)'
                        if verbose: print msg
                        continue

                else:
                    msg = 'Found nan values in ' + \
                          'composite_quantity_setting_function but ' + \
                          'nan_treatment is not a recognized value'
                    raise Exception(msg)

            # Record that the points have been set
            isSet[fInds] = 1

            # Enforce clip_range
            if clip_range is not None:
                lower_bound = clip_range[i][0]
                upper_bound = clip_range[i][1]
                quantityVal[fInds] = numpy.maximum(
                    quantityVal[fInds], lower_bound)
                quantityVal[fInds] = numpy.minimum(
                    quantityVal[fInds], upper_bound)

        # End of loop

        # Find points which were nan on their first preference dataset + are
        # inside nan_interpolation_region_polygon. Then reinterpolate their
        # values from the other x,y, quantityVal points.
        if (nan_interpolation_region_polygon is not None) &\
           (was_ever_nan.sum() > 0):
            if nan_interpolation_region_polygon == 'All':
                points_to_reinterpolate = was_ever_nan.nonzero()[0]
            else:
                # nan_interpolation_region_polygon contains information on 1 or
                # more polygons
                # Inside those polygons, we need to re-interpolate points which
                # first evaluted to na
                possible_points_to_reint = was_ever_nan.nonzero()[0]
                points_to_reinterpolate = numpy.array([]).astype(int) 

                for i in range(len(nan_interpolation_region_polygon)):
                    nan_pi = nan_interpolation_region_polygon[i]

                    # Ensure nan_pi = list of x,y points making a polygon
                    if(type(nan_pi) == str):
                        nan_pi = su.read_polygon(nan_pi)
              
                    points_in_nan_pi = inside_polygon(
                        xy_array_trans[possible_points_to_reint,:],
                        nan_pi) 
                    
                    if len(points_in_nan_pi)>0: 
                        points_to_reinterpolate = numpy.hstack(
                            [points_to_reinterpolate,
                             possible_points_to_reint[points_in_nan_pi]])


            if verbose: 
                print 'Re-interpolating ', len(points_to_reinterpolate),\
                      ' points which were nan under their',\
                      ' first-preference and are inside the',\
                      ' nan_interpolation_region_polygon'

            if len(points_to_reinterpolate) > 0:
                msg = 'WARNING: nan interpolation is being applied. This ',\
                      'should be done in serial prior to distributing the ',\
                      'domain, as there is no parallel communication ',\
                      'implemented yet [so parallel results might depend on ',\
                      'the number of processes]'
                if verbose:
                    print msg
                    

            # Find the interpolation points = points not needing reinterpolation
            ip = x*0 + 1
            ip[points_to_reinterpolate] = 0
            number_of_ip = ip.sum()
            ip = ip.nonzero()[0]

            # Check that none of the ip points has an nan value
            nan_ip = (quantityVal[ip] != quantityVal[ip]).nonzero()[0]

            if len(nan_ip) > 0:
                print 'There are ', len(nan_ip), ' points outside the ',\
                      'nan_interpolation_region_polygon have nan values.'
                print 'The user should ensure this does not happen.'
                print 'The points have the following coordinates:'
                print xy_array_trans[ip[nan_ip],:]
                msg = "There are nan points outside of " +\
                      "nan_interpolation_region_polygon, even after all " +\
                      "fall-through's"
                raise Exception(msg)
         
            if(number_of_ip < default_k_nearest_neighbours):
                raise Exception('Too few non-nan points to interpolate from') 

            # Make function for re-interpolation. Note this requires
            # x,y,z in georeferenced coordinates, whereas x,y are ANUGA
            # coordinates
            reinterp_F = make_nearestNeighbour_quantity_function(
                numpy.vstack([xy_array_trans[ip,0], xy_array_trans[ip,1],
                              quantityVal[ip]]).transpose(),
                domain, 
                k_nearest_neighbours = default_k_nearest_neighbours)

            # re-interpolate
            quantityVal[points_to_reinterpolate] = reinterp_F(
                x[points_to_reinterpolate], y[points_to_reinterpolate])

            isSet[points_to_reinterpolate] = 1
            
        # Check there are no remaining nan values
        if( min(isSet) != 1):
            print 'Some points remain as nan, which is not allowed'
            unset_inds = (isSet != 1).nonzero()[0]
            lui = min(5, len(unset_inds)) 
            print 'There are ', len(unset_inds), ' such points'
            print 'Here are a few:'
            for i in range(lui):
                print x[unset_inds[i]] + xll, y[unset_inds[i]] + yll
            raise Exception('It seems the input data needs to be fixed')

        return quantityVal