Ejemplo n.º 1
0
def satPressure(airT):
    """ calculates saturated vp from airt temperature Murray (1967) """
    # airT      - air temperature [degree C] */
    satPressure = pcr.ifthenelse(
        airT >= 0.0, 0.61078 * pcr.exp(17.26939 * airT / (airT + 237.3)),
        0.61078 * pcr.exp(21.87456 * airT / (airT + 265.5)))
    return satPressure
Ejemplo n.º 2
0
    def dynamic(self):
        """
      *Required*
      
      This is where all the time dependent functions are executed. Time dependent
      output should also be saved here.
      """
        self.wf_updateparameters()  # read the temperature map for each step (see parameters())

        self.wf_multparameters()    # needed so parameters can be altered in the inifile under [variable_change_once]

        # snow routine
        snowfall = self.precipitation
        snowfall = pcr.scalar(self.temperature < 3.0) * snowfall
        self.snow = self.snow + snowfall
        melt = (self.meltf * self.temperature)
        melt = pcr.scalar(self.temperature > 3.0) * melt
        melt = pcr.max(0.0, pcr.min(self.snow, melt))
        self.snow = self.snow - melt
        self.precipitation = self.precipitation - snowfall + melt

        # soil storage
        self.PotenEvap = self.PET * self.cropf
        Peff = self.precipitation - self.PotenEvap
        Aw_1 = self.Available_water

        # Soil wetting below capacity
        self.whc = pcr.max(0.0, self.whc)
        self.below_cap = (Aw_1 + pcr.max(0.0, Peff)) <= self.whc
        self.available_water_below_cap = (self.Available_water * pcr.scalar(self.below_cap)) + (pcr.max(0.0, Peff) * pcr.scalar(self.below_cap))

        # Soil wetting above capacity
        self.above_cap = (Aw_1 + Peff) > self.whc
        self.excess = (Aw_1 * pcr.scalar(self.above_cap)) + (Peff * pcr.scalar(self.above_cap)) - (self.whc * pcr.scalar(self.above_cap))
        self.available_water_above_cap = (self.whc * pcr.scalar(self.above_cap))
        self.Available_water = self.available_water_below_cap + self.available_water_above_cap
        
        
        # soil drying
        self.drying = Peff <= 0.0
        self.exp_content = (Peff)/(self.whc)
        self.available_water_drying = (Aw_1 * pcr.scalar(self.drying)) * pcr.exp(self.exp_content)

        # soil that is not drying
        self.not_drying = Peff > 0.0
        self.Available_water = self.Available_water * pcr.scalar(self.not_drying)
        self.Available_water = self.Available_water + self.available_water_drying
        self.excess = self.excess * pcr.scalar(self.not_drying)

        # seepage to groundwater
        self.runoff = self.togwf * self.excess
        self.togw = self.excess - self.runoff

        # adding water to groundwater and taking water from groundwater
        self.Ground_water = self.Ground_water + self.togw
        self.sloflo = (self.Ground_water/self.C)
        self.Ground_water = self.Ground_water - self.sloflo

        # adding water from groundwater to runoff
        self.runoff = self.runoff + self.sloflo
Ejemplo n.º 3
0
def sCurve(X, a=0.0, b=1.0, c=1.0):
    """
    sCurve function:

    Input:
        - X input map
        - C determines the steepness or "stepwiseness" of the curve.
          The higher C the sharper the function. A negative C reverses the function.
        - b determines the amplitude of the curve
        - a determines the centre level (default = 0)

    Output:
        - result
    """
    try:
        s = 1.0 / (b + pcr.exp(-c * (X - a)))
    except:
        s = 1.0 / (b + pcr.exp(-c * (X - a)))
    return s
Ejemplo n.º 4
0
    def dynamic(self):

        logger.info("Step 4: Monte Carlo simulation")

        # draw a random value (uniform for the entire map)
        z = pcr.mapnormal()
        #~ self.report(z,"z")

        # constraints, in order to make sure that random values are in the table of "lookup_table_average_thickness"
        z = pcr.max(-5.0, z)
        z = pcr.min(5.0, z)

        # assign average thickness (also uniform for the entire map) based on z
        self.Davg = pcr.lookupscalar(self.lookup_table_average_thickness, z)
        #
        self.report(self.Davg, "davg")
        self.lnDavg = pcr.ln(self.Davg)

        # sedimentary basin thickness (varying over cells and samples)
        lnD = self.F * (self.lnCV * self.lnDavg) + self.lnDavg

        # set the minimum depth (must be bigger than zero)
        minimum_depth = 0.005
        lnD = pcr.max(pcr.ln(minimum_depth), lnD)

        # extrapolation
        lnD = pcr.cover(lnD, \
              pcr.windowaverage(lnD, 1.50*vos.getMapAttributes(self.clone_map_file,"cellsize")))
        lnD = pcr.cover(lnD, \
              pcr.windowaverage(pcr.cover(lnD, pcr.ln(minimum_depth)), 3.00*vos.getMapAttributes(self.clone_map_file,"cellsize")))
        lnD = pcr.cover(lnD, \
              pcr.windowaverage(pcr.cover(lnD, pcr.ln(minimum_depth)), 0.50))

        # smoothing per quarter arc degree
        lnD = pcr.windowaverage(lnD, 0.25)

        # thickness in meter
        self.D = pcr.exp(lnD)

        #~ # smoothing  bottom elevation
        #~ dem_bottom = pcr.windowaverage(self.dem_average - self.D, 0.50)
        #~ # thickness in meter
        #~ self.D = pcr.max(0.0, self.dem_average - dem_bottom)

        #~ # smoothing
        #~ self.D = pcr.windowaverage(self.D, 1.50*vos.getMapAttributes(self.clone_map_file,"cellsize"))

        # accuracy until cm only
        self.D = pcr.rounddown(self.D * 100.) / 100.

        self.report(self.D, "damc")
Ejemplo n.º 5
0
 def updateWeight(self):
     print('#### UPDATEWEIGHTING')
     print('filter period', self.filterPeriod())
     print('filter timestep ',
           self._d_filterTimesteps[self.filterPeriod() - 1])
     print('lijst ', self._d_filterTimesteps)
     print('filter sample ', self.currentSampleNumber())
     modelledData = self.readmap('Rqs')
     observations = self.readDeterministic('observations/Rqs')
     #observations=pcr.ifthen(pit(self.ldd) != 0,syntheticData)
     measurementErrorSD = 3.0 * observations + 1.0
     sum = pcr.maptotal(((modelledData - observations)**2) /
                        (2.0 * (measurementErrorSD**2)))
     weight = pcr.exp(-sum)
     weightFloatingPoint, valid = pcr.cellvalue(weight, 1)
     return weightFloatingPoint
    def correction_per_aquifer(self, id):
        
        id = float(id); print id
        
        # identify aquifer mask  
        aquifer_landmask = pcr.ifthen(self.margat_aquifer_map == pcr.nominal(id), pcr.boolean(1))
        
        # obtain the logarithmic value of Margat value
        exp_margat_thick = pcr.cellvalue(\
                           pcr.mapmaximum(\
                           pcr.ifthen(aquifer_landmask, pcr.ln(self.margat_aquifer_thickness))), 1)[0]

        # obtain the logarithmic values of 'estimated thickness'
        exp_approx_thick = pcr.ifthen(aquifer_landmask, pcr.ln(self.approx_thick)) 
                       
        exp_approx_thick_array = pcr.pcr2numpy(exp_approx_thick, vos.MV)
        exp_approx_thick_array = exp_approx_thick_array[exp_approx_thick_array <> vos.MV]
        exp_approx_thick_array = exp_approx_thick_array[exp_approx_thick_array < 1000000.]
        
        # identify percentile
        exp_approx_minim = np.percentile(exp_approx_thick_array,  2.5);
        exp_approx_maxim = np.percentile(exp_approx_thick_array, 97.5); 

        # correcting
        exp_approx_thick_correct  = ( exp_approx_thick - exp_approx_minim ) / \
                                    ( exp_approx_maxim - exp_approx_minim )   
        exp_approx_thick_correct  = pcr.max(0.0, exp_approx_thick_correct )
        exp_approx_thick_correct *= pcr.max(0.0,\
                                    ( exp_margat_thick - exp_approx_minim ) )
        exp_approx_thick_correct += pcr.min(exp_approx_minim, exp_approx_thick)

        # maximum thickness
        exp_approx_thick_correct  = pcr.min(exp_margat_thick, exp_approx_thick_correct)

        # corrected thickness
        correct_thickness = pcr.exp(exp_approx_thick_correct)
        
        return correct_thickness
Ejemplo n.º 7
0
    def createInstancesInitial(self):
        import generalfunctions

        if readDistributionOfParametersFromDisk:
            path = '/home/derek/tmp/'
            maximumInterceptionCapacityPerLAI = pcr.scalar(
                path +
                pcrfw.generateNameS('RPic', self.currentSampleNumber()) +
                '.map')
            ksat = pcr.scalar(
                path +
                pcrfw.generateNameS('RPks', self.currentSampleNumber()) +
                '.map')
            regolithThicknessHomogeneous = pcr.scalar(
                path +
                pcrfw.generateNameS('RPrt', self.currentSampleNumber()) +
                '.map')
            saturatedConductivityMetrePerDay = pcr.scalar(
                path +
                pcrfw.generateNameS('RPsc', self.currentSampleNumber()) +
                '.map')
            multiplierMaxStomatalConductance = pcr.scalar(
                path +
                pcrfw.generateNameS('RPmm', self.currentSampleNumber()) +
                '.map')
        else:
            maximumInterceptionCapacityPerLAI = generalfunctions.areauniformBounds(
                0.0001, 0.0005, pcr.nominal(1),
                pcr.scalar(cfg.maximumInterceptionCapacityValue),
                createRealizations)
            ksat = generalfunctions.areauniformBounds(
                0.025, 0.05, pcr.nominal(1), pcr.scalar(cfg.ksatValue),
                createRealizations)
            regolithThicknessHomogeneous = generalfunctions.areauniformBounds(
                1.0, 3.5, cfg.areas,
                pcr.scalar(cfg.regolithThicknessHomogeneousValue),
                createRealizations)
            saturatedConductivityMetrePerDay = generalfunctions.mapuniformBounds(
                25.0, 40.0,
                pcr.scalar(cfg.saturatedConductivityMetrePerDayValue),
                createRealizations)
            multiplierMaxStomatalConductance = generalfunctions.mapuniformBounds(
                0.8, 1.1,
                pcr.scalar(cfg.multiplierMaxStomatalConductanceValue),
                createRealizations)

        if swapCatchments:
            regolithThicknessHomogeneous = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, regolithThicknessHomogeneous, True)

        self.d_randomparameters = randomparameters.RandomParameters(
            timeStepsToReportRqs, setOfVariablesToReport,
            maximumInterceptionCapacityPerLAI, ksat,
            regolithThicknessHomogeneous, saturatedConductivityMetrePerDay,
            multiplierMaxStomatalConductance)

        # class for exchange variables in initial and dynamic
        # introduced to make filtering possible
        self.d_exchangevariables = exchangevariables.ExchangeVariables(
            timeStepsToReportSome,
            setOfVariablesToReport,
        )

        ################
        # interception #
        ################

        self.ldd = cfg.lddMap

        initialInterceptionStore = pcr.scalar(0.000001)
        leafAreaIndex = pcr.scalar(cfg.leafAreaIndexValue)

        if swapCatchments:
            leafAreaIndex = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, leafAreaIndex, True)
        gapFraction = pcr.exp(
            -0.5 * leafAreaIndex)  # equation 40 in Brolsma et al 2010a
        maximumInterceptionStore = maximumInterceptionCapacityPerLAI * leafAreaIndex

        self.d_interceptionuptomaxstore = interceptionuptomaxstore.InterceptionUpToMaxStore(
            self.ldd, initialInterceptionStore, maximumInterceptionStore,
            gapFraction, self.timeStepDurationHours, timeStepsToReportSome,
            setOfVariablesToReport)

        #################
        # surface store #
        #################

        initialSurfaceStore = pcr.scalar(0.0)
        maxSurfaceStore = pcr.scalar(cfg.maxSurfaceStoreValue)
        self.d_surfaceStore = surfacestore.SurfaceStore(
            initialSurfaceStore, maxSurfaceStore, self.timeStepDurationHours,
            timeStepsToReportSome, setOfVariablesToReport)

        ################
        # infiltration #
        ################

        # N initialMoistureContentFraction taken from 1st July

        # DK
        # we do not use rts and Gs as input to calculate initial moisture fraction to avoid
        # problems when the initial regolith thickness is calibrated (it might be thinner than
        # initialMoistureThick -> problems!)
        # instead, we use initial moisture content fraction as input, read from disk, it is just calculated
        # by pcrcalc 'mergeInitialMoistureContentFraction=Gs000008.761/rts00008.761'
        # note that I also changed the name for the initial soil moisture as a fraction
        initialSoilMoistureFractionFromDisk = pcr.scalar(
            cfg.initialSoilMoistureFractionFromDiskValue)
        if swapCatchments:
            initialSoilMoistureFractionFromDisk = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, initialSoilMoistureFractionFromDisk, True)

        # initial soil moisture as a fraction should not be above soil porosity as a fraction, just a check
        soilPorosityFraction = pcr.scalar(cfg.soilPorosityFractionValue)
        if swapCatchments:
            soilPorosityFraction = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, soilPorosityFraction, True)
        initialSoilMoistureFraction = pcr.min(
            soilPorosityFraction, initialSoilMoistureFractionFromDisk)
        hf = pcr.scalar(-0.0000001)
        self.d_infiltrationgreenandampt = infiltrationgreenandampt.InfiltrationGreenAndAmpt(
            soilPorosityFraction, initialSoilMoistureFraction, ksat, hf,
            self.timeStepDurationHours, timeStepsToReportSome,
            setOfVariablesToReport)

        ####################
        # subsurface water #
        ####################

        demOfBedrockTopography = self.dem

        stream = pcr.boolean(cfg.streamValue)
        theSlope = pcr.slope(self.dem)
        regolithThickness = pcr.ifthenelse(stream, 0.01,
                                           regolithThicknessHomogeneous)

        self.multiplierWiltingPoint = pcr.scalar(1.0)
        limitingPointFraction = pcr.scalar(cfg.limitingPointFractionValue)

        if swapCatchments:
            limitingPointFraction = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, limitingPointFraction, True)
        mergeWiltingPointFractionFS = pcr.scalar(
            cfg.mergeWiltingPointFractionFSValue)
        if swapCatchments:
            mergeWiltingPointFractionFS = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, mergeWiltingPointFractionFS, True)
        wiltingPointFractionNotChecked = mergeWiltingPointFractionFS * self.multiplierWiltingPoint
        wiltingPointFraction = pcr.min(wiltingPointFractionNotChecked,
                                       limitingPointFraction)

        fieldCapacityFraction = pcr.scalar(cfg.fieldCapacityFractionValue)
        if swapCatchments:
            fieldCapacityFraction = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, fieldCapacityFraction, True)

        self.d_subsurfaceWaterOneLayer = subsurfacewateronelayer.SubsurfaceWaterOneLayer(
            self.ldd, demOfBedrockTopography, regolithThickness,
            initialSoilMoistureFraction, soilPorosityFraction,
            wiltingPointFraction, fieldCapacityFraction, limitingPointFraction,
            saturatedConductivityMetrePerDay, self.timeStepDurationHours,
            timeStepsToReportSome, setOfVariablesToReport)

        ##########
        # runoff #
        ##########

        self.d_runoffAccuthreshold = runoffaccuthreshold.RunoffAccuthreshold(
            self.ldd, self.timeStepDurationHours, timeStepsToReportRqs,
            setOfVariablesToReport)

        ######################
        # evapotranspiration #
        ######################

        albedo = pcr.scalar(cfg.albedoValue)
        if swapCatchments:
            albedo = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, albedo, True)

        maxStomatalConductance = pcr.scalar(
            cfg.maxStomatalConductanceValue) * multiplierMaxStomatalConductance
        if swapCatchments:
            maxStomatalConductance = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, maxStomatalConductance, True)

        vegetationHeight = pcr.scalar(cfg.vegetationHeightValue)
        if swapCatchments:
            vegetationHeight = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, vegetationHeight, True)
        self.d_evapotranspirationPenman = evapotranspirationpenman.EvapotranspirationPenman(
            self.timeStepDurationHours, albedo, maxStomatalConductance,
            vegetationHeight, leafAreaIndex, timeStepsToReportSome,
            setOfVariablesToReport)
Ejemplo n.º 8
0
def agriZone_hourlyEp_Sa_beta_frostSamax(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on LP
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa --> incorporation of beta function
    - Fa is based on storage in Sa
    - Fa is decreased in case of frozen soil
    - Code for ini-file: 11
    """

    # JarvisCoefficients.calcEp(self,k)
    # self.PotEvaporation = self.EpHour

    self.FrDur[k] = pcr.min(self.FrDur[k] + (self.Temperature) * self.dayDeg[k], 0)
    self.Ft = pcr.min(
        pcr.max(
            self.FrDur[k] / (self.FrDur1[k] - self.FrDur0[k])
            - self.FrDur0[k] / (self.FrDur1[k] - self.FrDur0[k]),
            0.1,
        ),
        1,
    )

    self.samax2 = self.samax[k] * pcr.scalar(self.catchArea) * self.Ft
    self.Qaadd = pcr.max(self.Sa_t[k] + self.Pe - self.samax2, 0)

    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd)
    self.SaN = pcr.min(self.Sa[k] / self.samax2, 1)
    self.SuN = self.Su[k] / self.sumax[k]

    self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min(
        self.Sa[k] / (self.samax2 * self.LP[k]), 1
    )
    self.Qa1 = (self.Pe - self.Qaadd) * (1 - (1 - self.SaN) ** self.beta[k])
    self.Fa1 = pcr.ifthenelse(
        self.SaN > 0,
        self.Fmin[k]
        + (self.Fmax[k] - self.Fmin[k]) * pcr.exp((-self.decF[k] * (1 - self.SaN))),
        0,
    )

    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Qa1 - self.Fa1 - self.Ea1

    self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0)
    self.Qa = (
        self.Qa1
        + (
            self.Qa1
            / pcr.ifthenelse(
                self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1
            )
        )
        * self.Sa_diff
    )
    self.Fa = (
        self.Fa1
        + (
            self.Fa1
            / pcr.ifthenelse(
                self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1
            )
        )
        * self.Sa_diff
    )
    self.Ea = (
        self.Ea1
        + (
            self.Ea1
            / pcr.ifthenelse(
                self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1
            )
        )
        * self.Sa_diff
    )
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Ea - self.Fa - self.Qa
    self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k])
    self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k])

    self.wbSa_[k] = (
        self.Pe - self.Ea - self.Qa - self.Qaadd - self.Fa - self.Sa[k] + self.Sa_t[k]
    )

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa + self.Qaadd
    self.Fa_[k] = self.Fa
    self.Ft_[k] = self.Ft
Ejemplo n.º 9
0
def agriZone_hourlyEp_Sa_beta_frostSamax(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on LP
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa --> incorporation of beta function
    - Fa is based on storage in Sa
    - Fa is decreased in case of frozen soil
    - Code for ini-file: 11
    """

    # JarvisCoefficients.calcEp(self,k)
    # self.PotEvaporation = self.EpHour

    self.FrDur[k] = pcr.min(
        self.FrDur[k] + (self.Temperature) * self.dayDeg[k], 0)
    self.Ft = pcr.min(
        pcr.max(
            self.FrDur[k] / (self.FrDur1[k] - self.FrDur0[k]) -
            self.FrDur0[k] / (self.FrDur1[k] - self.FrDur0[k]),
            0.1,
        ),
        1,
    )

    self.samax2 = self.samax[k] * pcr.scalar(self.catchArea) * self.Ft
    self.Qaadd = pcr.max(self.Sa_t[k] + self.Pe - self.samax2, 0)

    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd)
    self.SaN = pcr.min(self.Sa[k] / self.samax2, 1)
    self.SuN = self.Su[k] / self.sumax[k]

    self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min(
        self.Sa[k] / (self.samax2 * self.LP[k]), 1)
    self.Qa1 = (self.Pe - self.Qaadd) * (1 - (1 - self.SaN)**self.beta[k])
    self.Fa1 = pcr.ifthenelse(
        self.SaN > 0,
        self.Fmin[k] + (self.Fmax[k] - self.Fmin[k]) * pcr.exp(
            (-self.decF[k] * (1 - self.SaN))),
        0,
    )

    self.Sa[k] = self.Sa_t[k] + (self.Pe -
                                 self.Qaadd) - self.Qa1 - self.Fa1 - self.Ea1

    self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0)
    self.Qa = (self.Qa1 +
               (self.Qa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0,
                                          self.Fa1 + self.Ea1 + self.Qa1, 1)) *
               self.Sa_diff)
    self.Fa = (self.Fa1 +
               (self.Fa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0,
                                          self.Fa1 + self.Ea1 + self.Qa1, 1)) *
               self.Sa_diff)
    self.Ea = (self.Ea1 +
               (self.Ea1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0,
                                          self.Fa1 + self.Ea1 + self.Qa1, 1)) *
               self.Sa_diff)
    self.Sa[k] = self.Sa_t[k] + (self.Pe -
                                 self.Qaadd) - self.Ea - self.Fa - self.Qa
    self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k])
    self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k])

    self.wbSa_[k] = (self.Pe - self.Ea - self.Qa - self.Qaadd - self.Fa -
                     self.Sa[k] + self.Sa_t[k])

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa + self.Qaadd
    self.Fa_[k] = self.Fa
    self.Ft_[k] = self.Ft
    def __init__(self, clone_map_file,\
                       input_thickness_netcdf_file,\
                       input_thickness_var_name   ,\
                       margat_aquifers,\
                       tmp_directory,
                       landmask = None,
                       arcdegree = True):

        object.__init__(self)

        # aquifer table from Margat and van der Gun 
        self.margat_aquifers = margat_aquifers

        # clone map
        self.clone_map_file = clone_map_file
        self.clone_map_attr = vos.getMapAttributesALL(self.clone_map_file)
        if arcdegree == True:
            self.clone_map_attr['cellsize'] = round(self.clone_map_attr['cellsize'] * 360000.)/360000.
        xmin = self.clone_map_attr['xUL']
        xmax = xmin + self.clone_map_attr['cols'] * self.clone_map_attr['cellsize']
        ymax = self.clone_map_attr['yUL']
        ymin = ymax - self.clone_map_attr['rows'] * self.clone_map_attr['cellsize']
        pcr.setclone(self.clone_map_file)

        # temporary directory 
        self.tmp_directory = tmp_directory

        # thickness approximation (unit: m, file in netcdf with variable name = average 
        self.approx_thick = vos.netcdf2PCRobjCloneWithoutTime(input_thickness_netcdf_file,\
                                                              input_thickness_var_name,\
                                                              self.clone_map_file)
        # set minimum value to 0.1 mm
        self.approx_thick = pcr.max(0.0001, self.approx_thick)

        # rasterize the shape file 
        #               -        
        # save current directory and move to temporary directory
        current_dir = str(os.getcwd()+"/")
        os.chdir(str(self.tmp_directory))
        #
        cmd_line  = 'gdal_rasterize -a MARGAT '                                     # layer name = MARGAT
        cmd_line += '-te '+str(xmin)+' '+str(ymin)+' '+str(xmax)+' '+str(ymax)+ ' '       
        cmd_line += '-tr '+str(self.clone_map_attr['cellsize'])+' '+str(self.clone_map_attr['cellsize'])+' '
        cmd_line += str(margat_aquifers['shapefile'])+' '
        cmd_line += 'tmp.tif'
        print(cmd_line); os.system(cmd_line)
        #
        # make it nomial
        cmd_line = 'pcrcalc tmp.map = "nominal(tmp.tif)"' 
        print(cmd_line); os.system(cmd_line)
        #
        # make sure that the clone map is correct
        cmd_line = 'mapattr -c '+str(self.clone_map_file)+' tmp.map'
        print(cmd_line); os.system(cmd_line)
        #
        # read the map
        self.margat_aquifer_map = pcr.nominal(pcr.readmap("tmp.map"))
        #
        # clean temporary directory and return to the original directory
        vos.clean_tmp_dir(self.tmp_directory)
        os.chdir(current_dir)
        
        # extend the extent of each aquifer
        self.margat_aquifer_map = pcr.cover(self.margat_aquifer_map, 
                                  pcr.windowmajority(self.margat_aquifer_map, 1.25))

        # assign aquifer thickness, unit: m (lookuptable operation) 
        self.margat_aquifer_thickness = pcr.lookupscalar(margat_aquifers['txt_table'], self.margat_aquifer_map)
        self.margat_aquifer_thickness = pcr.ifthen(self.margat_aquifer_thickness > 0., \
                                                   self.margat_aquifer_thickness)
        #~ pcr.report(self.margat_aquifer_thickness,"thick.map"); os.system("aguila thick.map")

        # aquifer map
        self.margat_aquifer_map       = pcr.ifthen(self.margat_aquifer_thickness > 0., self.margat_aquifer_map)        
        
        # looping per aquifer: cirrecting or rescaling 
        aquifer_ids = np.unique(pcr.pcr2numpy(pcr.scalar(self.margat_aquifer_map), vos.MV))
        aquifer_ids = aquifer_ids[aquifer_ids > 0]
        aquifer_ids = aquifer_ids[aquifer_ids < 10000]
        self.rescaled_thickness = None
        for id in aquifer_ids:
            rescaled_thickness = self.correction_per_aquifer(id)
            try:
                self.rescaled_thickness = pcr.cover(self.rescaled_thickness, rescaled_thickness)
            except:
                self.rescaled_thickness = rescaled_thickness
        
        # integrating
        ln_aquifer_thickness  = self.mapFilling( pcr.ln(self.rescaled_thickness), pcr.ln(self.approx_thick) )
        self.aquifer_thickness = pcr.exp(ln_aquifer_thickness)
        #~ pcr.report(self.aquifer_thickness,"thick.map"); os.system("aguila thick.map")

        # cropping only in the landmask region
        if landmask == None: landmask = self.clone_map_file
        self.landmask = pcr.defined(vos.readPCRmapClone(landmask,self.clone_map_file,self.tmp_directory))
        #~ pcr.report(self.landmask,"test.map"); os.system("aguila test.map")

        self.aquifer_thickness = pcr.ifthen(self.landmask, self.aquifer_thickness)
def tanh(x):
  #-returns the hyperbolic tangent of a PCRaster map as (exp(2x)-1)/(exp(2x)+1)
  return (pcr.exp(2*x)-1.)/(pcr.exp(2*x)+1.)
Ejemplo n.º 12
0
 def integralLogisticFunction(self, x):
     #-returns a tupple of two values holding the integral of the logistic functions
     # of (x) and (-x)
     logInt = pcr.ln(pcr.exp(-x) + 1)
     return logInt, x + logInt
Ejemplo n.º 13
0
    def dynamic(self):
        """
          *Required*
          This is where all the time dependent functions are executed. Time dependent
          output should also be saved here.
        """
        # print 'useETPdata' , self.UseETPdata
        # Put the W3RA here. Stuff from W3RA_timestep_model.m
        # read meteo from file
        self.logger.debug("Running for: " + str(self.currentdatetime))
        self.PRECIP = pcr.cover(
            self.wf_readmap(self.PRECIP_mapstack, 0.0), pcr.scalar(0.0)
        )  # mm

        if self.UseETPdata == 1:
            self.TDAY = pcr.cover(
                self.wf_readmap(self.TDAY_mapstack, 10.0), pcr.scalar(10.0)
            )  # T in degC
            self.EPOT = pcr.cover(
                self.wf_readmap(self.EPOT_mapstack, 0.0), pcr.scalar(0.0)
            )  # mm
            self.WINDSPEED = pcr.cover(
                self.wf_readmap(self.WINDSPEED_mapstack, default=1.0), pcr.scalar(1.0)
            )
            self.AIRPRESS = pcr.cover(
                self.wf_readmap(self.AIRPRESS_mapstack, default=980.0),
                pcr.scalar(980.0),
            )
            # print "Using climatology for wind, air pressure and albedo."
        elif self.UseETPdata == 0:
            self.TMIN = pcr.cover(
                self.wf_readmap(self.TMIN_mapstack, 10.0), pcr.scalar(10.0)
            )  # T in degC
            self.TMAX = pcr.cover(
                self.wf_readmap(self.TMAX_mapstack, 10.0), pcr.scalar(10.0)
            )  # T in degC
            self.RAD = pcr.cover(
                self.wf_readmap(self.RAD_mapstack, 10.0), pcr.scalar(10.0)
            )  # W m-2 s-1
            self.WINDSPEED = pcr.cover(
                self.wf_readmap(self.WINDSPEED_mapstack, 10.0), pcr.scalar(10.0)
            )  # ms-1
            self.AIRPRESS = pcr.cover(
                self.wf_readmap(self.AIRPRESS_mapstack, 10.0), pcr.scalar(10.0)
            )  # Pa
            self.ALBEDO = pcr.cover(
                self.wf_readmapClimatology(self.ALBEDO_mapstack, default=0.1),
                pcr.scalar(0.1),
            )

        self.wf_multparameters()
        doy = self.currentdatetime.timetuple().tm_yday

        # conversion daylength
        pcr.setglobaloption("radians")
        m = pcr.scalar(1) - pcr.tan(
            (self.latitude * pcr.scalar(math.pi) / pcr.scalar(180))
        ) * pcr.tan(
            (
                (pcr.scalar(23.439) * pcr.scalar(math.pi) / pcr.scalar(180))
                * pcr.cos(
                    pcr.scalar(2)
                    * pcr.scalar(math.pi)
                    * (doy + pcr.scalar(9))
                    / pcr.scalar(365.25)
                )
            )
        )
        self.fday = pcr.min(
            pcr.max(
                pcr.scalar(0.02),
                pcr.scalar(
                    pcr.acos(
                        pcr.scalar(1)
                        - pcr.min(pcr.max(pcr.scalar(0), m), pcr.scalar(2))
                    )
                )
                / pcr.scalar(math.pi),
            ),
            pcr.scalar(1),
        )  # fraction daylength

        # Assign forcing and estimate effective meteorological variables

        Pg = self.PRECIP  # mm

        if self.UseETPdata == 1:
            Ta = self.TDAY  # T in degC
            T24 = self.TDAY  # T in degC
        elif self.UseETPdata == 0:
            Rg = pcr.max(
                self.RAD, pcr.scalar(0.0001)
            )  # already in W m-2 s-1; set minimum of 0.01 to avoid numerical problems
            Ta = self.TMIN + pcr.scalar(0.75) * (self.TMAX - self.TMIN)  # T in degC
            T24 = self.TMIN + pcr.scalar(0.5) * (self.TMAX - self.TMIN)  # T in degC
            pex = pcr.min(
                pcr.scalar(17.27) * (self.TMIN) / (pcr.scalar(237.3) + self.TMIN),
                pcr.scalar(10),
            )  # T in degC
            pe = pcr.min(
                pcr.scalar(610.8) * (pcr.exp(pex)), pcr.scalar(10000.0)
            )  # Mean actual vapour pressure, from dewpoint temperature
        # rescale factor because windspeed climatology is at 2m
        WindFactor = 1.0
        # u2 = pcr.scalar(WindFactor)*self.WINDSPEED*(pcr.scalar(1)-(pcr.scalar(1)-self.fday)*scalar(0.25))/self.fday
        self.u2 = (
            pcr.scalar(WindFactor)
            * self.WINDSPEED
            * (pcr.scalar(1) - (pcr.scalar(1) - self.fday) * pcr.scalar(0.25))
            / self.fday
        )
        pair = self.AIRPRESS  # already in Pa

        # diagnostic equations

        self.LAI1 = self.SLA1 * self.Mleaf1  # (5.3)
        self.LAI2 = self.SLA2 * self.Mleaf2  # (5.3)
        fveg1 = pcr.max(1 - pcr.exp(-self.LAI1 / self.LAIref1), 0.000001)  # (5.3)
        fveg2 = pcr.max(1 - pcr.exp(-self.LAI2 / self.LAIref2), 0.000001)

        # Vc = pcr.max(0,EVI-0.07)/fveg
        fsoil1 = 1 - fveg1
        fsoil2 = 1 - fveg2
        w01 = self.S01 / self.S0FC1  # (2.1)
        w02 = self.S02 / self.S0FC2
        ws1 = self.Ss1 / self.SsFC1  # (2.1)
        ws2 = self.Ss2 / self.SsFC2
        wd1 = self.Sd1 / self.SdFC1  # (2.1)
        wd2 = self.Sd2 / self.SdFC2  # (2.1)

        TotSnow1 = self.FreeWater1 + self.DrySnow1
        TotSnow2 = self.FreeWater2 + self.DrySnow2
        wSnow1 = self.FreeWater1 / (TotSnow1 + 1e-5)
        wSnow2 = self.FreeWater2 / (TotSnow2 + 1e-5)

        # Spatialise catchment fractions
        Sgfree = pcr.max(self.Sg, 0.0)
        # JS: Not sure if this is translated properly....
        # for i=1:par.Nhru
        fwater1 = pcr.min(0.005, (0.007 * self.Sr ** 0.75))
        fwater2 = pcr.min(0.005, (0.007 * self.Sr ** 0.75))
        fsat1 = pcr.min(
            1.0, pcr.max(pcr.min(0.005, 0.007 * self.Sr ** 0.75), Sgfree / self.Sgref)
        )
        fsat2 = pcr.min(
            1.0, pcr.max(pcr.min(0.005, 0.007 * self.Sr ** 0.75), Sgfree / self.Sgref)
        )
        Sghru1 = self.Sg
        Sghru2 = self.Sg

        # CALCULATION OF PET
        # Conversions and coefficients (3.1)
        pesx = pcr.min(
            (pcr.scalar(17.27) * Ta / (pcr.scalar(237.3) + Ta)), pcr.scalar(10)
        )
        pes = pcr.min(
            pcr.scalar((pcr.scalar(610.8)) * pcr.exp(pesx)), pcr.scalar(10000)
        )  # saturated vapour pressure
        # fRH = pe/pes  # relative air humidity                                  -------------- check
        cRE = 0.03449 + 4.27e-5 * Ta
        # Caero = self.fday*0.176*(1+Ta/209.1)*(pair-0.417*pe)*(1-fRH)         -------------- check
        # keps = 1.4e-3*((Ta/187)**2+Ta/107+1)*(6.36*pair+pe)/pes
        ga1 = self.ku2_1 * self.u2
        ga2 = self.ku2_2 * self.u2

        if self.UseETPdata == 1:
            self.E01 = pcr.max(self.EPOT, 0)
            self.E02 = pcr.max(self.EPOT, 0)
            keps = (
                0.655e-3 * pair / pes
            )  # See Appendix A3 (http://www.clw.csiro.au/publications/waterforahealthycountry/2010/wfhc-aus-water-resources-assessment-system.pdf) --------------------------------   check!

        elif self.UseETPdata == 0:
            # Aerodynamic conductance (3.7)

            ns_alb = self.ALBEDO
            Rgeff = Rg / self.fday
            # shortwave radiation balance (3.2)
            # alb_veg = 0.452*Vc
            # alb_soil = alb_wet+(alb_dry-alb_wet)*exp(-w0/w0ref_alb)
            # new equations for snow albedo
            alb_snow1 = 0.65 - 0.2 * wSnow1  # assumed; ideally some lit research needed
            alb_snow2 = 0.65 - 0.2 * wSnow2
            fsnow1 = pcr.min(
                1.0, 0.05 * TotSnow1
            )  # assumed; ideally some lit research needed
            fsnow2 = pcr.min(1.0, 0.05 * TotSnow2)
            # alb = fveg*alb_veg+(fsoil-fsnow)*alb_soil +fsnow*alb_snow
            # alb = albedo
            alb1 = (1 - fsnow1) * ns_alb + fsnow1 * alb_snow1
            alb2 = (1 - fsnow2) * ns_alb + fsnow2 * alb_snow2
            RSn1 = (1 - alb1) * Rgeff
            RSn2 = (1 - alb2) * Rgeff
            # long wave radiation balance (3.3 to 3.5)
            StefBolz = 5.67e-8
            Tkelv = Ta + 273.16
            self.RLin = (0.65 * (pe / Tkelv) ** 0.14) * StefBolz * Tkelv ** 4  # (3.3)
            RLout = StefBolz * Tkelv ** 4.0  # (3.4)
            self.RLn = self.RLin - RLout

            self.fGR1 = self.Gfrac_max1 * (1 - pcr.exp(-fsoil1 / self.fvegref_G1))
            self.fGR2 = self.Gfrac_max2 * (
                1 - pcr.exp(-fsoil2 / self.fvegref_G2)
            )  # (3.5)
            self.Rneff1 = (RSn1 + self.RLn) * (1 - self.fGR1)
            self.Rneff2 = (RSn2 + self.RLn) * (1 - self.fGR2)

            fRH = pe / pes  # relative air humidity
            Caero = (
                self.fday * 0.176 * (1 + Ta / 209.1) * (pair - 0.417 * pe) * (1 - fRH)
            )  # -------------- check
            keps = 1.4e-3 * ((Ta / 187) ** 2 + Ta / 107 + 1) * (6.36 * pair + pe) / pes

            #  Potential evaporation
            kalpha1 = 1 + Caero * ga1 / self.Rneff1
            kalpha2 = 1 + Caero * ga2 / self.Rneff2
            self.E01 = cRE * (1 / (1 + keps)) * kalpha1 * self.Rneff1 * self.fday
            self.E02 = cRE * (1 / (1 + keps)) * kalpha2 * self.Rneff2 * self.fday
            self.E01 = pcr.max(self.E01, 0)
            self.E02 = pcr.max(self.E02, 0)

        # CALCULATION OF ET FLUXES AND ROOT WATER UPTAKE
        # Root water uptake constraint (4.4)
        Usmax1 = pcr.max(
            0, self.Us01 * pcr.min(1, ws1 / self.wslimU1)
        )  ##0-waarden omdat ws1 bevat 0-waarden (zie regel 116)
        Usmax2 = pcr.max(
            0, self.Us02 * pcr.min(1, ws2 / self.wslimU2)
        )  ##0-waarden omdat ws2 bevat 0-waarden (zie regel 117)
        Udmax1 = pcr.max(
            0, self.Ud01 * pcr.min(1, wd1 / self.wdlimU1)
        )  ##0-waarden omdat wd1 bevat 0-waarden (zie regel 118)
        Udmax2 = pcr.max(
            0, self.Ud02 * pcr.min(1, wd2 / self.wdlimU2)
        )  ##0-waarden omdat wd2 bevat 0-waarden (zie regel 119)
        # U0max = pcr.max(0, Us0*min(1,w0/wslimU))
        U0max1 = pcr.scalar(0)
        U0max2 = pcr.scalar(0)
        Utot1 = pcr.max(Usmax1, pcr.max(Udmax1, U0max1))
        Utot2 = pcr.max(Usmax2, pcr.max(Udmax2, U0max2))

        # Maximum transpiration (4.3)
        Gsmax1 = self.cGsmax1 * self.Vc1
        gs1 = fveg1 * Gsmax1
        ft1 = 1 / (1 + (keps / (1 + keps)) * ga1 / gs1)
        Etmax1 = ft1 * self.E01
        Gsmax2 = self.cGsmax2 * self.Vc2
        gs2 = fveg2 * Gsmax2
        ft2 = 1 / (1 + (keps / (1 + keps)) * ga2 / gs2)
        Etmax2 = ft2 * self.E02

        # Actual transpiration (4.1)
        Et1 = pcr.min(Utot1, Etmax1)
        Et2 = pcr.min(Utot2, Etmax2)

        # # Root water uptake distribution (2.3)
        U01 = pcr.max(
            pcr.min((U0max1 / (U0max1 + Usmax1 + Udmax1)) * Et1, self.S01 - 1e-2), 0
        )
        Us1 = pcr.max(
            pcr.min((Usmax1 / (U0max1 + Usmax1 + Udmax1)) * Et1, self.Ss1 - 1e-2), 0
        )
        Ud1 = pcr.max(
            pcr.min((Udmax1 / (U0max1 + Usmax1 + Udmax1)) * Et1, self.Sd1 - 1e-2), 0
        )
        Et1 = U01 + Us1 + Ud1  # to ensure mass balance

        U02 = pcr.max(
            pcr.min((U0max2 / (U0max2 + Usmax2 + Udmax2)) * Et2, self.S02 - 1e-2), 0
        )
        Us2 = pcr.max(
            pcr.min((Usmax2 / (U0max2 + Usmax2 + Udmax2)) * Et2, self.Ss2 - 1e-2), 0
        )
        Ud2 = pcr.max(
            pcr.min((Udmax2 / (U0max2 + Usmax2 + Udmax2)) * Et2, self.Sd2 - 1e-2), 0
        )
        Et2 = U02 + Us2 + Ud2

        # Soil evaporation (4.5)
        self.S01 = pcr.max(0, self.S01 - U01)
        self.S02 = pcr.max(0, self.S02 - U02)
        w01 = self.S01 / self.S0FC1  # (2.1)
        w02 = self.S02 / self.S0FC2  # (2.1)
        fsoilE1 = self.FsoilEmax1 * pcr.min(1, w01 / self.w0limE1)
        fsoilE2 = self.FsoilEmax2 * pcr.min(1, w02 / self.w0limE2)
        Es1 = pcr.max(
            0, pcr.min(((1 - fsat1) * fsoilE1 * (self.E01 - Et1)), self.S01 - 1e-2)
        )
        Es2 = pcr.max(
            0, pcr.min(((1 - fsat2) * fsoilE2 * (self.E02 - Et2)), self.S02 - 1e-2)
        )
        # Groundwater evaporation (4.6)
        Eg1 = pcr.min((fsat1 - fwater1) * self.FsoilEmax1 * (self.E01 - Et1), Sghru1)
        Eg2 = pcr.min((fsat2 - fwater2) * self.FsoilEmax2 * (self.E02 - Et2), Sghru2)
        # Open water evaporation (4.7)
        Er1 = pcr.min(fwater1 * self.FwaterE1 * pcr.max(0, self.E01 - Et1), self.Sr)
        Er2 = pcr.min(fwater2 * self.FwaterE2 * pcr.max(0, self.E02 - Et2), self.Sr)
        # Rainfall interception evaporation (4.2)
        Sveg1 = self.S_sls1 * self.LAI1
        fER1 = self.ER_frac_ref1 * fveg1
        Pwet1 = -pcr.ln(1 - fER1 / fveg1) * Sveg1 / fER1
        Ei1 = pcr.scalar(Pg < Pwet1) * fveg1 * Pg + pcr.scalar(Pg >= Pwet1) * (
            fveg1 * Pwet1 + fER1 * (Pg - Pwet1)
        )

        Sveg2 = self.S_sls2 * self.LAI2
        fER2 = self.ER_frac_ref2 * fveg2
        Pwet2 = -pcr.ln(1 - fER2 / fveg2) * Sveg2 / fER2
        Ei2 = pcr.scalar(Pg < Pwet2) * fveg2 * Pg + pcr.scalar(Pg >= Pwet2) * (
            fveg2 * Pwet2 + fER2 * (Pg - Pwet2)
        )

        self.EACT1 = (Et1 + Es1 + Eg1 + Er1 + Ei1) * self.Fhru1
        self.EACT2 = (Et2 + Es2 + Eg2 + Er2 + Ei2) * self.Fhru2
        self.EACT = self.EACT1 + self.EACT2

        # HBV snow routine
        # Matlab: function [FreeWater,DrySnow,InSoil]=snow_submodel(Precipitation,Temperature,FreeWater,DrySnow)
        # derived from HBV-96 shared by Jaap Schellekens (Deltares) in May 2011
        # original in PCraster, adapted to Matlab by Albert van Dijk
        # HBV snow routine
        Pn1 = Pg - Ei1
        Pn2 = Pg - Ei2
        Precipitation1 = Pn1
        Precipitation2 = Pn2

        # Snow routine parameters
        # parameters
        # TODO: Check this, not sure if this works.......
        x = pcr.scalar(Pg)
        Cfmax1 = 0.6 * 3.75653 * pcr.scalar(x >= 0)
        Cfmax2 = 3.75653 * pcr.scalar(x >= 0)
        TT1 = -1.41934 * pcr.scalar(
            x >= 0
        )  # critical temperature for snowmelt and refreezing
        TT2 = -1.41934 * pcr.scalar(x >= 0)
        TTI1 = 1.00000 * pcr.scalar(
            x >= 0
        )  # defines interval in which precipitation falls as rainfall and snowfall
        TTI2 = 1.00000 * pcr.scalar(x >= 0)
        CFR1 = 0.05000 * pcr.scalar(
            x >= 0
        )  # refreezing efficiency constant in refreezing of freewater in snow
        CFR2 = 0.05000 * pcr.scalar(x >= 0)
        WHC1 = 0.10000 * pcr.scalar(x >= 0)
        WHC2 = 0.10000 * pcr.scalar(x >= 0)

        # Partitioning into fractions rain and snow
        Temperature = T24  # Dimmie, let op: tijdelijke regel!!
        RainFrac1 = pcr.max(0, pcr.min((Temperature - (TT1 - TTI1 / 2)) / TTI1, 1))
        RainFrac2 = pcr.max(0, pcr.min((Temperature - (TT2 - TTI2 / 2)) / TTI2, 1))
        SnowFrac1 = 1 - RainFrac1  # fraction of precipitation which falls as snow
        SnowFrac2 = 1 - RainFrac2

        # Snowfall/melt calculations
        SnowFall1 = SnowFrac1 * Precipitation1  # snowfall depth
        SnowFall2 = SnowFrac2 * Precipitation2
        RainFall1 = RainFrac1 * Precipitation1  # rainfall depth
        RainFall2 = RainFrac2 * Precipitation2
        PotSnowMelt1 = Cfmax1 * pcr.max(
            0, Temperature - TT1
        )  # Potential snow melt, based on temperature
        PotSnowMelt2 = Cfmax2 * pcr.max(0, Temperature - TT2)
        PotRefreezing1 = (
            Cfmax1 * CFR1 * pcr.max(TT1 - Temperature, 0)
        )  # Potential refreezing, based on temperature
        PotRefreezing2 = Cfmax2 * CFR2 * pcr.max(TT2 - Temperature, 0)
        Refreezing1 = pcr.min(PotRefreezing1, self.FreeWater1)  # actual refreezing
        Refreezing2 = pcr.min(PotRefreezing2, self.FreeWater2)
        SnowMelt1 = pcr.min(PotSnowMelt1, self.DrySnow1)  # actual snow melt
        SnowMelt2 = pcr.min(PotSnowMelt2, self.DrySnow2)
        self.DrySnow1 = (
            self.DrySnow1 + SnowFall1 + Refreezing1 - SnowMelt1
        )  # dry snow content
        self.DrySnow2 = self.DrySnow2 + SnowFall2 + Refreezing2 - SnowMelt2
        self.FreeWater1 = self.FreeWater1 - Refreezing1  # free water content in snow
        self.FreeWater2 = self.FreeWater2 - Refreezing2
        MaxFreeWater1 = self.DrySnow1 * WHC1
        MaxFreeWater2 = self.DrySnow2 * WHC2
        self.FreeWater1 = self.FreeWater1 + SnowMelt1 + RainFall1
        self.FreeWater2 = self.FreeWater2 + SnowMelt2 + RainFall2
        InSoil1 = pcr.max(
            self.FreeWater1 - MaxFreeWater1, 0
        )  # abundant water in snow pack which goes into soil
        InSoil2 = pcr.max(self.FreeWater2 - MaxFreeWater2, 0)
        self.FreeWater1 = self.FreeWater1 - InSoil1
        self.FreeWater2 = self.FreeWater2 - InSoil2
        # End of Snow Module

        # CALCULATION OF WATER BALANCES
        # surface water fluxes (2.2)
        NetInSoil1 = pcr.max(0, (InSoil1 - self.InitLoss1))
        NetInSoil2 = pcr.max(0, (InSoil2 - self.InitLoss2))
        Rhof1 = (1 - fsat1) * (NetInSoil1 / (NetInSoil1 + self.PrefR1)) * NetInSoil1
        Rhof2 = (1 - fsat2) * (NetInSoil2 / (NetInSoil2 + self.PrefR2)) * NetInSoil2
        Rsof1 = fsat1 * NetInSoil1
        Rsof2 = fsat2 * NetInSoil2
        QR1 = Rhof1 + Rsof1
        QR2 = Rhof2 + Rsof2
        I1 = InSoil1 - QR1
        I2 = InSoil2 - QR2
        # SOIL WATER BALANCES (2.1 & 2.4)
        # Topsoil water balance (S0)
        self.S01 = self.S01 + I1 - Es1 - U01
        self.S02 = self.S02 + I2 - Es2 - U02
        SzFC1 = self.S0FC1
        SzFC2 = self.S0FC2
        Sz1 = self.S01
        Sz2 = self.S02
        wz1 = pcr.max(1e-2, Sz1) / SzFC1
        wz2 = pcr.max(1e-2, Sz2) / SzFC2
        self.TMP = SzFC1

        # TODO: Check if this works
        fD1 = pcr.scalar(wz1 > 1) * pcr.max(self.FdrainFC1, 1 - 1 / wz1) + pcr.scalar(
            wz1 <= 1
        ) * self.FdrainFC1 * pcr.exp(self.beta1 * pcr.scalar(wz1 - 1))
        fD2 = pcr.scalar(wz2 > 1) * pcr.max(self.FdrainFC2, 1 - 1 / wz2) + pcr.scalar(
            wz2 <= 1
        ) * self.FdrainFC2 * pcr.exp(self.beta2 * pcr.scalar(wz2 - 1))
        Dz1 = pcr.max(0, pcr.min(fD1 * Sz1, Sz1 - 1e-2))
        Dz2 = pcr.max(0, pcr.min(fD2 * Sz2, Sz2 - 1e-2))
        D01 = Dz1
        D02 = Dz2
        self.S01 = self.S01 - D01
        self.S02 = self.S02 - D02
        # Shallow root zone water balance (Ss)
        self.Ss1 = self.Ss1 + D01 - Us1
        self.Ss2 = self.Ss2 + D02 - Us2
        SzFC1 = self.SsFC1
        SzFC2 = self.SsFC2
        Sz1 = self.Ss1
        Sz2 = self.Ss2
        wz1 = pcr.max(1e-2, Sz1) / SzFC1
        wz2 = pcr.max(1e-2, Sz2) / SzFC2
        fD1 = pcr.scalar(wz1 > 1) * pcr.max(self.FdrainFC1, 1 - 1 / wz1) + pcr.scalar(
            wz1 <= 1
        ) * self.FdrainFC1 * pcr.exp(self.beta1 * pcr.scalar(wz1 - 1))
        fD2 = pcr.scalar(wz2 > 1) * pcr.max(self.FdrainFC2, 1 - 1 / wz2) + pcr.scalar(
            wz2 <= 1
        ) * self.FdrainFC2 * pcr.exp(self.beta2 * pcr.scalar(wz2 - 1))
        Dz1 = pcr.max(0, pcr.min(fD1 * Sz1, Sz1 - 1e-2))
        Dz2 = pcr.max(0, pcr.min(fD2 * Sz2, Sz2 - 1e-2))
        Ds1 = Dz1
        Ds2 = Dz2
        self.Ss1 = self.Ss1 - Ds1
        self.Ss2 = self.Ss2 - Ds2
        # Deep root zone water balance (Sd) (2.6)
        self.Sd1 = self.Sd1 + Ds1 - Ud1
        self.Sd2 = self.Sd2 + Ds2 - Ud2
        SzFC1 = self.SdFC1
        SzFC2 = self.SdFC2
        Sz1 = self.Sd1
        Sz2 = self.Sd2
        wz1 = pcr.max(1e-2, Sz1) / SzFC1
        wz2 = pcr.max(1e-2, Sz2) / SzFC2
        fD1 = pcr.scalar(wz1 > 1) * pcr.max(self.FdrainFC1, 1 - 1 / wz1) + pcr.scalar(
            wz1 <= 1
        ) * self.FdrainFC1 * pcr.exp(self.beta1 * pcr.scalar(wz1 - 1))
        fD2 = pcr.scalar(wz2 > 1) * pcr.max(self.FdrainFC2, 1 - 1 / wz2) + pcr.scalar(
            wz2 <= 1
        ) * self.FdrainFC2 * pcr.exp(self.beta2 * pcr.scalar(wz2 - 1))
        Dz1 = pcr.max(0, pcr.min(fD1 * Sz1, Sz1 - 1e-2))
        Dz2 = pcr.max(0, pcr.min(fD2 * Sz2, Sz2 - 1e-2))
        Dd1 = Dz1
        Dd2 = Dz2
        self.Sd1 = self.Sd1 - Dd1
        self.Sd2 = self.Sd2 - Dd2
        Y1 = pcr.min(
            self.Fgw_conn1 * pcr.max(0, self.wdlimU1 * self.SdFC1 - self.Sd1),
            Sghru1 - Eg1,
        )
        Y2 = pcr.min(
            self.Fgw_conn2 * pcr.max(0, self.wdlimU2 * self.SdFC2 - self.Sd2),
            Sghru2 - Eg2,
        )
        # Y = Fgw_conn.*max(0,wdlimU.*SdFC-Sd); #nog matlab script
        self.Sd1 = self.Sd1 + Y1
        self.Sd2 = self.Sd2 + Y2

        # CATCHMENT WATER BALANCE
        # Groundwater store water balance (Sg) (2.5)
        NetGf = (self.Fhru1 * (Dd1 - Eg1 - Y1)) + (self.Fhru2 * (Dd2 - Eg2 - Y2))
        self.Sg = self.Sg + NetGf
        Sgfree = pcr.max(self.Sg, 0)
        Qg = pcr.min(Sgfree, (1 - pcr.exp(-self.K_gw)) * Sgfree)
        self.Sg = self.Sg - Qg

        # Surface water store water balance (Sr) (2.7)
        self.Sr = self.Sr + (self.Fhru1 * (QR1 - Er1)) + (self.Fhru2 * (QR2 - Er2)) + Qg
        self.Qtot = pcr.min(self.Sr, (1 - pcr.exp(-self.K_rout)) * self.Sr)
        self.Sr = self.Sr - self.Qtot

        # VEGETATION ADJUSTMENT (5)

        fveq1 = (
            (1 / pcr.max((self.E01 / Utot1) - 1, 1e-3))
            * (keps / (1 + keps))
            * (ga1 / Gsmax1)
        )
        fveq2 = (
            (1 / pcr.max((self.E02 / Utot2) - 1, 1e-3))
            * (keps / (1 + keps))
            * (ga2 / Gsmax2)
        )
        fvmax1 = 1 - pcr.exp(-self.LAImax1 / self.LAIref1)
        fvmax2 = 1 - pcr.exp(-self.LAImax2 / self.LAIref2)
        fveq1 = pcr.min(fveq1, fvmax1)
        fveq2 = pcr.min(fveq2, fvmax2)
        dMleaf1 = -pcr.ln(1 - fveq1) * self.LAIref1 / self.SLA1 - self.Mleaf1
        dMleaf2 = -pcr.ln(1 - fveq2) * self.LAIref2 / self.SLA2 - self.Mleaf2

        # Mleafnet1 = dMleaf1 * (dMleaf1/self.Tgrow1) + dMleaf1 * dMleaf1/self.Tsenc1
        # Mleafnet2 = dMleaf2 * (dMleaf1/self.Tgrow2) + dMleaf2 * dMleaf2/self.Tsenc2
        Mleafnet1 = (
            pcr.scalar(dMleaf1 > 0) * (dMleaf1 / self.Tgrow1)
            + pcr.scalar(dMleaf1 < 0) * dMleaf1 / self.Tsenc1
        )
        Mleafnet2 = (
            pcr.scalar(dMleaf2 > 0) * (dMleaf2 / self.Tgrow2)
            + pcr.scalar(dMleaf2 < 0) * dMleaf2 / self.Tsenc2
        )

        self.Mleaf1 = self.Mleaf1 + Mleafnet1
        self.Mleaf2 = self.Mleaf2 + Mleafnet2
        self.LAI1 = self.SLA1 * self.Mleaf1  # (5.3)
        self.LAI2 = self.SLA2 * self.Mleaf2

        # Updating diagnostics
        self.LAI1 = self.SLA1 * self.Mleaf1  # (5.3)
        self.LAI2 = self.SLA2 * self.Mleaf2
        fveg1 = 1 - pcr.exp(-self.LAI1 / self.LAIref1)  # (5.3)
        fveg2 = 1 - pcr.exp(-self.LAI2 / self.LAIref2)
        fsoil1 = 1 - fveg1
        fsoil2 = 1 - fveg2
        w01 = self.S01 / self.S0FC1  # (2.1)
        w02 = self.S02 / self.S0FC2
        ws1 = self.Ss1 / self.SsFC1  # (2.1)
        ws2 = self.Ss2 / self.SsFC2
        wd1 = self.Sd1 / self.SdFC1  # (2.1)
        wd2 = self.Sd2 / self.SdFC2
Ejemplo n.º 14
0
    def dynamic(self):
        """
        *Required*

        This is where all the time dependent functions are executed. Time dependent
        output should also be saved here.
        """
        self.wf_updateparameters()

        # Get the date as a Python datetime object and as the day of the year (DOY): used for cropping calendar and daylength.
        self.date = datetime.utcfromtimestamp(
            self.wf_supplyStartTime()) + dt.timedelta(self.currentTimeStep() -
                                                      1)
        self.enddate = datetime.utcfromtimestamp(self.wf_supplyEndTime(
        ))  # wf_supplyEndTime() in wflow_dyamicframework? todo
        DOY = self.wf_supplyJulianDOY()

        # Some Boolean PCRaster variables to check if crop is still developing, in terms of thermal time/phenology:
        TSUM_not_Finished = self.TSUM <= self.TTSUM
        DVS_not_Finished = self.DVS <= 2.01
        Not_Finished = TSUM_not_Finished

        # Start calculating the accumulated preciptation from a certain date on (defined by RainSumStart_Month, RainSumStart_Day),
        # to judge when there's enough water for rice crop establishment.
        if (self.date.month == self.RainSumStart_Month
                and self.date.day == self.RainSumStart_Day):
            Calc_RainSum = True
            self.PSUM += self.RAIN + TINY
        else:
            Calc_RainSum = False

        # Check whether the precipitation sum is positive
        WeveGotRain = self.PSUM > 0.0
        # Check whether the precipitation sum is still below the threshhold for crop establishment (and hence calculation of the sum should still proceed):
        NotEnoughRainYet = self.PSUM <= self.RainSumReq
        EnoughRain = self.PSUM >= self.RainSumReq
        KeepAddingRain = WeveGotRain & NotEnoughRainYet

        # The first season is defined here as starting on November 1. The 2md and 3rd season are following the 1st with break periods of <self.Pausedays> days,
        # to account for the time that the farmer needs for rice harvesting and crop establishment.
        # self.Season      += pcr.ifthenelse(Calc_RainSum, self.ricemask, 0.)
        FirstSeason = self.Season == 1
        SecondSeason = self.Season == 2
        ThirdSeason = self.Season == 3
        self.Season += pcr.ifthenelse(
            EnoughRain, self.ricemask,
            0.0)  # beware, this variable is also modified in another equation
        # Add rain when the precipitation sum is positive but still below the threshold for crop establishment, reset to 0. when this is no longer the case.
        self.PSUM = (self.PSUM + pcr.ifthenelse(KeepAddingRain, self.RAIN, 0.0)
                     ) * pcr.ifthenelse(KeepAddingRain, pcr.scalar(1.0), 0.0)

        # Initializing crop harvest:
        # If a fixed planting and a fixed harvest date are forced for the whole catchment:
        if self.CropStartDOY > -1:

            if self.HarvestDAP > 0:
                HarvNow = DOY >= (self.CropStartDOY + self.HarvestDAP)
                print(
                    "Warning: harvest date read from ini file, not from Crop Profile map..."
                )
            elif self.HarvestDAP == 0:
                HarvNow = Not_Finished == False
                print(
                    "Harvest date not specified; crop harvest at crop maturity"
                )
            else:
                print(
                    "Crop harvest not initialized, found strange values in ini file... CTRL + C to exit..."
                )
                time.sleep(100)
            CropHarvNow = HarvNow & self.ricemask_BOOL

            # Initializing crop growth, optionally from a single start day (CropStartDOY in the ini file),
            # but normally from a crop profile forcing variable.
            StartNow = DOY == self.CropStartDOY
            CropStartNow = StartNow & self.ricemask_BOOL
            CropStartNow_scalar = pcr.scalar(CropStartNow)
            Started = self.STARTED > 0
            CropStarted = Started & self.ricemask_BOOL
            self.STARTED = (self.STARTED + CropStartNow_scalar +
                            pcr.scalar(CropStarted)) * pcr.ifthenelse(
                                CropHarvNow, pcr.scalar(0.0), 1.0)
            print(
                "Warning: using start date from ini file, not read from Crop Profile..."
            )

        elif self.CropStartDOY == -1:

            if self.AutoStartStop == False:
                Started = self.STARTED > 0.0
                if self.HarvestDAP == 0:
                    crpprfl_eq_zero = self.CRPST == 0.0
                    CropHarvNow = Started & crpprfl_eq_zero & self.ricemask_BOOL
                elif self.HarvestDAP > 0:
                    HarvNow = self.STARTED == self.HarvestDAP
                    CropHarvNow = HarvNow & self.ricemask_BOOL
                print("Start date read from Crop Profile...")
                # Two auxilliary variables:
                CRPST_gt_0 = self.CRPST > 0.0
                CRPST_eq_STARTED = self.CRPST == self.STARTED
                CropStartNow = CRPST_gt_0 & CRPST_eq_STARTED & self.ricemask_BOOL
                CropStarted = Started & self.ricemask_BOOL
                self.STARTED = (self.STARTED + self.CRPST) * pcr.ifthenelse(
                    CropHarvNow, pcr.scalar(0.0),
                    1.0)  # - pcr.ifthenelse(CropHarvNow, self.STARTED, 0.)

            elif self.AutoStartStop == True:
                if self.HarvestDAP == 0:
                    HarvNow = (Not_Finished == False) | Calc_RainSum
                    CropHarvNow = HarvNow & self.ricemask_BOOL
                elif self.HarvestDAP > 0:
                    HarvNow = self.STARTED == self.HarvestDAP
                    CropHarvNow = (HarvNow & self.ricemask_BOOL) | Calc_RainSum
                # Two auxilliary variables:
                Time2Plant1stCrop = self.PSUM >= self.RainSumReq
                StdMin1 = self.STARTED == -1
                CropStartNow_Season1 = Time2Plant1stCrop & self.ricemask_BOOL
                CropStartNow_Season2 = StdMin1 & self.ricemask_BOOL
                CropStartNow = CropStartNow_Season1 | CropStartNow_Season2
                CropStartNow_scalar = pcr.scalar(CropStartNow)
                if self.Sim3rdSeason == False:
                    HarvSeason1_temp = FirstSeason & CropHarvNow
                    HarvSeasonOne = HarvSeason1_temp & self.ricemask_BOOL
                    HarvSeason2_temp = SecondSeason & CropHarvNow
                    HarvSeasonTwo = HarvSeason2_temp & self.ricemask_BOOL
                    self.Season = (
                        self.Season +
                        pcr.ifthenelse(HarvSeasonOne, self.ricemask, 0.0) -
                        pcr.ifthenelse(HarvSeasonTwo, self.ricemask * 2.0, 0.0)
                    )  # beware, this variable is also modified in another equation
                    Started = self.STARTED > 0
                    CropStarted = Started & self.ricemask_BOOL
                    SeasonOneHarvd = self.STARTED < 0
                    SeasonOneHarvd_Scalar = pcr.scalar(SeasonOneHarvd)
                    PrepareField_temp = pcr.scalar(self.Pausedays)
                    PrepareField = pcr.ifthenelse(FirstSeason,
                                                  PrepareField_temp, 0.0)
                    self.STARTED = (
                        (self.STARTED + CropStartNow_scalar +
                         pcr.scalar(CropStarted)) *
                        pcr.ifthenelse(CropHarvNow, pcr.scalar(0.0), 1.0) -
                        pcr.ifthenelse(HarvSeasonOne, PrepareField, 0.0) +
                        SeasonOneHarvd_Scalar)
                elif self.Sim3rdSeason == True:
                    HarvSeason12_temp = FirstSeason | SecondSeason
                    HarvSeasonOneTwo = HarvSeason12_temp & CropHarvNow
                    HarvSeasonThree = (ThirdSeason & CropHarvNow) | (
                        ThirdSeason & Calc_RainSum)
                    self.Season = (
                        self.Season + pcr.ifthenelse(HarvSeasonOneTwo,
                                                     pcr.scalar(1.0), 0.0) -
                        pcr.ifthenelse(HarvSeasonThree, pcr.scalar(3.0), 0.0)
                    )  # beware, this variable is also modified in another equation
                    Started = self.STARTED > 0
                    CropStarted = Started & self.ricemask_BOOL
                    Season12Harvd = self.STARTED < 0
                    Season12Harvd_Scalar = pcr.scalar(Season12Harvd)
                    PrepareField_temp = pcr.scalar(self.Pausedays)
                    FirstorSecondSeason = FirstSeason | SecondSeason
                    PrepareField = pcr.ifthenelse(FirstorSecondSeason,
                                                  PrepareField_temp, 0.0)
                    self.STARTED = (
                        (self.STARTED + CropStartNow_scalar +
                         pcr.scalar(CropStarted)) *
                        pcr.ifthenelse(CropHarvNow, pcr.scalar(0.0), 1.0) -
                        pcr.ifthenelse(HarvSeasonOneTwo, PrepareField, 0.0) +
                        Season12Harvd_Scalar)
                else:
                    print(self.Sim3rdSeason)
                    time.sleep(10)

            else:
                print(
                    "Strange value of variable AutoStartStop found... ctrl + c to exit..."
                )
                time.sleep(100)
        else:
            print(
                "Strange (negative?) value of variable CropStartDOY found... ctrl + c to exit..."
            )
            time.sleep(100)

        if self.WATERLIMITED == "True":
            TRANRF = self.Transpiration / NOTNUL_pcr(self.PotTrans)
            WAWP = WCWP * self.ROOTD_mm
            Enough_water = pcr.ifthenelse(
                CropStartNow, True, self.WA > WAWP)  # timestep delay...! todo
        else:
            print("Warning, run without water effects on crop growth...")
            TRANRF = pcr.scalar(1.0)
            Enough_water = True

        # self.T = (self.TMIN + self.TMAX)/2. # for testing with Wageningen weather files only - sdv
        # Calculate thermal time (for TSUM and DVS):
        Warm_Enough = self.T >= self.TBASE
        DegreeDay = self.T - self.TBASE
        DTEFF = pcr.ifthenelse(Warm_Enough, DegreeDay, 0.0)
        # Check if leaves are present:
        Leaves_Present = self.LAI > 0.0

        # Check whether certain critical moments, external circumstances or crop growth stages occur that influence crop growth and development:
        BeforeAnthesis = self.TSUM < self.TSUMAN
        UntilAnthesis = self.TSUM <= self.TSUMAN
        AtAndAfterAnthesis = self.TSUM >= self.TSUMAN
        AfterAnthesis = self.TSUM > self.TSUMAN
        Roots_Dying = self.DVS >= self.DVSDR

        Vegetative = CropStarted & UntilAnthesis
        Generative = CropStarted & AfterAnthesis
        EarlyStages = self.DVS < 0.2
        LaterStages = self.DVS >= 0.2
        SmallLeaves = self.LAI < 0.75
        BiggerLeaves = self.LAI >= 0.75
        Juvenile = EarlyStages & SmallLeaves
        Adult = LaterStages | BiggerLeaves

        # Calculate daylength (assumed similar throughout the catchment area -> scalar, no array), based on latitude and Day Of Year (DOY)
        DAYL = astro_py(DOY, self.LAT)

        # Calculate the specific leaf area (m2 (leaf) g−1 (leaf)) by interpolation of development stage in SLAF, multiplication with self.SLACF
        SLA = self.SLAC * self.SLACF.lookup_linear(self.DVS)
        # Obtain the fractions (-) of daily dry matter production allocated (in absence of water shortage) to, respectively, root growth (FRTWET), leaf growth (FLVT),
        # growth of stems (FSTT) and growth of storage organs (FSO, i.e. rice grains), as a function of development stage (DVS), by interpolation.
        FRTWET = self.FRTTB.lookup_linear(self.DVS)
        FLVT = self.FLVTB.lookup_linear(self.DVS)
        FSTT = self.FSTTB.lookup_linear(self.DVS)
        FSOT = self.FSOTB.lookup_linear(self.DVS)
        RDRTMP = self.RDRTB.lookup_linear(self.DVS)

        # Many growth processes can only occur when EMERG = TRUE; this is the case when crop phenological development has started, soil water content is above
        # permanent wilting point, the crop has leaves and is not yet harvested or growth has otherwise been terminated:
        EMERG = CropStarted & Enough_water & Leaves_Present & Not_Finished

        # Determine the influence of astronomical daylength on crop development (via thermal time - TSUM) by interpolation in the PHOTTB table
        PHOTT = self.PHOTTB.lookup_linear(DAYL)
        # Daylength only potentially has a  modifying influence on crop development (via thermal time, TSUM) before anthesis:
        PHOTPF = pcr.ifthenelse(BeforeAnthesis, PHOTT, pcr.scalar(1.0))
        # Influence (if any) of daylength results in a modified daily change in thermal time (TSUM).
        RTSUMP = DTEFF * PHOTPF
        # TSUM (state): at crop establishment TSUMI is added (the TSUM that was accumulated in the nursery in the case of transplanted rice);
        # during crop growth, the daily rate of change RTSUMP is added if EMERG = TRUE. Upon crop harvest, TSUM is reset (i.e. multiplied with 0.).
        self.TSUM = (self.TSUM + pcr.ifthenelse(CropStartNow,
                                                pcr.scalar(self.TSUMI), 0.0) +
                     pcr.ifthenelse(EMERG, RTSUMP, 0.0)) * pcr.ifthenelse(
                         CropHarvNow, pcr.scalar(0.0), 1.0)

        # Calculation of DVS (state).
        # In LINTUL1 and LINTUL2, TSUM directly steered all processes influenced by crop phenological development.
        # However, Shibu et al. (2010) derived some code from ORYZA_2000 (Bouman et al., 2001), including the use DVS instead of TSUM.
        # Hence in LINTUL3, some processes are still controlled directly by TSUM and some are controlled by its derived variable DVS
        # – a somewhat confusing situation that offers scope for future improvement.
        # After anthesis DVS proceeds at a different rate (DVS_gen) than before (DVS_veg). Throughout crop development DVS is calculated as the DVS_veg + DVS_gen.
        DVS_veg = (self.TSUM / self.TSUMAN *
                   pcr.ifthenelse(CropHarvNow, pcr.scalar(0.0), 1.0))
        DVS_gen = (1.0 +
                   (self.TSUM - self.TSUMAN) / self.TSUMMT) * pcr.ifthenelse(
                       CropHarvNow, pcr.scalar(0.0), 1.0)
        self.DVS = pcr.ifthenelse(Vegetative, DVS_veg, 0.0) + pcr.ifthenelse(
            Generative, DVS_gen, 0.0)

        # Root depth growth can occur as long as the maximum rooting depth has not yet been achieved:
        CanGrowDownward = self.ROOTD_mm <= self.ROOTDM_mm
        # Root growth occurs before anthesis if there is crop growth (EMERG = TRUE), enough water (already in EMERG - todo) and the maximum rooting depth has not yet been reached.
        RootGrowth = Enough_water & BeforeAnthesis & EMERG & CanGrowDownward
        # If root growth occurs, it occurs at a fixed pace (mm/day):
        RROOTD_mm = pcr.ifthenelse(RootGrowth, self.RRDMAX_mm, pcr.scalar(0.0))
        # Rooting depth (state): at crop establishment ROOTDI_mm is added (the rooting depth at transplanting); during crop growth, the daily rate of change
        # self.ROOTDI_mm is added. Upon crop harvest, rooting depth is reset (i.e. multiplied with 0.).
        self.ROOTD_mm = (
            self.ROOTD_mm +
            pcr.ifthenelse(CropStartNow, self.ROOTDI_mm, pcr.scalar(0.0)) +
            RROOTD_mm) * pcr.ifthenelse(CropHarvNow, pcr.scalar(0.0), 1.0)
        # By depth growth, roots explore deeper layers of soil that contain previously untapped water supplies, the assumption is.
        # In the case of irrigated rice, it seems reasonable to assume that those layers are saturated with water (WCST = volumetric soil water content at saturation).
        # The volume of additional water that becomes available to the crop is then equal to EXPLOR:
        EXPLOR = RROOTD_mm * WCST

        #############################################################################################################
        # Water Limitation: effects on partitioning
        # If TRANRF falls below 0.5, root growth is accelerated:
        FRTMOD = pcr.max(1.0, 1.0 / (TRANRF + 0.5))
        FRT = FRTWET * FRTMOD
        # ... and shoot growth (i.e. growth of all aboveground parts) diminshed:
        FSHMOD = (1.0 - FRT) / (1 - FRT / FRTMOD)
        FLV = FLVT * FSHMOD
        FST = FSTT * FSHMOD
        FSO = FSOT * FSHMOD

        # Daily intercepted Photosynthetically Active Radiation (PAR), according to (Lambert-)Beer's law.
        # The factor 0.5 accounts for the fact that about 50% (in terms of energy) of the frequency spectrum of incident solar radiation
        # can be utilized for photosynthesis by green plants.
        PARINT = pcr.ifthenelse(
            Not_Finished,
            0.5 * self.IRRAD * 0.001 * (1.0 - pcr.exp(-self.K * self.LAI)),
            0.0,
        )
        # The total growth rate is proportional to the intercepted PAR with a fixed Light Use Efficiency (LUE) - the core of the LINTUL apporach.
        GTOTAL = self.LUE * PARINT * TRANRF

        # Leaf dying due to ageing occurs from anthesis on (actually that is already arranged in the interpolation table - double!), with a relative death rate RDRTMP:
        RDRDV = pcr.ifthenelse(AtAndAfterAnthesis, RDRTMP, pcr.scalar(0.0))
        # Leaf dying due to mutual shading occurs when LAI > LAICR:
        RDRSH = pcr.max(0.0,
                        self.RDRSHM * (self.LAI - self.LAICR) / self.LAICR)
        # The largest of the two effects determines the relative death rate of foliage:
        RDR = pcr.max(RDRDV, RDRSH)

        # Impact of leaf dying on leaf weight - N limitation stuff not (yet) implemented
        N_Limitation = NNI < 1.0
        DLVNS = pcr.ifthenelse(
            CropStarted, pcr.scalar(1.0), 0.0) * pcr.ifthenelse(
                N_Limitation, self.WLVG * self.RDRNS * (1.0 - NNI), 0.0)
        DLVS = self.WLVG * RDR
        DLV = (DLVS + DLVNS) * pcr.scalar(Not_Finished)
        RWLVG = pcr.ifthenelse(EMERG, GTOTAL * FLV - DLV, pcr.scalar(0.0))
        self.WLVG = (self.WLVG + pcr.ifthenelse(CropStartNow, self.WLVGI,
                                                pcr.scalar(0.0)) +
                     RWLVG) * (1.0 - pcr.scalar(CropHarvNow))
        self.WLVD = (self.WLVD + DLV) * (1.0 - pcr.scalar(CropHarvNow))

        # Growth of leaves in terms of mass (GLV) and in terms of LAI (GLAI).
        GLV = FLV * GTOTAL
        Adt_or_Harv = pcr.pcror(Adult, CropHarvNow)
        Juv_or_Harv = pcr.pcror(Juvenile, CropHarvNow)
        NoLeavesYet = self.LAI == 0.0
        LetsGo = pcr.pcrand(Enough_water, CropStartNow)
        LetsGro = pcr.pcrand(NoLeavesYet, LetsGo)

        GLAI = (pcr.ifthenelse(Adt_or_Harv, SLA * GLV, pcr.scalar(0.0)) +
                pcr.ifthenelse(
                    Juv_or_Harv,
                    self.LAI * (pcr.exp(self.RGRL * DTEFF * DELT) - 1.0) /
                    DELT * TRANRF * pcr.exp(-self.LAI * (1.0 - NNI)),
                    0.0,
                ) + pcr.ifthenelse(LetsGro, self.LAII / DELT, pcr.scalar(0.0)))

        # (Abs.) impact of leaf dying on LAI
        # Daily decrease in LAI due to dying of leaves (if any), due to aging and/or mutual shading:
        DLAIS = self.LAI * RDR
        # Daily decrease in LAI due to nitrogen shortage (presently non-functional):
        DLAINS = pcr.ifthenelse(CropStarted,
                                pcr.scalar(1.0), 0.0) * pcr.ifthenelse(
                                    N_Limitation, DLVNS * SLA, 0.0)
        # Total daily decrease in LAI due to leaf death (aging, mutual shading, N shortage):
        DLAI = (DLAIS + DLAINS) * pcr.scalar(Not_Finished)
        # The initial LAI (LAII, transplanted rice) is added to GLAI at crop establishment, not in below state equation as done by Shibu et al. (2010).
        self.LAI = (self.LAI + GLAI - DLAI) * pcr.ifthenelse(
            CropHarvNow, pcr.scalar(0.0), 1.0)

        # Daily death rate of roots: if self.DVS >= self.DVSDR, a fraction self.DRRT of the roots is dying every day:
        DRRT = pcr.ifthenelse(Roots_Dying, self.WRT * self.RDRRT,
                              pcr.scalar(0.0))
        # Net daily change in root weight: if there is crop growth, this is equal to daily weight increase (GTOTAL * FRT) minus the daily decrease due to dying roots (if any).
        RWRT = pcr.ifthenelse(EMERG, GTOTAL * FRT - DRRT, pcr.scalar(0.0))
        # Calculation of the root weight (state): when the crop is planted, the initial root weight WRTLI is added. After that, the net (daily) rate of change RWRT is added.
        # Upon crop harvest, RWRT is reset (i.e. multiplied with 0.)
        self.WRT = (self.WRT +
                    pcr.ifthenelse(CropStartNow, self.WRTLI, pcr.scalar(0.0)) +
                    RWRT) * (1.0 - pcr.scalar(CropHarvNow))
        # WDRT (state) is the total quantity of leaves that has died (mostly relevant for mass balance checking purposes). Simply calculated by adding the daily dying roots (if any);
        # (the variable is reset upon crop harvest).
        self.WDRT = (self.WDRT + DRRT) * (1.0 - pcr.scalar(CropHarvNow))

        # Daily change in the weight of the storage organs (rice grains) is fraction FSO of the total growth rate (GTOTAL). FSO is determined by phenology and moisture stress
        # (which can modify the root/shoort ratio)
        RWSO = pcr.ifthenelse(EMERG, GTOTAL * FSO, pcr.scalar(0.0))
        # Weight of storage organs (state) is simply calculated by accumulating the daily growth RWSO. At crop harvest, it is reset to 0.
        self.WSO = (self.WSO +
                    pcr.ifthenelse(CropStartNow, self.WSOI, pcr.scalar(0.0)) +
                    RWSO) * (1.0 - pcr.scalar(CropHarvNow))
        # WSO in tons/ha:
        WSOTHA = self.WSO / 100.0

        # Daily change in the weight of the stems is a fraction FST of the total growth rate (GTOTAL). FST is determined by phenology and moisture stress
        RWST = pcr.ifthenelse(EMERG, GTOTAL * FST, pcr.scalar(0.0))
        # Weight of storage organs (state) is simply calculated by accumulating the daily growth RWSO. At crop harvest, it is reset to 0.
        self.WST = (self.WST +
                    pcr.ifthenelse(CropHarvNow, self.WSTI, pcr.scalar(0.0)) +
                    RWST) * (1.0 - pcr.scalar(CropHarvNow))

        # An additional state, handy for testing purposes:
        self.Test += 1.0
	def integralLogisticFunction(self,x):
		#-returns a tupple of two values holding the integral of the logistic functions
		# of (x) and (-x)
		logInt=pcr.ln(pcr.exp(-x)+1)
		return logInt,x+logInt