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)
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)
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)
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)
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 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 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)
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
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
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
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
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
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)
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
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
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
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