Exemple #1
0
    def adj_for_low_temp(self, param, Tk, lower_bound=0.0, upper_bound=10.0):
        """ 
        Function allowing Jmax/Vcmax to be forced linearly to zero at low T
        """
        Tc = Tk - const.DEG_TO_KELVIN

        if float_lt(Tc, lower_bound):
            param = 0.0
        elif float_lt(Tc, upper_bound):
            param *= (Tc - lower_bound) / (upper_bound - lower_bound)

        return param
Exemple #2
0
    def decay_in_dry_soils(self, decay_rate, decay_rate_dry):
        """Decay rates (e.g. leaf litterfall) can increase in dry soil, adjust
        decay param

        Parameters:
        -----------
        decay_rate : float
            default model parameter decay rate [tonnes C/ha/day]
        decay_rate_dry : float
            default model parameter dry deacy rate [tonnes C/ha/day]

        Returns:
        --------
        decay_rate : float
            adjusted deacy rate if the soil is dry [tonnes C/ha/day]

        """
        # turn into fraction...
        smc_root = self.state.pawater_root / self.params.wcapac_root
        
        new_decay_rate = (decay_rate_dry - (decay_rate_dry - decay_rate) * 
                         (smc_root - self.params.watdecaydry) /
                         (self.params.watdecaywet - self.params.watdecaydry))

        if float_lt(new_decay_rate, decay_rate):
            new_decay_rate = decay_rate

        if float_gt(new_decay_rate, decay_rate_dry):
            new_decay_rate = decay_rate_dry

        return new_decay_rate
Exemple #3
0
    def assim(self, ci, gamma_star, a1, a2):
        """Morning and afternoon calcultion of photosynthesis with the 
        limitation defined by the variables passed as a1 and a2, i.e. if we 
        are calculating vcmax or jmax limited.
        
        Parameters:
        ----------
        ci : float
            intercellular CO2 concentration.
        gamma_star : float
            CO2 compensation point in the abscence of mitochondrial respiration
        a1 : float
            variable depends on whether the calculation is light or rubisco 
            limited.
        a2 : float
            variable depends on whether the calculation is light or rubisco 
            limited.

        Returns:
        -------
        assimilation_rate : float
            assimilation rate assuming either light or rubisco limitation.
        """
        if float_lt(ci, gamma_star):
            return 0.0
        else:
            return a1 * (ci - gamma_star) / (a2 + ci)
Exemple #4
0
    def nc_limit(self, cpool, npool, ncmin, ncmax):
        """ Release N to 'Inorgn' pool or fix N from 'Inorgn', in order to keep
        the  N:C ratio of a litter pool within the range 'ncmin' to 'ncmax'.

        Parameters:
        -----------
        cpool : float
            various C pool (state)
        npool : float
            various N pool (state)
        ncmin : float
            maximum N:C ratio
        ncmax : float
            minimum N:C ratio

        Returns:
        --------
        fix/rel : float
            amount of N to be added/released from the inorganic pool

        """
        nmax = cpool * ncmax
        nmin = cpool * ncmin

        if float_gt(npool, nmax):  #release
            rel = npool - nmax
            self.fluxes.nlittrelease += rel
            return -rel
        elif float_lt(npool, nmin):  #fix
            fix = nmin - npool
            self.fluxes.nlittrelease -= fix
            return fix
        else:
            return 0.0
Exemple #5
0
    def adj_params_for_low_temp(self,
                                param,
                                Tk,
                                lower_bound=0.0,
                                upper_bound=10.0):
        """ 
        Function allowing Jmax/Vcmax to be forced linearly to zero at low T
        """
        Tc = Tk - const.DEG_TO_KELVIN

        if float_lt(Tc, lower_bound):
            param = 0.0
        elif float_lt(Tc, upper_bound):
            param *= (Tc - lower_bound) / (upper_bound - lower_bound)

        return param
Exemple #6
0
    def soil_temp_factor(self, project_day):
        """Soil-temperature activity factor (A9).

        Parameters:
        -----------
        project_day : int
            current simulation day (index)

        Returns:
        --------
        tfac : float
            soil temperature factor [degC]

        """
        tsoil = self.met_data["tsoil"][project_day]

        if float_gt(tsoil, 0.0):
            tfac = 0.0326 + 0.00351 * tsoil ** 1.652 - (tsoil / 41.748) ** 7.19
            if float_lt(tfac, 0.0):
                tfac = 0.0
        else:
            # negative number cannot be raised to a fractional power
            # number would need to be complex
            tfac = 0.0

        return tfac
def nc_ratio(carbon_val, nitrogen_val, pool):
    """Calculate nitrogen:carbon ratios

    Parameters:
    ----------
    carbon_val : float
        C value
    nitrogen_val: float
        N value#

    Returns:
    --------
    value : float
        N:C ratio
    """
    if float_lt(carbon_val, 0.0):
        # Note, previously the else branch was set to 1E6...presumably this 
        # was a hack to deal with the scenario for example where 
        # self.state.metabsurf and self.state.metabsurfn both start at zero.  
        # This was fine as this ratio isn't used in the code. Since I have 
        # commented out these diagnostics we shouldn't end up here unless there 
        # really is an error!!
        msg = "Dianostic for %s pool N:C has invalid values C:%s, N:%s" % \
                (pool, carbon_val, nitrogen_val)
        raise ValueError(msg)
    return nitrogen_val / carbon_val
Exemple #8
0
    def assim(self, ci, gamma_star, a1, a2):
        """Morning and afternoon calcultion of photosynthesis with the 
        limitation defined by the variables passed as a1 and a2, i.e. if we 
        are calculating vcmax or jmax limited.
        
        Parameters:
        ----------
        ci : float
            intercellular CO2 concentration.
        gamma_star : float
            CO2 compensation point in the abscence of mitochondrial respiration
        a1 : float
            variable depends on whether the calculation is light or rubisco 
            limited.
        a2 : float
            variable depends on whether the calculation is light or rubisco 
            limited.

        Returns:
        -------
        assimilation_rate : float
            assimilation rate assuming either light or rubisco limitation.
        """
        if float_lt(ci, gamma_star):
            return 0.0
        else:
            return a1 * (ci - gamma_star) / (a2 + ci) 
Exemple #9
0
    def soil_temp_factor(self, project_day):
        """Soil-temperature activity factor (A9). Fit to Parton's fig 2a 

        Parameters:
        -----------
        project_day : int
            current simulation day (index)

        Returns:
        --------
        tfac : float
            soil temperature factor [degC]

        """
        tsoil = self.met_data['tsoil'][project_day]

        if float_gt(tsoil, 0.0):
            self.fluxes.tfac_soil_decomp = (0.0326 + 0.00351 * tsoil**1.652 - 
                                            (tsoil / 41.748)**7.19)
            if float_lt(self.fluxes.tfac_soil_decomp, 0.0):
                self.fluxes.tfac_soil_decomp = 0.0
        else:
            # negative number cannot be raised to a fractional power
            # number would need to be complex
            self.fluxes.tfac_soil_decomp = 0.0

        return self.fluxes.tfac_soil_decomp
Exemple #10
0
    def soil_temp_factor(self, project_day):
        """Soil-temperature activity factor (A9). Fit to Parton's fig 2a 

        Parameters:
        -----------
        project_day : int
            current simulation day (index)

        Returns:
        --------
        tfac : float
            soil temperature factor [degC]

        """
        tsoil = self.met_data['tsoil'][project_day]

        if float_gt(tsoil, 0.0):
            self.fluxes.tfac_soil_decomp = (0.0326 + 0.00351 * tsoil**1.652 -
                                            (tsoil / 41.748)**7.19)
            if float_lt(self.fluxes.tfac_soil_decomp, 0.0):
                self.fluxes.tfac_soil_decomp = 0.0
        else:
            # negative number cannot be raised to a fractional power
            # number would need to be complex
            self.fluxes.tfac_soil_decomp = 0.0

        return self.fluxes.tfac_soil_decomp
Exemple #11
0
    def nc_limit(self, cpool, npool, ncmin, ncmax):
        """ Release N to 'Inorgn' pool or fix N from 'Inorgn', in order to keep
        the  N:C ratio of a litter pool within the range 'ncmin' to 'ncmax'.

        Parameters:
        -----------
        cpool : float
            various C pool (state)
        npool : float
            various N pool (state)
        ncmin : float
            maximum N:C ratio
        ncmax : float
            minimum N:C ratio

        Returns:
        --------
        fix/rel : float
            amount of N to be added/released from the inorganic pool

        """
        nmax = cpool * ncmax
        nmin = cpool * ncmin
    
        if float_gt(npool, nmax):  #release
            rel = npool - nmax
            self.fluxes.nlittrelease += rel 
            return -rel
        elif float_lt(npool, nmin):   #fix
            fix = nmin - npool
            self.fluxes.nlittrelease -= fix
            return fix
        else:
            return 0.0 
def main():

    # sweep the cmd line
    options, args = cmdline_parser()

    from file_parser import initialise_model_data
    # pylint: disable=C0103
    # pylint: disable=C0324
    # pylint: disable=C0103

    fname = "gday"
    fdir = "/Users/mdekauwe/src/python/GDAY_model/params"
    (adj_control, adj_params,
        adj_state, adj_files,
        adj_fluxes, met_data) = initialise_model_data(fname, default_dir=fdir)

    # figure out photosynthesis
    P = PlantProdModel(adj_control, adj_params, adj_state, adj_fluxes, met_data)

    adj_state.lai = (adj_params.slainit * const.M2_AS_HA /
                            const.KG_AS_TONNES / adj_params.cfracts *
                            adj_state.shoot)

    # Specific LAI (m2 onesided/kg DW)
    adj_state.sla = adj_params.slainit



    adj_control.assim_model = 3

    num_days = len(met_data['doy'])
    for i in xrange(num_days):

        if float_lt(adj_state.lai, adj_params.lai_cover):
            gcover = adj_state.lai / adj_params.lai_cover
        else:
            gcover = 1.0

        adj_state.fapar = ((1.0 - exp(-adj_params.kext * adj_state.lai /
                    gcover)) * gcover)

        adj_state.shootnc = adj_state.shootn / adj_state.shoot

        P.run_sim(i)


        print adj_fluxes.gpp / const.HA_AS_M2 * const.TONNES_AS_G

        #print adj_state.lai


        # this is done in derive so do here
        # Specific LAI (m2 onesided/kg DW)
        adj_state.sla = (adj_state.lai / const.M2_AS_HA *
                            const.KG_AS_TONNES *
                            adj_params.cfracts / adj_state.shoot)


    return
Exemple #13
0
    def carbon_production(self, project_day, daylen):
        """ Calculate GPP, NPP and plant respiration

        Parameters:
        -----------
        project_day : integer
            simulation day
        daylen : float
            daytime length (hrs)

        References:
        -----------
        * Jackson, J. E. and Palmer, J. W. (1981) Annals of Botany, 47, 561-565.
        """

        if self.state.lai > 0.0:
            # average leaf nitrogen content (g N m-2 leaf)
            leafn = (self.state.shootnc * self.params.cfracts /
                     self.state.sla * const.KG_AS_G)
            
            # total nitrogen content of the canopy
            self.state.ncontent = leafn * self.state.lai
        else:
            self.state.ncontent = 0.0
         
        # fractional ground cover.
        if float_lt(self.state.lai, self.params.lai_cover):
            frac_gcover = self.state.lai / self.params.lai_cover
        else:
            frac_gcover = 1.0

        # Radiance intercepted by the canopy, accounting for partial closure
        # Jackson and Palmer (1981), derived from beer's law
        if self.state.lai > 0.0:
            self.state.light_interception = ((1.0 - exp(-self.params.kext *
                                             self.state.lai / frac_gcover)) *
                                             frac_gcover)
        else:
            self.state.light_interception = 0.0
        
        if self.control.water_stress:
            # Calculate the soil moisture availability factors [0,1] in the 
            # topsoil and the entire root zone
            (self.state.wtfac_tsoil, 
             self.state.wtfac_root) = self.sm.calculate_soil_water_fac()
        else:
            # really this should only be a debugging option!
            self.state.wtfac_tsoil = 1.0
            self.state.wtfac_root = 1.0
            
        # Estimate photosynthesis 
        if self.control.assim_model == "BEWDY":
            self.bw.calculate_photosynthesis(frac_gcover, project_day, daylen)
        elif self.control.assim_model == "MATE":
            self.mt.calculate_photosynthesis(project_day, daylen)
        else:
            raise AttributeError('Unknown assimilation model')
Exemple #14
0
def clip(value, min=None, max=None):
    """ clip value btw defined range """
    if float_lt(value, min):
        value = min
    elif float_gt(value, max):
        value = max
    return value
    

 
    
    
Exemple #15
0
def day_length(date, latitude):
    """ Figure out number of sunlight hours, (hours day-1)
    
    Routine from sdgvm. date is a python object, see datetime library for 
    more info 
    
    Parameters:
    -----------
    date : date format string
        date object, yr/month/day
    latitude : float    
        latitude [degrees]
        
    Returns:
    --------
    dayl : float 
        daylength [hrs]
    
    """
    conv = math.pi / 180.0
    
    # day of year 1-365/366
    doy = int(date.strftime('%j'))
    
    # Total number of days in year
    if calendar.isleap(date.year):
        yr_days = 366.
    else:
        yr_days = 365.
    
    solar_declin = -23.4 * math.cos(conv * yr_days * (doy + 10.0) / yr_days)
    temx = -math.tan(latitude * conv) * math.tan(solar_declin * conv) 
    
    if float_lt(math.fabs(temx), 1.0):
        has = math.acos(temx) / conv
        dayl = 2.0 * has / 15.0
    elif float_gt(temx, 0.0):
        dayl = 0.0
    else:
        dayl = 24.0
    
    return dayl
Exemple #16
0
    def grazer_inputs(self):
        """ Grazer inputs from faeces and urine, flux detd by faeces c:n """
        if self.control.grazing:
            self.params.faecesn = self.fluxes.faecesc / self.params.faecescn
        else:
            self.params.faecesn = 0.0

        # make sure faecesn <= total n input to soil from grazing
        arg = self.fluxes.neaten * self.params.fractosoil
        if float_gt(self.params.faecesn, arg):
            self.params.faecesn = self.fluxes.neaten * self.params.fractosoil

        # urine=total-faeces
        if self.control.grazing:
            self.fluxes.nurine = self.fluxes.neaten * self.params.fractosoil - self.params.faecesn
        else:
            self.fluxes.nurine = 0.0

        if float_lt(self.fluxes.nurine, 0.0):
            self.fluxes.nurine = 0.0
Exemple #17
0
    def grazer_inputs(self):
        """ Grazer inputs from faeces and urine, flux detd by faeces c:n """
        if self.control.grazing:
            self.params.faecesn = self.fluxes.faecesc / self.params.faecescn
        else:
            self.params.faecesn = 0.0

        # make sure faecesn <= total n input to soil from grazing
        arg = self.fluxes.neaten * self.params.fractosoil
        if float_gt(self.params.faecesn, arg):
            self.params.faecesn = self.fluxes.neaten * self.params.fractosoil

        # urine=total-faeces
        if self.control.grazing:
            self.fluxes.nurine = (self.fluxes.neaten * self.params.fractosoil -
                                  self.params.faecesn)
        else:
            self.fluxes.nurine = 0.0

        if float_lt(self.fluxes.nurine, 0.0):
            self.fluxes.nurine = 0.0
Exemple #18
0
def calc_npp(M, control, params, state, fluxes, met_data):
    
    state.lai = (params.slainit * const.M2_AS_HA /
                            const.KG_AS_TONNES / params.cfracts *
                            state.shoot)
    
    # Specific LAI (m2 onesided/kg DW)
    state.sla = params.slainit
    
    
    year = str(control.startyear)
    month = str(control.startmonth)
    day = str(control.startday)
    datex = datetime.datetime.strptime((year + month + day), "%Y%m%d")
        
    npp = np.zeros(0)
    for project_day in xrange(365):
    
        state.shootnc = state.shootn / state.shoot
        state.ncontent = (state.shootnc * params.cfracts /
                                state.sla * const.KG_AS_G)
        daylen = day_length(datex, params.latitude)
        state.wtfac_root = 1.0
        #state.lai = laidata[project_day]
    
    
        if float_lt(state.lai, params.lai_cover):
            frac_gcover = state.lai / params.lai_cover
        else:
            frac_gcover = 1.0
    
        state.light_interception = ((1.0 - math.exp(-params.kext *
                                            state.lai / frac_gcover)) *
                                            frac_gcover)

        M.calculate_photosynthesis(project_day, daylen)
        
        npp = np.append(npp, fluxes.npp_gCm2)
        datex += datetime.timedelta(days=1)
    return npp.sum()
Exemple #19
0
def mate_day_length(date, latitude):
    """ Calculate number of sunlight hours (units = h d-1)
    
    Routine comes from MATE, though not sure how right this is, are the 
    hemispheres inverted? Check
    
    Parameters:
    -----------
    date : date format string
        date object, yr/month/day
    latitude : float    
        latitude [degrees]
        
    Returns:
    --------
    dayl : float 
        daylength [hrs]
    
    """
    conv = math.pi / 180.0
    
    # day of year 1-365/366
    doy = int(date.strftime('%j'))
    
    # Total number of days in year
    if calendar.isleap(date.year):
        yr_days = 366.
    else:
        yr_days = 365.
    
    solar_dec = (23.4 * math.pi / 180.0 * math.cos(2.0 * math.pi / 
                    yr_days * (doy + 10.0)))
    
    if float_lt(latitude, 0.0):
        solar_dec *= -1.0
	 
    dayl = (math.acos(-math.tan(latitude * conv) * math.tan(solar_dec)) * 
	            24.0 / math.pi)

    return dayl
Exemple #20
0
    def decay_in_dry_soils(self, decay_rate, decay_rate_dry):
        """Decay rates (e.g. leaf litterfall) can increase in dry soil, adjust
        decay param. This is based on field measurements by F. J. Hingston 
        (unpublished) cited in Corbeels.

        Parameters:
        -----------
        decay_rate : float
            default model parameter decay rate [tonnes C/ha/day]
        decay_rate_dry : float
            default model parameter dry deacy rate [tonnes C/ha/day]

        Returns:
        --------
        decay_rate : float
            adjusted deacy rate if the soil is dry [tonnes C/ha/day]
        
        Reference:
        ----------
        Corbeels et al. (2005) Ecological Modelling, 187, 449-474.
        
        """
        # turn into fraction...
        smc_root = self.state.pawater_root / self.params.wcapac_root

        new_decay_rate = (decay_rate_dry - (decay_rate_dry - decay_rate) *
                          (smc_root - self.params.watdecaydry) /
                          (self.params.watdecaywet - self.params.watdecaydry))

        if float_lt(new_decay_rate, decay_rate):
            new_decay_rate = decay_rate

        if float_gt(new_decay_rate, decay_rate_dry):
            new_decay_rate = decay_rate_dry

        return new_decay_rate
Exemple #21
0
    def decay_in_dry_soils(self, decay_rate, decay_rate_dry):
        """Decay rates (e.g. leaf litterfall) can increase in dry soil, adjust
        decay param. This is based on field measurements by F. J. Hingston 
        (unpublished) cited in Corbeels.

        Parameters:
        -----------
        decay_rate : float
            default model parameter decay rate [tonnes C/ha/day]
        decay_rate_dry : float
            default model parameter dry deacy rate [tonnes C/ha/day]

        Returns:
        --------
        decay_rate : float
            adjusted deacy rate if the soil is dry [tonnes C/ha/day]
        
        Reference:
        ----------
        Corbeels et al. (2005) Ecological Modelling, 187, 449-474.
        
        """
        # turn into fraction...
        smc_root = self.state.pawater_root / self.params.wcapac_root

        new_decay_rate = decay_rate_dry - (decay_rate_dry - decay_rate) * (smc_root - self.params.watdecaydry) / (
            self.params.watdecaywet - self.params.watdecaydry
        )

        if float_lt(new_decay_rate, decay_rate):
            new_decay_rate = decay_rate

        if float_gt(new_decay_rate, decay_rate_dry):
            new_decay_rate = decay_rate_dry

        return new_decay_rate
    def update_plant_state(self, fdecay, rdecay):
        """ Daily change in C content

        Parameters:
        -----------
        fdecay : float
            foliage decay rate
        rdecay : float
            fine root decay rate

        """
        self.state.shoot += (self.fluxes.cpleaf - self.fluxes.deadleaves -
                                self.fluxes.ceaten)
        self.state.root += self.fluxes.cproot - self.fluxes.deadroots
        self.state.branch += self.fluxes.cpbranch - self.fluxes.deadbranch
        self.state.stem += self.fluxes.cpstem - self.fluxes.deadstems
        self.state.shootn += (self.fluxes.npleaf - fdecay * self.state.shootn -
                                self.fluxes.neaten)
        self.state.rootn += self.fluxes.nproot - rdecay * self.state.rootn
        self.state.branchn += (self.fluxes.npbranch - self.params.bdecay *
                                self.state.branchn)
        self.state.stemnimm += (self.fluxes.npstemimm - self.params.wdecay *
                                self.state.stemnimm)
        self.state.stemnmob += (self.fluxes.npstemmob - self.params.wdecay *
                                self.state.stemnmob -
                                self.params.retransmob * self.state.stemnmob)
        self.state.stemn = self.state.stemnimm + self.state.stemnmob

        # maximum leaf n:c ratio is function of stand age
        #  - switch off age effect by setting ncmaxfyoung = ncmaxfold
        age_effect = ((self.state.age - self.params.ageyoung) / 
                        (self.params.ageold - self.params.ageyoung))
        
        ncmaxf = (self.params.ncmaxfyoung - (self.params.ncmaxfyoung -
                    self.params.ncmaxfold) * age_effect)
               
        if float_lt(ncmaxf, self.params.ncmaxfold):
            ncmaxf = self.params.ncmaxfold

        if float_gt(ncmaxf, self.params.ncmaxfyoung):
            ncmaxf = self.params.ncmaxfyoung

        # if foliage or root n:c ratio exceeds its max, then nitrogen uptake is
        # cut back n.b. new ring n/c max is already set because it is related
        # to leaf n:c
        extrar = 0.
        extras = 0.
        if float_gt(self.state.shootn, (self.state.shoot * ncmaxf)):
            extras = self.state.shootn - self.state.shoot * ncmaxf

            #n uptake cannot be reduced below zero.
            if float_gt(extras, self.fluxes.nuptake):
                extras = self.fluxes.nuptake

            self.state.shootn -= extras
            self.fluxes.nuptake -= extras

        ncmaxr = ncmaxf * self.params.ncrfac  # max root n:c

        if float_gt(self.state.rootn, (self.state.root * ncmaxr)):
            extrar = self.state.rootn - self.state.root * ncmaxr

            #n uptake cannot be reduced below zero.
            if float_gt((extras + extrar), self.fluxes.nuptake):
                extrar = self.fluxes.nuptake - extras

            self.state.rootn -= extrar
            self.fluxes.nuptake -= extrar 
Exemple #23
0
    
    for i, yr in enumerate(years):
        daylen = calculate_daylength(days_in_year[i], params.latitude)
        for doy in xrange(days_in_year[i]):
            state.wtfac_root = 1.0
            #state.lai = lai_data[project_day]
            state.lai = 2.0
            if state.lai > 0.0:
                state.shootnc = 0.03 #state.shootn / state.shoot
                state.ncontent = (state.shootnc * params.cfracts /
                                        state.sla * const.KG_AS_G)
            else:
                state.ncontent = 0.0        
        
        
            if float_lt(state.lai, params.lai_cover):
                frac_gcover = state.lai / params.lai_cover
            else:
                frac_gcover = 1.0

            state.fipar = ((1.0 - exp(-params.kext *
                                      state.lai / frac_gcover)) *
                                                frac_gcover)
            
            
            M.calculate_photosynthesis(project_day, daylen[doy])

            print fluxes.gpp_gCm2#, state.lai
        
            project_day += 1
Exemple #24
0
    def update_plant_state(self, fdecay, rdecay, project_day):
        """ Daily change in C content

        Parameters:
        -----------
        fdecay : float
            foliage decay rate
        rdecay : float
            fine root decay rate

        """
        self.state.shoot += (self.fluxes.cpleaf - self.fluxes.deadleaves -
                                self.fluxes.ceaten)
        self.state.root += self.fluxes.cproot - self.fluxes.deadroots
        self.state.branch += self.fluxes.cpbranch - self.fluxes.deadbranch
        self.state.stem += self.fluxes.cpstem - self.fluxes.deadstems
        
        if self.control.deciduous_model:
            self.state.shootn += (self.fluxes.npleaf - 
                                 (self.fluxes.deadleafn - self.fluxes.neaten))
        else:
            self.state.shootn += (self.fluxes.npleaf - 
                                  fdecay * self.state.shootn - 
                                  self.fluxes.neaten)
        self.state.shootn = max(0.0, self.state.shootn)
        
        self.state.rootn += self.fluxes.nproot - rdecay * self.state.rootn
        self.state.branchn += (self.fluxes.npbranch - self.params.bdecay *
                                self.state.branchn)
        self.state.stemnimm += (self.fluxes.npstemimm - self.params.wdecay *
                                self.state.stemnimm)
        self.state.stemnmob += (self.fluxes.npstemmob - self.params.wdecay *
                                self.state.stemnmob -
                                self.params.retransmob * self.state.stemnmob)
        self.state.stemn = self.state.stemnimm + self.state.stemnmob
        
        self.state.exu_pool += self.fluxes.cprootexudate
        self.fluxes.microbial_resp = self.calc_microbial_resp(project_day)
        self.state.exu_pool -= self.fluxes.microbial_resp
        #print self.fluxes.microbial_resp, self.fluxes.cprootexudate
        
        self.calculate_cn_store()
        
        if not self.control.deciduous_model:
            
            # maximum leaf n:c ratio is function of stand age
            #  - switch off age effect by setting ncmaxfyoung = ncmaxfold
            age_effect = ((self.state.age - self.params.ageyoung) / 
                            (self.params.ageold - self.params.ageyoung))
            
            ncmaxf = (self.params.ncmaxfyoung - (self.params.ncmaxfyoung -
                        self.params.ncmaxfold) * age_effect)
                   
            if float_lt(ncmaxf, self.params.ncmaxfold):
                ncmaxf = self.params.ncmaxfold
    
            if float_gt(ncmaxf, self.params.ncmaxfyoung):
                ncmaxf = self.params.ncmaxfyoung
    
            # if foliage or root n:c ratio exceeds its max, then nitrogen 
            # uptake is cut back n.b. new ring n/c max is already set because 
            # it is related to leaf n:c
            extrar = 0.
            extras = 0.
            if float_gt(self.state.shootn, (self.state.shoot * ncmaxf)):
                extras = self.state.shootn - self.state.shoot * ncmaxf
    
                #n uptake cannot be reduced below zero.
                if float_gt(extras, self.fluxes.nuptake):
                    extras = self.fluxes.nuptake
    
                self.state.shootn -= extras
                self.fluxes.nuptake -= extras
    
            ncmaxr = ncmaxf * self.params.ncrfac  # max root n:c
    
            if float_gt(self.state.rootn, (self.state.root * ncmaxr)):
                extrar = self.state.rootn - self.state.root * ncmaxr
    
                #n uptake cannot be reduced below zero.
                if float_gt((extras + extrar), self.fluxes.nuptake):
                    extrar = self.fluxes.nuptake - extras
    
                self.state.rootn -= extrar
                self.fluxes.nuptake -= extrar 
    def update_plant_state(self, fdecay, rdecay):
        """ Daily change in C content

        Parameters:
        -----------
        fdecay : float
            foliage decay rate
        rdecay : float
            fine root decay rate

        """
        self.state.shoot += (self.fluxes.cpleaf - self.fluxes.deadleaves -
                                self.fluxes.ceaten)
        self.state.root += self.fluxes.cproot - self.fluxes.deadroots
        self.state.branch += self.fluxes.cpbranch - self.fluxes.deadbranch
        self.state.stem += self.fluxes.cpstem - self.fluxes.deadstems
        
        if self.control.deciduous_model:
            self.state.shootn += (self.fluxes.npleaf - 
                                 (self.fluxes.deadleafn - self.fluxes.neaten))
        else:
            self.state.shootn += (self.fluxes.npleaf - 
                                  fdecay * self.state.shootn - 
                                  self.fluxes.neaten)
        self.state.shootn = max(0.0, self.state.shootn)
        
        self.state.rootn += self.fluxes.nproot - rdecay * self.state.rootn
        self.state.branchn += (self.fluxes.npbranch - self.params.bdecay *
                                self.state.branchn)
        self.state.stemnimm += (self.fluxes.npstemimm - self.params.wdecay *
                                self.state.stemnimm)
        self.state.stemnmob += (self.fluxes.npstemmob - self.params.wdecay *
                                self.state.stemnmob -
                                self.params.retransmob * self.state.stemnmob)
        self.state.stemn = self.state.stemnimm + self.state.stemnmob
        
        
        
        
        # maximum leaf n:c ratio is function of stand age
        #  - switch off age effect by setting ncmaxfyoung = ncmaxfold
        age_effect = ((self.state.age - self.params.ageyoung) / 
                        (self.params.ageold - self.params.ageyoung))
        
        ncmaxf = (self.params.ncmaxfyoung - (self.params.ncmaxfyoung -
                    self.params.ncmaxfold) * age_effect)
               
        if float_lt(ncmaxf, self.params.ncmaxfold):
            ncmaxf = self.params.ncmaxfold

        if float_gt(ncmaxf, self.params.ncmaxfyoung):
            ncmaxf = self.params.ncmaxfyoung

        # if foliage or root n:c ratio exceeds its max, then nitrogen uptake is
        # cut back n.b. new ring n/c max is already set because it is related
        # to leaf n:c
        extrar = 0.
        extras = 0.
        if float_gt(self.state.shootn, (self.state.shoot * ncmaxf)):
            extras = self.state.shootn - self.state.shoot * ncmaxf

            #n uptake cannot be reduced below zero.
            if float_gt(extras, self.fluxes.nuptake):
                extras = self.fluxes.nuptake

            self.state.shootn -= extras
            self.fluxes.nuptake -= extras

        ncmaxr = ncmaxf * self.params.ncrfac  # max root n:c

        if float_gt(self.state.rootn, (self.state.root * ncmaxr)):
            extrar = self.state.rootn - self.state.root * ncmaxr

            #n uptake cannot be reduced below zero.
            if float_gt((extras + extrar), self.fluxes.nuptake):
                extrar = self.fluxes.nuptake - extras

            self.state.rootn -= extrar
            self.fluxes.nuptake -= extrar 
        
        if self.control.deciduous_model:
            # update annual fluxes - store for next year
            self.state.clabile_store += self.fluxes.npp
            self.state.aroot_uptake += self.fluxes.nuptake
            
            self.state.aretrans += self.fluxes.retrans
            self.state.anloss += self.fluxes.nloss
            
            # update N:C of plant pools
            if float_eq(self.state.shoot, 0.0):
                self.state.shootnc = 0.0
            else:
                self.state.shootnc = max(self.state.shootn / self.state.shoot, 
                                         self.params.ncfmin)
                
            # N:C of stuctural wood as function of N:C of foliage 
            # (kgN kg-1C)(Medlyn et al 2000)  
            self.state.nc_ws = (self.params.nc_wsa + self.params.nc_wsb * 
                                self.state.shootnc)    
           
            # N:C of new wood as function of N:C of foliage
            self.state.nc_wnew = (self.params.nc_wnewa + self.params.nc_wnewb * 
                                  self.state.shootnc)  
Exemple #26
0
    def update_plant_state(self, fdecay, rdecay, project_day, doy):
        """ Daily change in C content

        Parameters:
        -----------
        fdecay : float
            foliage decay rate
        rdecay : float
            fine root decay rate

        """
        #
        # Carbon pools
        #
        self.state.shoot += (self.fluxes.cpleaf - self.fluxes.deadleaves -
                             self.fluxes.ceaten)
        self.state.root += self.fluxes.cproot - self.fluxes.deadroots
        self.state.branch += self.fluxes.cpbranch - self.fluxes.deadbranch
        self.state.stem += self.fluxes.cpstem - self.fluxes.deadstems

        # annoying but can't see an easier way with the code as it is.
        # If we are modelling grases, i.e. no stem them without this
        # the sapwood will end up being reduced to a silly number as
        # deadsapwood will keep being removed from the pool, even though there
        # is no wood.
        if self.state.stem <= 0.01:
            self.state.sapwood = 0.01
        else:
            self.state.sapwood += self.fluxes.cpstem - self.fluxes.deadsapwood

        #
        # Nitrogen pools
        #
        if self.control.deciduous_model:
            self.state.shootn += (
                self.fluxes.npleaf -
                (self.fluxes.lnrate * self.state.remaining_days[doy]) -
                self.fluxes.neaten)
        else:
            self.state.shootn += (self.fluxes.npleaf -
                                  fdecay * self.state.shootn -
                                  self.fluxes.neaten)

        self.state.branchn += (self.fluxes.npbranch -
                               self.params.bdecay * self.state.branchn)
        self.state.rootn += self.fluxes.nproot - rdecay * self.state.rootn

        self.state.stemnimm += (self.fluxes.npstemimm -
                                self.params.wdecay * self.state.stemnimm)
        self.state.stemnmob += (self.fluxes.npstemmob -
                                self.params.wdecay * self.state.stemnmob -
                                self.params.retransmob * self.state.stemnmob)

        #print self.state.stemnmob, self.fluxes.npstemmob - self.params.wdecay * self.state.stemnmob, self.fluxes.npstemmob, self.params.wdecay * self.state.stemnmob

        self.state.stemn = self.state.stemnimm + self.state.stemnmob

        if self.control.deciduous_model:
            self.calculate_cn_store()

        #============================
        # Enforce maximum N:C ratios.
        # ===========================
        # This doesn't make sense for the deciduous model because of the ramp
        # function. The way the deciduous logic works we now before we start
        # how much N we have to allocate so it is impossible to allocate in
        # excess. Therefore this is only relevant for evergreen model.
        if not self.control.deciduous_model:

            # If foliage or root N/C exceeds its max, then N uptake is cut back

            # maximum leaf n:c ratio is function of stand age
            #  - switch off age effect by setting ncmaxfyoung = ncmaxfold
            age_effect = ((self.state.age - self.params.ageyoung) /
                          (self.params.ageold - self.params.ageyoung))

            ncmaxf = (
                self.params.ncmaxfyoung -
                (self.params.ncmaxfyoung - self.params.ncmaxfold) * age_effect)

            if float_lt(ncmaxf, self.params.ncmaxfold):
                ncmaxf = self.params.ncmaxfold

            if float_gt(ncmaxf, self.params.ncmaxfyoung):
                ncmaxf = self.params.ncmaxfyoung

            extras = 0.0
            if self.state.lai > 0.0:

                if float_gt(self.state.shootn, (self.state.shoot * ncmaxf)):
                    extras = self.state.shootn - self.state.shoot * ncmaxf

                    # Ensure N uptake cannot be reduced below zero.
                    if float_gt(extras, self.fluxes.nuptake):
                        extras = self.fluxes.nuptake

                    self.state.shootn -= extras
                    self.fluxes.nuptake -= extras

            # if root N:C ratio exceeds its max, then nitrogen uptake is cut
            # back. n.b. new ring n/c max is already set because it is related
            # to leaf n:c
            ncmaxr = ncmaxf * self.params.ncrfac  # max root n:c
            extrar = 0.0
            if float_gt(self.state.rootn, (self.state.root * ncmaxr)):

                extrar = self.state.rootn - self.state.root * ncmaxr

                # Ensure N uptake cannot be reduced below zero.
                if float_gt((extras + extrar), self.fluxes.nuptake):
                    extrar = self.fluxes.nuptake - extras

                self.state.rootn -= extrar
                self.fluxes.nuptake -= extrar
Exemple #27
0
    # days in each year
    years = uniq(met_data["year"])
    # years = years[:-1] # dump last year as missing "site" LAI

    days_in_year = [met_data["year"].count(yr) for yr in years]

    for i, yr in enumerate(years):
        daylen = calculate_daylength(days_in_year[i], params.latitude)
        for doy in xrange(days_in_year[i]):
            state.wtfac_root = 1.0
            # state.lai = lai_data[project_day]
            state.lai = 2.0
            if state.lai > 0.0:
                state.shootnc = 0.03  # state.shootn / state.shoot
                state.ncontent = state.shootnc * params.cfracts / params.sla * const.KG_AS_G
            else:
                state.ncontent = 0.0

            if float_lt(state.lai, params.lai_cover):
                frac_gcover = state.lai / params.lai_cover
            else:
                frac_gcover = 1.0

            state.fipar = (1.0 - exp(-params.kext * state.lai / frac_gcover)) * frac_gcover

            M.calculate_photosynthesis(project_day, daylen[doy])

            print fluxes.gpp_gCm2  # , state.lai

            project_day += 1
Exemple #28
0
    def update_plant_state(self, fdecay, rdecay, project_day, doy):
        """ Daily change in C content

        Parameters:
        -----------
        fdecay : float
            foliage decay rate
        rdecay : float
            fine root decay rate

        """
        # 
        # Carbon pools
        #
        self.state.shoot += (self.fluxes.cpleaf - self.fluxes.deadleaves -
                             self.fluxes.ceaten)
        self.state.root += self.fluxes.cproot - self.fluxes.deadroots
        self.state.croot += self.fluxes.cpcroot - self.fluxes.deadcroots
        self.state.branch += self.fluxes.cpbranch - self.fluxes.deadbranch
        self.state.stem += self.fluxes.cpstem - self.fluxes.deadstems
        
        # annoying but can't see an easier way with the code as it is.
        # If we are modelling grases, i.e. no stem them without this
        # the sapwood will end up being reduced to a silly number as 
        # deadsapwood will keep being removed from the pool, even though there
        # is no wood. 
        if self.state.stem <= 0.01:
            self.state.sapwood = 0.01
        else:
            self.state.sapwood += self.fluxes.cpstem - self.fluxes.deadsapwood
        
        # 
        # Nitrogen pools
        #
        if self.control.deciduous_model:       
            self.state.shootn += (self.fluxes.npleaf - 
                                 (self.fluxes.lnrate * 
                                  self.state.remaining_days[doy]) - 
                                  self.fluxes.neaten)                        
        else:
            self.state.shootn += (self.fluxes.npleaf - 
                                  fdecay * self.state.shootn - 
                                  self.fluxes.neaten)
                                
        self.state.branchn += (self.fluxes.npbranch - self.params.bdecay *
                               self.state.branchn)
        self.state.rootn += self.fluxes.nproot - rdecay * self.state.rootn
        self.state.crootn += self.fluxes.npcroot - self.params.crdecay * self.state.crootn
        
        self.state.stemnimm += (self.fluxes.npstemimm - self.params.wdecay *
                                self.state.stemnimm)
        self.state.stemnmob += (self.fluxes.npstemmob - self.params.wdecay *
                                self.state.stemnmob -
                                self.params.retransmob * self.state.stemnmob)        
        self.state.stemn = self.state.stemnimm + self.state.stemnmob

        if self.control.deciduous_model:
            self.calculate_cn_store()
        
        #============================
        # Enforce maximum N:C ratios.
        # ===========================    
        # This doesn't make sense for the deciduous model because of the ramp
        # function. The way the deciduous logic works we now before we start
        # how much N we have to allocate so it is impossible (well) to allocate in 
        # excess. Therefore this is only relevant for evergreen model.
        if not self.control.deciduous_model:
            
            # If foliage or root N/C exceeds its max, then N uptake is cut back
            
            # maximum leaf n:c ratio is function of stand age
            #  - switch off age effect by setting ncmaxfyoung = ncmaxfold
            age_effect = ((self.state.age - self.params.ageyoung) / 
                          (self.params.ageold - self.params.ageyoung))

            ncmaxf = (self.params.ncmaxfyoung - 
                     (self.params.ncmaxfyoung - self.params.ncmaxfold) * 
                      age_effect)
            
            if float_lt(ncmaxf, self.params.ncmaxfold):
                ncmaxf = self.params.ncmaxfold

            if float_gt(ncmaxf, self.params.ncmaxfyoung):
                ncmaxf = self.params.ncmaxfyoung
            
            extras = 0.0
            if self.state.lai > 0.0:

                if float_gt(self.state.shootn, (self.state.shoot * ncmaxf)):
                    extras = self.state.shootn - self.state.shoot * ncmaxf
                    
                    # Ensure N uptake cannot be reduced below zero.
                    if float_gt(extras, self.fluxes.nuptake):
                        extras = self.fluxes.nuptake

                    self.state.shootn -= extras
                    self.fluxes.nuptake -= extras
                    
            # if root N:C ratio exceeds its max, then nitrogen uptake is cut 
            # back. n.b. new ring n/c max is already set because it is related 
            # to leaf n:c
            ncmaxr = ncmaxf * self.params.ncrfac  # max root n:c
            extrar = 0.0
            if float_gt(self.state.rootn, (self.state.root * ncmaxr)):
       
                extrar = self.state.rootn - self.state.root * ncmaxr

                # Ensure N uptake cannot be reduced below zero.
                if float_gt((extras + extrar), self.fluxes.nuptake):
                    extrar = self.fluxes.nuptake - extras

                self.state.rootn -= extrar
                self.fluxes.nuptake -= extrar 
    def carbon_production(self, date, day, daylen):
        """ Calculate GPP, NPP and plant respiration

        Parameters:
        -----------
        day : intefer
            simulation day
        date : date string object
            date object string (yr/mth/day)
        daylen : float
            daytime length (hrs)

        References:
        -----------
        * Jackson, J. E. and Palmer, J. W. (1981) Annals of Botany, 47, 561-565.
        """

        # leaf nitrogen content
        self.state.ncontent = (self.state.shootnc * self.params.cfracts /
                                self.state.sla * const.KG_AS_G)

        # fractional ground cover.
        if float_lt(self.state.lai, self.params.lai_cover):
            frac_gcover = self.state.lai / self.params.lai_cover
        else:
            frac_gcover = 1.0

        # Radiance intercepted by the canopy, accounting for partial closure
        # Jackson and Palmer (1981), derived from beer's law
        self.state.light_interception = ((1.0 - math.exp(-self.params.kext *
                                            self.state.lai / frac_gcover)) *
                                            frac_gcover)
        
        
        
        sys.path.append("/Users/mdekauwe/src/fortran/maestra")
        import physiol
        import utils
        import maestcom as m
        
        RDFIPT = 7.29966089E-02
        TUIPT = 0.71114331
        TDIPT = 0.16205148
        RNET = 17.933075
        WIND = 8.20037797E-02
        PAR = 17.746254
        TAIR = -0.55100000
        
        RH = 0.73264003
        VPD = 157.64043
        VMFD = 1.5811477
        PRESS = 99700.000
        SOILMOIST = 0.0000000
        
        IECO = 1
        
        
        
        TVJUP = -100.00000
        TVJDN = -100.00000
        THETA = 0.94999999
        AJQ = 0.30000001
        RD0 = 0.50000006
        Q10F = 0.10260000
        RTEMP = 28.000000
        DAYRESP = 0.60000002
        TBELOW = -100.00000
        MODELGS = 4
        GSREF = 0.0000000
        I0 = 0.0000000
        D0 = 2.66481364E-21
        VK1 = 0.0000000
        VK2 = 0.0000000
        VPD1 = 0.0000000
        VPD2 = 0.0000000
        VMFD0 = 0.0000000
        GSJA = 0.0000000
        GSJB = 0.0000000
        T0 = 0.0000000
        TREF = 0.0000000
        TMAX = 0.0000000
        SMD1 = 0.0000000
        SMD2 = 0.0000000
        SOILDATA = 0
        SWPEXP = 0.0000000
        G0 = 0.0000000
        D0L = 2.66246708E-44
        GAMMA = 0.0000000
        G1 = 3.0573249
        GK = 0.0000000
        
        
        
        GSC = 3.10860965E-02
        RD = 2.08401568E-02
        
        
        print 
        
        
        VPD = 157.64043
        gsmin = 0.0
        jmax25 = self.params.jmaxn * self.state.ncontent
        vcmax25 = self.params.vcmaxn * self.state.ncontent
        itermax = 0
        nsides = 1
        aleaf = 0.0
        eavj = 43790.000
        edvj = 200000.00
        eavc = 51560.0
        edvc = 0.0
        delsc = 0.0
        et = 0.0
        fheat = 0.0
        tleaf = 0.0
        gbh = 0.0
        decoup = 0.0
        delsj = 644.43378
        wleaf = 2.00000009E-03
        if self.control.co2_conc == 0:
            ca = self.met_data['amb_co2'][day]
        elif self.control.co2_conc == 1:
            ca = self.met_data['ele_co2'][day]
        
        
        (aleaf, et, gbh, decoup, tleaf) = physiol.pstransp(RDFIPT,TUIPT,TDIPT,RNET,WIND,PAR,TAIR, ca, RH,VPD,
                         VMFD,PRESS,SOILMOIST,jmax25, IECO, eavj, edvj, delsj,
                         vcmax25,eavc, edvc, delsc,TVJUP,TVJDN,THETA,AJQ,RD0,
                         Q10F,RTEMP,DAYRESP,TBELOW,MODELGS,GSREF, gsmin,I0,
                         D0,VK1,VK2,VPD1,VPD2,VMFD0,GSJA,GSJB,T0,TREF,TMAX,
                         SMD1,SMD2,SOILDATA,SWPEXP,G0,D0L,GAMMA,G1,GK, wleaf,
                         nsides, itermax, GSC, aleaf, RD, et, fheat, tleaf, gbh, decoup)
        
        print et, aleaf, gbh, decoup, tleaf
        sys.exit()
        
        

        
        sys.exit()
        # Calculate the soil moisture availability factors [0,1] in the topsoil
        # and the entire root zone
        (self.state.wtfac_tsoil, 
            self.state.wtfac_root) = self.wb.calculate_soil_water_fac()

        # Estimate photosynthesis using an empirical model
        if self.control.assim_model >=0 and self.control.assim_model <= 4:
            self.pp.calculate_photosynthesis(day)
        # Estimate photosynthesis using the mechanistic BEWDY model
        elif self.control.assim_model >=5 and self.control.assim_model <= 6:
            # calculate plant C uptake using bewdy
            self.bw.calculate_photosynthesis(frac_gcover, date, day, daylen)
        # Estimate photosynthesis using the mechanistic MATE model. Also need to
        # calculate a water availability scalar to determine Ci:Ca reln.
        elif self.control.assim_model ==7:
            self.mt.calculate_photosynthesis(day, daylen)
        else:
            raise AttributeError('Unknown assimilation model')
Exemple #30
0
    def carbon_production(self, project_day, daylen):
        """ Calculate GPP, NPP and plant respiration

        Parameters:
        -----------
        project_day : integer
            simulation day
        daylen : float
            daytime length (hrs)

        References:
        -----------
        * Jackson, J. E. and Palmer, J. W. (1981) Annals of Botany, 47, 561-565.
        """

        # leaf nitrogen content
        if self.state.lai > 0.0:
            # Leaf N content (g m-2)                       
            self.state.ncontent = (self.state.shootnc * self.params.cfracts /
                                   self.state.sla * const.KG_AS_G)
        else:
            self.state.ncontent = 0.0
            
        # fractional ground cover.
        if float_lt(self.state.lai, self.params.lai_cover):
            frac_gcover = self.state.lai / self.params.lai_cover
        else:
            frac_gcover = 1.0

        # Radiance intercepted by the canopy, accounting for partial closure
        # Jackson and Palmer (1981), derived from beer's law
        if self.state.lai > 0.0:
            self.state.light_interception = ((1.0 - exp(-self.params.kext *
                                             self.state.lai / frac_gcover)) *
                                             frac_gcover)
        else:
            self.state.light_interception = 0.0
        
        if self.control.water_stress:
            # Calculate the soil moisture availability factors [0,1] in the 
            # topsoil and the entire root zone
            (self.state.wtfac_tsoil, 
                self.state.wtfac_root) = self.sm.calculate_soil_water_fac()
        else:
            # really this should only be a debugging option!
            self.state.wtfac_tsoil = 1.0
            self.state.wtfac_root = 1.0
            
        # Estimate photosynthesis using an empirical model
        if self.control.assim_model >=0 and self.control.assim_model <= 4:
            self.pp.calculate_photosynthesis(project_day)
        # Estimate photosynthesis using the mechanistic BEWDY model
        elif self.control.assim_model >=5 and self.control.assim_model <= 6:
            # calculate plant C uptake using bewdy
            self.bw.calculate_photosynthesis(frac_gcover, project_day, daylen)
        # Estimate photosynthesis using the mechanistic MATE model. Also need to
        # calculate a water availability scalar to determine Ci:Ca reln.
        elif self.control.assim_model ==7:
            self.mt.calculate_photosynthesis(project_day, daylen)
        else:
            raise AttributeError('Unknown assimilation model')