def test_real(self): from lib.raster import Raster, PrintArr from lib.shapefileloader import Shapefile r = Raster("D:/CHaMP/Harold/2014/Entiat/ENT00001-1BC1/VISIT_2447/Topo/GISLayers/DEM.tif") theArr = r.rasterMaskLayer("D:/CHaMP/Harold/2014/Entiat/ENT00001-1BC1/VISIT_2447/Topo/GISLayers/Channel_Units.shp", 'Unit_Numbe') PrintArr(theArr)
def calc(self, channelName, shpWaterExtent, shpCenterline, rasDepth): if not os.path.isfile(shpCenterline): raise MissingException("Missing centerline shapefile") if not os.path.isfile(shpWaterExtent): raise MissingException("Missing water extent shapefile") if not os.path.isfile(rasDepth): raise MissingException("Missing depth raster") # Load the depth raster depthRaster = Raster(rasDepth) # Load the water extent ShapeFile and sum the area of all features shpExtent = Shapefile(shpWaterExtent) feats = shpExtent.featuresToShapely() arrMask = depthRaster.rasterMaskLayer(shpWaterExtent) self.metrics['Area'] = 0 # TODO: See issue #79 and #15. We need to use a different strategy if we want volume for bankfull https://github.com/SouthForkResearch/CHaMP_Metrics/issues/79 if channelName == "Bankfull": self.metrics['Volume'] = None for aFeat in feats: self.metrics['Area'] += aFeat['geometry'].area else: self.metrics['Volume'] = np.sum( depthRaster.array[arrMask > 0]) * (depthRaster.cellWidth**2) for aFeat in feats: self.metrics['Area'] += aFeat['geometry'].area dDepth = {} dDepth['Max'] = float(np.amax(depthRaster.array[arrMask > 0])) dDepth['Mean'] = np.mean(depthRaster.array[arrMask > 0]) self.metrics['Depth'] = dDepth # Retrieve the centerline mainstem. If the ShapeFile possesses a 'Channel field then # find the 1 feature with a value of 'Main', otherwise this is simply the only ShapeFile feature mainstem = self._getMainstemGeometry(shpCenterline) self.metrics['IntegratedWidth'] = None if mainstem and mainstem.length > 0: self.metrics[ 'IntegratedWidth'] = self.metrics['Area'] / mainstem.length
def calc(self, shpCUPath, shpThalweg, rasDepth, visitMetrics, dUnits, unitDefs): if not os.path.isfile(shpCUPath): raise MissingException("Channel units file not found") if not os.path.isfile(shpThalweg): raise MissingException("Thalweg shape file not found") if not os.path.isfile(rasDepth): raise MissingException("Depth raster file not found") siteLength = visitMetrics['Wetted']['Centerline']['MainstemLength'] if siteLength is None: raise DataException("No valid site length found in visit metrics") # Give us a fresh template with 0's in the value positions self.metrics = self._templateMaker(0, unitDefs) dResultsChannelSummary = self.metrics['ResultsChannelSummary'] dResultsTier1 = self.metrics['ResultsTier1'] dResultsTier2 = self.metrics['ResultsTier2'] resultsCU = self.metrics['resultsCU'] #Load the Thalweg feature thalweg = Shapefile(shpThalweg).featuresToShapely() thalwegLine = thalweg[0]['geometry'] # Load the depth raster depthRaster = Raster(rasDepth) # Load the channel unit polygons and calculate the total area # The channel units should be clipped to the wetted extent and so this # can be used as the site area wetted shpCU = Shapefile(shpCUPath) arrCU = depthRaster.rasterMaskLayer(shpCUPath, "UnitNumber") feats = shpCU.featuresToShapely() for aFeat in feats: dResultsChannelSummary['Main']['Area'] += aFeat['geometry'].area # Loop over each channel unit and calculate topometrics for aFeat in feats: nCUNumber = int(aFeat['fields']['UnitNumber']) if nCUNumber not in dUnits: self.log.error( "Channel Unit: '{0}' not present in the aux data.".format( nCUNumber)) # Keep it general for the exception so we can aggregate them raise DataException( "The Channel Unit ShapeFile contains a unit number that is not present in the aux data." ) tier1Name = dUnits[nCUNumber][0] tier2Name = dUnits[nCUNumber][1] nSegment = dUnits[nCUNumber][2] #print "Channel Unit Number {0}, Segment {1}, Tier 1 - {2}, Tier 2 - {3}".format(nCUNumber, nSegment, tier1Name, tier2Name) unitMetrics = {} resultsCU.append(unitMetrics) unitMetrics['ChannelUnitNumber'] = nCUNumber unitMetrics['Area'] = aFeat['geometry'].area unitMetrics['Tier1'] = tier1Name unitMetrics['Tier2'] = tier2Name unitMetrics['Length'] = None unitMetrics['ResidualDepth'] = None unitMetrics['DepthAtThalwegExit'] = None unitMetrics['ThalwegIntersect'] = 0 # Get the depth raster for this unit as variable so we can check # whether it is entirely masked below. depArr = depthRaster.array[arrCU == nCUNumber] if depArr.count() == 0: unitMetrics['MaxDepth'] = 0 unitMetrics['Volume'] = 0 else: unitMetrics['MaxDepth'] = np.max(depArr) unitMetrics['Volume'] = np.sum(depthRaster.array[ arrCU == nCUNumber]) * (depthRaster.cellWidth**2) if nSegment != 1: dSideChannelSummary = dResultsChannelSummary[ 'SideChannelSummary'] dMain = dResultsChannelSummary['Main'] # Side channel summary captures both small and large side channels dSideChannelSummary['Area'] += aFeat['geometry'].area dSideChannelSummary['Count'] += 1 dSideChannelSummary['Percent'] = 100 * dSideChannelSummary[ 'Area'] / dMain['Area'] dSideChannelSummary['Volume'] += unitMetrics['Volume'] if 'side' in tier1Name.lower(): dSmallSideChannel = dResultsChannelSummary[ 'SmallSideChannel'] dSmallSideChannel['Area'] += aFeat['geometry'].area dSmallSideChannel['Count'] += 1 dSmallSideChannel['Percent'] = 100 * dSmallSideChannel[ 'Area'] / dMain['Area'] dSmallSideChannel['Volume'] += unitMetrics['Volume'] else: dLargeSideChannel = dResultsChannelSummary[ 'LargeSideChannel'] dLargeSideChannel['Area'] += aFeat['geometry'].area dLargeSideChannel['Count'] += 1 dLargeSideChannel['Percent'] = 100 * dLargeSideChannel[ 'Area'] / dMain['Area'] dLargeSideChannel['Volume'] += unitMetrics['Volume'] if tier1Name is None: raise DataException("tier1Name cannot be 'None'") if 'side' in tier1Name.lower(): dResultsChannelSummary['ChannelUnitBreakdown'][ 'SmallSideChannel'] += 1 else: dResultsChannelSummary['ChannelUnitBreakdown']['Other'] += 1 if (thalwegLine.intersects(aFeat['geometry'])): cuThalwegLine = thalwegLine.intersection(aFeat['geometry']) exitPoint = None if cuThalwegLine.type == 'LineString': exitPoint = cuThalwegLine.coords[0] else: exitPoint = cuThalwegLine[0].coords[0] # Retrieve a list of points along the Thalweg in the channel unit thalwegPoints = ChannelUnitMetrics.interpolatePointsAlongLine( cuThalwegLine, 0.13) thalwegDepths = ChannelUnitMetrics.lookupRasterValuesAtPoints( thalwegPoints, depthRaster) unitMetrics['MaxDepth'] = np.nanmax(thalwegDepths['values']) unitMetrics['DepthAtThalwegExit'] = depthRaster.getPixelVal( exitPoint) unitMetrics['ResidualDepth'] = unitMetrics[ 'MaxDepth'] - unitMetrics['DepthAtThalwegExit'] unitMetrics['Length'] = cuThalwegLine.length unitMetrics['ThalwegIntersect'] = 1 # Tier 1 and tier 2 topometrics. Note that metric dictionary keys are used for XML tags & require cleaning tier1NameClean = getCleanTierName(tier1Name) self._calcTierLevelMetrics(dResultsTier1[tier1NameClean], tier1Name, unitMetrics, siteLength, dResultsChannelSummary['Main']['Area']) tier2NameClean = getCleanTierName(tier2Name) self._calcTierLevelMetrics(dResultsTier2[tier2NameClean], tier2Name, unitMetrics, siteLength, dResultsChannelSummary['Main']['Area']) # Calculate the average of the channel unit max depths for each tier 1 and tier 2 type for tierKey, tierMetrics in { 'Tier1': dResultsTier1, 'Tier2': dResultsTier2 }.iteritems(): for tierName, metricDict in tierMetrics.iteritems(): maxDepthList = [ aResult['MaxDepth'] for aResult in resultsCU if getCleanTierName(aResult[tierKey]) == tierName ] if len(maxDepthList) > 0: metricDict['AvgMaxDepth'] = np.average(maxDepthList) # Convert the sum of residual depth and depth at thalweg exist # to average residual depth for each tier 1 and tier 2 type for tierMetricDict in [dResultsTier1, dResultsTier2]: for tierName, tierMetrics in tierMetricDict.iteritems(): # channel unit types that don't occur should retain the value None for Residual Depth and Depth at Thalweg exit if tierMetrics['Count'] > 0 and tierMetrics[ 'ThalwegIntersectCount'] > 0: for metricName in ['ResidualDepth', 'DepthAtThalwegExit']: if tierMetrics[metricName] is not None and tierMetrics[ metricName] != 0: tierMetrics[metricName] = tierMetrics[ metricName] / tierMetrics[ 'ThalwegIntersectCount'] else: tierMetrics[metricName] = 0