Parameter fitting
The fit method
The package provides methods to the generic fit
function from PlantSimEngine
to calibrate a model with data.
The arguments depends on the methods, but usually takes several parameters:
- the model type, e.g.
FvCB
- a
DataFrame
with the data (depends on the given method) - keyword arguments (also depend on the fit method)
Example with FvCB
A fit method is provided by the package to calibrate the parameters of the FvCB
model (Farquhar et al., 1980).
Here is an example usage from the documentation of the method:
using PlantBiophysics, PlantSimEngine
using DataFrames, Plots
df = read_walz(joinpath(dirname(dirname(pathof(PlantBiophysics))),"test","inputs","data","P1F20129.csv"))
# Removing the Rh and light curves for the fitting because temperature varies
filter!(x -> x.curve != "Rh Curve" && x.curve != "ligth Curve", df)
# Fit the parameter values:
VcMaxRef, JMaxRef, RdRef, TPURef = fit(Fvcb, df; Tᵣ = 25.0)
(VcMaxRef = 46.2467784134993, JMaxRef = 80.36773471227262, RdRef = 0.49949504402060546, TPURef = 5.596944472747526, Tᵣ = 25.0)
Now that our parameters are optimized, we can check how close to the data a simulation would get.
First, let's select only the data used for the CO₂ curve:
# Checking the results:
filter!(x -> x.curve == "CO2 Curve", df)
Now let's re-simulate the assimilation with our optimized parameter values:
leaf =
ModelList(
FvcbRaw(VcMaxRef = VcMaxRef, JMaxRef = JMaxRef, RdRef = RdRef, TPURef = TPURef),
status = (Tₗ = df.Tₗ, aPPFD = df.aPPFD, Cᵢ = df.Cᵢ)
)
run!(leaf)
df_sim = DataFrame(leaf);
Row | aPPFD | Tₗ | Cᵢ | A | timestep |
---|---|---|---|---|---|
Float64 | Float64 | Float64 | Float64 | Int64 | |
1 | 1274.91 | 26.44 | 192.911 | 7.06117 | 1 |
2 | 1274.91 | 26.44 | 193.668 | 7.09454 | 2 |
3 | 1275.0 | 26.38 | 155.41 | 5.3488 | 3 |
4 | 1275.6 | 26.37 | 156.248 | 5.39005 | 4 |
5 | 1274.75 | 26.41 | 113.152 | 3.23804 | 5 |
6 | 1274.91 | 26.45 | 112.554 | 3.2002 | 6 |
7 | 1274.91 | 26.42 | 72.8297 | 1.03639 | 7 |
8 | 1274.91 | 26.42 | 73.0643 | 1.04978 | 8 |
9 | 1274.75 | 26.43 | 51.7086 | -0.20059 | 9 |
10 | 1274.91 | 26.42 | 51.7036 | -0.199125 | 10 |
11 | 1275.34 | 26.38 | 211.703 | 7.8809 | 11 |
12 | 1275.0 | 26.38 | 210.069 | 7.8114 | 12 |
13 | 1274.91 | 26.39 | 210.115 | 7.81245 | 13 |
14 | 1275.6 | 26.37 | 209.925 | 7.80616 | 14 |
15 | 1274.91 | 26.33 | 316.568 | 11.9153 | 15 |
16 | 1274.91 | 26.34 | 315.842 | 11.8904 | 16 |
17 | 1275.0 | 26.35 | 451.148 | 14.4488 | 17 |
18 | 1274.91 | 26.33 | 448.555 | 14.4191 | 18 |
19 | 1274.91 | 26.42 | 575.086 | 15.4166 | 19 |
20 | 1274.15 | 26.42 | 570.874 | 15.3896 | 20 |
21 | 1275.0 | 26.42 | 700.044 | 16.0729 | 21 |
22 | 1274.91 | 26.42 | 695.757 | 16.0537 | 22 |
23 | 1274.91 | 26.42 | 867.609 | 16.245 | 23 |
24 | 1274.15 | 26.44 | 867.318 | 16.2443 | 24 |
25 | 1274.75 | 26.41 | 1067.01 | 16.2453 | 25 |
26 | 1274.91 | 26.39 | 1068.94 | 16.246 | 26 |
27 | 1274.75 | 26.47 | 1273.12 | 16.2433 | 27 |
28 | 1275.6 | 26.47 | 1273.82 | 16.2433 | 28 |
29 | 1274.75 | 26.48 | 1392.7 | 16.243 | 29 |
30 | 1275.6 | 26.45 | 1385.67 | 16.244 | 30 |
Finally, we can make an A-Cᵢ plot using our custom ACi
structure as follows:
aci = PlantBiophysics.ACi(VcMaxRef, JMaxRef, RdRef, df[:,:A], df_sim[:,:A], df[:,:Cᵢ], df_sim[:,:Cᵢ])
plot(aci, leg=:bottomright)
Our simulation fits very closely the observations, nice!
There are another implementation of the FvCB model in our package. One that couples the photosynthesis with the stomatal conductance. And this one computes Cᵢ too. Let's check if it works with this one too by using dummy parameter values for the conductance model:
leaf = ModelList(
Fvcb(VcMaxRef = VcMaxRef, JMaxRef = JMaxRef, RdRef = RdRef, Tᵣ = 25.0, TPURef = TPURef),
Medlyn(0.03, 12.),
status = (Tₗ = df.Tₗ, aPPFD = df.aPPFD, Cₛ = df.Cₐ, Dₗ = 0.1)
)
w = Weather(select(df, :T, :P, :Rh, :Cₐ, :T => (x -> 10) => :Wind))
run!(leaf, w)
df_sim2 = DataFrame(leaf)
aci2 = PlantBiophysics.ACi(VcMaxRef, JMaxRef, RdRef, df[:,:A], df_sim2[:,:A], df[:,:Cᵢ], df_sim2[:,:Cᵢ])
plot(aci2, leg = :bottomright)
We can see the results differ a bit, but it is because we add a lot more computation here, hence adding some degrees of liberty.