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