Пример #1
0
def derive_HAND(dem,
                ldd,
                accuThreshold,
                rivers=None,
                basin=None,
                up_area=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
        up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a
                        full catchment area)
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        # prepare stream from a strahler threshold
        stream = pcr.ifthenelse(
            pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1),
            pcr.boolean(0))
    else:
        # convert stream network to boolean
        stream = pcr.boolean(pcr.cover(rivers, 0))
    # determine height in river (in DEM*100 unit as ordinal)
    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area
        if up_area is None:
            up_area = pcr.accuflux(ldd, 1)
        up_area = pcr.ifthen(stream, up_area)  # mask areas outside streams
        friction = 1. / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0))
        # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river
        up_elevation = pcr.ifthenelse(
            basin, pcr.scalar(pcr.subcatchment(ldd, height_river)),
            pcr.scalar(pcr.spreadzone(height_river, 0, friction)))
        # replace areas outside of basin by a spread zone calculation.
    hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation,
                   0) / 100  # convert back to float in DEM units
    # hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100  # convert back to float in DEM units
    dist = pcr.ldddist(ldd, stream, 1)  # compute horizontal distance estimate
    return hand, dist
Пример #2
0
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None, up_area=None, neg_HAND=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
        up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a
                        full catchment area)
        neg_HAND=None -- if set to 1, HAND maps can have negative values when elevation outside of stream is lower than
                        stream (for example when there are natural embankments)
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        # prepare stream from a strahler threshold
        stream = pcr.ifthenelse(pcr.accuflux(ldd, 1) >= accuThreshold,
                                pcr.boolean(1), pcr.boolean(0))
    else:
        # convert stream network to boolean
        stream = pcr.boolean(pcr.cover(rivers, 0))
    # determine height in river (in DEM*100 unit as ordinal)
    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem*100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area
        if up_area is None:
            up_area = pcr.accuflux(ldd, 1)
        up_area = pcr.ifthen(stream, up_area)  # mask areas outside streams
        friction = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0))
        # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river
        up_elevation = pcr.ifthenelse(basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, friction)))
        # replace areas outside of basin by a spread zone calculation.
    # make negative HANDS also possible
    if neg_HAND == 1:
        hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100  # convert back to float in DEM units
    else:
        hand = pcr.max(pcr.scalar(pcr.ordinal(dem*100))-up_elevation, 0)/100  # convert back to float in DEM units
    dist = pcr.ldddist(ldd, stream, 1)  # compute horizontal distance estimate
    return hand, dist
Пример #3
0
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        stream = pcr.ifthenelse(
            pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)
        )
    else:
        stream = pcr.boolean(pcr.cover(rivers, 0))

    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        drainage_surf = pcr.ifthen(rivers, pcr.accuflux(ldd, 1))
        weight = 1.0 / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0)
        )
        up_elevation = pcr.ifthenelse(
            basin,
            pcr.scalar(pcr.subcatchment(ldd, height_river)),
            pcr.scalar(pcr.spreadzone(height_river, 0, weight)),
        )
        # replace areas outside of basin by a spread zone calculation.
    hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100
    dist = pcr.ldddist(ldd, stream, 1)

    return hand, dist
Пример #4
0
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        stream = pcr.ifthenelse(
            pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)
        )
    else:
        stream = pcr.boolean(pcr.cover(rivers, 0))

    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        drainage_surf = pcr.ifthen(rivers, pcr.accuflux(ldd, 1))
        weight = 1.0 / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0)
        )
        up_elevation = pcr.ifthenelse(
            basin,
            pcr.scalar(pcr.subcatchment(ldd, height_river)),
            pcr.scalar(pcr.spreadzone(height_river, 0, weight)),
        )
        # replace areas outside of basin by a spread zone calculation.
    hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100
    dist = pcr.ldddist(ldd, stream, 1)

    return hand, dist
 def totalSoilMoistureThickInUpstreamArea(self):
     self.totalSoilMoistureThickInUpstreamAreaCubicMetre = pcr.accuflux(
         self.ldd, self.soilMoistureThick) * self.cellArea
 def totalActualAbstractionInUpstreamArea(self):
     self.totalActualAbstractionInUpstreamAreaCubicMetrePerHour = pcr.accuflux(
         self.ldd, self.actualAbstractionFlux) * self.cellArea
 def totalUpwardSeepageInUpstreamArea(self):
     self.totalUpwardSeepageInUpstreamAreaCubicMetrePerHour = pcr.accuflux(
         self.ldd, self.upwardSeepageFlux) * self.cellArea
Пример #8
0
def subcatch_stream(
    ldd,
    threshold,
    min_strahler=-999,
    max_strahler=999,
    assign_edge=False,
    assign_existing=False,
    up_area=None,
):
    """
    (From Deltares Hydrotools)

    Derive catchments based upon strahler threshold
    Input:
        ldd -- pcraster object direction, local drain directions
        threshold -- integer, strahler threshold, subcatchments ge threshold
            are derived
        min_strahler -- integer, minimum strahler threshold of river catchments
            to return
        max_strahler -- integer, maximum strahler threshold of river catchments
            to return
        assign_unique=False -- if set to True, unassigned connected areas at
            the edges of the domain are assigned a unique id as well. If set
            to False, edges are not assigned
        assign_existing=False == if set to True, unassigned edges are assigned
            to existing basins with an upstream weighting. If set to False,
            edges are assigned to unique IDs, or not assigned
    output:
        stream_ge -- pcraster object, streams of strahler order ge threshold
        subcatch -- pcraster object, subcatchments of strahler order ge threshold

    """
    # derive stream order

    stream = pcr.streamorder(ldd)
    stream_ge = pcr.ifthen(stream >= threshold, stream)
    stream_up_sum = pcr.ordinal(pcr.upstream(ldd, pcr.cover(pcr.scalar(stream_ge), 0)))
    # detect any transfer of strahler order, to a higher strahler order.
    transition_strahler = pcr.ifthenelse(
        pcr.downstream(ldd, stream_ge) != stream_ge,
        pcr.boolean(1),
        pcr.ifthenelse(
            pcr.nominal(ldd) == 5,
            pcr.boolean(1),
            pcr.ifthenelse(
                pcr.downstream(ldd, pcr.scalar(stream_up_sum)) > pcr.scalar(stream_ge),
                pcr.boolean(1),
                pcr.boolean(0),
            ),
        ),
    )
    # make unique ids (write to file)
    transition_unique = pcr.ordinal(pcr.uniqueid(transition_strahler))

    # derive upstream catchment areas (write to file)
    subcatch = pcr.nominal(pcr.subcatchment(ldd, transition_unique))

    if assign_edge:
        # fill unclassified areas (in pcraster equal to zero) with a unique id, above the maximum id assigned so far
        unique_edge = pcr.clump(pcr.ifthen(subcatch == 0, pcr.ordinal(0)))
        subcatch = pcr.ifthenelse(
            subcatch == 0,
            pcr.nominal(pcr.mapmaximum(pcr.scalar(subcatch)) + pcr.scalar(unique_edge)),
            pcr.nominal(subcatch),
        )
    elif assign_existing:
        # unaccounted areas are added to largest nearest draining basin
        if up_area is None:
            up_area = pcr.ifthen(
                pcr.boolean(pcr.cover(stream_ge, 0)), pcr.accuflux(ldd, 1)
            )
        riverid = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), subcatch)

        friction = 1.0 / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)
        )  # *(pcr.scalar(ldd)*0+1)
        delta = pcr.ifthen(
            pcr.scalar(ldd) >= 0,
            pcr.ifthen(
                pcr.cover(subcatch, 0) == 0,
                pcr.spreadzone(pcr.cover(riverid, 0), 0, friction),
            ),
        )
        subcatch = pcr.ifthenelse(pcr.boolean(pcr.cover(subcatch, 0)), subcatch, delta)

    # finally, only keep basins with minimum and maximum river order flowing through them
    strahler_subcatch = pcr.areamaximum(stream, subcatch)
    subcatch = pcr.ifthen(
        pcr.ordinal(strahler_subcatch) >= min_strahler,
        pcr.ifthen(pcr.ordinal(strahler_subcatch) <= max_strahler, subcatch),
    )

    return stream_ge, pcr.ordinal(subcatch)
Пример #9
0
pcr.report(river,river_map)
pcr.report(catchments,catchments_map)
if not EPSG == None:
    call(('gdal_translate','-of','GTiff','-stats','-a_srs',EPSG,'-ot','Float32',catchments_map,catchments_tif))
else: call(('gdal_translate','-of','GTiff','-stats','-ot','Float32',catchments_map,catchments_tif))
wt.Raster2Pol(catchments_tif,catchshp,srs)

riversid_map = workdir + 'riverid.map'
drain_map = workdir + 'drain.map'
ldd_mask = pcr.ifthen(river, ldd)
upstream = pcr.upstream(ldd_mask, pcr.scalar(river))
downstream = pcr.downstream(ldd_mask, upstream)
#pcr.report(downstream,'downstream.map')
confluences = pcr.boolean(pcr.ifthen(downstream >= 2, pcr.boolean(1)))
#pcr.report(confluences,'confluences.map')
boundaries = pcr.boolean(pcr.ifthen(pcr.scalar(ldd_mask) == 5, pcr.boolean(1)))
catch_points = pcr.nominal(pcr.uniqueid(pcr.cover(confluences,boundaries)))
catchmentsid   = pcr.nominal(pcr.subcatchment(ldd, catch_points))
drain    = pcr.accuflux(ldd_mask, 1)
riversid = pcr.ifthen(river, catchmentsid)

if not keepall:
    riversid = pcr.nominal(pcr.ifthen(pcr.mapmaximum(pcr.areatotal(pcr.scalar(catchments)*0+1,pcr.nominal(catchments))) == pcr.areatotal(pcr.scalar(catchments)*0+1,pcr.nominal(catchments)),riversid))

pcr.report(riversid,riversid_map)
pcr.report(drain,drain_map)

print 'converting river map-file to shape-file...'
wt.PCR_river2Shape(riversid_map, drain_map,streamorder_map,ldd_map,rivshp,catchments_map,srs)
#if __name__ == "__main__":
#    main()
Пример #10
0
    def dynamic(self):
        """ dynamic part of the water use module
            init water use before sub step routing
        """
        settings = LisSettings.instance()
        option = settings.options
        binding = settings.binding
        maskinfo = MaskInfo.instance()
        if option['wateruse']:
            # ************************************************************
            # ***** READ WATER DEMAND DATA *****************************
            # ************************************************************

            if option['TransientWaterDemandChange']:
                if option['readNetcdfStack']:
                    if option['useWaterDemandAveYear']:
                        # using average year in NetCDF file format
                        self.var.DomesticDemandMM = readnetcdf(
                            binding['DomesticDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest',
                            averageyearflag=True) * self.var.DtDay
                        self.var.IndustrialDemandMM = readnetcdf(
                            binding['IndustrialDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest',
                            averageyearflag=True) * self.var.DtDay
                        self.var.LivestockDemandMM = readnetcdf(
                            binding['LivestockDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest',
                            averageyearflag=True) * self.var.DtDay
                        self.var.EnergyDemandMM = readnetcdf(
                            binding['EnergyDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest',
                            averageyearflag=True) * self.var.DtDay
                    else:
                        # Read from stack of maps in NetCDF format. Get time step corresponding to model step.
                        # added management for sub-daily model time steps
                        self.var.DomesticDemandMM = readnetcdf(
                            binding['DomesticDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest') * self.var.DtDay
                        self.var.IndustrialDemandMM = readnetcdf(
                            binding['IndustrialDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest') * self.var.DtDay
                        self.var.LivestockDemandMM = readnetcdf(
                            binding['LivestockDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest') * self.var.DtDay
                        self.var.EnergyDemandMM = readnetcdf(
                            binding['EnergyDemandMaps'],
                            self.var.currentTimeStep(),
                            timestampflag='closest') * self.var.DtDay
                else:
                    # Read from stack of maps in Pcraster format
                    self.var.DomesticDemandMM = readmapsparse(
                        binding['DomesticDemandMaps'],
                        self.var.currentTimeStep(),
                        self.var.DomesticDemandMM) * self.var.DtDay
                    self.var.IndustrialDemandMM = readmapsparse(
                        binding['IndustrialDemandMaps'],
                        self.var.currentTimeStep(),
                        self.var.IndustrialDemandMM) * self.var.DtDay
                    self.var.LivestockDemandMM = readmapsparse(
                        binding['LivestockDemandMaps'],
                        self.var.currentTimeStep(),
                        self.var.LivestockDemandMM) * self.var.DtDay
                    self.var.EnergyDemandMM = readmapsparse(
                        binding['EnergyDemandMaps'],
                        self.var.currentTimeStep(),
                        self.var.EnergyDemandMM) * self.var.DtDay

            # ************************************************************
            # ***** LIVESTOCK ********************************************
            # ************************************************************

            self.var.LivestockAbstractionMM = self.var.LivestockDemandMM
            self.var.LivestockConsumptiveUseMM = self.var.LivestockAbstractionMM * self.var.LivestockConsumptiveUseFraction
            # the amount that is not returned to the hydrological cycle

            LivestockAbstractionFromGroundwaterM3 = np.where(
                self.var.GroundwaterBodies > 0,
                self.var.FractionGroundwaterUsed *
                self.var.LivestockConsumptiveUseMM * self.var.MMtoM3,
                maskinfo.in_zero())
            LivestockAbstractionFromNonConventionalWaterM3 = self.var.FractionNonConventionalWaterUsed * self.var.LivestockConsumptiveUseMM * self.var.MMtoM3
            LivestockAbstractionFromSurfaceWaterM3 = self.var.LivestockConsumptiveUseMM * self.var.MMtoM3 - LivestockAbstractionFromGroundwaterM3 - LivestockAbstractionFromNonConventionalWaterM3

            self.var.TotalLivestockAbstractionM3 += LivestockAbstractionFromGroundwaterM3 + LivestockAbstractionFromSurfaceWaterM3 + LivestockAbstractionFromNonConventionalWaterM3

            # ************************************************************
            # ***** DOMESTIC *********************************************
            # ************************************************************

            self.var.DomesticAbstractionMM = self.var.DomesticDemandMM * self.var.DomesticWaterSavingConstant * self.var.DomesticLeakageConstant
            # Domestic Water Abstraction (mm per day), already taking into account water saving in households and leakage of the supply network
            # Domestic water abstraction is larger if there is leakage, but is smaller if there is water savings
            self.var.LeakageMM = (
                self.var.DomesticLeakageConstant - 1
            ) * self.var.DomesticDemandMM * self.var.DomesticWaterSavingConstant
            # Leakage in mm per day
            self.var.LeakageLossMM = self.var.LeakageMM * self.var.LeakageWaterLossFraction
            # The leakage amount that is lost (evaporated)
            self.var.LeakageSoilMM = self.var.LeakageMM - self.var.LeakageLossMM
            self.var.DomesticConsumptiveUseMM = self.var.DomesticDemandMM * self.var.DomesticWaterSavingConstant * self.var.DomesticConsumptiveUseFraction + self.var.LeakageLossMM
            # DomesticConsumptiveUseMM is the amount that disappears from the waterbalance
            # Assumption here is that leakage is partially lost/evaporated (LeakageWaterLoss fraction)

            DomAbstractionFromGroundwaterM3 = np.where(
                self.var.GroundwaterBodies > 0,
                self.var.FractionGroundwaterUsed *
                self.var.DomesticConsumptiveUseMM * self.var.MMtoM3,
                maskinfo.in_zero())
            DomAbstractionFromNonConventionalWaterM3 = self.var.FractionNonConventionalWaterUsed * self.var.DomesticConsumptiveUseMM * self.var.MMtoM3
            DomAbstractionFromSurfaceWaterM3 = self.var.DomesticConsumptiveUseMM * self.var.MMtoM3 - DomAbstractionFromGroundwaterM3 - DomAbstractionFromNonConventionalWaterM3

            # ************************************************************
            # ***** INDUSTRY *********************************************
            # ************************************************************

            self.var.IndustrialAbstractionMM = self.var.IndustrialDemandMM * (
                1 - self.var.WaterReUseFraction)
            self.var.IndustrialConsumptiveUseMM = self.var.IndustrialAbstractionMM * self.var.IndustryConsumptiveUseFraction
            # IndustrialAbstractionMM = scalar(timeinputsparse(IndustrialAbstractionMaps)) * (1-WaterReUseFraction);
            # Industrial Water Demand (mm per day)
            # WaterReUseFraction: Fraction of water re-used in industry (e.g. 50% = 0.5 = half of the water is re-used, used twice (baseline=0, maximum=1)
            # IndustrialConsumptiveUseMM is the amount that evaporates etc
            # only 1 map so this one is loaded in initial!

            IndustrialWaterAbstractionM3 = self.var.IndustrialConsumptiveUseMM * self.var.MMtoM3
            IndustrialAbstractionFromGroundwaterM3 = np.where(
                self.var.GroundwaterBodies > 0,
                self.var.FractionGroundwaterUsed *
                IndustrialWaterAbstractionM3, maskinfo.in_zero())
            IndustrialAbstractionFromNonConventionalWaterM3 = self.var.FractionNonConventionalWaterUsed * IndustrialWaterAbstractionM3
            IndustrialAbstractionFromSurfaceWaterM3 = IndustrialWaterAbstractionM3 - IndustrialAbstractionFromGroundwaterM3 - IndustrialAbstractionFromNonConventionalWaterM3

            # ************************************************************
            # ***** ENERGY ***********************************************
            # ************************************************************

            self.var.EnergyAbstractionMM = self.var.EnergyDemandMM
            self.var.EnergyConsumptiveUseMM = self.var.EnergyAbstractionMM * self.var.EnergyConsumptiveUseFraction
            # EnergyConsumptiveUseMM is the amount that evaporates etc

            EnergyAbstractionFromSurfaceWaterM3 = self.var.EnergyConsumptiveUseMM * self.var.MMtoM3
            # all taken from surface water

            # ************************************************************
            # ***** IRRIGATION *******************************************
            # ************************************************************

            # water demand from loop3 = irrigated zone
            self.var.Ta[2] = np.maximum(
                np.minimum(self.var.RWS[2] * self.var.TranspirMaxCorrected,
                           self.var.W1[2] - self.var.WWP1[2]),
                maskinfo.in_zero())

            IrrigationWaterDemandMM = (
                self.var.TranspirMaxCorrected -
                self.var.Ta[2]) * self.var.IrrigationMult
            #  a factor (IrrigationMult) add some water (to prevent salinisation)
            # irrigationWaterNeed assumed to be equal to potential transpiration minus actual transpiration
            # in mm here, assumed for the entire pixel, thus later to be corrected with IrrigationFraction
            # IrrigationType (value between 0 and 1) is used here to distinguish between additional adding water until fieldcapacity (value set to 1) or not (value set to 0)
            IrrigationWaterDemandMM = np.where(
                self.var.FrostIndex > self.var.FrostIndexThreshold,
                maskinfo.in_zero(), IrrigationWaterDemandMM)
            # IrrigationWaterDemand is 0 when soil is frozen

            IrrigationWaterAbstractionMM = np.where(
                (self.var.IrrigationEfficiency * self.var.ConveyanceEfficiency)
                > 0, IrrigationWaterDemandMM * self.var.IrrigationFraction /
                (self.var.IrrigationEfficiency *
                 self.var.ConveyanceEfficiency), maskinfo.in_zero())
            self.var.IrrigationWaterAbstractionM3 = np.maximum(
                IrrigationWaterAbstractionMM * self.var.MMtoM3,
                maskinfo.in_zero())
            # irrigation efficiency max 1, ~0.90 drip irrigation, ~0.75 sprinkling
            # conveyance efficiency, around 0.80 for average channel
            # multiplied by actual irrigated area (fraction) and cellsize(MMtoM3) in M3 per pixel

            IrrigationAbstractionFromGroundwaterM3 = np.where(
                self.var.GroundwaterBodies > 0,
                self.var.FractionGroundwaterUsed *
                self.var.IrrigationWaterAbstractionM3, maskinfo.in_zero())
            IrrigationAbstractionFromSurfaceWaterM3 = np.maximum(
                self.var.IrrigationWaterAbstractionM3 -
                IrrigationAbstractionFromGroundwaterM3, maskinfo.in_zero())

            # ************************************************************
            # ***** TOTAL ABSTRACTIONS (DEMANDED) ************************
            # ************************************************************

            self.var.TotalAbstractionFromGroundwaterM3 = IrrigationAbstractionFromGroundwaterM3 + DomAbstractionFromGroundwaterM3 + LivestockAbstractionFromGroundwaterM3 + IndustrialAbstractionFromGroundwaterM3
            self.var.TotalAbstractionFromSurfaceWaterM3 = IrrigationAbstractionFromSurfaceWaterM3 + self.var.PaddyRiceWaterAbstractionFromSurfaceWaterM3 + DomAbstractionFromSurfaceWaterM3 + LivestockAbstractionFromSurfaceWaterM3 + IndustrialAbstractionFromSurfaceWaterM3 + EnergyAbstractionFromSurfaceWaterM3

            PaddyRiceWaterAbstractionFromSurfaceWaterMM = self.var.PaddyRiceWaterAbstractionFromSurfaceWaterM3 * self.var.M3toMM
            # taken from paddy rice routine

            self.var.TotalDemandM3 = (
                self.var.LivestockAbstractionMM +
                self.var.DomesticAbstractionMM + IrrigationWaterAbstractionMM +
                PaddyRiceWaterAbstractionFromSurfaceWaterMM +
                self.var.IndustrialAbstractionMM +
                self.var.EnergyAbstractionMM) * self.var.MMtoM3

            self.var.TotalIrrigationAbstractionM3 += IrrigationAbstractionFromGroundwaterM3 + IrrigationAbstractionFromSurfaceWaterM3
            self.var.TotalPaddyRiceIrrigationAbstractionM3 += self.var.PaddyRiceWaterAbstractionFromSurfaceWaterM3
            # totals calculated for reporting, for comparing with national reported values and possible calibration

            # ************************************************************
            # ***** ABSTRACTION FROM GROUNDWATER *************************
            # ************************************************************

            self.var.LZ = self.var.LZ - self.var.TotalAbstractionFromGroundwaterM3 * self.var.M3toMM
            self.var.IrriLossCUM = self.var.IrriLossCUM + self.var.TotalAbstractionFromGroundwaterM3
            # Abstraction is taken from lower groundwater zone
            # for mass balance calculation also summed up in IrrilossCUM (in M3)

            # ***********************************************************************
            # ***** ABSTRACTION SUPPLIED BY NONCONVENTIONAL SOURCES (DESALINATION) **
            # ***********************************************************************

            self.var.NonConventionalWaterM3 = DomAbstractionFromNonConventionalWaterM3 + LivestockAbstractionFromNonConventionalWaterM3 + IndustrialAbstractionFromNonConventionalWaterM3
            # Non conventional water producted is not abstracted from surface water

            # ************************************************************
            # ***** ABSTRACTION FROM LAKES AND RESERVOIRS ****************
            # ************************************************************

            if option['simulateReservoirs']:
                # PotentialAbstractionFromReservoirsM3 = np.minimum(0.02 * self.var.ReservoirStorageM3, 0.01*self.var.TotalReservoirStorageM3C) #original
                PotentialAbstractionFromReservoirsM3 = np.minimum(
                    0.02 * self.var.ReservoirStorageM3,
                    0.01 * self.var.TotalReservoirStorageM3C) * self.var.DtDay

                PotentialAbstractionFromReservoirsM3 = np.where(
                    np.isnan(PotentialAbstractionFromReservoirsM3), 0,
                    PotentialAbstractionFromReservoirsM3)
            else:
                PotentialAbstractionFromReservoirsM3 = maskinfo.in_zero()

            if option['simulateLakes']:
                # CM
                # PotentialAbstractionFromLakesM3 = 0.10 * self.var.LakeStorageM3  #original
                PotentialAbstractionFromLakesM3 = 0.10 * self.var.LakeStorageM3 * self.var.DtDay

                PotentialAbstractionFromLakesM3 = np.where(
                    np.isnan(PotentialAbstractionFromLakesM3), 0,
                    PotentialAbstractionFromLakesM3)
            else:
                PotentialAbstractionFromLakesM3 = maskinfo.in_zero()

            if option['simulateReservoirs'] or option['simulateLakes']:
                PotentialAbstractionFromLakesAndReservoirsM3 = PotentialAbstractionFromLakesM3 + PotentialAbstractionFromReservoirsM3
                # potential total m3 that can be extracted from all lakes and reservoirs in a pixel
            else:
                PotentialAbstractionFromLakesAndReservoirsM3 = maskinfo.in_zero(
                )

            AreatotalPotentialAbstractionFromLakesAndReservoirsM3 = np.take(
                np.bincount(
                    self.var.WUseRegionC,
                    weights=PotentialAbstractionFromLakesAndReservoirsM3),
                self.var.WUseRegionC)
            # potential total m3 that can be extracted from all lakes and reservoirs in the water region

            AreatotalWaterAbstractionFromAllSurfaceSourcesM3 = np.take(
                np.bincount(
                    self.var.WUseRegionC,
                    weights=self.var.TotalAbstractionFromSurfaceWaterM3),
                self.var.WUseRegionC)
            # the total amount that needs to be extracted from surface water, lakes and reservoirs in the water region
            # self.var.FractionAllSurfaceWaterUsed = np.maximum(1 - self.var.FractionGroundwaterUsed - self.var.FractionNonConventionalWaterUsed,maskinfo.in_zero())
            # self.var.FractionSurfaceWaterUsed = np.maximum(1 - self.var.FractionGroundwaterUsed - self.var.FractionNonConventionalWaterUsed-self.var.FractionLakeReservoirWaterUsed,maskinfo.in_zero())
            # AreatotalWaterToBeAbstractedfromLakesReservoirsM3 = np.where( (self.var.FractionSurfaceWaterUsed+self.var.FractionLakeReservoirWaterUsed)> 0, (self.var.FractionLakeReservoirWaterUsed / (self.var.FractionSurfaceWaterUsed+self.var.FractionLakeReservoirWaterUsed)) * AreatotalWaterAbstractionFromAllSurfaceSourcesM3,maskinfo.in_zero())
            AreatotalWaterToBeAbstractedfromLakesReservoirsM3 = self.var.FractionLakeReservoirWaterUsed * AreatotalWaterAbstractionFromAllSurfaceSourcesM3
            self.var.AreatotalWaterAbstractedfromLakesReservoirsM3 = np.minimum(
                AreatotalWaterToBeAbstractedfromLakesReservoirsM3,
                AreatotalPotentialAbstractionFromLakesAndReservoirsM3)
            # total amount of m3 abstracted from all lakes and reservoirs in the water regions
            FractionAbstractedByLakesReservoirs = np.where(
                AreatotalWaterAbstractionFromAllSurfaceSourcesM3 > 0,
                self.var.AreatotalWaterAbstractedfromLakesReservoirsM3 /
                AreatotalWaterAbstractionFromAllSurfaceSourcesM3,
                maskinfo.in_zero())

            self.var.TotalAbstractionFromSurfaceWaterM3 = self.var.TotalAbstractionFromSurfaceWaterM3 * (
                1 - FractionAbstractedByLakesReservoirs)
            # the original surface water abstraction amount is corrected for what is now already abstracted by lakes and reservoirs

            FractionLakesReservoirsEmptying = np.where(
                AreatotalPotentialAbstractionFromLakesAndReservoirsM3 > 0,
                self.var.AreatotalWaterAbstractedfromLakesReservoirsM3 /
                AreatotalPotentialAbstractionFromLakesAndReservoirsM3,
                maskinfo.in_zero())

            self.var.LakeAbstractionM3 = PotentialAbstractionFromLakesM3 * FractionLakesReservoirsEmptying
            if option['simulateLakes']:
                self.var.LakeStorageM3 = self.var.LakeStorageM3 - self.var.LakeAbstractionM3

            self.var.ReservoirAbstractionM3 = PotentialAbstractionFromReservoirsM3 * FractionLakesReservoirsEmptying
            if option['simulateReservoirs']:
                self.var.ReservoirStorageM3 = self.var.ReservoirStorageM3 - self.var.ReservoirAbstractionM3
                # subtract abstracted water from lakes and reservoir storage

            # ************************************************************
            # ***** Abstraction from channels ****************************
            # ***** average abstraction taken from entire waterregion ****
            # ***** limited by available channel water and e-flow minimum*
            # ************************************************************

            AreaTotalDemandedAbstractionFromSurfaceWaterM3 = np.maximum(
                np.take(
                    np.bincount(
                        self.var.WUseRegionC,
                        weights=self.var.TotalAbstractionFromSurfaceWaterM3),
                    self.var.WUseRegionC), 0)

            PixelAvailableWaterFromChannelsM3 = np.maximum(
                self.var.ChanM3Kin - self.var.EFlowThreshold * self.var.DtSec,
                0) * (1 - self.var.WUsePercRemain)
            # respecting e-flow

            AreaTotalAvailableWaterFromChannelsM3 = np.maximum(
                np.take(
                    np.bincount(self.var.WUseRegionC,
                                weights=PixelAvailableWaterFromChannelsM3),
                    self.var.WUseRegionC), 0)
            AreaTotalDemandedWaterFromChannelsM3 = np.minimum(
                AreaTotalAvailableWaterFromChannelsM3,
                AreaTotalDemandedAbstractionFromSurfaceWaterM3)

            self.var.FractionAbstractedFromChannels = np.where(
                AreaTotalAvailableWaterFromChannelsM3 > 0,
                np.minimum(
                    AreaTotalDemandedWaterFromChannelsM3 /
                    AreaTotalAvailableWaterFromChannelsM3, 1), 0)
            # IS THE DEFINITION OF AreaTotalDemandedWaterFromChannelsM3 REDUNDANT WITH np.minimum(...) ABOVE?
            # fraction that is abstracted from channels (should be 0-1)
            self.var.WUseAddM3 = self.var.FractionAbstractedFromChannels * PixelAvailableWaterFromChannelsM3
            # pixel abstracted water in m3

            self.var.WUseAddM3Dt = self.var.WUseAddM3 * self.var.InvNoRoutSteps
            # splitting water use per timestep into water use per sub time step

            self.var.wateruseCum += self.var.WUseAddM3
            # summing up for water balance calculation
            # If report wateruse
            if (option['repwateruseGauges']) or (option['repwateruseSites']):
                self.var.WUseSumM3 = accuflux(
                    self.var.Ldd,
                    decompress(self.var.WUseAddM3) * self.var.InvDtSec)

            # totalAdd = areatotal(decompress(WUseAddM3),self.var.WUseRegion);
            self.var.totalAddM3 = np.take(
                np.bincount(self.var.WUseRegionC, weights=self.var.WUseAddM3),
                self.var.WUseRegionC)

            self.var.WaterUseShortageM3 = self.var.TotalAbstractionFromSurfaceWaterM3 - self.var.WUseAddM3
            # amount of M3 that cannot be extracted from any source, including the channels

            self.var.PotentialSurfaceWaterAvailabilityForIrrigationM3 = np.maximum(
                PixelAvailableWaterFromChannelsM3 -
                self.var.TotalAbstractionFromSurfaceWaterM3 +
                IrrigationAbstractionFromSurfaceWaterM3 +
                self.var.PaddyRiceWaterAbstractionFromSurfaceWaterM3, 0.0)
            # available water excluding the surface water irrigation needs

            # ************************************************************
            # ***** Water Allocation *************************************
            # ***** average abstraction taken from entire waterregion ****
            # ***** limited by available channel water and e-flow minimum*
            # ************************************************************

            # totalAbstr = areatotal(decompress(TotalAbstractionFromSurfaceWaterM3),self.var.WUseRegion)
            self.var.AreaTotalAbstractionFromSurfaceWaterM3 = np.take(
                np.bincount(
                    self.var.WUseRegionC,
                    weights=self.var.TotalAbstractionFromSurfaceWaterM3 -
                    self.var.WUseAddM3), self.var.WUseRegionC)
            self.var.AreaTotalAbstractionFromGroundwaterM3 = np.take(
                np.bincount(
                    self.var.WUseRegionC,
                    weights=self.var.TotalAbstractionFromGroundwaterM3),
                self.var.WUseRegionC)

            # demand
            self.var.AreaTotalDemandM3 = np.take(
                np.bincount(self.var.WUseRegionC,
                            weights=self.var.TotalDemandM3),
                self.var.WUseRegionC)

            # totalEne = areatotal(decompress(self.var.EnergyConsumptiveUseMM*self.var.MMtoM3),self.var.WUseRegion)
            AreatotalIrriM3 = np.take(
                np.bincount(
                    self.var.WUseRegionC,
                    weights=IrrigationAbstractionFromSurfaceWaterM3 +
                    self.var.PaddyRiceWaterAbstractionFromSurfaceWaterM3),
                self.var.WUseRegionC)
            # AreatotalDomM3 = np.take(np.bincount(self.var.WUseRegionC, weights=DomAbstractionFromSurfaceWaterM3),
            #                          self.var.WUseRegionC)
            # AreatotalLiveM3 = np.take(np.bincount(self.var.WUseRegionC, weights=LivestockAbstractionFromSurfaceWaterM3),
            #                           self.var.WUseRegionC)
            # AreatotalIndM3 = np.take(np.bincount(self.var.WUseRegionC, weights=IndustrialAbstractionFromSurfaceWaterM3),
            #                          self.var.WUseRegionC)
            # AreatotalEneM3 = np.take(np.bincount(self.var.WUseRegionC, weights=EnergyAbstractionFromSurfaceWaterM3),
            #                          self.var.WUseRegionC)

            # Allocation rule: Domestic ->  Energy -> Livestock -> Industry -> Irrigation
            self.var.AreatotalIrrigationShortageM3 = np.take(
                np.bincount(self.var.WUseRegionC,
                            weights=self.var.WaterUseShortageM3),
                self.var.WUseRegionC)
            self.var.AreatotalIrrigationUseM3 = np.maximum(
                AreatotalIrriM3 - self.var.AreatotalIrrigationShortageM3, 0.0)

            with np.errstate(all='ignore'):
                fractionIrrigationAvailability = np.where(
                    AreatotalIrriM3 > 0,
                    self.var.AreatotalIrrigationUseM3 / AreatotalIrriM3, 1.0)

                self.var.IrrigationWaterAbstractionM3 = fractionIrrigationAvailability * IrrigationAbstractionFromSurfaceWaterM3 + IrrigationAbstractionFromGroundwaterM3
                # real irrigation is percentage of avail/demand for waterregion * old surface + old groundwater abstraction
                IrrigationWaterDemand = self.var.IrrigationWaterAbstractionM3 * self.var.M3toMM
                IrrigationWaterDemand = np.where(
                    self.var.IrrigationFraction > 0,
                    IrrigationWaterDemand / self.var.IrrigationFraction, 0.0)

            # for mass balance calculate the loss of irrigation water
            # ---------------------------------------------------------
            # updating soil in loop3=irrigation
            # ---------------------------------------------------------

            Wold = self.var.W1[2]
            IrrigationDemandW1b = np.maximum(
                IrrigationWaterDemand - (self.var.WFilla - self.var.W1a[2]), 0)
            self.var.W1a[2] = np.where(
                self.var.W1a[2] >= self.var.WFilla, self.var.W1a[2],
                np.minimum(self.var.WFilla,
                           self.var.W1a[2] + IrrigationWaterDemand))
            self.var.W1b[2] = np.where(
                self.var.W1b[2] >= self.var.WFillb, self.var.W1b[2],
                np.minimum(self.var.WFillb,
                           self.var.W1b[2] + IrrigationDemandW1b))
            self.var.W1[2] = np.add(self.var.W1a[2], self.var.W1b[2])
            # if irrigated soil is less than Pf3 then fill up to Pf3 (if there is water demand)
            # if more than Pf3 the additional water is transpirated
            # there is already no water demand if the soil is frozen
            Wdiff = self.var.W1[2] - Wold
            self.var.Ta[2] = self.var.Ta[2] + IrrigationWaterDemand - Wdiff

            self.var.IrriLossCUM = self.var.IrriLossCUM - self.var.IrrigationWaterAbstractionM3 * self.var.IrrigationEfficiency * self.var.ConveyanceEfficiency - Wdiff * self.var.MMtoM3 * self.var.IrrigationFraction

            # Added to TA but also
            # for mass balance calculate the loss of irrigation water
            # AdR: irrigation demand added to W1 and Ta; so assumption here that soil moisture stays the same
            # we could also abstract more water equivalent to satisfy Ta and bring soil moisture to pF2 or so, for later consideration#
            # self.var.Ta[2] = np.where(self.var.FrostIndex > self.var.FrostIndexThreshold, maskinfo.in_zero(), self.var.Ta[2])
            # transpiration is 0 when soil is frozen

            # ---------------------------------------------------------
            # E-flow
            # ---------------------------------------------------------

            self.var.EFlowIndicator = np.where(
                self.var.ChanQ <= self.var.EFlowThreshold,
                maskinfo.in_zero() + 1.0, maskinfo.in_zero())
            # if ChanQ is less than EflowThreshold, EFlowIndicator becomes 1

            # ************************************************************
            # ***** update state variables                             ***
            # ************************************************************
            # CM Update state variables for changes to W1a[2] and W1b[2]
            self.var.Theta1a[2] = self.var.W1a[2] / self.var.SoilDepth1a[2]
            self.var.Theta1b[2] = self.var.W1b[2] / self.var.SoilDepth1b[2]

            # ************************************************************
            # ***** smooth lower zone with correction                  ***
            # ************************************************************

            if option['groundwaterSmooth']:
                LZPcr = decompress(self.var.LZ)

                Range = self.var.LZSmoothRange * celllength()

                LZTemp1 = ifthen(self.var.GroundwaterBodiesPcr == 1, LZPcr)
                LZTemp2 = ifthen(self.var.GroundwaterBodiesPcr == 1,
                                 windowtotal(LZTemp1, Range))
                LZTemp3 = windowtotal(LZTemp1 * 0 + 1, Range)
                LZSmooth = ifthenelse(LZTemp3 == 0, 0.0,
                                      pcrDiv(LZTemp2, LZTemp3))
                LZPcr = ifthenelse(self.var.GroundwaterBodiesPcr == 0, LZPcr,
                                   0.9 * LZPcr + 0.1 * LZSmooth)

                diffCorr = 0.1 * areaaverage(LZSmooth - LZTemp1,
                                             self.var.groundwaterCatch)
                # error of 0.1  LZSmooth operation (same factor of 0.1 as above)
                LZPcr -= cover(diffCorr, 0)
                # correction of LZ by the average error from smoothing operation

                self.var.LZ = compressArray(LZPcr)
Пример #11
0
    def initial(self):
        """ initial part of the routing module
        """
        maskinfo = MaskInfo.instance()
        self.var.avgdis = maskinfo.in_zero()
        self.var.Beta = loadmap('beta')
        self.var.InvBeta = 1 / self.var.Beta
        # Inverse of beta for kinematic wave
        self.var.ChanLength = loadmap('ChanLength').astype(float)
        self.var.InvChanLength = 1 / self.var.ChanLength
        # Inverse of channel length [1/m]

        self.var.NoRoutSteps = int(
            np.maximum(1, round(self.var.DtSec / self.var.DtSecChannel, 0)))
        # Number of sub-steps based on value of DtSecChannel,
        # or 1 if DtSec is smaller than DtSecChannel
        settings = LisSettings.instance()
        option = settings.options
        if option['InitLisflood']:
            self.var.NoRoutSteps = 1
            # InitLisflood is used!
            # so channel routing step is the same as the general time step
        self.var.DtRouting = self.var.DtSec / self.var.NoRoutSteps
        # Corresponding sub-timestep (seconds)
        self.var.InvDtRouting = 1 / self.var.DtRouting
        self.var.InvNoRoutSteps = 1 / float(self.var.NoRoutSteps)
        # inverse for faster calculation inside the dynamic section

        # -------------------------- LDD

        self.var.Ldd = lddmask(loadmap('Ldd', pcr=True, lddflag=True),
                               self.var.MaskMap)
        # Cut ldd to size of MaskMap (NEW, 29/9/2004)
        # Prevents 'unsound' ldd if MaskMap covers sub-area of ldd

        # Count (inverse of) upstream area for each pixel
        # Needed if we want to calculate average values of variables
        # upstream of gauge locations

        self.var.UpArea = accuflux(self.var.Ldd, self.var.PixelAreaPcr)
        # Upstream contributing area for each pixel
        # Note that you might expext that values of UpArea would be identical to
        # those of variable CatchArea (see below) at the outflow points.
        # This is NOT actually the case, because outflow points are shifted 1
        # cell in upstream direction in the calculation of CatchArea!
        self.var.InvUpArea = 1 / self.var.UpArea
        # Calculate inverse, so we can multiply in dynamic (faster than divide)

        self.var.IsChannelPcr = boolean(loadmap('Channels', pcr=True))
        self.var.IsChannel = np.bool8(compressArray(self.var.IsChannelPcr))
        # Identify channel pixels
        self.var.IsChannelKinematic = self.var.IsChannel.copy()
        # Identify kinematic wave channel pixels
        # (identical to IsChannel, unless dynamic wave is used, see below)
        #self.var.IsStructureKinematic = pcraster.boolean(0)
        self.var.IsStructureKinematic = np.bool8(maskinfo.in_zero())

        # Map that identifies special inflow/outflow structures (reservoirs, lakes) within the
        # kinematic wave channel routing. Set to (dummy) value of zero modified in reservoir and lake
        # routines (if those are used)
        LddChan = lddmask(self.var.Ldd, self.var.IsChannelPcr)
        # ldd for Channel network
        self.var.MaskMap = boolean(self.var.Ldd)
        # Use boolean version of Ldd as calculation mask
        # (important for correct mass balance check
        # any water generated outside of Ldd won't reach
        # channel anyway)
        self.var.LddToChan = lddrepair(
            ifthenelse(self.var.IsChannelPcr, 5, self.var.Ldd))
        # Routing of runoff (incl. ground water)en
        AtOutflow = boolean(pit(self.var.Ldd))
        # find outlet points...

        if option['dynamicWave']:
            IsChannelDynamic = boolean(loadmap('ChannelsDynamic', pcr=True))
            # Identify channel pixels where dynamic wave is used
            self.var.IsChannelKinematic = (self.var.IsChannelPcr
                                           == 1) & (IsChannelDynamic == 0)
            # Identify (update) channel pixels where kinematic wave is used
            self.var.LddKinematic = lddmask(self.var.Ldd,
                                            self.var.IsChannelKinematic)
            # Ldd for kinematic wave: ends (pit) just before dynamic stretch
            LddDynamic = lddmask(self.var.Ldd, IsChannelDynamic)
            # Ldd for dynamic wave

            # Following statements produce an ldd network that connects the pits in
            # LddKinematic to the nearest downstream dynamic wave pixel
            LddToDyn = lddrepair(ifthenelse(IsChannelDynamic, 5, self.var.Ldd))
            # Temporary ldd: flow paths end in dynamic pixels
            PitsKinematic = cover(boolean(pit(self.var.LddKinematic)), 0)
            # Define start of each flow path at pit on LddKinematic
            PathKinToDyn = path(LddToDyn, PitsKinematic)
            # Identify paths that connect pits in LddKinematic to dynamic wave
            # pixels
            LddKinToDyn = lddmask(LddToDyn, PathKinToDyn)
            # Create ldd
            DynWaveBoundaryCondition = boolean(pit(LddDynamic))
            # NEW 12-7-2005 (experimental)
            # Location of boundary condition dynamic wave

            self.var.AtLastPoint = (downstream(
                self.var.Ldd,
                AtOutflow) == 1) & (AtOutflow != 1) & self.var.IsChannelPcr

            # NEW 23-6-2005
            # Dynamic wave routine gives no outflow out of pits, so we calculate this
            # one cell upstream (WvD)
            # (implies that most downstream cell is not taken into account in mass balance
            # calculations, even if dyn wave is not used)
            # Only include points that are on a channel (otherwise some small 'micro-catchments'
            # are included, for which the mass balance cannot be calculated
            # properly)

        else:
            self.var.LddKinematic = LddChan
            # No dynamic wave, so kinematic ldd equals channel ldd
            self.var.AtLastPoint = AtOutflow
            self.var.AtLastPointC = np.bool8(
                compressArray(self.var.AtLastPoint))
            # assign unique identifier to each of them
        maskinfo = MaskInfo.instance()
        lddC = compressArray(self.var.LddKinematic)
        inAr = decompress(np.arange(maskinfo.info.mapC[0], dtype="int32"))
        # giving a number to each non missing pixel as id
        self.var.downstruct = (compressArray(
            downstream(self.var.LddKinematic, inAr))).astype("int32")
        # each upstream pixel gets the id of the downstream pixel
        self.var.downstruct[lddC == 5] = maskinfo.info.mapC[0]
        # all pits gets a high number
        #d3=np.bincount(self.var.down, weights=loadmap('AvgDis'))[:-1]
        # upstream function in numpy

        OutflowPoints = nominal(uniqueid(self.var.AtLastPoint))
        # and assign unique identifier to each of them
        self.var.Catchments = (compressArray(
            catchment(self.var.Ldd, OutflowPoints))).astype(np.int32)
        CatchArea = np.bincount(
            self.var.Catchments,
            weights=self.var.PixelArea)[self.var.Catchments]
        #CatchArea = CatchArea[self.var.Catchments]
        # define catchment for each outflow point
        #CatchArea = areatotal(self.var.PixelArea, self.var.Catchments)

        # Compute area of each catchment [m2]
        # Note: in earlier versions this was calculated using the "areaarea" function,
        # changed to "areatotal" in order to enable handling of grids with spatially
        # variable cell areas (e.g. lat/lon grids)
        self.var.InvCatchArea = 1 / CatchArea
        # inverse of catchment area [1/m2]

        # ************************************************************
        # ***** CHANNEL GEOMETRY  ************************************
        # ************************************************************

        self.var.ChanGrad = np.maximum(loadmap('ChanGrad'),
                                       loadmap('ChanGradMin'))
        # avoid calculation of Alpha using ChanGrad=0: this creates MV!
        self.var.CalChanMan = loadmap('CalChanMan')
        self.var.ChanMan = self.var.CalChanMan * loadmap('ChanMan')
        # Manning's n is multiplied by ChanManCal
        # enables calibration for peak timing
        self.var.ChanBottomWidth = loadmap('ChanBottomWidth')
        ChanDepthThreshold = loadmap('ChanDepthThreshold')
        ChanSdXdY = loadmap('ChanSdXdY')
        self.var.ChanUpperWidth = self.var.ChanBottomWidth + 2 * ChanSdXdY * ChanDepthThreshold
        # Channel upper width [m]
        self.var.TotalCrossSectionAreaBankFull = 0.5 * \
            ChanDepthThreshold * (self.var.ChanUpperWidth + self.var.ChanBottomWidth)
        # Area (sq m) of bank full discharge cross section [m2]
        # (trapezoid area equation)
        TotalCrossSectionAreaHalfBankFull = 0.5 * self.var.TotalCrossSectionAreaBankFull
        # Cross-sectional area at half bankfull [m2]
        # This can be used to initialise channel flow (see below)

        TotalCrossSectionAreaInitValue = loadmap(
            'TotalCrossSectionAreaInitValue')
        self.var.TotalCrossSectionArea = np.where(
            TotalCrossSectionAreaInitValue == -9999,
            TotalCrossSectionAreaHalfBankFull, TotalCrossSectionAreaInitValue)
        # Total cross-sectional area [m2]: if initial value in binding equals -9999 the value at half bankfull is used,
        # otherwise TotalCrossSectionAreaInitValue (typically end map from previous simulation)

        if option['SplitRouting']:
            # in_zero = maskinfo.in_zero()
            CrossSection2AreaInitValue = loadmap('CrossSection2AreaInitValue')
            self.var.CrossSection2Area = np.where(
                CrossSection2AreaInitValue == -9999, maskinfo.in_zero(),
                CrossSection2AreaInitValue)
            # cross-sectional area [m2] for 2nd line of routing: if initial value in binding equals -9999 the value is set to 0
            # otherwise CrossSection2AreaInitValue (typically end map from previous simulation)

            PrevSideflowInitValue = loadmap('PrevSideflowInitValue')

            self.var.Sideflow1Chan = np.where(PrevSideflowInitValue == -9999,
                                              maskinfo.in_zero(),
                                              PrevSideflowInitValue)
            # sideflow from previous run for 1st line of routing: if initial value in binding equals -9999 the value is set to 0
            # otherwise PrevSideflowInitValue (typically end map from previous simulation)

        # ************************************************************
        # ***** CHANNEL ALPHA (KIN. WAVE)*****************************
        # ************************************************************
        # Following calculations are needed to calculate Alpha parameter in kinematic
        # wave. Alpha currently fixed at half of bankful depth (this may change in
        # future versions!)

        ChanWaterDepthAlpha = np.where(self.var.IsChannel,
                                       0.5 * ChanDepthThreshold, 0.0)
        # Reference water depth for calculation of Alpha: half of bankfull
        self.var.ChanWettedPerimeterAlpha = self.var.ChanBottomWidth + 2 * \
            np.sqrt(np.square(ChanWaterDepthAlpha) + np.square(ChanWaterDepthAlpha * ChanSdXdY))
        # Channel wetted perimeter [m](Pythagoras)
        AlpTermChan = (self.var.ChanMan /
                       (np.sqrt(self.var.ChanGrad)))**self.var.Beta
        self.var.AlpPow = 2.0 / 3.0 * self.var.Beta

        self.var.ChannelAlpha = (
            AlpTermChan *
            (self.var.ChanWettedPerimeterAlpha**self.var.AlpPow)).astype(float)
        self.var.InvChannelAlpha = 1 / self.var.ChannelAlpha
        # ChannelAlpha for kinematic wave

        # ************************************************************
        # ***** CHANNEL INITIAL DISCHARGE ****************************
        # ************************************************************

        self.var.ChanM3 = self.var.TotalCrossSectionArea * self.var.ChanLength
        # channel water volume [m3]
        self.var.ChanIniM3 = self.var.ChanM3.copy()
        self.var.ChanM3Kin = self.var.ChanIniM3.copy().astype(float)
        # Initialise water volume in kinematic wave channels [m3]
        self.var.ChanQKin = np.where(self.var.ChannelAlpha > 0,
                                     (self.var.TotalCrossSectionArea /
                                      self.var.ChannelAlpha)**self.var.InvBeta,
                                     0).astype(float)

        # Initialise discharge at kinematic wave pixels (note that InvBeta is
        # simply 1/beta, computational efficiency!)

        self.var.CumQ = maskinfo.in_zero()
        # ininialise sum of discharge to calculate average

        # ************************************************************
        # ***** CHANNEL INITIAL DYNAMIC WAVE *************************
        # ************************************************************
        if option['dynamicWave']:
            pass
            # TODO !!!!!!!!!!!!!!!!!!!!

    #     lookchan = lookupstate(TabCrossSections, ChanCrossSections, ChanBottomLevel, self.var.ChanLength,
    #                            DynWaveConstantHeadBoundary + ChanBottomLevel)
    #     ChanIniM3 = ifthenelse(AtOutflow, lookchan, ChanIniM3)
    # Correct ChanIniM3 for constant head boundary in pit (only if
    # dynamic wave is used)
    #     ChanM3Dyn = ChanIniM3
    # Set volume of water in dynamic wave channel to initial value
    # (note that initial condition is expressed as a state in [m3] for the dynamic wave,
    # and as a rate [m3/s] for the kinematic wave (a bit confusing)

    # Estimate number of iterations needed in first time step (based on Courant criterium)
    # TO DO !!!!!!!!!!!!!!!!!!!!
    #    Potential = lookuppotential(
    #        TabCrossSections, ChanCrossSections, ChanBottomLevel, self.var.ChanLength, ChanM3Dyn)
    # Potential
    #    WaterLevelDyn = Potential - ChanBottomLevel
    # Water level [m above bottom level)
    #    WaveCelerityDyn = pcraster.sqrt(9.81 * WaterLevelDyn)
    # Dynamic wave celerity [m/s]
    #    CourantDynamic = self.var.DtSec * \
    #        (WaveCelerityDyn + 2) / self.var.ChanLength
    # Courant number for dynamic wave
    # We don't know the water velocity at this time so
    # we just guess it's 2 m/s (Odra tests show that flow velocity
    # is typically much lower than wave celerity, and 2 m/s is quite
    # high already so this gives a pretty conservative/safe estimate
    # for DynWaveIterations)
    #    DynWaveIterationsTemp = max(
    #        1, roundup(CourantDynamic / CourantDynamicCrit))
    #    DynWaveIterations = ordinal(mapmaximum(DynWaveIterationsTemp))
    # Number of sub-steps needed for required numerical
    # accuracy. Always greater than or equal to 1
    # (otherwise division by zero!)

    # TEST
    # If polder option is used, we need an estimate of the initial channel discharge, but we don't know this
    # for the dynamic wave pixels (since only initial state is known)! Try if this works (dyn wave flux based on zero inflow 1 iteration)
    # Note that resulting ChanQ is ONLY used in the polder routine!!!
    # Since we need instantaneous estimate at start of time step, a
    # ChanQM3Dyn is calculated for one single one-second time step!!!

    #    ChanQDyn = dynwaveflux(TabCrossSections,
    #                           ChanCrossSections,
    #                           LddDynamic,
    #                           ChanIniM3,
    #                           0.0,
    #                           ChanBottomLevel,
    #                           self.var.ChanMan,
    #                           self.var.ChanLength,
    #                           1,
    #                           1,
    #                           DynWaveBoundaryCondition)
    # Compute volume and discharge in channel after dynamic wave
    # ChanM3Dyn in [cu m]
    # ChanQDyn in [cu m / s]
    #    self.var.ChanQ = ifthenelse(
    #        IsChannelDynamic, ChanQDyn, self.var.ChanQKin)
    # Channel discharge: combine results of kinematic and dynamic wave
        else:

            # ***** NO DYNAMIC WAVE *************************
            # Dummy code if dynamic wave is not used, in which case ChanQ equals ChanQKin
            # (needed only for polder routine)

            PrevDischarge = loadmap('PrevDischarge')
            self.var.ChanQ = np.where(PrevDischarge == -9999,
                                      self.var.ChanQKin, PrevDischarge)
            # initialise channel discharge: cold start: equal to ChanQKin
            # [m3/s]

        # Initialising cumulative output variables
        # These are all needed to compute the cumulative mass balance error

        self.var.DischargeM3Out = maskinfo.in_zero()
        # cumulative discharge at outlet [m3]
        self.var.TotalQInM3 = maskinfo.in_zero()
        # cumulative inflow from inflow hydrographs [m3]
        #self.var.sumDis = maskinfo.in_zero()
        self.var.sumDis = maskinfo.in_zero()
        self.var.sumIn = maskinfo.in_zero()
Пример #12
0
def subcatch_stream(ldd, threshold, stream=None, min_strahler=-999, max_strahler=999, assign_edge=False, assign_existing=False, up_area=None, basin=None):
    """
    Derive catchments based upon strahler threshold
    Input:
        ldd -- pcraster object direction, local drain directions
        threshold -- integer, strahler threshold, subcatchments ge threshold
            are derived
        stream=None -- pcraster object ordinal, stream order map (made with pcr.streamorder), if provided, stream order
            map is not generated on the fly but used from this map. Useful when a subdomain within a catchment is
            provided, which would cause edge effects in the stream order map
        min_strahler=-999 -- integer, minimum strahler threshold of river catchments
            to return
        max_strahler=999 -- integer, maximum strahler threshold of river catchments
            to return
        assign_unique=False -- if set to True, unassigned connected areas at
            the edges of the domain are assigned a unique id as well. If set
            to False, edges are not assigned
        assign_existing=False == if set to True, unassigned edges are assigned
            to existing basins with an upstream weighting. If set to False,
            edges are assigned to unique IDs, or not assigned
    output:
        stream_ge -- pcraster object, streams of strahler order ge threshold
        subcatch -- pcraster object, subcatchments of strahler order ge threshold

    """
    # derive stream order

    if stream is None:
        stream = pcr.streamorder(ldd)

    stream_ge = pcr.ifthen(stream >= threshold, stream)
    stream_up_sum = pcr.ordinal(pcr.upstream(ldd, pcr.cover(pcr.scalar(stream_ge), 0)))
    # detect any transfer of strahler order, to a higher strahler order.
    transition_strahler = pcr.ifthenelse(pcr.downstream(ldd, stream_ge) != stream_ge, pcr.boolean(1),
                                         pcr.ifthenelse(pcr.nominal(ldd) == 5, pcr.boolean(1), pcr.ifthenelse(pcr.downstream(ldd, pcr.scalar(stream_up_sum)) > pcr.scalar(stream_ge), pcr.boolean(1),
                                                                                                              pcr.boolean(0))))
    # make unique ids (write to file)
    transition_unique = pcr.ordinal(pcr.uniqueid(transition_strahler))

    # derive upstream catchment areas (write to file)
    subcatch = pcr.nominal(pcr.subcatchment(ldd, transition_unique))
    # mask out areas outside basin
    if basin is not None:
        subcatch = pcr.ifthen(basin, subcatch)

    if assign_edge:
        # fill unclassified areas (in pcraster equal to zero) with a unique id, above the maximum id assigned so far
        unique_edge = pcr.clump(pcr.ifthen(subcatch==0, pcr.ordinal(0)))
        subcatch = pcr.ifthenelse(subcatch==0, pcr.nominal(pcr.mapmaximum(pcr.scalar(subcatch)) + pcr.scalar(unique_edge)), pcr.nominal(subcatch))
    elif assign_existing:
        # unaccounted areas are added to largest nearest draining basin
        if up_area is None:
            up_area = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), pcr.accuflux(ldd, 1))
        riverid = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), subcatch)

        friction = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)) # *(pcr.scalar(ldd)*0+1)
        delta = pcr.ifthen(pcr.scalar(ldd)>=0, pcr.ifthen(pcr.cover(subcatch, 0)==0, pcr.spreadzone(pcr.cover(riverid, 0), 0, friction)))
        subcatch = pcr.ifthenelse(pcr.boolean(pcr.cover(subcatch, 0)),
                                      subcatch,
                                      delta)

    # finally, only keep basins with minimum and maximum river order flowing through them
    strahler_subcatch = pcr.areamaximum(stream, subcatch)
    subcatch = pcr.ifthen(pcr.ordinal(strahler_subcatch) >= min_strahler, pcr.ifthen(pcr.ordinal(strahler_subcatch) <= max_strahler, subcatch))

    return stream_ge, pcr.ordinal(subcatch)
Пример #13
0
def main():
    ### Read input arguments #####
    parser = OptionParser()
    usage = "usage: %prog [options]"
    parser = OptionParser(usage=usage)
    parser.add_option('-q',
                      '--quiet',
                      dest='verbose',
                      default=True,
                      action='store_false',
                      help='do not print status messages to stdout')
    parser.add_option('-i',
                      '--ini',
                      dest='inifile',
                      default='hand_contour_inun.ini',
                      nargs=1,
                      help='ini configuration file')
    parser.add_option('-f',
                      '--flood_map',
                      nargs=1,
                      dest='flood_map',
                      help='Flood map file (NetCDF point time series file')
    parser.add_option('-v',
                      '--flood_variable',
                      nargs=1,
                      dest='flood_variable',
                      default='water_level',
                      help='variable name of flood water level')
    parser.add_option(
        '-b',
        '--bankfull_map',
        dest='bankfull_map',
        default='',
        help=
        'Map containing bank full level (is subtracted from flood map, in NetCDF)'
    )
    parser.add_option(
        '-c',
        '--catchment',
        dest='catchment_strahler',
        default=7,
        type='int',
        help='Strahler order threshold >= are selected as catchment boundaries'
    )
    parser.add_option('-s',
                      '--hand_strahler',
                      dest='hand_strahler',
                      default=7,
                      type='int',
                      help='Strahler order threshold >= selected as riverine')
    parser.add_option('-d',
                      '--destination',
                      dest='dest_path',
                      default='inun',
                      help='Destination path')
    (options, args) = parser.parse_args()

    if not os.path.exists(options.inifile):
        print 'path to ini file cannot be found'
        sys.exit(1)
    options.dest_path = os.path.abspath(options.dest_path)

    if not (os.path.isdir(options.dest_path)):
        os.makedirs(options.dest_path)

    # set up the logger
    flood_name = os.path.split(options.flood_map)[1].split('.')[0]
    case_name = 'inun_{:s}_hand_{:02d}_catch_{:02d}'.format(
        flood_name, options.hand_strahler, options.catchment_strahler)
    logfilename = os.path.join(options.dest_path, 'hand_contour_inun.log')
    logger, ch = inun_lib.setlogger(logfilename, 'HAND_INUN', options.verbose)
    logger.info('$Id: $')
    logger.info('Flood map: {:s}'.format(options.flood_map))
    logger.info('Bank full map: {:s}'.format(options.bankfull_map))
    logger.info('Destination path: {:s}'.format(options.dest_path))
    # read out ini file
    ### READ CONFIG FILE
    # open config-file
    config = inun_lib.open_conf(options.inifile)

    # read settings
    options.dem_file = inun_lib.configget(config, 'maps', 'dem_file', True)
    options.ldd_file = inun_lib.configget(config, 'maps', 'ldd_file', True)
    options.stream_file = inun_lib.configget(config, 'maps', 'stream_file',
                                             True)
    options.riv_length_file = inun_lib.configget(config, 'maps',
                                                 'riv_length_file', True)
    options.riv_width_file = inun_lib.configget(config, 'maps',
                                                'riv_width_file', True)
    options.file_format = inun_lib.configget(config,
                                             'maps',
                                             'file_format',
                                             0,
                                             datatype='int')
    options.x_tile = inun_lib.configget(config,
                                        'tiling',
                                        'x_tile',
                                        10000,
                                        datatype='int')
    options.y_tile = inun_lib.configget(config,
                                        'tiling',
                                        'y_tile',
                                        10000,
                                        datatype='int')
    options.x_overlap = inun_lib.configget(config,
                                           'tiling',
                                           'x_overlap',
                                           1000,
                                           datatype='int')
    options.y_overlap = inun_lib.configget(config,
                                           'tiling',
                                           'y_overlap',
                                           1000,
                                           datatype='int')
    options.iterations = inun_lib.configget(config,
                                            'inundation',
                                            'iterations',
                                            20,
                                            datatype='int')
    options.initial_level = inun_lib.configget(config,
                                               'inundation',
                                               'initial_level',
                                               32.,
                                               datatype='float')
    options.area_multiplier = inun_lib.configget(config,
                                                 'inundation',
                                                 'area_multiplier',
                                                 1.,
                                                 datatype='float')
    logger.info('DEM file: {:s}'.format(options.dem_file))
    logger.info('LDD file: {:s}'.format(options.ldd_file))
    logger.info('Columns per tile: {:d}'.format(options.x_tile))
    logger.info('Rows per tile: {:d}'.format(options.y_tile))
    logger.info('Columns overlap: {:d}'.format(options.x_overlap))
    logger.info('Rows overlap: {:d}'.format(options.y_overlap))
    metadata_global = {}
    # add metadata from the section [metadata]
    meta_keys = config.options('metadata_global')
    for key in meta_keys:
        metadata_global[key] = config.get('metadata_global', key)
    # add a number of metadata variables that are mandatory
    metadata_global['config_file'] = os.path.abspath(options.inifile)
    metadata_var = {}
    metadata_var['units'] = 'm'
    metadata_var[
        'standard_name'] = 'water_surface_height_above_reference_datum'
    metadata_var['long_name'] = 'Coastal flooding'
    metadata_var[
        'comment'] = 'water_surface_reference_datum_altitude is given in file {:s}'.format(
            options.dem_file)
    if not os.path.exists(options.dem_file):
        logger.error('path to dem file {:s} cannot be found'.format(
            options.dem_file))
        sys.exit(1)
    if not os.path.exists(options.ldd_file):
        logger.error('path to ldd file {:s} cannot be found'.format(
            options.ldd_file))
        sys.exit(1)

    # Read extent from a GDAL compatible file
    try:
        extent = inun_lib.get_gdal_extent(options.dem_file)
    except:
        msg = 'Input file {:s} not a gdal compatible file'.format(
            options.dem_file)
        inun_lib.close_with_error(logger, ch, msg)
        sys.exit(1)

    try:
        x, y = inun_lib.get_gdal_axes(options.dem_file, logging=logger)
        srs = inun_lib.get_gdal_projection(options.dem_file, logging=logger)
    except:
        msg = 'Input file {:s} not a gdal compatible file'.format(
            options.dem_file)
        inun_lib.close_with_error(logger, ch, msg)
        sys.exit(1)

    # read history from flood file
    if options.file_format == 0:
        a = nc.Dataset(options.flood_map, 'r')
        metadata_global[
            'history'] = 'Created by: $Id: $, boundary conditions from {:s},\nhistory: {:s}'.format(
                os.path.abspath(options.flood_map), a.history)
        a.close()
    else:
        metadata_global[
            'history'] = 'Created by: $Id: $, boundary conditions from {:s},\nhistory: {:s}'.format(
                os.path.abspath(options.flood_map),
                'PCRaster file, no history')

    # first write subcatch maps and hand maps
    ############### TODO ######
    # setup a HAND file
    dem_name = os.path.split(options.dem_file)[1].split('.')[0]
    hand_file = os.path.join(
        options.dest_path,
        '{:s}_hand_strahler_{:02d}.tif'.format(dem_name,
                                               options.hand_strahler))
    if not (os.path.isfile(hand_file)):
        # hand file does not exist yet! Generate it, otherwise skip!
        logger.info(
            'HAND file {:s} setting up...please wait...'.format(hand_file))
        hand_file_tmp = os.path.join(
            options.dest_path,
            '{:s}_hand_strahler_{:02d}.tif.tmp'.format(dem_name,
                                                       options.hand_strahler))
        ds_hand = inun_lib.prepare_gdal(hand_file_tmp,
                                        x,
                                        y,
                                        logging=logger,
                                        srs=srs)
        band_hand = ds_hand.GetRasterBand(1)

        # Open terrain data for reading
        ds_dem, rasterband_dem = inun_lib.get_gdal_rasterband(options.dem_file)
        ds_ldd, rasterband_ldd = inun_lib.get_gdal_rasterband(options.ldd_file)
        ds_stream, rasterband_stream = inun_lib.get_gdal_rasterband(
            options.stream_file)
        n = 0
        for x_loop in range(0, len(x), options.x_tile):
            x_start = np.maximum(x_loop, 0)
            x_end = np.minimum(x_loop + options.x_tile, len(x))
            # determine actual overlap for cutting
            for y_loop in range(0, len(y), options.y_tile):
                x_overlap_min = x_start - np.maximum(
                    x_start - options.x_overlap, 0)
                x_overlap_max = np.minimum(x_end + options.x_overlap,
                                           len(x)) - x_end
                n += 1
                # print('tile {:001d}:'.format(n))
                y_start = np.maximum(y_loop, 0)
                y_end = np.minimum(y_loop + options.y_tile, len(y))
                y_overlap_min = y_start - np.maximum(
                    y_start - options.y_overlap, 0)
                y_overlap_max = np.minimum(y_end + options.y_overlap,
                                           len(y)) - y_end
                # cut out DEM
                logger.debug(
                    'Computing HAND for xmin: {:d} xmax: {:d} ymin {:d} ymax {:d}'
                    .format(x_start, x_end, y_start, y_end))
                terrain = rasterband_dem.ReadAsArray(
                    x_start - x_overlap_min, y_start - y_overlap_min,
                    (x_end + x_overlap_max) - (x_start - x_overlap_min),
                    (y_end + y_overlap_max) - (y_start - y_overlap_min))

                drainage = rasterband_ldd.ReadAsArray(
                    x_start - x_overlap_min, y_start - y_overlap_min,
                    (x_end + x_overlap_max) - (x_start - x_overlap_min),
                    (y_end + y_overlap_max) - (y_start - y_overlap_min))
                stream = rasterband_stream.ReadAsArray(
                    x_start - x_overlap_min, y_start - y_overlap_min,
                    (x_end + x_overlap_max) - (x_start - x_overlap_min),
                    (y_end + y_overlap_max) - (y_start - y_overlap_min))
                # write to temporary file
                terrain_temp_file = os.path.join(options.dest_path,
                                                 'terrain_temp.map')
                drainage_temp_file = os.path.join(options.dest_path,
                                                  'drainage_temp.map')
                stream_temp_file = os.path.join(options.dest_path,
                                                'stream_temp.map')
                if rasterband_dem.GetNoDataValue() is not None:
                    inun_lib.gdal_writemap(terrain_temp_file,
                                           'PCRaster',
                                           np.arange(0, terrain.shape[1]),
                                           np.arange(0, terrain.shape[0]),
                                           terrain,
                                           rasterband_dem.GetNoDataValue(),
                                           gdal_type=gdal.GDT_Float32,
                                           logging=logger)
                else:
                    # in case no nodata value is found
                    logger.warning(
                        'No nodata value found in {:s}. assuming -9999'.format(
                            options.dem_file))
                    inun_lib.gdal_writemap(terrain_temp_file,
                                           'PCRaster',
                                           np.arange(0, terrain.shape[1]),
                                           np.arange(0, terrain.shape[0]),
                                           terrain,
                                           -9999.,
                                           gdal_type=gdal.GDT_Float32,
                                           logging=logger)

                inun_lib.gdal_writemap(drainage_temp_file,
                                       'PCRaster',
                                       np.arange(0, terrain.shape[1]),
                                       np.arange(0, terrain.shape[0]),
                                       drainage,
                                       rasterband_ldd.GetNoDataValue(),
                                       gdal_type=gdal.GDT_Int32,
                                       logging=logger)
                inun_lib.gdal_writemap(stream_temp_file,
                                       'PCRaster',
                                       np.arange(0, terrain.shape[1]),
                                       np.arange(0, terrain.shape[0]),
                                       stream,
                                       rasterband_ldd.GetNoDataValue(),
                                       gdal_type=gdal.GDT_Int32,
                                       logging=logger)
                # read as pcr objects
                pcr.setclone(terrain_temp_file)
                terrain_pcr = pcr.readmap(terrain_temp_file)
                drainage_pcr = pcr.lddrepair(
                    pcr.ldd(pcr.readmap(
                        drainage_temp_file)))  # convert to ldd type map
                stream_pcr = pcr.scalar(
                    pcr.readmap(stream_temp_file))  # convert to ldd type map

                # compute streams
                stream_ge, subcatch = inun_lib.subcatch_stream(
                    drainage_pcr, stream_pcr,
                    options.hand_strahler)  # generate streams

                basin = pcr.boolean(subcatch)
                hand_pcr, dist_pcr = inun_lib.derive_HAND(
                    terrain_pcr,
                    drainage_pcr,
                    3000,
                    rivers=pcr.boolean(stream_ge),
                    basin=basin)
                # convert to numpy
                hand = pcr.pcr2numpy(hand_pcr, -9999.)
                # cut relevant part
                if y_overlap_max == 0:
                    y_overlap_max = -hand.shape[0]
                if x_overlap_max == 0:
                    x_overlap_max = -hand.shape[1]
                hand_cut = hand[0 + y_overlap_min:-y_overlap_max,
                                0 + x_overlap_min:-x_overlap_max]

                band_hand.WriteArray(hand_cut, x_start, y_start)
                os.unlink(terrain_temp_file)
                os.unlink(drainage_temp_file)
                band_hand.FlushCache()
        ds_dem = None
        ds_ldd = None
        ds_stream = None
        band_hand.SetNoDataValue(-9999.)
        ds_hand = None
        logger.info('Finalizing {:s}'.format(hand_file))
        # rename temporary file to final hand file
        os.rename(hand_file_tmp, hand_file)
    else:
        logger.info(
            'HAND file {:s} already exists...skipping...'.format(hand_file))

    #####################################################################################
    #  HAND file has now been prepared, moving to flood mapping part                    #
    #####################################################################################
    # load the staticmaps needed to estimate volumes across all
    xax, yax, riv_length, fill_value = inun_lib.gdal_readmap(
        options.riv_length_file, 'GTiff')
    riv_length = np.ma.masked_where(riv_length == fill_value, riv_length)
    xax, yax, riv_width, fill_value = inun_lib.gdal_readmap(
        options.riv_width_file, 'GTiff')
    riv_width[riv_width == fill_value] = 0

    x_res = np.abs((xax[-1] - xax[0]) / (len(xax) - 1))
    y_res = np.abs((yax[-1] - yax[0]) / (len(yax) - 1))

    flood_folder = os.path.join(options.dest_path, case_name)
    flood_vol_map = os.path.join(
        flood_folder, '{:s}_vol.tif'.format(
            os.path.split(options.flood_map)[1].split('.')[0]))
    if not (os.path.isdir(flood_folder)):
        os.makedirs(flood_folder)
    inun_file_tmp = os.path.join(flood_folder,
                                 '{:s}.tif.tmp'.format(case_name))
    inun_file = os.path.join(flood_folder, '{:s}.tif'.format(case_name))
    hand_temp_file = os.path.join(flood_folder, 'hand_temp.map')
    drainage_temp_file = os.path.join(flood_folder, 'drainage_temp.map')
    stream_temp_file = os.path.join(flood_folder, 'stream_temp.map')
    flood_vol_temp_file = os.path.join(flood_folder, 'flood_warp_temp.tif')
    # load the data with river levels and compute the volumes
    if options.file_format == 0:
        # assume we need the maximum value in a NetCDF time series grid
        a = nc.Dataset(options.flood_map, 'r')
        xax = a.variables['x'][:]
        yax = a.variables['y'][:]

        flood_series = a.variables[options.flood_variable][:]
        flood_data = flood_series.max(axis=0)
        if np.ma.is_masked(flood_data):
            flood = flood_data.data
            flood[flood_data.mask] = 0
        if yax[-1] > yax[0]:
            yax = np.flipud(yax)
            flood = np.flipud(flood)
        a.close()
    elif options.file_format == 1:
        xax, yax, flood, flood_fill_value = inun_lib.gdal_readmap(
            options.flood_map, 'PCRaster')
        flood[flood == flood_fill_value] = 0.
    #res_x = x[1]-x[0]
    #res_y = y[1]-y[0]

    # load the bankfull depths
    if options.bankfull_map == '':
        bankfull = np.zeros(flood.shape)
    else:
        if options.file_format == 0:
            a = nc.Dataset(options.bankfull_map, 'r')
            xax = a.variables['x'][:]
            yax = a.variables['y'][:]
            bankfull = a.variables[options.flood_variable][0, :, :]
            if yax[-1] > yax[0]:
                yax = np.flipud(yax)
                bankfull = np.flipud(bankful)
            a.close()
        elif options.file_format == 1:
            xax, yax, bankfull, bankfull_fill_value = inun_lib.gdal_readmap(
                options.bankfull_map, 'PCRaster')


#     flood = bankfull*2
# res_x = 2000
# res_y = 2000
# subtract the bankfull water level to get flood levels (above bankfull)
    flood_vol = np.maximum(flood - bankfull, 0)
    flood_vol_m = riv_length * riv_width * flood_vol / (
        x_res * y_res
    )  # volume expressed in meters water disc (1e6 is the surface area of one wflow grid cell)
    flood_vol_m_data = flood_vol_m.data
    flood_vol_m_data[flood_vol_m.mask] = -999.
    print('Saving water layer map to {:s}'.format(flood_vol_map))
    # write to a tiff file
    inun_lib.gdal_writemap(flood_vol_map, 'GTiff', xax, yax,
                           np.maximum(flood_vol_m_data, 0), -999.)
    ds_hand, rasterband_hand = inun_lib.get_gdal_rasterband(hand_file)
    ds_ldd, rasterband_ldd = inun_lib.get_gdal_rasterband(options.ldd_file)
    ds_stream, rasterband_stream = inun_lib.get_gdal_rasterband(
        options.stream_file)

    logger.info(
        'Preparing flood map in {:s} ...please wait...'.format(inun_file))
    ds_inun = inun_lib.prepare_gdal(inun_file_tmp,
                                    x,
                                    y,
                                    logging=logger,
                                    srs=srs)
    band_inun = ds_inun.GetRasterBand(1)

    # loop over all the tiles
    n = 0
    for x_loop in range(0, len(x), options.x_tile):
        x_start = np.maximum(x_loop, 0)
        x_end = np.minimum(x_loop + options.x_tile, len(x))
        # determine actual overlap for cutting
        for y_loop in range(0, len(y), options.y_tile):
            x_overlap_min = x_start - np.maximum(x_start - options.x_overlap,
                                                 0)
            x_overlap_max = np.minimum(x_end + options.x_overlap,
                                       len(x)) - x_end
            n += 1
            # print('tile {:001d}:'.format(n))
            y_start = np.maximum(y_loop, 0)
            y_end = np.minimum(y_loop + options.y_tile, len(y))
            y_overlap_min = y_start - np.maximum(y_start - options.y_overlap,
                                                 0)
            y_overlap_max = np.minimum(y_end + options.y_overlap,
                                       len(y)) - y_end
            x_tile_ax = x[x_start - x_overlap_min:x_end + x_overlap_max]
            y_tile_ax = y[y_start - y_overlap_min:y_end + y_overlap_max]

            # cut out DEM
            logger.debug(
                'handling xmin: {:d} xmax: {:d} ymin {:d} ymax {:d}'.format(
                    x_start, x_end, y_start, y_end))
            hand = rasterband_hand.ReadAsArray(
                x_start - x_overlap_min, y_start - y_overlap_min,
                (x_end + x_overlap_max) - (x_start - x_overlap_min),
                (y_end + y_overlap_max) - (y_start - y_overlap_min))

            drainage = rasterband_ldd.ReadAsArray(
                x_start - x_overlap_min, y_start - y_overlap_min,
                (x_end + x_overlap_max) - (x_start - x_overlap_min),
                (y_end + y_overlap_max) - (y_start - y_overlap_min))
            stream = rasterband_stream.ReadAsArray(
                x_start - x_overlap_min, y_start - y_overlap_min,
                (x_end + x_overlap_max) - (x_start - x_overlap_min),
                (y_end + y_overlap_max) - (y_start - y_overlap_min))
            print('len x-ax: {:d} len y-ax {:d} x-shape {:d} y-shape {:d}'.
                  format(len(x_tile_ax), len(y_tile_ax), hand.shape[1],
                         hand.shape[0]))
            inun_lib.gdal_writemap(hand_temp_file,
                                   'PCRaster',
                                   x_tile_ax,
                                   y_tile_ax,
                                   hand,
                                   rasterband_hand.GetNoDataValue(),
                                   gdal_type=gdal.GDT_Float32,
                                   logging=logger)
            inun_lib.gdal_writemap(drainage_temp_file,
                                   'PCRaster',
                                   x_tile_ax,
                                   y_tile_ax,
                                   drainage,
                                   rasterband_ldd.GetNoDataValue(),
                                   gdal_type=gdal.GDT_Int32,
                                   logging=logger)
            inun_lib.gdal_writemap(stream_temp_file,
                                   'PCRaster',
                                   x_tile_ax,
                                   y_tile_ax,
                                   stream,
                                   rasterband_stream.GetNoDataValue(),
                                   gdal_type=gdal.GDT_Int32,
                                   logging=logger)
            # read as pcr objects
            pcr.setclone(hand_temp_file)
            hand_pcr = pcr.readmap(hand_temp_file)
            drainage_pcr = pcr.lddrepair(
                pcr.ldd(pcr.readmap(
                    drainage_temp_file)))  # convert to ldd type map
            stream_pcr = pcr.scalar(
                pcr.readmap(drainage_temp_file))  # convert to ldd type map
            # prepare a subcatchment map

            stream_ge, subcatch = inun_lib.subcatch_stream(
                drainage_pcr, stream_pcr,
                options.catchment_strahler)  # generate subcatchments
            drainage_surf = pcr.ifthen(
                stream_ge > 0, pcr.accuflux(
                    drainage_pcr,
                    1))  # proxy of drainage surface inaccurate at tile edges
            # compute weights for spreadzone (1/drainage_surf)
            subcatch = pcr.spreadzone(subcatch, 0, 0)

            # TODO check weighting scheme, perhaps not necessary
            # weight = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0))
            # subcatch_fill = pcr.scalar(pcr.spreadzone(subcatch, 0, weight))
            # # cover subcatch with subcatch_fill
            # pcr.report(weight, 'weight_{:02d}.map'.format(n))
            # pcr.report(subcatch, 'subcatch_{:02d}.map'.format(n))
            # pcr.report(pcr.nominal(subcatch_fill), 'subcatch_fill_{:02d}.map'.format(n))
            inun_lib.gdal_warp(flood_vol_map,
                               hand_temp_file,
                               flood_vol_temp_file,
                               gdal_interp=gdalconst.GRA_NearestNeighbour)  # ,
            x_tile_ax, y_tile_ax, flood_meter, fill_value = inun_lib.gdal_readmap(
                flood_vol_temp_file, 'GTiff')
            # convert meter depth to volume [m3]
            flood_vol = pcr.numpy2pcr(pcr.Scalar, flood_meter, fill_value) * (
                (x_tile_ax[1] - x_tile_ax[0]) * (y_tile_ax[0] - y_tile_ax[1])
            )  # resolution of SRTM *1166400000.
            ## now we have some nice volume. Now we need to redistribute!
            inundation_pcr = inun_lib.volume_spread(
                drainage_pcr,
                hand_pcr,
                subcatch,
                flood_vol,
                volume_thres=0.,
                iterations=options.iterations,
                area_multiplier=options.area_multiplier)  # 1166400000.
            inundation = pcr.pcr2numpy(inundation_pcr, -9999.)
            # cut relevant part
            if y_overlap_max == 0:
                y_overlap_max = -inundation.shape[0]
            if x_overlap_max == 0:
                x_overlap_max = -inundation.shape[1]
            inundation_cut = inundation[0 + y_overlap_min:-y_overlap_max,
                                        0 + x_overlap_min:-x_overlap_max]
            # inundation_cut
            band_inun.WriteArray(inundation_cut, x_start, y_start)
            band_inun.FlushCache()
            # clean up
            os.unlink(flood_vol_temp_file)
            os.unlink(drainage_temp_file)
            os.unlink(hand_temp_file)

            # if n == 35:
            #     band_inun.SetNoDataValue(-9999.)
            #     ds_inun = None
            #     sys.exit(0)
    os.unlink(flood_vol_map)

    logger.info('Finalizing {:s}'.format(inun_file))
    # add the metadata to the file and band
    band_inun.SetNoDataValue(-9999.)
    ds_inun.SetMetadata(metadata_global)
    band_inun.SetMetadata(metadata_var)
    ds_inun = None
    ds_hand = None
    ds_ldd = None
    # rename temporary file to final hand file
    if os.path.isfile(inun_file):
        # remove an old result if available
        os.unlink(inun_file)
    os.rename(inun_file_tmp, inun_file)

    logger.info('Done! Thank you for using hand_contour_inun.py')
    logger, ch = inun_lib.closeLogger(logger, ch)
    del logger, ch
    sys.exit(0)
Пример #14
0
def generate_hydro_datasets(path, output_dir, step):
    print(path)

    file_name = os.path.splitext(os.path.basename(path))[0]
    map_path = output_dir + "/" + file_name + ".map"
    path_prefix = map_path[:-14]

    if step == "ldd":
        cmd = u"gdal_translate -a_nodata -9999 -of PCRaster -ot Float32 " + path + " " + map_path
        print(cmd)
        subprocess.call(cmd, shell=True)

    # slope = pcr.slope(dem)
    # pcr.report(slope, path_prefix + '_slope.map')

    # pcr.setglobaloption("lddin")

    if step == "ldd":
        dem = pcr.readmap(map_path)

        print("Computing LDD ...")
        # enable pit filling
        ldd = pcr.lddcreate(dem, 9999999, 9999999, 9999999, 9999999)
        pcr.report(ldd, path_prefix + "_ldd.map")

        return
    elif step == "ldddem":
        dem = pcr.readmap(map_path)

        print("Computing LDD DEM ...")
        dem_pitfilled = pcr.lddcreatedem(dem, 9999999, 9999999, 9999999, 9999999)
        dem_diff = dem_pitfilled - dem
        pcr.report(dem_diff, path_prefix + "_dem_pits_diff.map")

        return

    # print("Computing LDD without pit filling ...")
    # ldd_pits = pcr.lddcreate(dem, 0, 0, 0, 0)
    # pcr.report(ldd_pits, path_prefix + '_ldd_with_pits.map')

    # print("Computing pits ...")
    # pits = pcr.pit(ldd_pits)

    # pcr.report(pits, path_prefix + '_pits.map')

    if step == "fa":
        ldd = pcr.readmap(path_prefix + "_ldd.map")

        print("Computing flow accumulation ...")
        fa = pcr.accuflux(ldd, 1)
        pcr.report(fa, path_prefix + "_fa.map")

        return

    if step == "catchments":
        ldd = pcr.readmap(path_prefix + "_ldd.map")

        print("Delineating catchments ...")
        catchments = pcr.catchment(ldd, pcr.pit(ldd))
        pcr.report(catchments, path_prefix + "_catchments.map")

        return

    if step == "stream_order":
        ldd = pcr.readmap(path_prefix + "_ldd.map")

        print("Computing stream order ...")
        stream_order = pcr.streamorder(ldd)
        pcr.report(stream_order, path_prefix + "_streamorder.map")

        return

    if step == "stream":
        ldd = pcr.readmap(path_prefix + "_ldd.map")
        accuThreshold = 100
        print("Computing stream ...")
        stream = pcr.ifthenelse(pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0))
        pcr.report(stream, path_prefix + "_stream.map")
        return

    if step == "height_river":
        print("Computing heigh_river ...")

        stream = pcr.readmap(path_prefix + "_stream.map")
        dem = pcr.readmap(map_path)
        height_river = pcr.ifthenelse(stream, pcr.ordinal(dem), 0)
        pcr.report(height_river, path_prefix + "_height_river.map")
        return

    if step == "up_elevation":
        print("Computing up_elevation ...")

        height_river = pcr.readmap(path_prefix + "_height_river.map")
        ldd = pcr.readmap(path_prefix + "_ldd.map")
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
        pcr.report(up_elevation, path_prefix + "_up_elevation.map")
        return

    if step == "hand":
        print("Computing HAND ...")
        dem = pcr.readmap(map_path)
        up_elevation = pcr.readmap(path_prefix + "_up_elevation.map")
        hand = pcr.max(dem - up_elevation, 0)
        pcr.report(hand, path_prefix + "_hand.map")
        return

    if step == "dand":
        print("Computing DAND ...")
        ldd = pcr.readmap(path_prefix + "_ldd.map")
        stream = pcr.readmap(path_prefix + "_stream.map")
        dist = pcr.ldddist(ldd, stream, 1)
        pcr.report(dist, path_prefix + "_dist.map")
        return

    if step == "fa_river":
        print("Computing FA river ...")
        fa = pcr.readmap(path_prefix + "_fa.map")
        stream = pcr.readmap(path_prefix + "_stream.map")
        fa_river = pcr.ifthenelse(stream, pcr.ordinal(fa), 0)
        pcr.report(fa_river, path_prefix + "_fa_river.map")
        return

    if step == "faand":
        print("Computing FAAND ...")
        fa_river = pcr.readmap(path_prefix + "_fa_river.map")
        ldd = pcr.readmap(path_prefix + "_ldd.map")
        up_fa = pcr.scalar(pcr.subcatchment(ldd, fa_river))
        pcr.report(up_fa, path_prefix + "_faand.map")
        return
Пример #15
0
def main():
    ### Read input arguments #####
    parser = OptionParser()
    usage = "usage: %prog [options]"
    parser = OptionParser(usage=usage)
    parser.add_option('-q', '--quiet',
                      dest='verbose', default=True, action='store_false',
                      help='do not print status messages to stdout')
    parser.add_option('-i', '--ini', dest='inifile',
                      default='hand_contour_inun.ini', nargs=1,
                      help='ini configuration file')
    parser.add_option('-f', '--flood_map',
                      nargs=1, dest='flood_map',
                      help='Flood map file (NetCDF point time series file')
    parser.add_option('-v', '--flood_variable',
                      nargs=1, dest='flood_variable',
                      default='water_level',
                      help='variable name of flood water level')
    parser.add_option('-b', '--bankfull_map',
                      dest='bankfull_map', default='',
                      help='Map containing bank full level (is subtracted from flood map, in NetCDF)')
    parser.add_option('-c', '--catchment',
                      dest='catchment_strahler', default=7, type='int',
                      help='Strahler order threshold >= are selected as catchment boundaries')
    parser.add_option('-s', '--hand_strahler',
                      dest='hand_strahler', default=7, type='int',
                      help='Strahler order threshold >= selected as riverine')
    parser.add_option('-d', '--destination',
                      dest='dest_path', default='inun',
                      help='Destination path')
    (options, args) = parser.parse_args()

    if not os.path.exists(options.inifile):
        print 'path to ini file cannot be found'
        sys.exit(1)
    options.dest_path = os.path.abspath(options.dest_path)

    if not(os.path.isdir(options.dest_path)):
        os.makedirs(options.dest_path)

    # set up the logger
    flood_name = os.path.split(options.flood_map)[1].split('.')[0]
    case_name = 'inun_{:s}_hand_{:02d}_catch_{:02d}'.format(flood_name, options.hand_strahler, options.catchment_strahler)
    logfilename = os.path.join(options.dest_path, 'hand_contour_inun.log')
    logger, ch = inun_lib.setlogger(logfilename, 'HAND_INUN', options.verbose)
    logger.info('$Id: $')
    logger.info('Flood map: {:s}'.format(options.flood_map))
    logger.info('Bank full map: {:s}'.format(options.bankfull_map))
    logger.info('Destination path: {:s}'.format(options.dest_path))
    # read out ini file
    ### READ CONFIG FILE
    # open config-file
    config = inun_lib.open_conf(options.inifile)
    
    # read settings
    options.dem_file = inun_lib.configget(config, 'maps',
                                  'dem_file',
                                  True)
    options.ldd_file = inun_lib.configget(config, 'maps',
                                'ldd_file',
                                 True)
    options.stream_file = inun_lib.configget(config, 'maps',
                                'stream_file',
                                 True)
    options.riv_length_file = inun_lib.configget(config, 'maps',
                                'riv_length_file',
                                 True)
    options.riv_width_file = inun_lib.configget(config, 'maps',
                                'riv_width_file',
                                 True)
    options.file_format = inun_lib.configget(config, 'maps',
                                'file_format', 0, datatype='int')
    options.x_tile = inun_lib.configget(config, 'tiling',
                                  'x_tile', 10000, datatype='int')
    options.y_tile = inun_lib.configget(config, 'tiling',
                                  'y_tile', 10000, datatype='int')
    options.x_overlap = inun_lib.configget(config, 'tiling',
                                  'x_overlap', 1000, datatype='int')
    options.y_overlap = inun_lib.configget(config, 'tiling',
                                  'y_overlap', 1000, datatype='int')
    options.iterations = inun_lib.configget(config, 'inundation',
                                  'iterations', 20, datatype='int')
    options.initial_level = inun_lib.configget(config, 'inundation',
                                  'initial_level', 32., datatype='float')
    options.area_multiplier = inun_lib.configget(config, 'inundation',
                                  'area_multiplier', 1., datatype='float')
    logger.info('DEM file: {:s}'.format(options.dem_file))
    logger.info('LDD file: {:s}'.format(options.ldd_file))
    logger.info('Columns per tile: {:d}'.format(options.x_tile))
    logger.info('Rows per tile: {:d}'.format(options.y_tile))
    logger.info('Columns overlap: {:d}'.format(options.x_overlap))
    logger.info('Rows overlap: {:d}'.format(options.y_overlap))
    metadata_global = {}
    # add metadata from the section [metadata]
    meta_keys = config.options('metadata_global')
    for key in meta_keys:
        metadata_global[key] = config.get('metadata_global', key)
    # add a number of metadata variables that are mandatory
    metadata_global['config_file'] = os.path.abspath(options.inifile)
    metadata_var = {}
    metadata_var['units'] = 'm'
    metadata_var['standard_name'] = 'water_surface_height_above_reference_datum'
    metadata_var['long_name'] = 'Coastal flooding'
    metadata_var['comment'] = 'water_surface_reference_datum_altitude is given in file {:s}'.format(options.dem_file)
    if not os.path.exists(options.dem_file):
        logger.error('path to dem file {:s} cannot be found'.format(options.dem_file))
        sys.exit(1)
    if not os.path.exists(options.ldd_file):
        logger.error('path to ldd file {:s} cannot be found'.format(options.ldd_file))
        sys.exit(1)

    # Read extent from a GDAL compatible file
    try:
        extent = inun_lib.get_gdal_extent(options.dem_file)
    except:
        msg = 'Input file {:s} not a gdal compatible file'.format(options.dem_file)
        inun_lib.close_with_error(logger, ch, msg)
        sys.exit(1)

    try:
        x, y = inun_lib.get_gdal_axes(options.dem_file, logging=logger)
        srs = inun_lib.get_gdal_projection(options.dem_file, logging=logger)
    except:
        msg = 'Input file {:s} not a gdal compatible file'.format(options.dem_file)
        inun_lib.close_with_error(logger, ch, msg)
        sys.exit(1)

    # read history from flood file
    if options.file_format == 0:
        a = nc.Dataset(options.flood_map, 'r')
        metadata_global['history'] = 'Created by: $Id: $, boundary conditions from {:s},\nhistory: {:s}'.format(os.path.abspath(options.flood_map), a.history)
        a.close()
    else:
        metadata_global['history'] = 'Created by: $Id: $, boundary conditions from {:s},\nhistory: {:s}'.format(os.path.abspath(options.flood_map), 'PCRaster file, no history')

    # first write subcatch maps and hand maps
    ############### TODO ######
    # setup a HAND file
    dem_name = os.path.split(options.dem_file)[1].split('.')[0]
    hand_file = os.path.join(options.dest_path, '{:s}_hand_strahler_{:02d}.tif'.format(dem_name, options.hand_strahler))
    if not(os.path.isfile(hand_file)):
    # hand file does not exist yet! Generate it, otherwise skip!
        logger.info('HAND file {:s} setting up...please wait...'.format(hand_file))
        hand_file_tmp = os.path.join(options.dest_path, '{:s}_hand_strahler_{:02d}.tif.tmp'.format(dem_name, options.hand_strahler))
        ds_hand = inun_lib.prepare_gdal(hand_file_tmp, x, y, logging=logger, srs=srs)
        band_hand = ds_hand.GetRasterBand(1)

        # Open terrain data for reading
        ds_dem, rasterband_dem = inun_lib.get_gdal_rasterband(options.dem_file)
        ds_ldd, rasterband_ldd = inun_lib.get_gdal_rasterband(options.ldd_file)
        ds_stream, rasterband_stream = inun_lib.get_gdal_rasterband(options.stream_file)
        n = 0
        for x_loop in range(0, len(x), options.x_tile):
            x_start = np.maximum(x_loop, 0)
            x_end = np.minimum(x_loop + options.x_tile, len(x))
            # determine actual overlap for cutting
            for y_loop in range(0, len(y), options.y_tile):
                x_overlap_min = x_start - np.maximum(x_start - options.x_overlap, 0)
                x_overlap_max = np.minimum(x_end + options.x_overlap, len(x)) - x_end
                n += 1
                # print('tile {:001d}:'.format(n))
                y_start = np.maximum(y_loop, 0)
                y_end = np.minimum(y_loop + options.y_tile, len(y))
                y_overlap_min = y_start - np.maximum(y_start - options.y_overlap, 0)
                y_overlap_max = np.minimum(y_end + options.y_overlap, len(y)) - y_end
                # cut out DEM
                logger.debug('Computing HAND for xmin: {:d} xmax: {:d} ymin {:d} ymax {:d}'.format(x_start, x_end,y_start, y_end))
                terrain = rasterband_dem.ReadAsArray(x_start - x_overlap_min,
                                                     y_start - y_overlap_min,
                                                     (x_end + x_overlap_max) - (x_start - x_overlap_min),
                                                     (y_end + y_overlap_max) - (y_start - y_overlap_min)
                                                     )

                drainage = rasterband_ldd.ReadAsArray(x_start - x_overlap_min,
                                                     y_start - y_overlap_min,
                                                     (x_end + x_overlap_max) - (x_start - x_overlap_min),
                                                     (y_end + y_overlap_max) - (y_start - y_overlap_min)
                                                     )
                stream = rasterband_stream.ReadAsArray(x_start - x_overlap_min,
                                                       y_start - y_overlap_min,
                                                       (x_end + x_overlap_max) - (x_start - x_overlap_min),
                                                       (y_end + y_overlap_max) - (y_start - y_overlap_min)
                                                       )
                # write to temporary file
                terrain_temp_file = os.path.join(options.dest_path, 'terrain_temp.map')
                drainage_temp_file = os.path.join(options.dest_path, 'drainage_temp.map')
                stream_temp_file = os.path.join(options.dest_path, 'stream_temp.map')
                if rasterband_dem.GetNoDataValue() is not None:
                    inun_lib.gdal_writemap(terrain_temp_file, 'PCRaster',
                                      np.arange(0, terrain.shape[1]),
                                      np.arange(0, terrain.shape[0]),
                                      terrain, rasterband_dem.GetNoDataValue(),
                                      gdal_type=gdal.GDT_Float32,
                                      logging=logger)
                else:
                    # in case no nodata value is found
                    logger.warning('No nodata value found in {:s}. assuming -9999'.format(options.dem_file))
                    inun_lib.gdal_writemap(terrain_temp_file, 'PCRaster',
                                      np.arange(0, terrain.shape[1]),
                                      np.arange(0, terrain.shape[0]),
                                      terrain, -9999.,
                                      gdal_type=gdal.GDT_Float32,
                                      logging=logger)

                inun_lib.gdal_writemap(drainage_temp_file, 'PCRaster',
                                  np.arange(0, terrain.shape[1]),
                                  np.arange(0, terrain.shape[0]),
                                  drainage, rasterband_ldd.GetNoDataValue(),
                                  gdal_type=gdal.GDT_Int32,
                                  logging=logger)
                inun_lib.gdal_writemap(stream_temp_file, 'PCRaster',
                                  np.arange(0, terrain.shape[1]),
                                  np.arange(0, terrain.shape[0]),
                                  stream, rasterband_ldd.GetNoDataValue(),
                                  gdal_type=gdal.GDT_Int32,
                                  logging=logger)
                # read as pcr objects
                pcr.setclone(terrain_temp_file)
                terrain_pcr = pcr.readmap(terrain_temp_file)
                drainage_pcr = pcr.lddrepair(pcr.ldd(pcr.readmap(drainage_temp_file)))  # convert to ldd type map
                stream_pcr = pcr.scalar(pcr.readmap(stream_temp_file))  # convert to ldd type map

                # compute streams
                stream_ge, subcatch = inun_lib.subcatch_stream(drainage_pcr, stream_pcr, options.hand_strahler) # generate streams

                basin = pcr.boolean(subcatch)
                hand_pcr, dist_pcr = inun_lib.derive_HAND(terrain_pcr, drainage_pcr, 3000, rivers=pcr.boolean(stream_ge), basin=basin)
                # convert to numpy
                hand = pcr.pcr2numpy(hand_pcr, -9999.)
                # cut relevant part
                if y_overlap_max == 0:
                    y_overlap_max = -hand.shape[0]
                if x_overlap_max == 0:
                    x_overlap_max = -hand.shape[1]
                hand_cut = hand[0+y_overlap_min:-y_overlap_max, 0+x_overlap_min:-x_overlap_max]

                band_hand.WriteArray(hand_cut, x_start, y_start)
                os.unlink(terrain_temp_file)
                os.unlink(drainage_temp_file)
                band_hand.FlushCache()
        ds_dem = None
        ds_ldd = None
        ds_stream = None
        band_hand.SetNoDataValue(-9999.)
        ds_hand = None
        logger.info('Finalizing {:s}'.format(hand_file))
        # rename temporary file to final hand file
        os.rename(hand_file_tmp, hand_file)
    else:
        logger.info('HAND file {:s} already exists...skipping...'.format(hand_file))

    #####################################################################################
    #  HAND file has now been prepared, moving to flood mapping part                    #
    #####################################################################################
    # load the staticmaps needed to estimate volumes across all
    xax, yax, riv_length, fill_value = inun_lib.gdal_readmap(options.riv_length_file, 'GTiff')
    riv_length = np.ma.masked_where(riv_length==fill_value, riv_length)
    xax, yax, riv_width, fill_value = inun_lib.gdal_readmap(options.riv_width_file, 'GTiff')
    riv_width[riv_width == fill_value] = 0

    x_res = np.abs((xax[-1]-xax[0])/(len(xax)-1))
    y_res = np.abs((yax[-1]-yax[0])/(len(yax)-1))

    flood_folder = os.path.join(options.dest_path, case_name)
    flood_vol_map = os.path.join(flood_folder, '{:s}_vol.tif'.format(os.path.split(options.flood_map)[1].split('.')[0]))
    if not(os.path.isdir(flood_folder)):
        os.makedirs(flood_folder)
    inun_file_tmp = os.path.join(flood_folder, '{:s}.tif.tmp'.format(case_name))
    inun_file = os.path.join(flood_folder, '{:s}.tif'.format(case_name))
    hand_temp_file = os.path.join(flood_folder, 'hand_temp.map')
    drainage_temp_file = os.path.join(flood_folder, 'drainage_temp.map')
    stream_temp_file = os.path.join(flood_folder, 'stream_temp.map')
    flood_vol_temp_file = os.path.join(flood_folder, 'flood_warp_temp.tif')
    # load the data with river levels and compute the volumes
    if options.file_format == 0:
        # assume we need the maximum value in a NetCDF time series grid
        a = nc.Dataset(options.flood_map, 'r')
        xax = a.variables['x'][:]
        yax = a.variables['y'][:]

        flood_series = a.variables[options.flood_variable][:]
        flood_data = flood_series.max(axis=0)
        if np.ma.is_masked(flood_data):
            flood = flood_data.data
            flood[flood_data.mask] = 0
        if yax[-1] > yax[0]:
            yax = np.flipud(yax)
            flood = np.flipud(flood)
        a.close()
    elif options.file_format == 1:
        xax, yax, flood, flood_fill_value = inun_lib.gdal_readmap(options.flood_map, 'PCRaster')
        flood[flood==flood_fill_value] = 0.
    #res_x = x[1]-x[0]
    #res_y = y[1]-y[0]

    # load the bankfull depths
    if options.bankfull_map == '':
        bankfull = np.zeros(flood.shape)
    else:
        if options.file_format == 0:
            a = nc.Dataset(options.bankfull_map, 'r')
            xax = a.variables['x'][:]
            yax = a.variables['y'][:]
            bankfull = a.variables[options.flood_variable][0, :, :]
            if yax[-1] > yax[0]:
                yax = np.flipud(yax)
                bankfull = np.flipud(bankful)
            a.close()
        elif options.file_format == 1:
            xax, yax, bankfull, bankfull_fill_value = inun_lib.gdal_readmap(options.bankfull_map, 'PCRaster')
#     flood = bankfull*2
    # res_x = 2000
    # res_y = 2000
    # subtract the bankfull water level to get flood levels (above bankfull)
    flood_vol = np.maximum(flood-bankfull, 0)
    flood_vol_m = riv_length*riv_width*flood_vol/(x_res * y_res)  # volume expressed in meters water disc (1e6 is the surface area of one wflow grid cell)
    flood_vol_m_data = flood_vol_m.data
    flood_vol_m_data[flood_vol_m.mask] = -999.
    print('Saving water layer map to {:s}'.format(flood_vol_map))
    # write to a tiff file
    inun_lib.gdal_writemap(flood_vol_map, 'GTiff', xax, yax, np.maximum(flood_vol_m_data, 0), -999.)
    ds_hand, rasterband_hand = inun_lib.get_gdal_rasterband(hand_file)
    ds_ldd, rasterband_ldd = inun_lib.get_gdal_rasterband(options.ldd_file)
    ds_stream, rasterband_stream = inun_lib.get_gdal_rasterband(options.stream_file)

    logger.info('Preparing flood map in {:s} ...please wait...'.format(inun_file))
    ds_inun = inun_lib.prepare_gdal(inun_file_tmp, x, y, logging=logger, srs=srs)
    band_inun = ds_inun.GetRasterBand(1)

    # loop over all the tiles
    n = 0
    for x_loop in range(0, len(x), options.x_tile):
        x_start = np.maximum(x_loop, 0)
        x_end = np.minimum(x_loop + options.x_tile, len(x))
        # determine actual overlap for cutting
        for y_loop in range(0, len(y), options.y_tile):
            x_overlap_min = x_start - np.maximum(x_start - options.x_overlap, 0)
            x_overlap_max = np.minimum(x_end + options.x_overlap, len(x)) - x_end
            n += 1
            # print('tile {:001d}:'.format(n))
            y_start = np.maximum(y_loop, 0)
            y_end = np.minimum(y_loop + options.y_tile, len(y))
            y_overlap_min = y_start - np.maximum(y_start - options.y_overlap, 0)
            y_overlap_max = np.minimum(y_end + options.y_overlap, len(y)) - y_end
            x_tile_ax = x[x_start - x_overlap_min:x_end + x_overlap_max]
            y_tile_ax = y[y_start - y_overlap_min:y_end + y_overlap_max]

            # cut out DEM
            logger.debug('handling xmin: {:d} xmax: {:d} ymin {:d} ymax {:d}'.format(x_start, x_end, y_start, y_end))
            hand = rasterband_hand.ReadAsArray(x_start - x_overlap_min,
                                                 y_start - y_overlap_min,
                                                 (x_end + x_overlap_max) - (x_start - x_overlap_min),
                                                 (y_end + y_overlap_max) - (y_start - y_overlap_min)
                                                 )

            drainage = rasterband_ldd.ReadAsArray(x_start - x_overlap_min,
                                                 y_start - y_overlap_min,
                                                 (x_end + x_overlap_max) - (x_start - x_overlap_min),
                                                 (y_end + y_overlap_max) - (y_start - y_overlap_min)
                                                 )
            stream = rasterband_stream.ReadAsArray(x_start - x_overlap_min,
                                                   y_start - y_overlap_min,
                                                   (x_end + x_overlap_max) - (x_start - x_overlap_min),
                                                   (y_end + y_overlap_max) - (y_start - y_overlap_min)
                                                   )
            print('len x-ax: {:d} len y-ax {:d} x-shape {:d} y-shape {:d}'.format(len(x_tile_ax), len(y_tile_ax), hand.shape[1], hand.shape[0]))
            inun_lib.gdal_writemap(hand_temp_file, 'PCRaster',
                              x_tile_ax,
                              y_tile_ax,
                              hand, rasterband_hand.GetNoDataValue(),
                              gdal_type=gdal.GDT_Float32,
                              logging=logger)
            inun_lib.gdal_writemap(drainage_temp_file, 'PCRaster',
                              x_tile_ax,
                              y_tile_ax,
                              drainage, rasterband_ldd.GetNoDataValue(),
                              gdal_type=gdal.GDT_Int32,
                              logging=logger)
            inun_lib.gdal_writemap(stream_temp_file, 'PCRaster',
                              x_tile_ax,
                              y_tile_ax,
                              stream, rasterband_stream.GetNoDataValue(),
                              gdal_type=gdal.GDT_Int32,
                              logging=logger)
            # read as pcr objects
            pcr.setclone(hand_temp_file)
            hand_pcr = pcr.readmap(hand_temp_file)
            drainage_pcr = pcr.lddrepair(pcr.ldd(pcr.readmap(drainage_temp_file)))  # convert to ldd type map
            stream_pcr = pcr.scalar(pcr.readmap(drainage_temp_file))  # convert to ldd type map
            # prepare a subcatchment map

            stream_ge, subcatch = inun_lib.subcatch_stream(drainage_pcr, stream_pcr, options.catchment_strahler) # generate subcatchments
            drainage_surf = pcr.ifthen(stream_ge > 0, pcr.accuflux(drainage_pcr, 1))  # proxy of drainage surface inaccurate at tile edges
           # compute weights for spreadzone (1/drainage_surf)
            subcatch = pcr.spreadzone(subcatch, 0, 0)

            # TODO check weighting scheme, perhaps not necessary
            # weight = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0))
            # subcatch_fill = pcr.scalar(pcr.spreadzone(subcatch, 0, weight))
            # # cover subcatch with subcatch_fill
            # pcr.report(weight, 'weight_{:02d}.map'.format(n))
            # pcr.report(subcatch, 'subcatch_{:02d}.map'.format(n))
            # pcr.report(pcr.nominal(subcatch_fill), 'subcatch_fill_{:02d}.map'.format(n))
            inun_lib.gdal_warp(flood_vol_map, hand_temp_file, flood_vol_temp_file, gdal_interp=gdalconst.GRA_NearestNeighbour) # ,
            x_tile_ax, y_tile_ax, flood_meter, fill_value = inun_lib.gdal_readmap(flood_vol_temp_file, 'GTiff')
            # convert meter depth to volume [m3]
            flood_vol = pcr.numpy2pcr(pcr.Scalar, flood_meter, fill_value)*((x_tile_ax[1] - x_tile_ax[0]) * (y_tile_ax[0] - y_tile_ax[1]))  # resolution of SRTM *1166400000.
            ## now we have some nice volume. Now we need to redistribute!
            inundation_pcr = inun_lib.volume_spread(drainage_pcr, hand_pcr, subcatch, flood_vol,
                                           volume_thres=0., iterations=options.iterations,
                                           area_multiplier=options.area_multiplier) # 1166400000.
            inundation = pcr.pcr2numpy(inundation_pcr, -9999.)
            # cut relevant part
            if y_overlap_max == 0:
                y_overlap_max = -inundation.shape[0]
            if x_overlap_max == 0:
                x_overlap_max = -inundation.shape[1]
            inundation_cut = inundation[0+y_overlap_min:-y_overlap_max, 0+x_overlap_min:-x_overlap_max]
            # inundation_cut
            band_inun.WriteArray(inundation_cut, x_start, y_start)
            band_inun.FlushCache()
            # clean up
            os.unlink(flood_vol_temp_file)
            os.unlink(drainage_temp_file)
            os.unlink(hand_temp_file)

            # if n == 35:
            #     band_inun.SetNoDataValue(-9999.)
            #     ds_inun = None
            #     sys.exit(0)
    os.unlink(flood_vol_map)

    logger.info('Finalizing {:s}'.format(inun_file))
    # add the metadata to the file and band
    band_inun.SetNoDataValue(-9999.)
    ds_inun.SetMetadata(metadata_global)
    band_inun.SetMetadata(metadata_var)
    ds_inun = None
    ds_hand = None
    ds_ldd = None
    # rename temporary file to final hand file
    if os.path.isfile(inun_file):
        # remove an old result if available
        os.unlink(inun_file)
    os.rename(inun_file_tmp, inun_file)

    logger.info('Done! Thank you for using hand_contour_inun.py')
    logger, ch = inun_lib.closeLogger(logger, ch)
    del logger, ch
    sys.exit(0)
 def totalSoilMoistureFractionInUpstreamArea(self):
     self.calculateSoilMoistureFraction()
     self.totalSoilMoistureFractionInUpstreamAreaTimesCellArea = pcr.accuflux(
         self.ldd, self.soilMoistureFraction) * self.cellArea
 def totalSaturatedThickInUpstreamArea(self):
     self.totalSaturatedThickInUpstreamAreaCubicMetre = pcr.accuflux(
         self.ldd, self.saturatedLayerThick) * self.cellArea
def generate_hydro_datasets(path, output_dir, step):
    print(path)

    file_name = os.path.splitext(os.path.basename(path))[0]
    map_path = output_dir + '/' + file_name + '.map'
    path_prefix = map_path[:-14]

    if step == 'ldd':
        cmd = u'gdal_translate -a_nodata -9999 -of PCRaster -ot Float32 ' + path + ' ' + map_path
        print(cmd)
        subprocess.call(cmd, shell=True)

    # slope = pcr.slope(dem)
    # pcr.report(slope, path_prefix + '_slope.map')

    # pcr.setglobaloption("lddin")

    if step == 'ldd':
        dem = pcr.readmap(map_path)

        print("Computing LDD ...")
        # enable pit filling
        ldd = pcr.lddcreate(dem, 9999999, 9999999, 9999999, 9999999)
        pcr.report(ldd, path_prefix + '_ldd.map')

        return
    elif step == 'ldddem':
        dem = pcr.readmap(map_path)

        print("Computing LDD DEM ...")
        dem_pitfilled = pcr.lddcreatedem(dem, 9999999, 9999999, 9999999,
                                         9999999)
        dem_diff = dem_pitfilled - dem
        pcr.report(dem_diff, path_prefix + '_dem_pits_diff.map')

        return

    # print("Computing LDD without pit filling ...")
    # ldd_pits = pcr.lddcreate(dem, 0, 0, 0, 0)
    # pcr.report(ldd_pits, path_prefix + '_ldd_with_pits.map')

    # print("Computing pits ...")
    # pits = pcr.pit(ldd_pits)

    # pcr.report(pits, path_prefix + '_pits.map')

    if step == 'fa':
        ldd = pcr.readmap(path_prefix + '_ldd.map')

        print("Computing flow accumulation ...")
        fa = pcr.accuflux(ldd, 1)
        pcr.report(fa, path_prefix + '_fa.map')

        return

    if step == 'catchments':
        ldd = pcr.readmap(path_prefix + '_ldd.map')

        print("Delineating catchments ...")
        catchments = pcr.catchment(ldd, pcr.pit(ldd))
        pcr.report(catchments, path_prefix + '_catchments.map')

        return

    if step == 'stream_order':
        ldd = pcr.readmap(path_prefix + '_ldd.map')

        print("Computing stream order ...")
        stream_order = pcr.streamorder(ldd)
        pcr.report(stream_order, path_prefix + '_streamorder.map')

        return

    if step == 'stream':
        ldd = pcr.readmap(path_prefix + '_ldd.map')
        accuThreshold = 100
        print("Computing stream ...")
        stream = pcr.ifthenelse(
            pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1),
            pcr.boolean(0))
        pcr.report(stream, path_prefix + '_stream.map')
        return

    if step == 'height_river':
        print("Computing heigh_river ...")

        stream = pcr.readmap(path_prefix + '_stream.map')
        dem = pcr.readmap(map_path)
        height_river = pcr.ifthenelse(stream, pcr.ordinal(dem), 0)
        pcr.report(height_river, path_prefix + '_height_river.map')
        return

    if step == 'up_elevation':
        print("Computing up_elevation ...")

        height_river = pcr.readmap(path_prefix + '_height_river.map')
        ldd = pcr.readmap(path_prefix + '_ldd.map')
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
        pcr.report(up_elevation, path_prefix + '_up_elevation.map')
        return

    if step == 'hand':
        print("Computing HAND ...")
        dem = pcr.readmap(map_path)
        up_elevation = pcr.readmap(path_prefix + '_up_elevation.map')
        hand = pcr.max(dem - up_elevation, 0)
        pcr.report(hand, path_prefix + '_hand.map')
        return

    if step == 'dand':
        print("Computing DAND ...")
        ldd = pcr.readmap(path_prefix + '_ldd.map')
        stream = pcr.readmap(path_prefix + '_stream.map')
        dist = pcr.ldddist(ldd, stream, 1)
        pcr.report(dist, path_prefix + '_dist.map')
        return

    if step == 'fa_river':
        print("Computing FA river ...")
        fa = pcr.readmap(path_prefix + '_fa.map')
        stream = pcr.readmap(path_prefix + '_stream.map')
        fa_river = pcr.ifthenelse(stream, pcr.ordinal(fa), 0)
        pcr.report(fa_river, path_prefix + '_fa_river.map')
        return

    if step == 'faand':
        print("Computing FAAND ...")
        fa_river = pcr.readmap(path_prefix + '_fa_river.map')
        ldd = pcr.readmap(path_prefix + '_ldd.map')
        up_fa = pcr.scalar(pcr.subcatchment(ldd, fa_river))
        pcr.report(up_fa, path_prefix + '_faand.map')
        return