9  非直角双曲线模型

Thornley (1976) 提出了非直角双曲线模型,它的表达式为:

P_{n} = \frac{\alpha I + P_{nmax} \sqrt{(\alpha I + P_{nmax})^{2} - 4 \theta \alpha I P_{nmax}}}{2 \theta} - R_{d} \tag{9.1}

其中,\theta 为表示曲线弯曲程度的曲角参数,取值为0\leq \theta \leq 1。其他参数意义同式 公式  8.1。同样如同直角双曲线模型,式仍然没有极值,无法求得 I_{sat},可以仍然参考直角双曲线模型的方式进行计算。

9.1 非直角双曲线模型的实现

Code
library(minpack.lm)

# 读取数据,同fitaci数据格式
lrc <- read.csv("data/lrc.csv")
lrc <- subset(lrc, Obs > 0)

# 光响应曲线没有太多参数,
# 直接调出相应的光强和光合速率
# 方便后面调用
lrc_Q <- lrc$PARi
lrc_A <- lrc$Photo 

# 非直角双曲线模型的拟合
lrcnls <- nlsLM(lrc_A ~ 
                (1/(2*theta))*
                (alpha*lrc_Q+Am-sqrt((alpha*lrc_Q+Am)^2 - 
                4*alpha*theta*Am*lrc_Q))- Rd,
                start=list(Am=(max(lrc_A)-min(lrc_A)),
                alpha=0.05,Rd=-min(lrc_A),theta=1)) 

fitlrc_nrec <- summary(lrcnls)

# 光补偿点
Ic <- function(Ic){
  (1/(2 * fitlrc_nrec$coef[4,1])) * 
    (fitlrc_nrec$coef[2,1] * Ic + fitlrc_nrec$coef[1,1] - 
    sqrt((fitlrc_nrec$coef[2,1] * Ic + fitlrc_nrec$coef[1,1]
    )^2 -  4 * fitlrc_nrec$coef[2,1] * 
    fitlrc_nrec$coef[4,1] * fitlrc_nrec$coef[1,1] * Ic)) -
    fitlrc_nrec$coef[3,1]
}

uniroot(Ic, c(0,50))$root  
[1] 2.234292
Code
# 光饱和点
Isat <- function(Isat){
  (1/(2 * fitlrc_nrec$coef[4,1])) * (fitlrc_nrec$coef[2,1] * 
  Isat + fitlrc_nrec$coef[1,1] - sqrt(
  (fitlrc_nrec$coef[2,1] * Isat +fitlrc_nrec$coef[1,1])^2 - 
  4*fitlrc_nrec$coef[2,1] * fitlrc_nrec$coef[4,1] * 
  fitlrc_nrec$coef[1,1] * Isat)) - 
  fitlrc_nrec$coef[3,1] - (0.9*fitlrc_nrec$coef[1,1])}

uniroot(Isat, c(0,2000))$root
[1] 1596.286
Code
# 使用ggplot2进行作图并拟合曲线
library(ggplot2)
light <- data.frame(lrc_Q = lrc$PARi, lrc_A = lrc$Photo)

nonrec_form <- y ~ 
  (1/(2*theta))*(alpha*x+Am-sqrt((alpha*x+Am)^2 - 
   4*alpha*theta*Am*x))- Rd

ggplot(light, aes(x = lrc_Q, y = lrc_A)) + 
  geom_point(shape = 16, size = 3, color = "green") + 
  geom_smooth(method="nls", formula = nonrec_form, se = FALSE,
  method.args = list(start = c(Am=(max(lrc_A)-min(lrc_A)), 
  alpha=0.05, Rd=-min(lrc_A), theta=1), 
  aes(color='blue', size = 1.2))) +
  labs(y=expression(paste("photosynthetic rate  ", 
          "(", mu, mol%.%m^-2%.%s^-1, ")")), 
       x=expression(paste("PAR ", 
           "(", mu, mol%.%m^-2%.%s^-1, ")"))) +
  theme_light()
Figure 9.1: 非直角双曲线模型拟合
Table 9.1: 非直角双曲线模型结果
Estimate Std. Error t value Pr(>|t|)
Am 15.8017296 0.1513064 104.435285 0.0000000
alpha 0.0658067 0.0020216 32.551422 0.0000000
Rd 0.1461717 0.0420800 3.473659 0.0070082
theta 0.3700908 0.0493403 7.500783 0.0000369

最终的数据拟结果如图 Figure 9.1 所示,拟合的参数及结果见表 Table 9.1。单纯从作图来看,本例数据使用非直角双曲线与散点图重合程度更高。

9.2 利用函数来拟合

上面的方式是手动实现,也并不复杂,phtosynthesisFitAQ 软件包提供了非直角双曲线模型的相应的函数,可以让我们方便的进行处理。

9.2.1 使用 photosynthesis 处理

安装可以通过 CRAN:

Code
install.packages('photosynthesis')

我们看一下 LI-6400 数据的使用:

Code
library(photosynthesis)
fit6400 <- fit_aq_response(lrc, varnames = list(A_net = "Photo", PPFD = "PARi"))

他的拟合结果的查看方式为:

Code
summary(fit6400[[1]])

Formula: A_net ~ aq_response(k_sat, phi_J, Q_abs = data$Q_abs, theta_J) - 
    Rd

Parameters:
                Estimate Std. Error t value Pr(>|t|)    
k_sat          15.801730   0.151306 104.435 3.43e-15 ***
phi_J.Q_abs     0.065807   0.002022  32.551 1.20e-10 ***
theta_J         0.370091   0.049340   7.501 3.69e-05 ***
Rd.(Intercept)  0.146172   0.042080   3.474  0.00701 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.06845 on 9 degrees of freedom

Number of iterations to convergence: 6 
Achieved convergence tolerance: 1.49e-08

除此以外,它还提供了只看拟合结果的方式:

Code
fit6400[[2]]
         A_sat      phi_J   theta_J        Rd      LCP  resid_SSs
k_sat 15.80173 0.06580668 0.3700908 0.1461717 2.234292 0.04216531

他们的意义按顺序为:

  1. 饱和光下的净光合速率 (A_sat),

  2. 表观量子效率 (phi_J),

  3. 曲线的弯曲程度 (theta_J),

  4. 暗呼吸速率 (Rd),

  5. 光补偿点 (LCP),

  6. 残差的平方和 (resid_SS)。

也可以直接输出图形,只不过要想定制化,还要自己做:

Code
fit6400[[3]]

photosynthesis 软件包的非直角双曲线拟合图形查看

如果是 LI-6800,稍微修改一下参数即可,这里不再进行一步一步的演示:

Code
aq6800 <- read.csv("data/lrc6800.csv")
fit6800 <-
  fit_aq_response(aq6800, varnames = list(A_net = "A", PPFD = "Qin"))

9.2.2 使用 FitAQ 处理

安装必须是从 github 安装,当然,如果你和我遇到一样登录 github 困难的话,我把他 fork 到 gitee 上去了:


remotes::install_git("https://gitee.com/zhu_jie_dong/FitAQ")
#或
remotes::install_github("MarkusLoew/FitAQ")

使用也比较方便,默认这样操作就行了:

Code
library(FitAQ)
FitAQ(data = lrc, A = Photo, Q = PARi)
         Amax        phi        Rd     theta
Amax 15.80173 0.06580667 0.1461717 0.3700909

如果觉得不满意,还可以手动调整初值,作者考虑的比较周到:

Code
fit1 <- FitAQ(
  data = lrc,
  A = Photo,
  Q = PARi,
  provide.model = TRUE,
  nlscontrol = c(maxiter = 500),
  start = list(
    Amax = 15,
    phi = 0.06,
    Rd = 0.14,
    theta = 0.3
  ),
  lower = c(12, 0, 0, 0),
  upper = c(17, 0.1, 3, 0.5),
  trace = TRUE
)
  0:     2.6244459:  15.0000 0.0600000 0.140000 0.300000
  1:   0.021848654:  15.7837 0.0658725 0.146820 0.377608
  2:   0.021082662:  15.8019 0.0658089 0.146186 0.370045
  3:   0.021082654:  15.8017 0.0658067 0.146172 0.370090
  4:   0.021082654:  15.8017 0.0658067 0.146172 0.370091
Code
summary(fit1)

Formula: A ~ ((phi * Q + Amax - sqrt((phi * Q + Amax)^2 - 4 * theta * 
    phi * Q * Amax)))/(2 * theta) - Rd

Parameters:
       Estimate Std. Error t value Pr(>|t|)    
Amax  15.801729   0.151306 104.435 3.43e-15 ***
phi    0.065807   0.002022  32.551 1.20e-10 ***
Rd     0.146172   0.042080   3.474  0.00701 ** 
theta  0.370091   0.049340   7.501 3.69e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.06845 on 9 degrees of freedom

Algorithm "port", convergence message: relative convergence (4)
Code
predict_range <- data.frame(Q = seq(from = 0, to = 3000, by = 20))

addline <-
  within(predict_range, A <-
           predict(fit1, newdata = predict_range))
plot(
  Photo ~ PARi,
  data = lrc,
  xlim = c(0, 3000),
  ylim = c(0, 16)
)
lines(A ~ Q, data = addline, col = "blue", lwd = 3.2)

FitAQ 的非直角双曲线拟合

这里需要说明,FitAQ 作者使用的 base R 的语法,而 photosynthesis 则喜欢 ggplot2,这两个谈不上优劣,只是相比而言,photosynthesis 把一些细节都做了,出结果比较省事,但是要做一些定制化图形的时候没有接口,而 FitAQ 则把细节美化留给用户自己来操作,但出基本结果的时候代码量会大一些。定制程度更高一些。

提醒

这里做拟合曲线图形的时候用了一个小技巧,与我 Figure 9.1 所采用的方式完全不同,我的作图实际上是强行把非线性拟合放到 ggplot2 内,而这里不需要拟合过程,只需要参数带入模型,得出数据点来,只要数据点足够密集,我们用线连接所有数据点后,看上去就是一条平滑的曲线,这种方式虽然是欺骗,但是并没有错误,数据点足够密集,我们根本看不出是点还是线来。

饱和点和补偿点的计算也提供了方便的函数:

Code
FitLCP(fit1)
     LCP 
2.234292 
Code
FitSat(fit1)
     LSP 
1455.489 
Code
FitSat(fit1, sat.fac = 0.95, range = c(0, 3200))
     LSP 
2986.574 

饱和点也是使用了达到最大饱和光强多少比例时候的值,带入模型求的光强而得到,例如这里修改后使用了 0.95,看上去结果就不不正常了。

至于 LI-6800 的分析,也是一样,修改光合速率和光合有效辐射两个参数的名称即可:

Code
aq6800 <- read.csv("data/lrc6800.csv")
FitAQ(data = aq6800, A = A, Q = Qin)
         Amax      phi       Rd     theta
Amax 39.05857 0.063463 3.243814 0.7451511

为了减少篇幅,不在展开做过多的介绍,使用方式和上面演示的 LI-6400 一致。