The rate of photosynthesis is determined by light, CO2, and the temperature-dependent kinetics of the enzyme whose nickname is *rubisco*, represented here according to the model first described by Farquahr et al (1980) and described in Denning (1993) and Bonan 2008.

We *choose the smallest of three potential rates* of carboxylation: \(w_c\) (limited by CO2 and rubisco), \(w_j\) (limited by light and electron transport), and \(w_s\) (limited by accumulating starch at the chloroplast). Following Bonan (2008, page 246), these three limiting rates are written as

\[w_c = \frac{V_{max} (c_i - \Gamma_*)}{c_i+K_c(1+O_i/K_o)}\]

\[w_j = \frac{J(c_i - \Gamma_*)}{4(c_i + 2 \Gamma_*)}\]

\[w_s = V_{max} / 2 \]

where \(c_i\) is the partial pressure (in Pascals, roughly ppmv/10) of \(CO_2\) in the leaf chloroplast or intercellular fluid, \(\Gamma_*\) is the \(CO_2\) compensation point (Pascals), \(O_i\) is the partial pressure of oxygen (assumed to be the same as ambient air, 0.209 \(p_{sfc}\)), and \(K_C\) and \(K_o\) are Michaelis-Menten coefficients (Pascals) for carboxylation and oxidation reactions catalyzed by rubisco.

The potential rate of electron transport (*J*, \(\mu\) mol electrons m\(^{-2}\) s\(^{-1}\)) depends on the amount of photosynthetically-active radiation absorbed by the leaf (\(\phi\), \(\mu\) mol photons m\(^{-2}\) s\(^{-1}\))) and is determined as the smaller of the two roots of the equation

\[ 0.7 J^2 - (J_{max} + 0.385 \phi)J + 0.385 J_{max} \phi = 0 \]

where \(J_{max}\) is the maximum rate of electron transport (\(\mu\) mol electrons m\(^{-2}\) s\(^{-1}\)), which depends on the amount of leaf chlorophyll. The maximum rate of carboxylation \(V_{max}, \mu\) mol CO\(_2\) m\(^{-2}\) s\(^{-1}\)) is proportional to the amount of rubisco in the leaf. Because both rubisco and chlorophyll contain a lot of nitrogen, the parameters \(V_{max}\) and \(J_{max}\) depend critically on the bioavailable nitrogen obtained by the plant during the growth of the leaves.

All the parameters \(K_C\), \(K_o\), \(V_{max}\), and \(J_{max}\) also depend on temperature.

The program that does the calculation is very simple, and the code that controls this website is surprisingly simple too! It is all written in the programming language R, using a web programming package called shiny. You can read all about it on the “**Website Code**” tab to the right.

This website is controlled using the R package “shiny.” There are five important components:

- A script (farquhar.R) that contains the enzyme-kinetic model
- A script (plot.light.response.R) that plots photosynthesis vs light
- A script (plot.CO2.response.R) that plots photosynthesis vs CO2
- The user interface (ui.R) that controls the sliders and passes inputs to the model
- The “server” (server.R) that responds to user interface events in the web browser

Scroll down or click links in the list above to read all about it!

**farquhar.R:**

```
farquhar <- function(V.max=50, J.max=100, APAR=500, c.i=30) {
# Model inputs:
# V.max = maximum rubisco-limited rate in micromoles per (m^2 sec)
# J.max = maximum light-limited rate in micromoles per (m^2 sec)
# APAR = absorbed photosynthetically-active radiation in micromoles per (m^2 sec)
# c.i = intercellular CO2 partial pressure in Pascals (roughly ppm/10)
# Some local parameters we need
p.sfc <- 101325 # surface air pressure (Pascals)
gamma <- 3. # CO2 compensation point (Pascals)
O.i <- 0.209 * p.sfc # oxygen partial pressure in chloroplast
K.c <- 30 # Michaelis-Menten constant for carboxylation (Pascals)
K.o <- 30000 # Michaelis-Menten constant for oxidation (Pascals)
# Solution of quadratic (Bonan 17.8)
a <- 0.7
b <- -(J.max + 0.385 * APAR)
c <- 0.385 * J.max * APAR
J.1 <- (-b + sqrt(b^2 - 4 * a * c) ) / (2 * a)
J.2 <- (-b - sqrt(b^2 - 4 * a * c) ) / (2 * a)
J <- min(J.1, J.2)
# Rubisco-limited rate of photosynthesis
w.c <- V.max * (c.i - gamma) / (c.i + K.c * (1 + O.i/K.o)) # Bonan 17.6
# Light-limited rate of photosynthesis
w.j <- J * (c.i - gamma) / (4 * (c.i + 2 * gamma)) # Bonan 17.7
# Sink-limited rate of photosynthesis
w.s <- V.max / 2
# Dark respiration
R.d <- 0.015 * V.max
# Net assimilation
A.n <- min(w.c, w.j, w.s)-R.d
return(A.n)
}
```

**plot.light.response.R:**

```
plot.light.response <- function(V.max=50, J.max=100, c.i=30) {
A.n <- replicate(100, NA)
light <- replicate(100, NA)
for (i in 1:100) {
light[i] <- 10 * i
A.n[i] <- farquhar(V.max=V.max, J.max=J.max, c.i=30, APAR=light[i])
}
orig.par <- par(no.readonly=TRUE)
par(mar=c(5,5,4,2)+0.1)
plot(light, A.n, main='Light Response of Photosynthesis',
xlab=expression(paste('PPFD (',mu, 'mol photons ',m^{-2},s^{-1},')')),
ylab=expression(paste(mu, 'mol ', CO[2], ' ',m^{-2}, s^{-1},)),
cex.main=2, cex.axis=1.5, cex.lab=1.5)
par(orig.par)
}
```

**plot.CO2.response.R:**

```
plot.CO2.response <- function(V.max=50, J.max=100, APAR=500) {
A.n <- replicate(100, NA)
CO2 <- replicate(100, NA)
for (i in 1:100) {
CO2[i] <- 10 * i
A.n[i] <- farquhar(V.max=V.max, J.max=J.max, c.i=CO2[i]/10, APAR=500)
}
orig.par <- par(no.readonly=TRUE)
par(mar=c(5,5,4,2)+0.1)
plot(CO2, A.n, main='CO2 Response of Photosynthesis', xlab='Intercellular CO2 (ppm)',
ylab=expression(paste(mu, 'mol ', CO[2], ' ',m^{-2}, s^{-1},)),
cex.main=2, cex.axis=1.5, cex.lab=1.5)
par(orig.par)
}
```

**ui.R:**

```
library(shiny)
library(markdown)
library(knitr)
# Define user interface for logistic growth model
shinyUI(pageWithSidebar(
# Application title
headerPanel("Farquhar Photosynthesis Model"),
# Sidebar on the left with controls for the user to specify atmospheric properties
sidebarPanel(
img(src='psoverview.gif'),
h4('Set Models Parameter Below'),
# Set drainage times for each pool
sliderInput("V.max", "V.max: Maximum Rubisco-limited rate (micromoles per (m^2 sec))",
min = 1, max = 150, value = 50, step= 1),
sliderInput("J.max", "J.max: Maximum light-limited rate (micromoles per (m^2 sec))",
min = 1, max = 300, value = 100, step= 1),
sliderInput("temp", "Temperature (Celsius)",
min = 1, max = 50, value = 25, step=1)
),
# Show a tabset in the main panel of the browser that displays model output
mainPanel(
tabsetPanel(
# First tab shows plots of assimilation rate vs light and CO2
tabPanel("Output",
h4('Photosynthetic Responses'),
plotOutput('light.response.plot'),
plotOutput('CO2.response.plot')),
# Second tab displays a brief model description
tabPanel("Model Description",
includeHTML('doc/model.description.html')),
# Third tab displays website code
tabPanel("Website code",
includeMarkdown('doc/website.code.md'))
)
)
))
```

**server.R:**

```
library(shiny)
# Source required R scripts
source('model/farquhar.R')
source('model/plot.light.response.R')
source('model/plot.CO2.response.R')
shinyServer(function(input, output) {
# plot of model output
output$light.response.plot <- renderPlot(
plot.light.response(V.max=input$V.max, J.max=input$J.max))
output$CO2.response.plot <- renderPlot(
plot.CO2.response(V.max=input$V.max, J.max=input$J.max))
})
```