예제 #1
0
def nee2gpp_reichstein(dates,
                       nee,
                       t,
                       isday,
                       rg=False,
                       vpd=False,
                       undef=np.nan,
                       shape=False,
                       masked=False,
                       nogppnight=False):
    """
        Calculate photosynthesis (GPP) and ecosystem respiration (Reco) from original
        Eddy flux data, using several fits of Reco vs. temperature of nighttime data
        over the season, as in Reichstein et al. (2005), in order to calculate Reco
        and then GPP = Reco - NEE.


        Definition
        ----------
        def nee2gpp_reichstein(dates, nee, t, isday, undef=np.nan, shape=None, masked=False):


        Input
        -----
        Inputs are 1D arrays that can be masked or not.
        dates         julian days
        nee           net ecosystem exchange (uptake is <0) [umol m-2 s-1]
        t             temperature [K]


        Parameters
        ----------
        undef        undefined values in data  (default: np.nan)
                     Input arrays will be masked at undef, keeping the original mask
        shape        if False then outputs are 1D arrays (default)
                     if True, output have the same shape as datain
                     if a shape tuple is given, then this tuple is used to reshape
        masked       if False: outputs are undef where nee and t are masked or undef (default)
                     if True:  return masked arrays where outputs would be undef
        nogppnight   if True:  Resp=NEE, GPP=0 at night
                     if False: Resp=lloyd_taylor, GPP=Resp-NEE at night (default)


        Ouput
        -----
        GPP, Reco    photosynthesis, ecosystem respiration


        Restrictions
        ------------
        None.


        Literature
        ----------
        Reichstein et al. (2005)
            On the separation of net ecosystem exchange into assimilation and ecosystem
            respiration: review and improved algorithm.
            Global Change Biology 11, 1424-1439


        Examples
        --------
        >>> from jams.fread import fread # from jams
        >>> from jams.date2dec import date2dec # from jams
        >>> dat   = fread('test_nee2gpp.csv', skip=2, transpose=True)
        >>> dates = date2dec(dy=dat[0,:], mo=dat[1,:], yr=dat[2,:], hr=dat[3,:], mi=dat[4,:])
        >>> NEE   = np.squeeze(dat[5,:])
        >>> rg    = np.squeeze(dat[6,:])
        >>> tair  = np.squeeze(dat[7,:])
        >>> undef = -9999.
        >>> isday = np.where(rg > 10., True, False)
        >>> tt    = np.where(tair == undef, undef, tair+273.15)
        >>> # partition
        >>> GPP, Reco = nee2gpp(dates, NEE, tt, isday, undef=undef, method='local')
        >>> print(GPP[1120:1128])
        [-9.99900000e+03 -9.99900000e+03 -9.99900000e+03  4.40606871e+00
          8.31942152e+00  1.06242542e+01  8.49245664e+00  1.12381973e+01]
        >>> print(Reco[1120:1128])
        [1.68311981 1.81012431 1.9874173  2.17108871 2.38759152 2.64372415
         2.90076664 3.18592735]

        >>> GPP, Reco = nee2gpp(dates, NEE, tt, isday, undef=undef, method='local')
        >>> print(GPP[1120:1128])
        [-9.99900000e+03 -9.99900000e+03 -9.99900000e+03  4.40606871e+00
          8.31942152e+00  1.06242542e+01  8.49245664e+00  1.12381973e+01]

        >>> GPP, Reco = nee2gpp(dates, NEE, tt, isday, undef=undef, method='Reichstein', masked=True)
        >>> print(GPP[1120:1128])
        [-- -- -- 4.406068706013192 8.319421516040766 10.624254150217764
         8.492456637225963 11.238197347837367]

        >>> GPP, Reco = nee2gpp(dates, NEE, tt, isday, undef=undef, method='reichstein', shape=(np.size(NEE),1))
        >>> print(GPP[1120:1128])
        [[-9.99900000e+03]
         [-9.99900000e+03]
         [-9.99900000e+03]
         [ 4.40606871e+00]
         [ 8.31942152e+00]
         [ 1.06242542e+01]
         [ 8.49245664e+00]
         [ 1.12381973e+01]]


        License
        -------
        This file is part of the JAMS Python package, distributed under the MIT
        License. The JAMS Python package originates from the former UFZ Python library,
        Department of Computational Hydrosystems, Helmholtz Centre for Environmental
        Research - UFZ, Leipzig, Germany.

        Copyright (c) 2012-2013 Matthias Cuntz, Arndt Piayda - mc (at) macu (dot) de

        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.


        History
        -------
        Written  MC, Mar 2012
        Modified AP, Mar 2012 - undef=np.nan
                 MC, Nov 2012 - individual routine
                 MC, Feb 2013 - ported to Python 3
    """
    # Checks

    # remember shape if any
    if shape != False:
        if shape != True:
            inshape = shape
        else:
            inshape = nee.shape
    dates = np.squeeze(dates)
    nee = np.squeeze(nee)
    t = np.squeeze(t)
    isday = np.squeeze(isday)
    if shape == False: inshape = nee.shape
    # Check squeezed shape
    if dates.ndim != 1:
        raise ValueError(
            'Error nee2gpp_reichstein: squeezed dates must be 1D array.')
    if nee.ndim != 1:
        raise ValueError(
            'Error nee2gpp_reichstein: squeezed nee must be 1D array.')
    if t.ndim != 1:
        raise ValueError(
            'Error nee2gpp_reichstein: squeezed t must be 1D array.')
    if isday.ndim != 1:
        raise ValueError(
            'Error nee2gpp_reichstein: squeezed isday must be 1D array.')
    ndata = dates.size
    if ((nee.size != ndata) | (t.size != ndata) | (isday.size != ndata)):
        raise ValueError(
            'Error nee2gpp_reichstein: inputs must have the same size.')

    # Transform to masked array with 1D mask
    nee = np.ma.array(nee, mask=False)
    t = np.ma.array(t, mask=False)
    isday = np.ma.array(isday, mask=False)
    # mask also undef
    if np.isnan(undef):
        if np.ma.any(np.isnan(nee)): nee[np.isnan(nee)] = np.ma.masked
        if np.ma.any(np.isnan(t)): t[np.isnan(t)] = np.ma.masked
        if np.ma.any(np.isnan(isday)): isday[np.isnan(isday)] = np.ma.masked
    else:
        if np.ma.any(nee == undef): nee[nee == undef] = np.ma.masked
        if np.ma.any(t == undef): t[t == undef] = np.ma.masked
        if np.ma.any(isday == undef): isday[isday == undef] = np.ma.masked

    # Partition - Local relationship = Reichstein et al. (2005)

    # Select valid nighttime
    mask = isday | nee.mask | t.mask | isday.mask
    ii = np.where(~mask)[0]
    if (ii.size == 0):
        print('Warning nee2gpp_reichstein: no valid nighttime data.')
        if masked:
            GPP = np.ma.array(np.reshape(nee, inshape),
                              mask=np.ones(inshape, dtype=bool))
            Reco = np.ma.array(np.reshape(nee, inshape),
                               mask=np.ones(inshape, dtype=bool))
        else:
            GPP = np.ones(np.reshape(nee, inshape)) * undef
            Reco = np.ones(np.reshape(nee, inshape)) * undef
        return GPP, Reco
    jul = dates[ii]
    tt = np.ma.compressed(t[ii])
    net = np.ma.compressed(nee[ii])
    # 1. each 5 days, in 15 day period, fit if range of T > 5
    locp = []  # local param
    locs = []  # local err
    dmin = np.floor(np.amin(jul)).astype(
        int)  # be aware that julian days starts at noon, i.e. 1.0 is 12h
    dmax = np.ceil(np.amax(jul)).astype(
        int
    )  # so the search will be from noon to noon and thus includes all nights
    for i in range(dmin, dmax, 5):
        iii = np.where((jul >= i) & (jul < (i + 14)))[0]
        niii = iii.size
        if niii > 6:
            tt1 = tt[iii]
            net1 = net[iii]
            mm = ~mad(net1, z=4.5)  # make fit more robust by removing outliers
            if (np.ptp(tt[iii]) >= 5.) & (np.sum(mm) > 6):
                # print(i)
                #p     = opt.fmin(functions.cost_lloyd_fix, [2.,200.], args=(tt1[mm], net1[mm]), disp=False) # robust params

                p, temp1, temp2 = opt.fmin_tnc(functions.cost_lloyd_fix,
                                               [2., 200.],
                                               bounds=[[0., None], [0., None]],
                                               args=(tt1[mm], net1[mm]),
                                               approx_grad=True,
                                               disp=False)

                try:
                    p1, c = opt.curve_fit(functions.lloyd_fix,
                                          tt1[mm],
                                          net1[mm],
                                          p0=p,
                                          maxfev=10000)  # params, covariance
                    if np.all(np.isfinite(
                            c)):  # possible return of curvefit: c=inf
                        s = np.sqrt(np.diag(c))
                    else:
                        s = 10. * np.abs(p)
                except:
                    s = 10. * np.abs(p)
                locp += [p]
                locs += [s]
                # if ((s[1]/p[1])<0.5) & (p[1] > 0.): pdb.set_trace()
    if len(locp) == 0:
        raise ValueError(
            'Error nee2gpp_reichstein: No local relationship found.')
        print('Warning nee2gpp_reichstein: No local relationship found.')
        if masked:
            GPP = np.ma.array(np.reshape(nee, inshape),
                              mask=np.ones(inshape, dtype=bool))
            Reco = np.ma.array(np.reshape(nee, inshape),
                               mask=np.ones(inshape, dtype=bool))
        else:
            GPP = np.ones(np.reshape(nee, inshape)) * undef
            Reco = np.ones(np.reshape(nee, inshape)) * undef
        return GPP, Reco
    locp = np.squeeze(np.array(locp).astype(float))
    locs = np.squeeze(np.array(locs).astype(float))
    # 2. E0 = avg of best 3
    # Reichstein et al. (2005), p. 1430, 1st paragraph.
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        iii = np.where((locp[:, 1] > 0.) & (locp[:, 1] < 450.)
                       & (np.abs(locs[:, 1] / locp[:, 1]) < 0.5))[0]
    niii = iii.size
    if niii == 0:
        # raise ValueError('Error nee2gpp_reichstein: No good local relationship found.')
        # loosen the criteria: take the best three estimates anyway
        iii = np.where((locp[:, 1] > 0.))[0]
        niii = iii.size
        if niii < 1:
            raise ValueError('Error nee2gpp_reichstein: No E0>0 found.')
            print('Warning nee2gpp_reichstein: No E0>0 found.')
            if masked:
                GPP = np.ma.array(np.reshape(nee, inshape),
                                  mask=np.ones(inshape, dtype=bool))
                Reco = np.ma.array(np.reshape(nee, inshape),
                                   mask=np.ones(inshape, dtype=bool))
            else:
                GPP = np.ones(np.reshape(nee, inshape)) * undef
                Reco = np.ones(np.reshape(nee, inshape)) * undef
            return GPP, Reco
        lp = locp[iii, :]
        ls = locs[iii, :]
        iis = np.argsort(ls[:, 1])
        bestp = np.mean(lp[iis[0:np.minimum(3, niii)], :], axis=0)
        bests = np.mean(ls[iis[0:np.minimum(3, niii)], :], axis=0)
    elif niii == 1:
        bestp = np.squeeze(locp[iii, :])
        bests = np.squeeze(locs[iii, :])
    elif niii == 2:
        bestp = np.mean(locp[iii, :], axis=0)
        bests = np.mean(locs[iii, :], axis=0)
        # ls    = locs[iii,:]
        # iis   = np.argsort(ls[:,1])
    else:
        lp = locp[iii, :]
        ls = locs[iii, :]
        iis = np.argsort(ls[:, 1])
        bestp = np.mean(lp[iis[0:3], :], axis=0)
        bests = np.mean(ls[iis[0:3], :], axis=0)

    # 3. Refit Rref with fixed E0, each 4 days
    refp = []  # Rref param
    refii = []  # mean index of data points
    E0 = bestp[1]
    et = functions.lloyd_fix(tt, 1., E0)
    for i in range(dmin, dmax, 4):
        iii = np.where((jul >= i) & (jul < (i + 4)))[0]
        niii = iii.size
        if niii > 3:
            # Calc directly minisation of (nee-p*et)**2
            # p = np.sum(net[iii]*et[iii])/np.sum(et[iii]**2)
            # p, c = opt.curve_fit(functions.lloyd_only_rref, et[iii], net[iii], p0=[2.])
            #p      = opt.fmin(functions.cost_lloyd_only_rref, [2.], args=(et[iii], net[iii]), disp=False)
            #p = opt.fmin(functions.cost_abs, [2.], args=(functions.lloyd_only_rref_p, et[iii], net[iii]), disp=False)

            p, temp1, temp2 = opt.fmin_tnc(functions.cost_abs, [2.],
                                           bounds=[[0., None]],
                                           args=(functions.lloyd_only_rref_p,
                                                 et[iii], net[iii]),
                                           approx_grad=True,
                                           disp=False)

            refp += [p]
            refii += [int((iii[0] + iii[-1]) // 2)]
    if len(refp) == 0:
        raise ValueError(
            'Error nee2gpp_reichstein: No ref relationship found.')
        print('Warning nee2gpp_reichstein: No ref relationship found.')
        if masked:
            GPP = np.ma.array(np.reshape(nee, inshape),
                              mask=np.ones(inshape, dtype=bool))
            Reco = np.ma.array(np.reshape(nee, inshape),
                               mask=np.ones(inshape, dtype=bool))
        else:
            GPP = np.ones(np.reshape(nee, inshape)) * undef
            Reco = np.ones(np.reshape(nee, inshape)) * undef
        return GPP, Reco
    refp = np.squeeze(np.array(refp))
    refii = np.squeeze(np.array(refii))

    # 4. Interpol Rref
    Rref = np.interp(dates, jul[refii], refp)

    # 5. Calc Reco
    Reco = np.ones(ndata) * undef
    ii = np.where(~t.mask)[0]
    Reco[ii] = functions.lloyd_fix(t[ii], Rref[ii], E0)

    # 6. Calc GPP
    GPP = np.ones(ndata) * undef
    ii = np.where(~(t.mask | nee.mask))[0]
    GPP[ii] = Reco[ii] - nee[ii]

    # 7. Set GPP=0 at night, if wanted
    if nogppnight:
        mask = isday | nee.mask | t.mask | isday.mask  # night
        ii = np.where(~mask)[0]
        Reco[ii] = nee[ii]
        GPP[ii] = 0.
        # and prohibit negative gpp at any time
        mask = nee.mask | t.mask | (GPP > 0.)
        ii = np.where(~mask)[0]
        Reco[ii] -= GPP[ii]
        GPP[ii] = 0.

    if masked:
        if np.isnan(undef):
            GPP = np.ma.array(GPP, mask=np.isnan(GPP))
            Reco = np.ma.array(Reco, mask=np.isnan(Reco))
        else:
            GPP = np.ma.array(GPP, mask=(GPP == undef))
            Reco = np.ma.array(Reco, mask=(Reco == undef))

    return GPP.reshape(inshape), Reco.reshape(inshape)
예제 #2
0
def nee2gpp_lasslop(dates,
                    nee,
                    t,
                    isday,
                    rg,
                    vpd,
                    undef=np.nan,
                    shape=False,
                    masked=False,
                    nogppnight=False):
    """
        Calculate photosynthesis (GPP) and ecosystem respiration (Reco) from original
        Eddy flux data, using the daytime method of Lasslop et al. (2010),
        in order to calculate Reco and then GPP = Reco - NEE.


        Definition
        ----------
        def nee2gpp_lasslop(dates, nee, t, isday, rg, vpd, undef=np.nan,
                    shape=False, masked=False):


        Input
        -----
        Inputs are 1D arrays that can be masked or not.
        dates         julian days
        nee           net ecosystem exchange (uptake is <0) [umol m-2 s-1]
        t             temperature [K]
        rg            global radiation, i.e. shortwave down [W m-2]
        vpd           vapour pressure deficit [Pa]


        Parameters
        ----------
        undef        undefined values in data  (default: np.nan)
                     Input arrays will be masked at undef, keeping the original mask
        shape        if False then outputs are 1D arrays;
                     if True, output have the same shape as datain
                     if a shape tuple is given, then this tuple is used to reshape
        masked       if False: outputs are undef where nee and t are masked or undef
                     if True:  return masked arrays where outputs would be undef
        nogppnight   if True:  Resp=NEE, GPP=0 at night
                     if False: Resp=lloyd_taylor, GPP=Resp-NEE at night (default)


        Ouput
        -----
        GPP, Reco    photosynthesis, ecosystem respiration


        Restrictions
        ------------
        None.


        Literature
        ----------
        Lasslop et al. (2010)
            Separation of net ecosystem exchange into assimilation and respiration using
            a light response curve approach: critical issues and global evaluation
            Global Change Biology 16, 187-208


        Examples
        --------
        >>> from jams.fread import fread # from jams
        >>> from jams.date2dec import date2dec # from jams
        >>> dat   = fread('test_nee2gpp.csv', skip=2, transpose=True)
        >>> dates = date2dec(dy=dat[0,:], mo=dat[1,:], yr=dat[2,:], hr=dat[3,:], mi=dat[4,:])
        >>> NEE   = np.squeeze(dat[5,:])
        >>> rg    = np.squeeze(dat[6,:])
        >>> tair  = np.squeeze(dat[7,:])
        >>> undef = -9999.
        >>> isday = np.where(rg > 10., True, False)
        >>> tt    = np.where(tair == undef, undef, tair+273.15)
        >>> VPD = np.squeeze(dat[8,:])
        >>> vpd = np.where(VPD == undef, undef, VPD*100.)
        >>> # partition
        >>> GPP, Reco = nee2gpp(dates, NEE, tt, isday, rg, vpd, undef=undef, method='day')
        >>> print(GPP[1120:1128])
        [-9.99900000e+03 -9.99900000e+03 -9.99900000e+03  2.78457540e+00
          6.63212545e+00  8.88902165e+00  6.74243873e+00  9.51364527e+00]
        >>> print(Reco[1120:1128])
        [0.28786696 0.34594516 0.43893276 0.5495954  0.70029545 0.90849165
         1.15074873 1.46137527]


        License
        -------
        This file is part of the JAMS Python package, distributed under the MIT
        License. The JAMS Python package originates from the former UFZ Python library,
        Department of Computational Hydrosystems, Helmholtz Centre for Environmental
        Research - UFZ, Leipzig, Germany.

        Copyright (c) 2012-2013 Matthias Cuntz, Arndt Piayda - mc (at) macu (dot) de

        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.


        History
        -------
        Written  MC, Mar 2012
        Modified AP, Mar 2012 - undef=np.nan
                 MC, Nov 2012 - individual routine
                 MC, Feb 2013 - ported to Python 3
    """

    # Checks

    # remember shape if any
    inshape = nee.shape
    dates = np.squeeze(dates)
    nee = np.squeeze(nee)
    t = np.squeeze(t)
    isday = np.squeeze(isday)
    # Check squeezed shape
    if dates.ndim != 1:
        raise ValueError(
            'Error nee2gpp_lasslop: squeezed dates must be 1D array.')
    if nee.ndim != 1:
        raise ValueError(
            'Error nee2gpp_lasslop: squeezed nee must be 1D array.')
    if t.ndim != 1:
        raise ValueError('Error nee2gpp_lasslop: squeezed t must be 1D array.')
    if isday.ndim != 1:
        raise ValueError(
            'Error nee2gpp_lasslop: squeezed isday must be 1D array.')
    ndata = dates.size
    if ((nee.size != ndata) | (t.size != ndata) | (isday.size != ndata)):
        raise ValueError(
            'Error nee2gpp_lasslop: inputs must have the same size.')
    if rg.ndim != 1:
        raise ValueError(
            'Error nee2gpp_lasslop: squeezed rg must be 1D array.')
    if vpd.ndim != 1:
        raise ValueError(
            'Error nee2gpp_lasslop: squeezed vpd must be 1D array.')
    if ((rg.size != ndata) | (vpd.size != ndata)):
        raise ValueError(
            'Error nee2gpp_lasslop: lasslop inputs must have the same size as other inputs.'
        )

    # Transform to masked array with 1D mask
    nee = np.ma.array(nee, mask=False)
    t = np.ma.array(t, mask=False)
    isday = np.ma.array(isday, mask=False)
    rg = np.ma.array(rg, mask=False)
    vpd = np.ma.array(vpd, mask=False)
    # mask also undef
    if np.isnan(undef):
        if np.ma.any(np.isnan(nee)): nee[np.isnan(nee)] = np.ma.masked
        if np.ma.any(np.isnan(t)): t[np.isnan(t)] = np.ma.masked
        if np.ma.any(np.isnan(isday)): isday[np.isnan(isday)] = np.ma.masked
        if np.ma.any(np.isnan(rg)): rg[np.isnan(rg)] = np.ma.masked
        if np.ma.any(np.isnan(vpd)): vpd[np.isnan(vpd)] = np.ma.masked
    else:
        if np.ma.any(nee == undef): nee[nee == undef] = np.ma.masked
        if np.ma.any(t == undef): t[t == undef] = np.ma.masked
        if np.ma.any(isday == undef): isday[isday == undef] = np.ma.masked
        if np.ma.any(rg == undef): rg[rg == undef] = np.ma.masked
        if np.ma.any(vpd == undef): vpd[vpd == undef] = np.ma.masked

    # Partition - Lasslop et al. (2010) method
    do_lgpp = False
    mask = nee.mask | t.mask | isday.mask | rg.mask | vpd.mask
    # night
    nmask = isday | mask
    nii = np.squeeze(np.where(~nmask))
    njul = dates[nii]
    ntt = np.ma.compressed(t[nii])
    nnet = np.ma.compressed(nee[nii])
    aRref = np.mean(nnet)
    # day
    dmask = (~isday) | mask
    dii = np.squeeze(np.where(~dmask))
    djul = dates[dii]
    dtt = np.ma.compressed(t[dii])
    dnet = np.ma.compressed(nee[dii])
    drg = np.ma.compressed(rg[dii])
    dvpd = np.ma.compressed(vpd[dii])
    # starting values for optim
    aalpha = 0.01
    qnet = np.sort(dnet)
    nqnet = qnet.size
    abeta0 = np.abs(qnet[np.floor(0.97 * nqnet).astype(int)] -
                    qnet[np.ceil(0.03 * nqnet).astype(int)])
    ak = 0.
    # out
    lE0 = []
    lalpha = []
    if do_lgpp:
        lbeta0 = []
        lk = []
    lRref = []
    lii = []
    dmin = np.floor(np.amin(dates)).astype(int)
    dmax = np.ceil(np.amax(dates)).astype(int)
    zaehl = -1
    for i in range(dmin, dmax, 2):
        good = True
        # 1. Estimate E0 from nighttime data
        iii = np.squeeze(np.where((njul >= i) & (njul < (i + 12))))
        niii = iii.size
        if niii > 3:
            # p, c = opt.curve_fit(functions.lloyd_fix, ntt[iii], nnet[iii], p0=[aRref,100.])
            #p  = opt.fmin(functions.cost_lloyd_fix, [aRref,100.], args=(ntt[iii], nnet[iii]), disp=False)
            #p  = opt.fmin(functions.cost_abs, [aRref,100.], args=(functions.lloyd_fix_p, ntt[iii], nnet[iii]), disp=False)
            p, temp1, temp2 = opt.fmin_tnc(functions.cost_abs, [aRref, 100.],
                                           bounds=[[0., None], [0., None]],
                                           args=(functions.lloyd_fix_p,
                                                 ntt[iii], nnet[iii]),
                                           approx_grad=True,
                                           disp=False)

            E0 = np.maximum(p[1], 50.)
        else:
            if zaehl >= 0:
                E0 = lE0[zaehl]
            else:
                # large gap at beginning of data set, i.e. skip the period
                good = False
                continue
        # 2. Estimate alpha, k, beta0, Rref from daytime data
        iii = np.squeeze(np.where((djul >= i) & (djul < (i + 4))))
        niii = iii.size
        if niii > 3:
            et = functions.lloyd_fix(dtt[iii], 1., E0)
            again = True
            ialpha = aalpha
            ibeta0 = abeta0
            ik = ak
            iRref = aRref
            bounds = [[None, None], [None, None], [None, None], [None, None]]
            while again:
                again = False
                p, nfeval, rc = opt.fmin_tnc(functions.cost_lasslop,
                                             [ialpha, ibeta0, ik, iRref],
                                             bounds=bounds,
                                             args=(drg[iii], et, dvpd[iii],
                                                   dnet[iii]),
                                             approx_grad=True,
                                             disp=False)

                # if parameters beyond some bounds, set params and redo the optim or skip
                if ((p[0] < 0.) | (p[0] > 0.22)):  # alpha
                    again = True
                    if zaehl >= 0:
                        bounds[0] = [lalpha[zaehl], lalpha[zaehl]]
                        ialpha = lalpha[zaehl]
                    else:
                        bounds[0] = [0., 0.]
                        ialpha = 0.
                if p[1] < 0.:  # beta0
                    bounds[1] = [0., 0.]
                    ibeta0 = 0.
                    again = True
                if p[1] > 250.:
                    good = False
                    continue
                if p[2] < 0.:  # k
                    bounds[2] = [0., 0.]
                    ik = 0.
                    again = True
                if p[3] < 0:  # Rref
                    good = False
                    continue
            if good:
                lalpha = lalpha + [p[0]]
                if do_lgpp:
                    lbeta0 = lbeta0 + [p[1]]
                    lk = lk + [p[2]]
                lRref = lRref + [p[3]]
                lii = lii + [int((iii[0] + iii[-1]) / 2)]
            else:
                continue
        else:
            continue
        lE0 = lE0 + [E0]
        zaehl += 1
    if len(lE0) == 0:
        raise ValueError('Error nee2gpp_lasslop: No day relationship found.')
    lE0 = np.squeeze(np.array(lE0))
    if do_lgpp:
        lalpha = np.squeeze(np.array(lalpha))
        lbeta0 = np.squeeze(np.array(lbeta0))
        lk = np.squeeze(np.array(lk))
    lRref = np.squeeze(np.array(lRref))
    lii = np.squeeze(np.array(lii))

    # 3. Interpol E0 and Rref
    E0 = np.interp(dates, djul[lii], lE0)
    Rref = np.interp(dates, djul[lii], lRref)

    # 4. Calc Reco
    Reco = np.ones(ndata) * undef
    ii = np.squeeze(np.where(~t.mask))
    Reco[ii] = functions.lloyd_fix(t[ii], Rref[ii], E0[ii])

    # 5. Calc GPP from light response for check
    if do_lgpp:
        alpha = np.interp(dates, djul[lii], lE0)
        beta0 = np.interp(dates, djul[lii], lbeta0)
        k = np.interp(dates, djul[lii], lk)
        et = functions.lloyd_fix(t, 1., E0)
        lmask = t.mask | isday.mask | rg.mask | vpd.mask
        ii = np.squeeze(np.where(~lmask))
        lgpp = np.zeros(ndata)
        lgpp[ii] = functions.lasslop(rg[ii], et[ii], vpd[ii], alpha[ii],
                                     beta0[ii], k[ii], Rref[ii]) - Reco[ii]

    # 6. GPP
    GPP = np.ones(ndata) * undef
    ii = np.squeeze(np.where(~(t.mask | nee.mask)))
    GPP[ii] = Reco[ii] - nee[ii]

    # 7. Set GPP=0 at night, if wanted
    if nogppnight:
        mask = isday | nee.mask | t.mask | isday.mask  # night
        ii = np.where(~mask)[0]
        Reco[ii] = nee[ii]
        GPP[ii] = 0.
        # and prohibit negative gpp at any time
        mask = nee.mask | t.mask | (GPP > 0.)
        ii = np.where(~mask)[0]
        Reco[ii] -= GPP[ii]
        GPP[ii] = 0.

    if masked:
        if np.isnan(undef):
            GPP = np.ma.array(GPP, mask=np.isnan(GPP))
            Reco = np.ma.array(Reco, mask=np.isnan(Reco))
        else:
            GPP = np.ma.array(GPP, mask=(GPP == undef))
            Reco = np.ma.array(Reco, mask=(Reco == undef))

    if shape != False:
        if shape != True:
            return np.reshape(GPP, shape), np.reshape(Reco, shape)
        else:
            return np.reshape(GPP, inshape), np.reshape(Reco, inshape)
    else:
        return GPP, Reco
예제 #3
0
def nee2gpp_falge(dates,
                  nee,
                  t,
                  isday,
                  undef=np.nan,
                  shape=False,
                  masked=False):
    """
        Calculate photosynthesis (GPP) and ecosystem respiration (Reco) from original
        Eddy flux data, using a fit of Reco vs. temperature to all nighttime data,
        in order to calculate Reco and then GPP = Reco - NEE.


        Definition
        ----------
        def nee2gpp_falge(dates, nee, t, isday, undef=np.nan, shape=False, masked=False):


        Input
        -----
        Inputs are 1D arrays that can be masked or not.
        dates         julian days
        nee           net ecosystem exchange (uptake is <0) [umol m-2 s-1]
        t             temperature [K]


        Parameters
        ----------
        undef        undefined values in data  (default: np.nan)
                     Input arrays will be masked at undef, keeping the original mask
        shape        if False then outputs are 1D arrays;
                     if True, output have the same shape as datain
                     if a shape tuple is given, then this tuple is used to reshape
        masked       if False: outputs are undef where nee and t are masked or undef
                     if True:  return masked arrays where outputs would be undef


        Ouput
        -----
        GPP, Reco    photosynthesis, ecosystem respiration


        Restrictions
        ------------
        None.


        Literature
        ----------
        Falge et al. (2001)
            Gap filling strategies for defensible annual sums of net ecosystem exchange
            Acricultural and Forest Meteorology 107, 43-69


        Examples
        --------
        >>> from jams.fread import fread # from jams
        >>> from jams.date2dec import date2dec # from jams
        >>> dat   = fread('test_nee2gpp.csv', skip=2, transpose=True)
        >>> dates = date2dec(dy=dat[0,:], mo=dat[1,:], yr=dat[2,:], hr=dat[3,:], mi=dat[4,:])
        >>> NEE   = np.squeeze(dat[5,:])
        >>> rg    = np.squeeze(dat[6,:])
        >>> tair  = np.squeeze(dat[7,:])
        >>> undef = -9999.
        >>> isday = np.where(rg > 10., True, False)
        >>> tt    = np.where(tair == undef, undef, tair+273.15)
        >>> # partition
        >>> GPP, Reco = nee2gpp(dates, NEE, tt, isday, undef=undef, method='global')
        >>> print(GPP[1120:1128])
        [-9.99900000e+03 -9.99900000e+03 -9.99900000e+03  4.33166157e+00
          8.18228013e+00  1.04092252e+01  8.19395317e+00  1.08427448e+01]


        License
        -------
        This file is part of the JAMS Python package, distributed under the MIT
        License. The JAMS Python package originates from the former UFZ Python library,
        Department of Computational Hydrosystems, Helmholtz Centre for Environmental
        Research - UFZ, Leipzig, Germany.

        Copyright (c) 2012-2013 Matthias Cuntz, Arndt Piayda - mc (at) macu (dot) de

        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:

        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.


        History
        -------
        Written  MC, Mar 2012
        Modified AP, Mar 2012 - undef=np.nan
                 MC, Nov 2012 - individual routine
                 MC, Feb 2013 - ported to Python 3
    """

    # Checks

    # remember shape if any
    inshape = nee.shape
    dates = np.squeeze(dates)
    nee = np.squeeze(nee)
    t = np.squeeze(t)
    isday = np.squeeze(isday)
    # Check squeezed shape
    if dates.ndim != 1:
        raise Error('Error nee2gpp_falge: squeezed dates must be 1D array.')
    if nee.ndim != 1:
        raise Error('Error nee2gpp_falge: squeezed nee must be 1D array.')
    if t.ndim != 1:
        raise Error('Error nee2gpp_falge: squeezed t must be 1D array.')
    if isday.ndim != 1:
        raise Error('Error nee2gpp_falge: squeezed isday must be 1D array.')
    ndata = dates.size
    if ((nee.size != ndata) | (t.size != ndata) | (isday.size != ndata)):
        raise Error('Error nee2gpp_falge: inputs must have the same size.')

    # Transform to masked array with 1D mask
    nee = np.ma.array(nee, mask=False)
    t = np.ma.array(t, mask=False)
    isday = np.ma.array(isday, mask=False)
    # mask also undef
    if np.isnan(undef):
        if np.ma.any(np.isnan(nee)): nee[np.isnan(nee)] = np.ma.masked
        if np.ma.any(np.isnan(t)): t[np.isnan(t)] = np.ma.masked
        if np.ma.any(np.isnan(isday)): isday[np.isnan(isday)] = np.ma.masked
    else:
        if np.ma.any(nee == undef): nee[nee == undef] = np.ma.masked
        if np.ma.any(t == undef): t[t == undef] = np.ma.masked
        if np.ma.any(isday == undef): isday[isday == undef] = np.ma.masked

    # Partition - Global relationship as in Falge et al. (2001)

    # Select valid nighttime
    mask = isday | nee.mask | t.mask | isday.mask
    ii = np.where(~mask)[0]
    tt = np.ma.compressed(t[ii])
    net = np.ma.compressed(nee[ii])
    # p, c     = opt.curve_fit(functions.lloyd_fix, tt, net, p0=[2.,200.]) # global parameter, global cov matrix
    #p        = opt.fmin(functions.cost_lloyd_fix, [2.,200.], args=(tt, net), disp=False)
    p = opt.fmin(functions.cost_abs, [2., 200.],
                 args=(functions.lloyd_fix_p, tt, net),
                 disp=False)

    Reco = np.ones(ndata) * undef
    ii = np.where(~t.mask)[0]
    Reco[ii] = functions.lloyd_fix(t[ii], p[0], p[1])

    # GPP
    GPP = np.ones(ndata) * undef
    ii = np.where(~(t.mask | nee.mask))[0]
    GPP[ii] = Reco[ii] - nee[ii]

    # Return
    if masked:
        if np.isnan(undef):
            GPP = np.ma.array(GPP, mask=np.isnan(GPP))
            Reco = np.ma.array(Reco, mask=np.isnan(Reco))
        else:
            GPP = np.ma.array(GPP, mask=(GPP == undef))
            Reco = np.ma.array(Reco, mask=(Reco == undef))

    if shape != False:
        if shape != True:
            return np.reshape(GPP, shape), np.reshape(Reco, shape)
        else:
            return np.reshape(GPP, inshape), np.reshape(Reco, inshape)
    else:
        return GPP, Reco