def main(self,
             tair,
             par,
             vpd,
             wind,
             pressure,
             Ca,
             doy,
             hod,
             lai,
             rnet=None,
             tsoil=None):
        """
        Parameters:
        ----------
        tair : float
            air temperature (deg C)
        par : float
            Photosynthetically active radiation (umol m-2 s-1)
        vpd : float
            Vapour pressure deficit (kPa, needs to be in Pa, see conversion
            below)
        wind : float
            wind speed (m s-1)
        pressure : float
            air pressure (using constant) (Pa)
        Ca : float
            ambient CO2 concentration
        doy : float
            day of day
        hod : float
            hour of day
        lai : floar
            leaf area index

        Returns:
        --------
        An : float
            net leaf assimilation (umol m-2 s-1)
        gs : float
            stomatal conductance (mol m-2 s-1)
        et : float
            transpiration (mol H2O m-2 s-1)
        """

        F = FarquharC3(peaked_Jmax=self.peaked_Jmax,
                       peaked_Vcmax=self.peaked_Vcmax,
                       model_Q10=self.model_Q10,
                       gs_model=self.gs_model)
        PM = PenmanMonteith()

        An = np.zeros(2)  # sunlit, shaded
        Anc = np.zeros(2)  # sunlit, shaded
        Anj = np.zeros(2)  # sunlit, shaded
        gsc = np.zeros(2)  # sunlit, shaded
        et = np.zeros(2)  # sunlit, shaded
        Tcan = np.zeros(2)  # sunlit, shaded
        lai_leaf = np.zeros(2)
        sw_rad = np.zeros(2)  # VIS, NIR

        XX = np.zeros(2)

        (cos_zenith, elevation) = calculate_cos_zenith(doy, p.lat, hod)

        sw_rad[c.VIS] = 0.5 * (par * c.PAR_2_SW)  # W m-2
        sw_rad[c.NIR] = 0.5 * (par * c.PAR_2_SW)  # W m-2

        # get diffuse/beam frac, just use VIS as the answer is the same for NIR
        (diffuse_frac, direct_frac) = spitters(doy, sw_rad[0], cos_zenith)

        (qcan, apar, lai_leaf, kb,
         gradis) = calculate_absorbed_radiation(self.p, par, cos_zenith, lai,
                                                direct_frac, diffuse_frac, doy,
                                                sw_rad, tair, tsoil)

        # Calculate scaling term to go from a single leaf to canopy,
        # see Wang & Leuning 1998 appendix C
        scalex = calc_leaf_to_canopy_scalar(lai, kb=kb, kn=p.kn)

        if lai_leaf[0] < 1.e-3:  # to match line 336 of CABLE radiation
            scalex[0] = 0.

        if np.sum(sw_rad) < c.RAD_THRESH:
            scalex[0] = 0.0
            #scalex[1] = 0.0

        # Is the sun up?
        #print(doy, hod, elevation, par)
        yes = True
        if yes:
            #if elevation > 0.0 and par > 50.:

            # sunlit / shaded loop
            for ileaf in range(2):

                # initialise values of Tleaf, Cs, dleaf at the leaf surface
                dleaf = vpd
                Cs = Ca
                Tleaf = tair
                Tleaf_K = Tleaf + c.DEG_2_KELVIN

                iter = 0
                while True:

                    if scalex[ileaf] > 0.:
                        (An[ileaf],
                         gsc[ileaf]) = F.photosynthesis(p,
                                                        Cs=Cs,
                                                        Tleaf=Tleaf_K,
                                                        Par=apar[ileaf],
                                                        vpd=dleaf,
                                                        scalex=scalex[ileaf])
                    else:
                        An[ileaf] = 0.0
                        gsc[ileaf] = 0.0

                    # Calculate new Tleaf, dleaf, Cs
                    (new_tleaf, et[ileaf], le_et, gbH,
                     gw) = self.calc_leaf_temp(p,
                                               PM,
                                               Tleaf,
                                               tair,
                                               gsc[ileaf],
                                               None,
                                               vpd,
                                               pressure,
                                               wind,
                                               rnet=qcan[ileaf],
                                               lai=lai_leaf[ileaf],
                                               gradis=gradis[ileaf])

                    gbc = gbH * c.GBH_2_GBC
                    if gbc > 0.0 and An[ileaf] > 0.0:
                        Cs = Ca - An[ileaf] / gbc  # boundary layer of leaf
                    else:
                        Cs = Ca

                    if np.isclose(et[ileaf], 0.0) or np.isclose(gw, 0.0):
                        dleaf = vpd
                    else:
                        dleaf = (et[ileaf] * pressure / gw) * c.PA_2_KPA  # kPa
                        if dleaf < 0.05:
                            dleaf = 0.05

                    # Check for convergence...?
                    if math.fabs(Tleaf - new_tleaf) < 0.02:
                        Tcan[ileaf] = Tleaf
                        break

                    if iter > self.iter_max:
                        #raise Exception('No convergence: %d' % (iter))
                        An[ileaf] = 0.0
                        gsc[ileaf] = 0.0
                        et[ileaf] = 0.0
                        break

                    # Update temperature & do another iteration
                    Tleaf = new_tleaf
                    Tleaf_K = Tleaf + c.DEG_2_KELVIN
                    Tcan[ileaf] = Tleaf
                    """
                    # Update leaf surface vapour pressure deficit:
                    tetena = 6.106
                    tetenb = 17.27
                    tetenc = 237.3
                    TFRZ = 273.15
                    Tair_K = tair + c.DEG_2_KELVIN

                    # d(es)/dT (Pa/K)
                    a1 = tetena * tetenb * tetenc
                    a2 = ((Tair_K - TFRZ) + tetenc)**2
                    a3 = np.exp(tetenb * \
                                (Tair_K-TFRZ) / ((Tair_K-TFRZ) + tetenc))
                    dsatdk = 100.0 * a1 / a2 * a3 * c.PA_TO_KPA
                    dleafx = vpd + dsatdk * (Tleaf_K - Tair_K)
                    """

                    iter += 1

        return (An, et, Tcan, apar, lai_leaf)
Exemple #2
0
    def main(self,
             tair,
             par,
             vpd,
             wind,
             pressure,
             Ca,
             doy,
             hod,
             lat,
             lon,
             lai,
             rnet=None):
        """
        Parameters:
        ----------
        tair : float
            air temperature (deg C)
        par : float
            Photosynthetically active radiation (umol m-2 s-1)
        vpd : float
            Vapour pressure deficit (kPa, needs to be in Pa, see conversion
            below)
        wind : float
            wind speed (m s-1)
        pressure : float
            air pressure (using constant) (Pa)
        Ca : float
            ambient CO2 concentration
        doy : float
            day of day
        hod : float
            hour of day
        lat : float
            latitude
        lon : float
            longitude
        lai : floar
            leaf area index

        Returns:
        --------
        An : float
            net leaf assimilation (umol m-2 s-1)
        gs : float
            stomatal conductance (mol m-2 s-1)
        et : float
            transpiration (mol H2O m-2 s-1)
        """

        F = FarquharC3(theta_J=0.85,
                       peaked_Jmax=True,
                       peaked_Vcmax=True,
                       model_Q10=True,
                       gs_model=self.gs_model,
                       gamma=self.gamma,
                       g0=self.g0,
                       g1=self.g1,
                       D0=self.D0,
                       alpha=self.alpha)
        P = PenmanMonteith(self.leaf_width, self.SW_abs)

        An = np.zeros(2)  # sunlit, shaded
        gsc = np.zeros(2)  # sunlit, shaded
        et = np.zeros(2)  # sunlit, shaded
        Tcan = np.zeros(2)  # sunlit, shaded
        lai_leaf = np.zeros(2)

        #cos_zenith = calculate_solar_geometry(doy, hod, lat, lon)
        cos_zenith = sinbet(doy, lat, hod)

        #print(doy, lat, hod, cos_zenith)
        zenith_angle = np.rad2deg(np.arccos(cos_zenith))
        elevation = 90.0 - zenith_angle
        sw_rad = par * c.PAR_2_SW  # W m-2

        # this matches CABLE's logic ...  which means they are halving the
        # SW_down that is used to compute the direct/diffuse terms and presumbly
        # all other calcs
        sw_rad_half = par / 4.6  # W m-2

        # get diffuse/beam frac
        (diffuse_frac, direct_frac) = spitters(doy, sw_rad_half, cos_zenith)

        (apar, lai_leaf,
         kb) = calculate_absorbed_radiation(par, cos_zenith, lai, direct_frac,
                                            diffuse_frac, doy, sw_rad_half)

        # Calculate scaling term to go from a single leaf to canopy,
        # see Wang & Leuning 1998 appendix C
        scalex = calc_leaf_to_canopy_scalar(lai, kb)

        if lai_leaf[0] < 1.e-3:  # to match line 336 of CABLE radiation
            scalex[0] = 0.

        # Is the sun up?
        if elevation > 0.0 and par > 50.:

            # sunlit / shaded loop
            for ileaf in range(2):

                # initialise values of Tleaf, Cs, dleaf at the leaf surface
                dleaf = vpd
                Cs = Ca
                Tleaf = tair
                Tleaf_K = Tleaf + c.DEG_2_KELVIN

                iter = 0
                while True:

                    if scalex[ileaf] > 0.:
                        (An[ileaf],
                         gsc[ileaf]) = F.photosynthesis(Cs=Cs,
                                                        Tleaf=Tleaf_K,
                                                        Par=apar[ileaf],
                                                        Jmax25=self.Jmax25,
                                                        Vcmax25=self.Vcmax25,
                                                        Q10=self.Q10,
                                                        Eaj=self.Eaj,
                                                        Eav=self.Eav,
                                                        deltaSj=self.deltaSj,
                                                        deltaSv=self.deltaSv,
                                                        Rd25=self.Rd25,
                                                        Hdv=self.Hdv,
                                                        Hdj=self.Hdj,
                                                        vpd=dleaf,
                                                        scalex=scalex[ileaf])
                    else:
                        An[ileaf], gsc[ileaf] = 0., 0.

                    # Calculate new Tleaf, dleaf, Cs
                    (new_tleaf, et[ileaf], le_et, gbH,
                     gw) = self.calc_leaf_temp(P,
                                               Tleaf,
                                               tair,
                                               gsc[ileaf],
                                               apar[ileaf],
                                               vpd,
                                               pressure,
                                               wind,
                                               rnet=rnet,
                                               lai=lai_leaf[ileaf])

                    gbc = gbH * c.GBH_2_GBC
                    if gbc > 0.0 and An[ileaf] > 0.0:
                        Cs = Ca - An[ileaf] / gbc  # boundary layer of leaf
                    else:
                        Cs = Ca

                    if np.isclose(et[ileaf], 0.0) or np.isclose(gw, 0.0):
                        dleaf = vpd
                    else:
                        dleaf = (et[ileaf] * pressure / gw) * c.PA_2_KPA  # kPa

                    # Check for convergence...?
                    if math.fabs(Tleaf - new_tleaf) < 0.02:
                        break

                    if iter > self.iter_max:
                        #raise Exception('No convergence: %d' % (iter))
                        An[ileaf] = 0.0
                        gsc[ileaf] = 0.0
                        et[ileaf] = 0.0
                        break

                    # Update temperature & do another iteration
                    Tleaf = new_tleaf
                    Tleaf_K = Tleaf + c.DEG_2_KELVIN
                    Tcan[ileaf] = Tleaf

                    iter += 1

            # scale to canopy: sum contributions from beam and diffuse leaves
            an_canopy = np.sum(An)
            an_cansun = An[c.SUNLIT]
            an_cansha = An[c.SHADED]
            par_sun = apar[c.SUNLIT]
            par_sha = apar[c.SHADED]
            gsw_canopy = np.sum(gsc) * c.GSC_2_GSW
            et_canopy = np.sum(et)
            sun_frac = lai_leaf[c.SUNLIT] / np.sum(lai_leaf)
            sha_frac = lai_leaf[c.SHADED] / np.sum(lai_leaf)
            tcanopy = (Tcan[c.SUNLIT] * sun_frac) + (Tcan[c.SHADED] * sha_frac)
            lai_sun = lai_leaf[c.SUNLIT]
            lai_sha = lai_leaf[c.SHADED]
        else:
            an_canopy = 0.0
            an_cansun = 0.0
            an_cansha = 0.0
            gsw_canopy = 0.0
            et_canopy = 0.0
            par_sun = 0.0
            par_sha = 0.0
            tcanopy = tair
            lai_sun = 0.0
            lai_sha = lai

        return (an_canopy, gsw_canopy, et_canopy, tcanopy, an_cansun,
                an_cansha, par_sun, par_sha, lai_sun, lai_sha)
    def main(self,
             tair,
             par,
             vpd,
             wind,
             pressure,
             Ca,
             doy,
             hod,
             lat,
             lon,
             lai,
             rnet=None):
        """
        Parameters:
        ----------
        tair : float
            air temperature (deg C)
        par : float
            Photosynthetically active radiation (umol m-2 s-1)
        vpd : float
            Vapour pressure deficit (kPa, needs to be in Pa, see conversion
            below)
        wind : float
            wind speed (m s-1)
        pressure : float
            air pressure (using constant) (Pa)
        Ca : float
            ambient CO2 concentration
        doy : float
            day of day
        hod : float
            hour of day
        lat : float
            latitude
        lon : float
            longitude
        lai : floar
            leaf area index

        Returns:
        --------
        An : float
            net leaf assimilation (umol m-2 s-1)
        gs : float
            stomatal conductance (mol m-2 s-1)
        et : float
            transpiration (mol H2O m-2 s-1)
        """

        F = FarquharC3(theta_J=0.85,
                       peaked_Jmax=True,
                       peaked_Vcmax=True,
                       model_Q10=True,
                       gs_model=self.gs_model,
                       gamma=self.gamma,
                       g0=self.g0,
                       g1=self.g1,
                       D0=self.D0,
                       alpha=self.alpha)
        P = PenmanMonteith(self.leaf_width, self.SW_abs)

        An = np.zeros(2)  # sunlit, shaded
        gsc = np.zeros(2)  # sunlit, shaded
        et = np.zeros(2)  # sunlit, shaded
        Tcan = np.zeros(2)  # sunlit, shaded

        cos_zenith = calculate_solar_geometry(doy, hod, lat, lon)
        zenith_angle = np.rad2deg(np.arccos(cos_zenith))
        elevation = 90.0 - zenith_angle
        sw_rad = par * c.PAR_2_SW  # W m-2

        # get diffuse/beam frac
        (diffuse_frac, direct_frac) = spitters(doy, sw_rad, cos_zenith)

        # Is the sun up?
        if elevation > 0.0 and par > 50.0:

            (apar, lai_leaf, kb) = calculate_absorbed_radiation_big_leaf(
                par, cos_zenith, lai, direct_frac, diffuse_frac)

            # Calculate scaling term to go from a single leaf to canopy,
            # see Wang & Leuning 1998 appendix C
            scalex = calc_leaf_to_canopy_scalar(lai, kb)

            # initialise values of Tleaf, Cs, dleaf at the leaf surface
            dleaf = vpd
            Cs = Ca
            Tleaf = tair
            Tleaf_K = Tleaf + c.DEG_2_KELVIN

            iter = 0
            while True:
                (An, gsc) = F.photosynthesis(Cs=Cs,
                                             Tleaf=Tleaf_K,
                                             Par=apar,
                                             Jmax25=self.Jmax25,
                                             Vcmax25=self.Vcmax25,
                                             Q10=self.Q10,
                                             Eaj=self.Eaj,
                                             Eav=self.Eav,
                                             deltaSj=self.deltaSj,
                                             deltaSv=self.deltaSv,
                                             Rd25=self.Rd25,
                                             Hdv=self.Hdv,
                                             Hdj=self.Hdj,
                                             vpd=dleaf,
                                             scalex=scalex)

                # Calculate new Tleaf, dleaf, Cs
                (new_tleaf, et, le_et, gbH,
                 gw) = self.calc_leaf_temp(P,
                                           Tleaf,
                                           tair,
                                           gsc,
                                           apar,
                                           vpd,
                                           pressure,
                                           wind,
                                           rnet=rnet,
                                           lai=lai)

                gbc = gbH * c.GBH_2_GBC
                if gbc > 0.0 and An > 0.0:
                    Cs = Ca - An / gbc  # boundary layer of leaf
                else:
                    Cs = Ca

                if math.isclose(et, 0.0) or math.isclose(gw, 0.0):
                    dleaf = vpd
                else:
                    dleaf = (et * pressure / gw) * c.PA_2_KPA  # kPa

                # Check for convergence...?
                if math.fabs(Tleaf - new_tleaf) < 0.02:
                    break

                if iter > self.iter_max:
                    raise Exception('No convergence: %d' % (iter))

                # Update temperature & do another iteration
                Tleaf = new_tleaf
                Tleaf_K = Tleaf + c.DEG_2_KELVIN
                Tcan = Tleaf

                iter += 1

            # scale to canopy: sum contributions from beam and diffuse leaves
            an_canopy = An
            gsw_canopy = gsc * c.GSC_2_GSW
            et_canopy = et
            tcanopy = Tleaf
        else:
            an_canopy = 0.0
            gsw_canopy = 0.0
            et_canopy = 0.0
            tcanopy = tair

        return (an_canopy, gsw_canopy, et_canopy, tcanopy)