示例#1
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_fast(self, tair, par, vpd, wind, pressure, Ca):
        """
        Version as above but using a solver for Tleaf, rather than iterating

        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

        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.leaf_absorptance)

        # set initialise values
        dleaf = vpd
        dair = vpd
        Cs = Ca
        Tleaf = tair
        Tleaf_K = Tleaf + c.DEG_2_KELVIN

        (An, gsc) = F.calc_photosynthesis(Cs=Cs,
                                          Tleaf=Tleaf_K,
                                          Par=par,
                                          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)

        # Solve new Tleaf
        from scipy import optimize
        Tleaf = optimize.brent(self.fx,
                               brack=(Tleaf - 15, Tleaf + 15),
                               args=(P, Tleaf, gsc, par, vpd, pressure, wind))
        #print(Tleaf)
        Tleaf_K = Tleaf + c.DEG_2_KELVIN
        (An, gsc) = F.calc_photosynthesis(Cs=Cs,
                                          Tleaf=Tleaf_K,
                                          Par=par,
                                          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)

        # Clunking, but I can't be arsed to rewrite, need to get other vars
        # back
        (et, le_et, gbH,
         gw) = self.calc_leaf_temp_solved(P, Tleaf, tair, gsc, par, vpd,
                                          pressure, wind)

        gbc = gbH * c.GBH_2_GBC
        Cs = Ca - An / gbc  # boundary layer of leaf
        if et == 0.0 or gw == 0.0:
            dleaf = dair
        else:
            dleaf = (et * pressure / gw) * c.PA_2_KPA  # kPa

        gsw = gsc * c.GSC_2_GSW

        return (An, gsw, et, le_et)
    def main(self, tair, par, vpd, wind, pressure, Ca, Topt_hack=False):
        """
        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

        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.leaf_absorptance)

        # set initialise values
        dleaf = vpd
        dair = vpd
        Cs = Ca
        Tleaf = tair
        Tleaf_K = Tleaf + c.DEG_2_KELVIN

        #print "Start: %.3f %.3f %.3f" % (Cs, Tleaf, dleaf)
        #print

        Topt = 35.0
        Topt_K = Topt + c.DEG_2_KELVIN
        iter = 0
        while True:
            (An, gsc) = F.calc_photosynthesis(Cs=Cs,
                                              Tleaf=Tleaf_K,
                                              Par=par,
                                              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)

            if Topt_hack:
                if Tleaf > Topt:
                    (Anx, gsc) = F.calc_photosynthesis(Cs=Cs,
                                                       Tleaf=Topt_K,
                                                       Par=par,
                                                       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)

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

            gbc = gbH * c.GBH_2_GBC
            Cs = Ca - An / gbc  # boundary layer of leaf
            if et == 0.0 or gw == 0.0:
                dleaf = dair
            else:
                dleaf = (et * pressure / gw) * c.PA_2_KPA  # kPa

            #print "%f %f %f %f %f %f" %  (Cs, Tleaf, dleaf, An*12.*0.000001*86400., gs, et*18*0.001*86400.)

            # 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

            iter += 1
        #print(Tleaf)
        gsw = gsc * c.GSC_2_GSW

        return (An, gsw, et, le_et)
    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)
    def main(self, tair, par, vpd, wind, pressure, Ca, 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

        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)

        # set initialise values
        dleaf = vpd
        dair = tair
        Cs = Ca
        Tleaf = tair
        Tleaf_K = Tleaf + c.DEG_2_KELVIN

        #print "Start: %.3f %.3f %.3f" % (Cs, Tleaf, dleaf)
        #print


        iter = 0
        while True:
            (An, gsc, Ci) = F.calc_photosynthesis(Cs=Cs, Tleaf=Tleaf_K, Par=par,
                                                  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)

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

            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 = dair
            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

            iter += 1

        gsw = gsc * c.GSC_2_GSW

        if et < 0.0:
            raise Exception("ET shouldn't be negative, issue in energy balance")

        return (An, gsw, et, le_et, Cs, Ci)
    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)

        # set initial values
        dleaf = vpd
        Cs = Ca
        Tleaf = tair
        Tleaf_K = Tleaf + c.DEG_2_KELVIN

        cos_zenith = calculate_cos_zenith(doy, lat, hod)
        zenith_angle = np.rad2deg(np.arccos(cos_zenith))
        elevation = 90.0 - zenith_angle

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

            iter = 0
            while True:
                (An, gsc) = F.photosynthesis(Cs=Cs,
                                             Tleaf=Tleaf_K,
                                             Par=par,
                                             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)

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

                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 np.isclose(et, 0.0) or np.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))
                    An = 0.0
                    gsc = 0.0
                    et = 0.0
                    break

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

                iter += 1

            an_canopy = An * LAI
            gsw_canopy = gsc * c.GSC_2_GSW * LAI
            et_canopy = et * LAI
            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)
    def main(self,
             tair,
             par,
             vpd,
             wind,
             pressure,
             Ca,
             doy,
             hod,
             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(peaked_Jmax=self.peaked_Jmax,
                       peaked_Vcmax=self.peaked_Vcmax,
                       model_Q10=self.model_Q10,
                       gs_model=self.gs_model)
        PM = PenmanMonteith()

        # set initial values
        dleaf = vpd
        Cs = Ca
        Tleaf = tair

        Tleaf_K = Tleaf + c.DEG_2_KELVIN

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

        # Calculate big-leaf scaling term to go from a single leaf to canopy
        fpar = calc_leaf_to_canopy_scalar(lai, k=p.k, big_leaf=True)

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

            iter = 0
            while True:
                # Scale fractional PAR absorption at plant projective area level
                # (FPAR) to fractional absorption at leaf level (APAR)
                # Eqn 4, Haxeltine & Prentice 1996a
                apar = par * fpar
                (An, gsc) = F.photosynthesis(self.p,
                                             Cs=Cs,
                                             Tleaf=Tleaf_K,
                                             Par=apar,
                                             vpd=dleaf)

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

                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 np.isclose(et, 0.0) or np.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))
                    An = 0.0
                    gsc = 0.0
                    et = 0.0
                    break

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

                iter += 1

            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)
    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)