BESS-JPL 1.26.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bess_jpl-1.26.1/.github/workflows/ci.yml +31 -0
- bess_jpl-1.26.1/.github/workflows/python-publish.yml +39 -0
- bess_jpl-1.26.1/BESS_JPL/BESS_JPL.py +54 -0
- bess_jpl-1.26.1/BESS_JPL/C3_photosynthesis.py +165 -0
- bess_jpl-1.26.1/BESS_JPL/C4_fraction.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/C4_fraction.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/C4_fraction.tif.aux.xml +11 -0
- bess_jpl-1.26.1/BESS_JPL/C4_photosynthesis.py +133 -0
- bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-BESS-JPL-GEOS5FP-inputs.csv +1066 -0
- bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-BESS-JPL-inputs.csv +1066 -0
- bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-BESS-JPL-outputs.csv +1066 -0
- bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-FLiESANN-inputs.csv +1066 -0
- bess_jpl-1.26.1/BESS_JPL/ECOv002-static-tower-BESS-JPL-inputs.csv +122 -0
- bess_jpl-1.26.1/BESS_JPL/ECOv002_calval_BESS_inputs.py +30 -0
- bess_jpl-1.26.1/BESS_JPL/ECOv002_static_tower_BESS_inputs.py +19 -0
- bess_jpl-1.26.1/BESS_JPL/FVC_from_NDVI.py +22 -0
- bess_jpl-1.26.1/BESS_JPL/LAI_from_NDVI.py +28 -0
- bess_jpl-1.26.1/BESS_JPL/NDVI_maximum.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/NDVI_maximum.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/NDVI_minimum.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/NDVI_minimum.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/__init__.py +5 -0
- bess_jpl-1.26.1/BESS_JPL/ball_berry_intercept_C3.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/ball_berry_intercept_C3.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C3.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C3.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C4.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C4.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/calculate_VCmax.py +90 -0
- bess_jpl-1.26.1/BESS_JPL/calculate_bulk_aerodynamic_resistance.py +119 -0
- bess_jpl-1.26.1/BESS_JPL/calculate_friction_velocity.py +111 -0
- bess_jpl-1.26.1/BESS_JPL/canopy_energy_balance.py +110 -0
- bess_jpl-1.26.1/BESS_JPL/canopy_longwave_radiation.py +117 -0
- bess_jpl-1.26.1/BESS_JPL/canopy_shortwave_radiation.py +276 -0
- bess_jpl-1.26.1/BESS_JPL/carbon_uptake_efficiency.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/carbon_uptake_efficiency.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/carbon_water_fluxes.py +313 -0
- bess_jpl-1.26.1/BESS_JPL/colors.py +33 -0
- bess_jpl-1.26.1/BESS_JPL/constants.py +25 -0
- bess_jpl-1.26.1/BESS_JPL/exceptions.py +3 -0
- bess_jpl-1.26.1/BESS_JPL/generate_BESS_GEOS5FP_inputs.py +58 -0
- bess_jpl-1.26.1/BESS_JPL/generate_BESS_inputs_table.py +186 -0
- bess_jpl-1.26.1/BESS_JPL/generate_input_dataset.py +243 -0
- bess_jpl-1.26.1/BESS_JPL/generate_output_dataset.py +26 -0
- bess_jpl-1.26.1/BESS_JPL/interpolate_C3_C4.py +12 -0
- bess_jpl-1.26.1/BESS_JPL/kn.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/kn.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/load_C4_fraction.py +20 -0
- bess_jpl-1.26.1/BESS_JPL/load_NDVI_maximum.py +17 -0
- bess_jpl-1.26.1/BESS_JPL/load_NDVI_minimum.py +17 -0
- bess_jpl-1.26.1/BESS_JPL/load_ball_berry_intercept_C3.py +10 -0
- bess_jpl-1.26.1/BESS_JPL/load_ball_berry_slope_C3.py +10 -0
- bess_jpl-1.26.1/BESS_JPL/load_ball_berry_slope_C4.py +10 -0
- bess_jpl-1.26.1/BESS_JPL/load_carbon_uptake_efficiency.py +10 -0
- bess_jpl-1.26.1/BESS_JPL/load_kn.py +10 -0
- bess_jpl-1.26.1/BESS_JPL/load_peakVCmax_C3.py +12 -0
- bess_jpl-1.26.1/BESS_JPL/load_peakVCmax_C4.py +12 -0
- bess_jpl-1.26.1/BESS_JPL/meteorology.py +429 -0
- bess_jpl-1.26.1/BESS_JPL/model.py +594 -0
- bess_jpl-1.26.1/BESS_JPL/peakVCmax_C3.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/peakVCmax_C3.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/peakVCmax_C4.jpeg +0 -0
- bess_jpl-1.26.1/BESS_JPL/peakVCmax_C4.tif +0 -0
- bess_jpl-1.26.1/BESS_JPL/process_BESS_table.py +365 -0
- bess_jpl-1.26.1/BESS_JPL/process_paw_and_gao_LE.py +50 -0
- bess_jpl-1.26.1/BESS_JPL/retrieve_BESS_JPL_GEOS5FP_inputs.py +257 -0
- bess_jpl-1.26.1/BESS_JPL/retrieve_BESS_inputs.py +293 -0
- bess_jpl-1.26.1/BESS_JPL/soil_energy_balance.py +35 -0
- bess_jpl-1.26.1/BESS_JPL/verify.py +127 -0
- bess_jpl-1.26.1/BESS_JPL/version.py +3 -0
- bess_jpl-1.26.1/BESS_JPL.egg-info/PKG-INFO +102 -0
- bess_jpl-1.26.1/BESS_JPL.egg-info/SOURCES.txt +93 -0
- bess_jpl-1.26.1/BESS_JPL.egg-info/dependency_links.txt +1 -0
- bess_jpl-1.26.1/BESS_JPL.egg-info/requires.txt +23 -0
- bess_jpl-1.26.1/BESS_JPL.egg-info/top_level.txt +1 -0
- bess_jpl-1.26.1/Dockerfile +27 -0
- bess_jpl-1.26.1/ECOv002-cal-val-BESS-JPL-inputs-full.csv +1066 -0
- bess_jpl-1.26.1/ECOv002-cal-val-BESS-JPL-inputs-single-day.csv +3 -0
- bess_jpl-1.26.1/LICENSE +201 -0
- bess_jpl-1.26.1/MANIFEST.in +17 -0
- bess_jpl-1.26.1/PKG-INFO +102 -0
- bess_jpl-1.26.1/README.md +67 -0
- bess_jpl-1.26.1/SUMMARY.md +102 -0
- bess_jpl-1.26.1/check_input_distribution.py +13 -0
- bess_jpl-1.26.1/debug_GEOS5FP_timeseries.py +199 -0
- bess_jpl-1.26.1/fix_input_dataset.py +21 -0
- bess_jpl-1.26.1/generate_BESS_input_dataset_full.py +69 -0
- bess_jpl-1.26.1/generate_BESS_input_dataset_single_day.py +77 -0
- bess_jpl-1.26.1/generate_BESS_input_single_timestep.py +76 -0
- bess_jpl-1.26.1/generate_FLiES_input_dataset_single_day.py +38 -0
- bess_jpl-1.26.1/makefile +71 -0
- bess_jpl-1.26.1/pyproject.toml +55 -0
- bess_jpl-1.26.1/setup.cfg +4 -0
- bess_jpl-1.26.1/test_co2sc.py +102 -0
- bess_jpl-1.26.1/test_geos5fp_query.py +55 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout repository
|
|
17
|
+
uses: actions/checkout@v3 # This is already the latest version
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
uses: actions/setup-python@v4 # This is also the latest version
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install .[dev] # Use dev to install pytest
|
|
28
|
+
|
|
29
|
+
- name: Run tests
|
|
30
|
+
run: |
|
|
31
|
+
pytest
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# This workflow will upload a Python Package using Twine when a release is created
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
|
|
3
|
+
|
|
4
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
5
|
+
# They are provided by a third-party and are governed by
|
|
6
|
+
# separate terms of service, privacy policy, and support
|
|
7
|
+
# documentation.
|
|
8
|
+
|
|
9
|
+
name: Upload Python Package
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
release:
|
|
13
|
+
types: [published]
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
deploy:
|
|
20
|
+
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
- name: Set up Python
|
|
26
|
+
uses: actions/setup-python@v3
|
|
27
|
+
with:
|
|
28
|
+
python-version: '3.x'
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip
|
|
32
|
+
pip install build
|
|
33
|
+
- name: Build package
|
|
34
|
+
run: python -m build
|
|
35
|
+
- name: Publish package
|
|
36
|
+
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
|
|
37
|
+
with:
|
|
38
|
+
user: __token__
|
|
39
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
import logging
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
import rasters as rt
|
|
7
|
+
from rasters import Raster, RasterGeometry
|
|
8
|
+
|
|
9
|
+
from check_distribution import check_distribution
|
|
10
|
+
|
|
11
|
+
from sun_angles import calculate_SZA_from_DOY_and_hour
|
|
12
|
+
from solar_apparent_time import solar_day_of_year_for_area, solar_hour_of_day_for_area
|
|
13
|
+
|
|
14
|
+
from koppengeiger import load_koppen_geiger
|
|
15
|
+
from gedi_canopy_height import load_canopy_height
|
|
16
|
+
from FLiESANN import FLiESANN
|
|
17
|
+
from GEOS5FP import GEOS5FP
|
|
18
|
+
from MODISCI import MODISCI
|
|
19
|
+
from NASADEM import NASADEM
|
|
20
|
+
|
|
21
|
+
from .constants import *
|
|
22
|
+
from .C3_photosynthesis import *
|
|
23
|
+
from .C4_photosynthesis import *
|
|
24
|
+
from .canopy_energy_balance import *
|
|
25
|
+
from .canopy_longwave_radiation import *
|
|
26
|
+
from .canopy_shortwave_radiation import *
|
|
27
|
+
from .carbon_water_fluxes import *
|
|
28
|
+
from .FVC_from_NDVI import *
|
|
29
|
+
from .interpolate_C3_C4 import *
|
|
30
|
+
from .LAI_from_NDVI import *
|
|
31
|
+
from .load_C4_fraction import *
|
|
32
|
+
from .load_carbon_uptake_efficiency import *
|
|
33
|
+
from .load_kn import *
|
|
34
|
+
from .load_NDVI_minimum import *
|
|
35
|
+
from .load_NDVI_maximum import *
|
|
36
|
+
from .load_peakVCmax_C3 import *
|
|
37
|
+
from .load_peakVCmax_C4 import *
|
|
38
|
+
from .load_ball_berry_intercept_C3 import *
|
|
39
|
+
from .load_ball_berry_slope_C3 import *
|
|
40
|
+
from .load_ball_berry_slope_C4 import *
|
|
41
|
+
from .calculate_VCmax import *
|
|
42
|
+
from .meteorology import *
|
|
43
|
+
from .soil_energy_balance import *
|
|
44
|
+
from .model import *
|
|
45
|
+
from .process_BESS_table import *
|
|
46
|
+
from .generate_BESS_inputs_table import *
|
|
47
|
+
from .ECOv002_static_tower_BESS_inputs import *
|
|
48
|
+
from .ECOv002_calval_BESS_inputs import *
|
|
49
|
+
from .verify import *
|
|
50
|
+
from .colors import *
|
|
51
|
+
from .generate_input_dataset import *
|
|
52
|
+
from .generate_BESS_inputs_table import *
|
|
53
|
+
from .generate_output_dataset import *
|
|
54
|
+
from .exceptions import *
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def calculate_C3_photosynthesis(
|
|
5
|
+
Tf_K: np.ndarray, # leaf temperature in Kelvin (K)
|
|
6
|
+
Ci: np.ndarray, # intercellular CO2 concentration in micromoles per mole (μmol mol⁻¹)
|
|
7
|
+
APAR_μmolm2s1: np.ndarray, # absorbed photosynthetically active radiation in micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
8
|
+
Vcmax25: np.ndarray, # maximum carboxylation rate at 25°C in micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
9
|
+
Ps_Pa: np.ndarray, # surface pressure in Pascals (Pa)
|
|
10
|
+
carbon_uptake_efficiency: np.ndarray) -> dict: # intrinsic quantum efficiency for carbon uptake (unitless)
|
|
11
|
+
"""
|
|
12
|
+
photosynthesis for C3 plants
|
|
13
|
+
Collatz et al., 1991
|
|
14
|
+
https://www.sciencedirect.com/science/article/abs/pii/0168192391900028
|
|
15
|
+
Adapted from Youngryel Ryu's code by Gregory Halverson and Robert Freepartner
|
|
16
|
+
:param Tf_K: leaf temperature in Kelvin
|
|
17
|
+
:param Ci: intercellular CO2 concentration [umol mol-1]
|
|
18
|
+
:param APAR: leaf absorptance to photosynthetically active radiation [umol m-2 s-1]
|
|
19
|
+
:param Vcmax25: maximum carboxylation rate at 25C [umol m-2 s-1]
|
|
20
|
+
:param Ps_Pa: surface pressure in Pascal
|
|
21
|
+
:param carbon_uptake_efficiency: intrinsic quantum efficiency for carbon uptake
|
|
22
|
+
:return: dictionary containing photosynthesis, respiration, and net assimilation rates
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# Universal gas constant used in temperature corrections
|
|
26
|
+
# Units: kilojoules per Kelvin per mole (kJ K⁻¹ mol⁻¹)
|
|
27
|
+
R = 8.314e-3
|
|
28
|
+
|
|
29
|
+
# Calculate oxygen concentration, assuming oxygen is 21% of the atmospheric pressure
|
|
30
|
+
# Units: Pascals (Pa)
|
|
31
|
+
O2 = Ps_Pa * 0.21
|
|
32
|
+
|
|
33
|
+
# Convert intercellular CO2 concentration to partial pressure in Pascal
|
|
34
|
+
# Units: Pascals (Pa)
|
|
35
|
+
Pi = Ci * 1e-6 * Ps_Pa
|
|
36
|
+
|
|
37
|
+
# Calculate temperature difference from 25°C (298.15 K), scaled by 10 for Q10 calculations
|
|
38
|
+
# Unitless
|
|
39
|
+
item = (Tf_K - 298.15) / 10
|
|
40
|
+
|
|
41
|
+
# Michaelis-Menten constant for CO2 at 25°C
|
|
42
|
+
# Units: Pascals (Pa)
|
|
43
|
+
KC25 = 30
|
|
44
|
+
|
|
45
|
+
# Michaelis-Menten constant for O2 at 25°C
|
|
46
|
+
# Units: Pascals (Pa)
|
|
47
|
+
KO25 = 30000
|
|
48
|
+
|
|
49
|
+
# Specificity factor of RuBisCO at 25°C
|
|
50
|
+
# Units: Pascals (Pa)
|
|
51
|
+
tao25 = 2600
|
|
52
|
+
|
|
53
|
+
# Q10 value for temperature sensitivity of KC
|
|
54
|
+
# Unitless
|
|
55
|
+
KCQ10 = 2.1
|
|
56
|
+
|
|
57
|
+
# Q10 value for temperature sensitivity of KO
|
|
58
|
+
# Unitless
|
|
59
|
+
KOQ10 = 1.2
|
|
60
|
+
|
|
61
|
+
# Q10 value for temperature sensitivity of tao
|
|
62
|
+
# Unitless
|
|
63
|
+
taoQ10 = 0.57
|
|
64
|
+
|
|
65
|
+
# Adjusted Michaelis-Menten constant for CO2 at the given temperature
|
|
66
|
+
# Units: Pascals (Pa)
|
|
67
|
+
KC = KC25 * KCQ10 ** item
|
|
68
|
+
|
|
69
|
+
# Adjusted Michaelis-Menten constant for O2 at the given temperature
|
|
70
|
+
# Units: Pascals (Pa)
|
|
71
|
+
KO = KO25 * KOQ10 ** item
|
|
72
|
+
|
|
73
|
+
# Effective Michaelis-Menten constant for CO2 considering O2 competition
|
|
74
|
+
# Units: Pascals (Pa)
|
|
75
|
+
K = KC * (1.0 + O2 / KO)
|
|
76
|
+
|
|
77
|
+
# Adjusted specificity factor of RuBisCO at the given temperature
|
|
78
|
+
# Units: Pascals (Pa)
|
|
79
|
+
tao = tao25 * taoQ10 ** item
|
|
80
|
+
|
|
81
|
+
# CO2 compensation point in the absence of dark respiration
|
|
82
|
+
# Units: Pascals (Pa)
|
|
83
|
+
GammaS = O2 / (2.0 * tao)
|
|
84
|
+
|
|
85
|
+
# Q10 value for temperature sensitivity of Vcmax
|
|
86
|
+
# Unitless
|
|
87
|
+
VcmaxQ10 = 2.4
|
|
88
|
+
|
|
89
|
+
# Adjusted Vcmax at the given temperature without activation energy correction
|
|
90
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
91
|
+
Vcmax_o = Vcmax25 * VcmaxQ10 ** item
|
|
92
|
+
|
|
93
|
+
# Adjusted Vcmax at the given temperature with activation energy correction
|
|
94
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
95
|
+
Vcmax = Vcmax_o / (1.0 + np.exp((-220.0 + 0.703 * Tf_K) / (R * Tf_K)))
|
|
96
|
+
|
|
97
|
+
# Base dark respiration rate as a fraction of Vcmax
|
|
98
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
99
|
+
Rd_o = 0.015 * Vcmax
|
|
100
|
+
|
|
101
|
+
# Adjusted dark respiration rate at the given temperature
|
|
102
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
103
|
+
respiration_C3_μmolm2s1 = Rd_o * 1.0 / (1.0 + np.exp(1.3 * (Tf_K - 273.15 - 55.0)))
|
|
104
|
+
|
|
105
|
+
# Rubisco-limited rate, dependent on CO2 availability and RuBisCO activity
|
|
106
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
107
|
+
JC = Vcmax * (Pi - GammaS) / (Pi + K)
|
|
108
|
+
|
|
109
|
+
# Light-limited rate, dependent on light energy and CO2 availability
|
|
110
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
111
|
+
JE = carbon_uptake_efficiency * APAR_μmolm2s1 * (Pi - GammaS) / (Pi + 2.0 * GammaS)
|
|
112
|
+
|
|
113
|
+
# Export-limited rate, dependent on the capacity to export photosynthetic products
|
|
114
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
115
|
+
JS = Vcmax / 2.0
|
|
116
|
+
|
|
117
|
+
# Empirical colimitation factor for Rubisco-light limitation
|
|
118
|
+
# Unitless
|
|
119
|
+
a = 0.98
|
|
120
|
+
|
|
121
|
+
# Quadratic coefficient for colimitation (Rubisco-light limitation)
|
|
122
|
+
# Unitless
|
|
123
|
+
b = -(JC + JE)
|
|
124
|
+
|
|
125
|
+
# Quadratic coefficient for colimitation (Rubisco-light limitation)
|
|
126
|
+
# Unitless
|
|
127
|
+
c = JC * JE
|
|
128
|
+
|
|
129
|
+
# Combined Rubisco-light limitation
|
|
130
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
131
|
+
JCE = (-b + np.sign(b) * np.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
|
|
132
|
+
|
|
133
|
+
# Ensure the result is real-valued for Rubisco-light limitation
|
|
134
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
135
|
+
JCE = np.real(JCE)
|
|
136
|
+
|
|
137
|
+
# Empirical colimitation factor for Rubisco-light-export limitation
|
|
138
|
+
# Unitless
|
|
139
|
+
a = 0.95
|
|
140
|
+
|
|
141
|
+
# Quadratic coefficient for colimitation (Rubisco-light-export limitation)
|
|
142
|
+
# Unitless
|
|
143
|
+
b = -(JCE + JS)
|
|
144
|
+
|
|
145
|
+
# Quadratic coefficient for colimitation (Rubisco-light-export limitation)
|
|
146
|
+
# Unitless
|
|
147
|
+
c = JCE * JS
|
|
148
|
+
|
|
149
|
+
# Combined Rubisco-light-export limitation
|
|
150
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
151
|
+
photosynthesis_C3_μmolm2s1 = (-b + np.sign(b) * np.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
|
|
152
|
+
|
|
153
|
+
# Ensure the result is real-valued for Rubisco-light-export limitation
|
|
154
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
155
|
+
photosynthesis_C3_μmolm2s1 = np.real(photosynthesis_C3_μmolm2s1)
|
|
156
|
+
|
|
157
|
+
# Net assimilation rate, ensuring non-negative values
|
|
158
|
+
# Units: micromoles per square meter per second (μmol m⁻² s⁻¹)
|
|
159
|
+
net_assimilation_C3_μmolm2s1 = np.clip(photosynthesis_C3_μmolm2s1 - respiration_C3_μmolm2s1, 0, None)
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
"photosynthesis_C3_μmolm2s1": photosynthesis_C3_μmolm2s1,
|
|
163
|
+
"respiration_C3_μmolm2s1": respiration_C3_μmolm2s1,
|
|
164
|
+
"net_assimilation_C3_μmolm2s1": net_assimilation_C3_μmolm2s1
|
|
165
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<PAMDataset>
|
|
2
|
+
<PAMRasterBand band="1">
|
|
3
|
+
<Metadata>
|
|
4
|
+
<MDI key="STATISTICS_MAXIMUM">100</MDI>
|
|
5
|
+
<MDI key="STATISTICS_MEAN">3.2450253068732</MDI>
|
|
6
|
+
<MDI key="STATISTICS_MINIMUM">0</MDI>
|
|
7
|
+
<MDI key="STATISTICS_STDDEV">15.002005519213</MDI>
|
|
8
|
+
<MDI key="STATISTICS_VALID_PERCENT">100</MDI>
|
|
9
|
+
</Metadata>
|
|
10
|
+
</PAMRasterBand>
|
|
11
|
+
</PAMDataset>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def calculate_C4_photosynthesis(
|
|
5
|
+
Tf_K: np.ndarray,
|
|
6
|
+
Ci_μmol_per_mol: np.ndarray,
|
|
7
|
+
APAR_μmolm2s1: np.ndarray,
|
|
8
|
+
Vcmax25_μmolm2s1: np.ndarray) -> dict:
|
|
9
|
+
"""
|
|
10
|
+
=============================================================================
|
|
11
|
+
Collatz et al., 1992
|
|
12
|
+
|
|
13
|
+
Module : Photosynthesis for C4 plant
|
|
14
|
+
Description: This function calculates the net assimilation rate (An) for C4 plants
|
|
15
|
+
based on the biochemical model described by Collatz et al. (1992).
|
|
16
|
+
The model accounts for temperature corrections, light absorption,
|
|
17
|
+
and CO2 availability to simulate photosynthetic rates under varying
|
|
18
|
+
environmental conditions.
|
|
19
|
+
|
|
20
|
+
Parameters:
|
|
21
|
+
Tf_K (np.ndarray): Leaf temperature (Tf) in Kelvin. Temperature influences
|
|
22
|
+
enzyme kinetics and the rates of photosynthetic reactions.
|
|
23
|
+
Ci_μmol_per_mol (np.ndarray): Intercellular CO2 concentration (Ci) in
|
|
24
|
+
micromoles per mole. Represents the CO2 available for fixation.
|
|
25
|
+
APAR_μmolm2s1 (np.ndarray): Absorbed photosynthetically active radiation (APAR)
|
|
26
|
+
in micromoles per square meter per second. This is the light energy available for photosynthesis.
|
|
27
|
+
Vcmax25_μmolm2s1 (np.ndarray): Maximum carboxylation rate at 25°C (Vcmax25) in
|
|
28
|
+
micromoles per square meter per second. Reflects the activity of the enzyme Rubisco.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
dict: A dictionary containing the following keys:
|
|
32
|
+
- 'net_assimilation_C4_μmolm2s1' (np.ndarray): Net assimilation rate (An) in micromoles per square meter per second.
|
|
33
|
+
- 'photosynthesis_C4_μmolm2s1' (np.ndarray): Photosynthesis rate in micromoles per square meter per second.
|
|
34
|
+
- 'respiration_C4_μmolm2s1' (np.ndarray): Respiration rate in micromoles per square meter per second.
|
|
35
|
+
|
|
36
|
+
Explanation:
|
|
37
|
+
The net assimilation rate (An) is the balance between the carbon dioxide fixed
|
|
38
|
+
during photosynthesis and the carbon dioxide released during respiration. It
|
|
39
|
+
quantifies the net carbon gain by the plant under given environmental conditions.
|
|
40
|
+
This function models the biochemical processes that limit photosynthesis,
|
|
41
|
+
including light availability, CO2 concentration, and enzyme activity, while
|
|
42
|
+
accounting for temperature-dependent effects on these processes.
|
|
43
|
+
|
|
44
|
+
References:
|
|
45
|
+
Collatz, G. J., Ball, J. T., Grivet, C., & Berry, J. A. (1992). Physiological
|
|
46
|
+
and environmental regulation of stomatal conductance, photosynthesis, and
|
|
47
|
+
transpiration: A model that includes a laminar boundary layer. Agricultural
|
|
48
|
+
and Forest Meteorology, 54(2-4), 107-136.
|
|
49
|
+
|
|
50
|
+
DePury, D. G. G., & Farquhar, G. D. (1997). Simple scaling of photosynthesis
|
|
51
|
+
from leaves to canopies without the errors of big-leaf models. Plant, Cell &
|
|
52
|
+
Environment, 20(5), 537-557.
|
|
53
|
+
=============================================================================
|
|
54
|
+
"""
|
|
55
|
+
# Calculate the temperature deviation from 25°C (298.15 K)
|
|
56
|
+
# `temperature_deviation` represents the temperature difference normalized to 10°C intervals
|
|
57
|
+
temperature_deviation = (Tf_K - 298.15) / 10.0
|
|
58
|
+
|
|
59
|
+
# Define the Q10 coefficient, which describes the rate increase for every 10°C rise
|
|
60
|
+
# A Q10 of 2.0 means the reaction rate doubles for every 10°C increase in temperature
|
|
61
|
+
Q10 = 2.0
|
|
62
|
+
|
|
63
|
+
# Calculate the temperature-dependent rate constant for CO2 fixation
|
|
64
|
+
# `k` is the rate constant for CO2 fixation, adjusted for temperature
|
|
65
|
+
k = 0.7 * pow(Q10, temperature_deviation) # [mol m-2 s-1]
|
|
66
|
+
|
|
67
|
+
# Calculate the temperature-corrected maximum carboxylation rate
|
|
68
|
+
# `Vcmax_o` is the base maximum carboxylation rate adjusted for temperature
|
|
69
|
+
Vcmax_o = Vcmax25_μmolm2s1 * pow(Q10, temperature_deviation) # [umol m-2 s-1]
|
|
70
|
+
|
|
71
|
+
# Further adjust `Vcmax_o` for enzyme deactivation at extreme temperatures
|
|
72
|
+
# `Vcmax` is the effective maximum carboxylation rate after accounting for temperature sensitivity
|
|
73
|
+
Vcmax = Vcmax_o / (
|
|
74
|
+
(1.0 + np.exp(0.3 * (286.15 - Tf_K))) * (1.0 + np.exp(0.3 * (Tf_K - 309.15)))
|
|
75
|
+
) # [umol m-2 s-1]
|
|
76
|
+
|
|
77
|
+
# Calculate the temperature-corrected dark respiration rate
|
|
78
|
+
# `Rd_o` is the base dark respiration rate adjusted for temperature
|
|
79
|
+
Rd_o_μmolm2s1 = 0.8 * pow(Q10, temperature_deviation) # [umol m-2 s-1]
|
|
80
|
+
|
|
81
|
+
# `Rd` is the effective dark respiration rate after accounting for temperature sensitivity
|
|
82
|
+
respiration_C4_μmolm2s1 = Rd_o_μmolm2s1 / (1.0 + np.exp(1.3 * (Tf_K - 328.15))) # [umol m-2 s-1]
|
|
83
|
+
|
|
84
|
+
# Define the three limiting states of photosynthesis
|
|
85
|
+
# `Je` is the electron transport-limited rate, assumed to equal `Vcmax`
|
|
86
|
+
Je = Vcmax # [umol m-2 s-1]
|
|
87
|
+
|
|
88
|
+
# Calculate the light-limited rate
|
|
89
|
+
# `quantum_yield` is the quantum yield (mol CO2 fixed per mol photons absorbed)
|
|
90
|
+
quantum_yield = 0.067 # Quantum yield
|
|
91
|
+
|
|
92
|
+
# `Ji` is the light-limited rate, determined by absorbed light energy
|
|
93
|
+
Ji_μmolm2s1 = quantum_yield * APAR_μmolm2s1 # [umol m-2 s-1]
|
|
94
|
+
|
|
95
|
+
# Calculate the CO2-limited rate
|
|
96
|
+
# `ci` is the intercellular CO2 concentration converted to mol/mol
|
|
97
|
+
ci = Ci_μmol_per_mol * 1e-6 # Convert [umol mol-1] to [mol mol-1]
|
|
98
|
+
|
|
99
|
+
# `Jc` is the CO2-limited rate, based on `ci` and the rate constant `k`
|
|
100
|
+
Jc = ci * k * 1e6 # [umol m-2 s-1]
|
|
101
|
+
|
|
102
|
+
# Colimitation between the three limiting states of photosynthesis
|
|
103
|
+
# Step 1: Colimitation between `Je` and `Ji`
|
|
104
|
+
# `a`, `b`, and `c` are coefficients for the quadratic equation
|
|
105
|
+
a = 0.83 # Empirical coefficient for colimitation
|
|
106
|
+
b = -(Je + Ji_μmolm2s1)
|
|
107
|
+
c = Je * Ji_μmolm2s1
|
|
108
|
+
|
|
109
|
+
# `Jei` is the intermediate colimited rate between `Je` and `Ji`
|
|
110
|
+
Jei = (-b + np.sign(b) * np.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
|
|
111
|
+
Jei = np.real(Jei) # Ensure real values
|
|
112
|
+
|
|
113
|
+
# Step 2: Colimitation between `Jei` and `Jc`
|
|
114
|
+
# Update coefficients for the quadratic equation
|
|
115
|
+
a = 0.93 # Empirical coefficient for colimitation
|
|
116
|
+
b = -(Jei + Jc)
|
|
117
|
+
c = Jei * Jc
|
|
118
|
+
|
|
119
|
+
# `Jeic` is the final colimited rate between `Jei` and `Jc`
|
|
120
|
+
photosynthesis_C4_μmolm2s1 = (-b + np.sign(b) * np.sqrt(b * b - 4.0 * a * c)) / (2.0 * a)
|
|
121
|
+
photosynthesis_C4_μmolm2s1 = np.real(photosynthesis_C4_μmolm2s1) # Ensure real values
|
|
122
|
+
|
|
123
|
+
# Calculate the net assimilation rate
|
|
124
|
+
# `An` is the net assimilation rate, clipped to ensure non-negative values
|
|
125
|
+
# It represents the net carbon gain by the plant, accounting for photosynthesis and respiration
|
|
126
|
+
net_assimilation_C4_μmolm2s1 = np.clip(photosynthesis_C4_μmolm2s1 - respiration_C4_μmolm2s1, 0, None) # [umol m-2 s-1]
|
|
127
|
+
|
|
128
|
+
# Return results as a dictionary
|
|
129
|
+
return {
|
|
130
|
+
'net_assimilation_C4_μmolm2s1': net_assimilation_C4_μmolm2s1,
|
|
131
|
+
'photosynthesis_C4_μmolm2s1': photosynthesis_C4_μmolm2s1,
|
|
132
|
+
'respiration_C4_μmolm2s1': respiration_C4_μmolm2s1
|
|
133
|
+
}
|