Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simple SIF model to photosynthesis #706

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 32 additions & 11 deletions ext/CreateParametersExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Insolation.Parameters.InsolationParameters
import SurfaceFluxes.Parameters.SurfaceFluxesParameters
import SurfaceFluxes.UniversalFunctions as UF
import ClimaParams as CP

import ClimaLand
import ClimaLand.Soil
# Parameter structs
Expand All @@ -15,6 +14,7 @@ import ClimaLand.Soil.EnergyHydrologyParameters
import ClimaLand.Canopy.AutotrophicRespirationParameters
import ClimaLand.Canopy.FarquharParameters
import ClimaLand.Canopy.OptimalityFarquharParameters
import ClimaLand.Canopy.SIFParameters
import ClimaLand.Canopy.MedlynConductanceParameters
import ClimaLand.Canopy.BeerLambertParameters
import ClimaLand.Canopy.TwoStreamParameters
Expand Down Expand Up @@ -133,16 +133,24 @@ toml_dict = CP.create_toml_dict(Float32);
ClimaLand.Canopy.FarquharParameters(toml_dict, ClimaLand.Canopy.C3(); Vcmax25 = 99999999, pc = 444444444)
```
"""
FarquharParameters(
function FarquharParameters(
::Type{FT},
mechanism;
kwargs...,
) where {FT <: AbstractFloat} =
FarquharParameters(CP.create_toml_dict(FT), mechanism; kwargs...)
) where {FT <: AbstractFloat}
sif_parameters = SIFParameters{FT}()
FarquharParameters(
CP.create_toml_dict(FT),
mechanism,
sif_parameters;
kwargs...,
)
end

function FarquharParameters(
toml_dict::CP.AbstractTOMLDict,
mechanism;
mechanism,
sif_parameters;
Vcmax25 = 5e-5,
kwargs...,
)
Expand All @@ -167,9 +175,11 @@ function FarquharParameters(
parameters = CP.get_parameter_values(toml_dict, name_map, "Land")
FT = CP.float_type(toml_dict)
MECH = typeof(mechanism)
return FarquharParameters{FT, MECH}(;
SP = typeof(sif_parameters)
return FarquharParameters{FT, MECH, SP}(;
mechanism,
Vcmax25,
sif_parameters,
parameters...,
kwargs...,
)
Expand Down Expand Up @@ -199,13 +209,19 @@ toml_dict = CP.create_toml_dict(Float32);
ClimaLand.Canopy.OptimalityFarquharParameters(toml_dict; pc = 444444444)
```
"""
OptimalityFarquharParameters(
function OptimalityFarquharParameters(
::Type{FT};
kwargs...,
) where {FT <: AbstractFloat} =
OptimalityFarquharParameters(CP.create_toml_dict(FT); kwargs...)
) where {FT <: AbstractFloat}
sif_parameters = SIFParameters{FT}()
OptimalityFarquharParameters(
CP.create_toml_dict(FT),
sif_parameters;
kwargs...,
)
end

function OptimalityFarquharParameters(toml_dict; kwargs...)
function OptimalityFarquharParameters(toml_dict, sif_parameters; kwargs...)
name_map = (;
:Jmax_activation_energy => :ΔHJmax,
:intercellular_O2_concentration => :oi,
Expand All @@ -229,7 +245,12 @@ function OptimalityFarquharParameters(toml_dict; kwargs...)
params = CP.get_parameter_values(toml_dict, name_map, "Land")
FT = CP.float_type(toml_dict)
mechanism = ClimaLand.Canopy.C3()
return OptimalityFarquharParameters{FT}(; params..., kwargs..., mechanism)
return OptimalityFarquharParameters{FT, typeof(sif_parameters)}(;
sif_parameters,
params...,
kwargs...,
mechanism,
)
end


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function photosynthesis_harvard(;
ΔHΓstar = FT(37830),
ΔHJmax = FT(43540),
ΔHRd = FT(46390),
sif_parameters = SIFParameters{FT}(),
)
return FarquharParameters(
Vcmax25,
Expand All @@ -178,6 +179,7 @@ function photosynthesis_harvard(;
sc,
pc,
mechanism,
sif_parameters,
)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function photosynthesis_ozark(;
ΔHΓstar = FT(37830),
ΔHJmax = FT(43540),
ΔHRd = FT(46390),
sif_parameters = SIFParameters{FT}(),
)
return FarquharParameters(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to pass sif_parameters here? I thought in our methods in CreateParametersExt we have a default which makes the sif_params and uses them

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need it here because it calls the struct, not the function.

Note that we plan to refactor ClimaLandSimulations (with the help of Gabriele), to have it better designed in general, with PFT framework, global simulations... and ready for ClimaCalibrate

Vcmax25,
Expand All @@ -178,6 +179,7 @@ function photosynthesis_ozark(;
sc,
pc,
mechanism,
sif_parameters,
)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function photosynthesis_niwotridge(;
ΔHΓstar = FT(37830),
ΔHJmax = FT(43540),
ΔHRd = FT(46390),
sif_parameters = SIFParameters{FT}(),
)
return FarquharParameters(
Vcmax25,
Expand All @@ -178,6 +179,7 @@ function photosynthesis_niwotridge(;
sc,
pc,
mechanism,
sif_parameters,
)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function photosynthesis_vairaranch(;
ΔHΓstar = FT(37830),
ΔHJmax = FT(43540),
ΔHRd = FT(46390),
sif_parameters = SIFParameters{FT}(),
)
return FarquharParameters(
Vcmax25,
Expand All @@ -178,6 +179,7 @@ function photosynthesis_vairaranch(;
sc,
pc,
mechanism,
sif_parameters,
)
end

Expand Down
2 changes: 2 additions & 0 deletions src/standalone/Vegetation/Canopy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,12 @@ function ClimaLand.make_update_aux(

# Update Rd, An, Vcmax25 (if applicable to model) in place
Vcmax25 = p.canopy.photosynthesis.Vcmax25
SIF = p.canopy.photosynthesis.SIF
update_photosynthesis!(
Rd,
An,
Vcmax25,
SIF,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make these two things independent? Why does update_photosynthesis! needs SIF?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could, it just currently lives in the photosynthesis name space (stored in canopy.photosynthesis.SIF), we thought it was okay for now with a simple model...

Do you suggest making a new canopy output / model, stored in canopy.SIF, in a Vegetation/SIF.jl file? (similar to what we have, photosynthesis.jl, radiation.jl, stomatalconductance.jl, etc.)

If we do, it will be a bit more involved and a breaking change, but it will allow to have multiple SIF modules

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we could do that for a next PR?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I think it should be an independent module. If anything it is a radiative variable and it should live in radiation instead of photosynthesis.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like SIF would be equivalent to APAR. We measure it with a radiometer.

canopy.photosynthesis,
T_canopy,
p.canopy.radiative_transfer.par.abs,
Expand Down
37 changes: 37 additions & 0 deletions src/standalone/Vegetation/canopy_parameterizations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1041,3 +1041,40 @@ function plant_respiration_growth(f2::FT, An::FT, Rpm::FT) where {FT}
Rg = f2 * (An - Rpm)
return Rg
end

# 4 Solar Induced Fluorescence (SIF)

# call function below inside photosynthesis.jl p

"""
compute_SIF_at_a_point(Tc::FT,APAR::FT, Vcmax25::FT)

Computes observed SIF at 755 nm in W/m^2. Note that Tc is in Kelvin, and photo
synthetic rates are in mol/m^2/s, and APAR is in PPFD.
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
"""
function compute_SIF_at_a_point(
APAR::FT,
Tc::FT,
Vcmax25::FT,
R::FT,
photosynthesis_parameters,
) where {FT}

(; ΔHJmax, To, θj, ϕ, sif_parameters) = photosynthesis_parameters
Jmax = max_electron_transport(Vcmax25, ΔHJmax, Tc, To, R)
J = electron_transport(APAR, Jmax, θj, ϕ)
(; kf, kd_p1, kd_p2, min_kd, kn_p1, kn_p2, kp, kappa_p1, kappa_p2) =
sif_parameters
Tf = FT(273.15)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is kind of annoying, but we should get T_freeze from the earth_param_set in Canopy.jl update_aux!, and pass as an argument... like we do with R

Copy link
Member Author

@AlexisRenchon AlexisRenchon Jul 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do that together!
I am not sure of how to do it correctly, do you mean have Tf as an argument of compute_SIF_at_a_point and get that argument inside Canopy.jl update_aux!?

Is this to reduce allocation? or make sure we use params instead of hard coding?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1.

kd = max(kd_p1 * (Tc - Tf) + kd_p2, min_kd)
x = 1 - J / Jmax
kn = (kn_p1 * x - kn_p2) * x
ϕp0 = kp / (kf + kp + kn)
ϕp = J / Jmax * ϕp0
ϕf = kf / (kf + kd + kn) * (1 - ϕp)
κ = kappa_p1 * Vcmax25 * FT(1e6) + kappa_p2 # formula expects Vcmax25 in μmol/m^2/s
F = APAR * ϕf
SIF_755 = F / κ

return SIF_755
end
15 changes: 10 additions & 5 deletions src/standalone/Vegetation/optimality_farquhar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The required parameters for the optimality Farquhar photosynthesis model.
Currently, only C3 photosynthesis is supported.
$(DocStringExtensions.FIELDS)
"""
Base.@kwdef struct OptimalityFarquharParameters{FT <: AbstractFloat}
Base.@kwdef struct OptimalityFarquharParameters{FT <: AbstractFloat, SP}
"Photosynthesis mechanism: C3 only"
mechanism::C3
"Γstar at 25 °C (mol/mol)"
Expand Down Expand Up @@ -45,6 +45,8 @@ Base.@kwdef struct OptimalityFarquharParameters{FT <: AbstractFloat}
pc::FT
"Constant describing cost of maintaining electron transport (unitless)"
c::FT
"SIF Parameters"
sif_parameters::SP
end

Base.eltype(::OptimalityFarquharParameters{FT}) where {FT} = FT
Expand Down Expand Up @@ -72,14 +74,14 @@ function OptimalityFarquharModel{FT}(
end

ClimaLand.auxiliary_vars(model::OptimalityFarquharModel) =
(:An, :GPP, :Rd, :Vcmax25)
(:An, :GPP, :Rd, :Vcmax25, :SIF)
ClimaLand.auxiliary_types(model::OptimalityFarquharModel{FT}) where {FT} =
(FT, FT, FT, FT)
(FT, FT, FT, FT, FT)
ClimaLand.auxiliary_domain_names(::OptimalityFarquharModel) =
(:surface, :surface, :surface, :surface)
(:surface, :surface, :surface, :surface, :surface)

"""
update_photosynthesis!(Rd, An, Vcmax25,
update_photosynthesis!(Rd, An, Vcmax25,SIF,
model::OptimalityFarquharModel,
T,
APAR,
Expand All @@ -101,6 +103,7 @@ function update_photosynthesis!(
Rd,
An,
Vcmax25,
SIF,
model::OptimalityFarquharModel,
T,
APAR,
Expand Down Expand Up @@ -152,4 +155,6 @@ function update_photosynthesis!(
@. Vcmax25 = Vcmax / arrhenius_function(T, To, R, ΔHVcmax)
@. Rd = dark_respiration(Vcmax25, β, f, ΔHRd, T, To, R)
@. An = net_photosynthesis(Ac, Aj, Rd, β)
@. SIF = compute_SIF_at_a_point(APAR, T, Vcmax25, R, model.parameters)
end
Base.broadcastable(m::OptimalityFarquharParameters) = tuple(m)
50 changes: 43 additions & 7 deletions src/standalone/Vegetation/photosynthesis.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
export FarquharParameters, FarquharModel, C3, C4
export SIFParameters, FarquharParameters, FarquharModel, C3, C4

abstract type AbstractPhotosynthesisModel{FT} <: AbstractCanopyComponent{FT} end

"""
SIFParameters{FT<:AbstractFloat}

The required parameters for the SIF parameterisation [give citation].
$(DocStringExtensions.FIELDS)
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
"""
@kwdef struct SIFParameters{FT <: AbstractFloat}
""
kf::FT = FT(0.05)
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
""
kd_p1::FT = FT(0.03)
""
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
kd_p2::FT = FT(0.0273)
""
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
min_kd::FT = FT(0.087)
""
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
kn_p1::FT = FT(6.2473)
""
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
kn_p2::FT = FT(0.5944)
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
""
kp::FT = FT(4.0)
""
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
kappa_p1::FT = FT(0.045)
""
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
kappa_p2::FT = FT(7.85)
end
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved

abstract type AbstractPhotosynthesisMechanism end
"""
Expand All @@ -17,14 +46,15 @@ struct C4 <: AbstractPhotosynthesisMechanism end

abstract type AbstractPhotosynthesisModel{FT} <: AbstractCanopyComponent{FT} end
"""
FarquharParameters{FT<:AbstractFloat, MECH <: AbstractPhotosynthesisMechanism}
FarquharParameters{FT<:AbstractFloat, MECH <: AbstractPhotosynthesisMechanism, SP <: SIFParameters}

The required parameters for the Farquhar photosynthesis model.
$(DocStringExtensions.FIELDS)
"""
Base.@kwdef struct FarquharParameters{
FT <: AbstractFloat,
MECH <: AbstractPhotosynthesisMechanism,
SP <: SIFParameters,
}
"Vcmax at 25 °C (mol CO2/m^2/s)"
Vcmax25::FT
Expand Down Expand Up @@ -62,6 +92,8 @@ Base.@kwdef struct FarquharParameters{
pc::FT
"Photosynthesis mechanism: C3 or C4"
mechanism::MECH
""
sif_parameters::SP
AlexisRenchon marked this conversation as resolved.
Show resolved Hide resolved
end

Base.eltype(::FarquharParameters{FT}) where {FT} = FT
Expand All @@ -78,12 +110,12 @@ function FarquharModel{FT}(
end

ClimaLand.name(model::AbstractPhotosynthesisModel) = :photosynthesis
ClimaLand.auxiliary_vars(model::FarquharModel) = (:An, :GPP, :Rd, :Vcmax25)
ClimaLand.auxiliary_vars(model::FarquharModel) =
(:An, :GPP, :Rd, :Vcmax25, :SIF)
ClimaLand.auxiliary_types(model::FarquharModel{FT}) where {FT} =
(FT, FT, FT, FT)
(FT, FT, FT, FT, FT)
ClimaLand.auxiliary_domain_names(::FarquharModel) =
(:surface, :surface, :surface, :surface)

(:surface, :surface, :surface, :surface, :surface)

function photosynthesis_at_a_point_Farquhar(
T,
Expand Down Expand Up @@ -126,7 +158,7 @@ function photosynthesis_at_a_point_Farquhar(
end

"""
update_photosynthesis!(Rd, An, Vcmax25,
update_photosynthesis!(Rd, An, Vcmax25, SIF,
model::FarquharModel,
T,
APAR,
Expand All @@ -148,6 +180,7 @@ function update_photosynthesis!(
Rd,
An,
Vcmax25field,
SIF,
model::FarquharModel,
T,
APAR,
Expand All @@ -170,8 +203,11 @@ function update_photosynthesis!(
model.parameters,
)
Vcmax25field .= Vcmax25
@. SIF = compute_SIF_at_a_point(APAR, T, Vcmax25, R, model.parameters)

end
Base.broadcastable(m::AbstractPhotosynthesisMechanism) = tuple(m)
Base.broadcastable(m::FarquharParameters) = tuple(m)
Base.broadcastable(m::SIFParameters) = tuple(m)

include("./optimality_farquhar.jl")
Loading
Loading