Exemple #1
0
    def stomatal_conductance(self,
                             g0,
                             g1,
                             gb,
                             m,
                             A_net,
                             CO2,
                             RH,
                             drb,
                             gamma=U(10, 'umol/mol')):
        Cs = CO2 - (drb * A_net / gb)  # surface CO2 in mole fraction
        Cs = clip(Cs, lower=gamma)

        a = m * g1 * A_net / Cs
        b = g0 + gb - a
        c = (-RH * gb) - g0
        #hs = max(np.roots([a, b, c]))
        #hs = scipy.optimize.brentq(lambda x: np.polyval([a, b, c], x), 0, 1)
        #hs = scipy.optimize.fsolve(lambda x: np.polyval([a, b, c], x), 0)
        hs = quadratic_solve_upper(a, b, c)
        #hs = clip(hs, 0.1, 1.0) # preventing bifurcation: used to be (0.3, 1.0) for C4 maize

        #FIXME unused?
        #T_leaf = l.temperature
        #es = w.vp.saturation(T_leaf)
        #Ds = (1 - hs) * es # VPD at leaf surface
        #Ds = w.vp.deficit(T_leaf, hs)

        gs = g0 + (g1 * m * (A_net * hs / Cs))
        gs = clip(gs, lower=g0)
        return gs
Exemple #2
0
 def temperature_dependence_rate(self, Ea, T, Tb=U(25, 'degC')):
     R = U(8.314, 'J/K/mol')  # universal gas constant (J K-1 mol-1)
     #HACK handle too low temperature values during optimization
     Tk = clip(T, lower=0, unit='degK')
     Tbk = clip(Tb, lower=0, unit='degK')
     try:
         return np.exp(Ea * (T - Tb) / (Tbk * R * Tk))
     except ZeroDivisionError:
         return 0
Exemple #3
0
 def Vp(self, Vpmax, Cm, Kp):
     # PEP carboxylation rate, that is the rate of C4 acid generation
     Vp = (Cm * Vpmax) / (Cm + Kp / U(1, 'atm'))
     Vpr = U(80, 'umol/m^2/s CO2'
             )  # PEP regeneration limited Vp, value adopted from vC book
     Vp = clip(Vp, 0, Vpr)
     return Vp
Exemple #4
0
 def optical_air_mass_number(self, elevation_angle):
     t_s = clip(elevation_angle, lower=0, unit='rad')
     #FIXME need to do max(0.0001, sin(t_s))?
     try:
         #FIXME check 101.3 is indeed in kPa
         return self.atmospheric_pressure / (U(101.3, 'kPa') * sin(t_s))
     except:
         return 0
Exemple #5
0
 def evapotranspiration(self, vp='weather.vp'):
     gv = self.stomata.total_conductance_h2o
     ea = vp.ambient(self.weather.T_air, self.weather.RH)
     es_leaf = vp.saturation(self.temperature)
     ET = gv * ((es_leaf - ea) /
                self.weather.P_air) / (1 -
                                       (es_leaf + ea) / self.weather.P_air)
     return clip(
         ET,
         lower=0)  # 04/27/2011 dt took out the 1000 everything is moles now
Exemple #6
0
    def _temperature_effect(self, T_grow, T_peak, T_base):
        # T_peak is the optimal growth temperature at which the potential leaf size determined in calc_mophology achieved.
        # Similar concept to fig 3 of Fournier and Andreiu (1998)

        # phyllochron corresponds to PHY in Lizaso (2003)
        # phyllochron needed for next leaf appearance in degree days (GDD8) - 08/16/11, SK.
        #phyllochron = (dv->get_T_Opt()- Tb)/(dv->get_Rmax_LTAR());

        T_ratio = (T_grow - T_base) / (T_peak - T_base)
        # final leaf size is adjusted by growth temperature determining cell size during elongation
        return clip(T_ratio * exp(1 - T_ratio), lower=0)
Exemple #7
0
    def _water_potential_effect(self, psi_predawn, threshold):
        #psi_predawn = self.p.soil.WP_leaf_predawn
        psi_th = threshold  # threshold wp below which stress effect shows up

        # DT Oct 10, 2012 changed this so it was not as sensitive to stress near -0.5 lwp
        # SK Sept 16, 2014 recalibrated/rescaled parameter estimates in Yang's paper. The scale of Boyer data wasn't set correctly
        # sensitivity = 1.92, LeafWPhalf = -1.86, the sensitivity parameter may be raised by 0.3 to 0.5 to make it less sensitivy at high LWP, SK
        s_f = 0.4258  # 0.5
        psi_f = -1.4251  # -1.0
        e = (1 + exp(s_f * psi_f)) / (1 + exp(s_f * (psi_f -
                                                     (psi_predawn - psi_th))))
        return clip(e, upper=1.0)
Exemple #8
0
 def senescence_ratio(self):
     # for MAIZSIM
     # t = self.senescence_age
     # t_e = self.senescence_duration
     # if t >= t_e:
     #     return 1
     # else:
     #     t_m = t_e / 2
     #     r = (1 + (t_e - t) / (t_e - t_m)) * (t / t_e)**(t_e / (t_e - t_m))
     #     return clip(r, 0., 1.)
     # for garlic
     #HACK prevents nan
     if self.length == 0:
         r = 0.
     else:
         r = self.aging_rate * self.senescence_age / self.length
     return clip(r, 0., 1.)
Exemple #9
0
 def potential_expansion_rate(self):
     t = self.elongation_age
     t_e = self.growth_duration  # 1.5 * w_max / c_m
     t = clip(t, upper=t_e)
     #FIXME can we introduce new w_max here when w_max in t_e (growth duration) supposed to be potential length?
     w_max = self.potential_area
     # c_m from Eq. 9, r (= dw/dt / c_m) from Eq. 7 of Yin (2003)
     #HACK can be more simplified
     #c_m = 1.5 / t_e * w_max
     #r = 4 * t * (t_e - t) / t_e**2
     t_m = t_e / 2
     c_m = (2 * t_e -
            t_m) / (t_e * (t_e - t_m)) * (t_m / t_e)**(t_m /
                                                       (t_e - t_m)) * w_max
     r = (t_e - t) / (t_e - t_m) * (t / t_m)**(t_m / (t_e - t_m))
     #FIXME dt here is physiological time, whereas timestep multiplied in potential_area_increase is chronological time
     return c_m * r  # dw/dt
Exemple #10
0
    def maximum_electron_transport_rate(self,
                                        T,
                                        T_dep,
                                        N_dep,
                                        Jm25=U(300, 'umol/m^2/s Electron'),
                                        Eaj=U(32800, 'J/mol'),
                                        Sj=U(702.6, 'J/mol/degK'),
                                        Hj=U(220000, 'J/mol')):
        R = U(8.314, 'J/K/mol')

        Tb = U(25, 'degC')
        Tk = T.to('degK')
        Tbk = Tb.to('degK')

        r = Jm25 * N_dep \
                 * T_dep(Eaj) \
                 * (1 + np.exp((Sj*Tbk - Hj) / (R*Tbk))) \
                 / (1 + np.exp((Sj*Tk  - Hj) / (R*Tk)))
        return clip(r, lower=0)
Exemple #11
0
    def boundary_layer_conductance(self,
                                   lw='leaf.width',
                                   ww='leaf.weather.wind'):
        # maize is an amphistomatous species, assume 1:1 (adaxial:abaxial) ratio.
        #sr = 1.0
        # switchgrass adaxial : abaxial (Awada 2002)
        # https://doi.org/10.4141/P01-031
        sr = 1.28
        ratio = (sr + 1)**2 / (sr**2 + 1)

        # characteristic dimension of a leaf, leaf width in m
        d = lw * 0.72

        #return 1.42 # total BLC (both sides) for LI6400 leaf chamber
        gb = 1.4 * 0.147 * (clip(ww, lower=0.1) / d)**0.5 * ratio
        #gb = (1.4 * 1.1 * 6.62 * (wind / d)**0.5 * (P_air / (R * (273.15 + T_air)))) # this is an alternative form including a multiplier for conversion from mm s-1 to mol m-2 s-1
        # 1.1 is the factor to convert from heat conductance to water vapor conductance, an avarage between still air and laminar flow (see Table 3.2, HG Jones 2014)
        # 6.62 is for laminar forced convection of air over flat plates on projected area basis
        # when all conversion is done for each surface it becomes close to 0.147 as given in Norman and Campbell
        # multiply by 1.4 for outdoor condition, Campbell and Norman (1998), p109, also see Jones 2014, pg 59 which suggest using 1.5 as this factor.
        # multiply by ratio to get the effective blc (per projected area basis), licor 6400 manual p 1-9
        return gb
Exemple #12
0
 def senescence_duration(self):
     # end of growth period, time to maturity
     return clip(self.growth_duration -
                 self.senescence_water_stress_duration,
                 lower=0)
Exemple #13
0
 def stay_green_duration(self):
     # SK 8/20/10: as in Sinclair and Horie, 1989 Crop sciences, N availability index scaled between 0 and 1 based on
     #nitrogen_index = max(0, (2 / (1 + exp(-2.9 * (self.g_content - 0.25))) - 1))
     return clip(self.stay_green * self.growth_duration -
                 self.stay_green_water_stress_duration,
                 lower=0)
Exemple #14
0
 def light(self):
     I2 = self.leaf.light
     return clip(I2, lower=0)
Exemple #15
0
 def gross_photosynthesis(self):
     return clip(
         self.A_net + self.Rd, lower=0
     )  # gets negative when PFD = 0, Rd needs to be examined, 10/25/04, SK
Exemple #16
0
 def co2_mesophyll(self):
     Cm = self.leaf.co2_mesophyll
     return clip(Cm, lower=0)
Exemple #17
0
 def co2_mesophyll(self, A_net, w='weather', rvc='stomata.rvc'):
     P = w.P_air / U(100, 'kPa')
     Ca = w.CO2 * P  # conversion to partial pressure
     Cm = Ca - A_net * rvc * P
     #print(f"+ Cm = {Cm}, Ca = {Ca}, A_net = {A_net}, gs = {self.stomata.gs}, gb = {self.stomata.gb}, rvc = {rvc}, P = {P}")
     return clip(Cm, 0, 2 * Ca)
Exemple #18
0
 def leaf_number_effect(self, potential_leaves):
     # Fig 4 of Birch et al. (1998)
     return clip(exp(-1.17 + 0.047 * potential_leaves), 0.5, 1.0)
Exemple #19
0
 def solar_radiation(self, elevation_angle, day, SC):
     t_s = clip(elevation_angle, lower=0, unit='rad')
     g = 2 * pi * (day - 10) / 365
     return SC * sin(t_s) * (1 + 0.033 * cos(g))
Exemple #20
0
 def phase1_delay(self, rank):
     # not used in MAIZSIM because LTAR is used to initiate leaf growth.
     # Fournier's value : -5.16+1.94*rank;equa 11 Fournier and Andrieu(1998) YY, This is in plastochron unit
     return clip(-5.16 + 1.94 * rank, lower=0)