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.
Files changed (95) hide show
  1. bess_jpl-1.26.1/.github/workflows/ci.yml +31 -0
  2. bess_jpl-1.26.1/.github/workflows/python-publish.yml +39 -0
  3. bess_jpl-1.26.1/BESS_JPL/BESS_JPL.py +54 -0
  4. bess_jpl-1.26.1/BESS_JPL/C3_photosynthesis.py +165 -0
  5. bess_jpl-1.26.1/BESS_JPL/C4_fraction.jpeg +0 -0
  6. bess_jpl-1.26.1/BESS_JPL/C4_fraction.tif +0 -0
  7. bess_jpl-1.26.1/BESS_JPL/C4_fraction.tif.aux.xml +11 -0
  8. bess_jpl-1.26.1/BESS_JPL/C4_photosynthesis.py +133 -0
  9. bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-BESS-JPL-GEOS5FP-inputs.csv +1066 -0
  10. bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-BESS-JPL-inputs.csv +1066 -0
  11. bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-BESS-JPL-outputs.csv +1066 -0
  12. bess_jpl-1.26.1/BESS_JPL/ECOv002-cal-val-FLiESANN-inputs.csv +1066 -0
  13. bess_jpl-1.26.1/BESS_JPL/ECOv002-static-tower-BESS-JPL-inputs.csv +122 -0
  14. bess_jpl-1.26.1/BESS_JPL/ECOv002_calval_BESS_inputs.py +30 -0
  15. bess_jpl-1.26.1/BESS_JPL/ECOv002_static_tower_BESS_inputs.py +19 -0
  16. bess_jpl-1.26.1/BESS_JPL/FVC_from_NDVI.py +22 -0
  17. bess_jpl-1.26.1/BESS_JPL/LAI_from_NDVI.py +28 -0
  18. bess_jpl-1.26.1/BESS_JPL/NDVI_maximum.jpeg +0 -0
  19. bess_jpl-1.26.1/BESS_JPL/NDVI_maximum.tif +0 -0
  20. bess_jpl-1.26.1/BESS_JPL/NDVI_minimum.jpeg +0 -0
  21. bess_jpl-1.26.1/BESS_JPL/NDVI_minimum.tif +0 -0
  22. bess_jpl-1.26.1/BESS_JPL/__init__.py +5 -0
  23. bess_jpl-1.26.1/BESS_JPL/ball_berry_intercept_C3.jpeg +0 -0
  24. bess_jpl-1.26.1/BESS_JPL/ball_berry_intercept_C3.tif +0 -0
  25. bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C3.jpeg +0 -0
  26. bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C3.tif +0 -0
  27. bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C4.jpeg +0 -0
  28. bess_jpl-1.26.1/BESS_JPL/ball_berry_slope_C4.tif +0 -0
  29. bess_jpl-1.26.1/BESS_JPL/calculate_VCmax.py +90 -0
  30. bess_jpl-1.26.1/BESS_JPL/calculate_bulk_aerodynamic_resistance.py +119 -0
  31. bess_jpl-1.26.1/BESS_JPL/calculate_friction_velocity.py +111 -0
  32. bess_jpl-1.26.1/BESS_JPL/canopy_energy_balance.py +110 -0
  33. bess_jpl-1.26.1/BESS_JPL/canopy_longwave_radiation.py +117 -0
  34. bess_jpl-1.26.1/BESS_JPL/canopy_shortwave_radiation.py +276 -0
  35. bess_jpl-1.26.1/BESS_JPL/carbon_uptake_efficiency.jpeg +0 -0
  36. bess_jpl-1.26.1/BESS_JPL/carbon_uptake_efficiency.tif +0 -0
  37. bess_jpl-1.26.1/BESS_JPL/carbon_water_fluxes.py +313 -0
  38. bess_jpl-1.26.1/BESS_JPL/colors.py +33 -0
  39. bess_jpl-1.26.1/BESS_JPL/constants.py +25 -0
  40. bess_jpl-1.26.1/BESS_JPL/exceptions.py +3 -0
  41. bess_jpl-1.26.1/BESS_JPL/generate_BESS_GEOS5FP_inputs.py +58 -0
  42. bess_jpl-1.26.1/BESS_JPL/generate_BESS_inputs_table.py +186 -0
  43. bess_jpl-1.26.1/BESS_JPL/generate_input_dataset.py +243 -0
  44. bess_jpl-1.26.1/BESS_JPL/generate_output_dataset.py +26 -0
  45. bess_jpl-1.26.1/BESS_JPL/interpolate_C3_C4.py +12 -0
  46. bess_jpl-1.26.1/BESS_JPL/kn.jpeg +0 -0
  47. bess_jpl-1.26.1/BESS_JPL/kn.tif +0 -0
  48. bess_jpl-1.26.1/BESS_JPL/load_C4_fraction.py +20 -0
  49. bess_jpl-1.26.1/BESS_JPL/load_NDVI_maximum.py +17 -0
  50. bess_jpl-1.26.1/BESS_JPL/load_NDVI_minimum.py +17 -0
  51. bess_jpl-1.26.1/BESS_JPL/load_ball_berry_intercept_C3.py +10 -0
  52. bess_jpl-1.26.1/BESS_JPL/load_ball_berry_slope_C3.py +10 -0
  53. bess_jpl-1.26.1/BESS_JPL/load_ball_berry_slope_C4.py +10 -0
  54. bess_jpl-1.26.1/BESS_JPL/load_carbon_uptake_efficiency.py +10 -0
  55. bess_jpl-1.26.1/BESS_JPL/load_kn.py +10 -0
  56. bess_jpl-1.26.1/BESS_JPL/load_peakVCmax_C3.py +12 -0
  57. bess_jpl-1.26.1/BESS_JPL/load_peakVCmax_C4.py +12 -0
  58. bess_jpl-1.26.1/BESS_JPL/meteorology.py +429 -0
  59. bess_jpl-1.26.1/BESS_JPL/model.py +594 -0
  60. bess_jpl-1.26.1/BESS_JPL/peakVCmax_C3.jpeg +0 -0
  61. bess_jpl-1.26.1/BESS_JPL/peakVCmax_C3.tif +0 -0
  62. bess_jpl-1.26.1/BESS_JPL/peakVCmax_C4.jpeg +0 -0
  63. bess_jpl-1.26.1/BESS_JPL/peakVCmax_C4.tif +0 -0
  64. bess_jpl-1.26.1/BESS_JPL/process_BESS_table.py +365 -0
  65. bess_jpl-1.26.1/BESS_JPL/process_paw_and_gao_LE.py +50 -0
  66. bess_jpl-1.26.1/BESS_JPL/retrieve_BESS_JPL_GEOS5FP_inputs.py +257 -0
  67. bess_jpl-1.26.1/BESS_JPL/retrieve_BESS_inputs.py +293 -0
  68. bess_jpl-1.26.1/BESS_JPL/soil_energy_balance.py +35 -0
  69. bess_jpl-1.26.1/BESS_JPL/verify.py +127 -0
  70. bess_jpl-1.26.1/BESS_JPL/version.py +3 -0
  71. bess_jpl-1.26.1/BESS_JPL.egg-info/PKG-INFO +102 -0
  72. bess_jpl-1.26.1/BESS_JPL.egg-info/SOURCES.txt +93 -0
  73. bess_jpl-1.26.1/BESS_JPL.egg-info/dependency_links.txt +1 -0
  74. bess_jpl-1.26.1/BESS_JPL.egg-info/requires.txt +23 -0
  75. bess_jpl-1.26.1/BESS_JPL.egg-info/top_level.txt +1 -0
  76. bess_jpl-1.26.1/Dockerfile +27 -0
  77. bess_jpl-1.26.1/ECOv002-cal-val-BESS-JPL-inputs-full.csv +1066 -0
  78. bess_jpl-1.26.1/ECOv002-cal-val-BESS-JPL-inputs-single-day.csv +3 -0
  79. bess_jpl-1.26.1/LICENSE +201 -0
  80. bess_jpl-1.26.1/MANIFEST.in +17 -0
  81. bess_jpl-1.26.1/PKG-INFO +102 -0
  82. bess_jpl-1.26.1/README.md +67 -0
  83. bess_jpl-1.26.1/SUMMARY.md +102 -0
  84. bess_jpl-1.26.1/check_input_distribution.py +13 -0
  85. bess_jpl-1.26.1/debug_GEOS5FP_timeseries.py +199 -0
  86. bess_jpl-1.26.1/fix_input_dataset.py +21 -0
  87. bess_jpl-1.26.1/generate_BESS_input_dataset_full.py +69 -0
  88. bess_jpl-1.26.1/generate_BESS_input_dataset_single_day.py +77 -0
  89. bess_jpl-1.26.1/generate_BESS_input_single_timestep.py +76 -0
  90. bess_jpl-1.26.1/generate_FLiES_input_dataset_single_day.py +38 -0
  91. bess_jpl-1.26.1/makefile +71 -0
  92. bess_jpl-1.26.1/pyproject.toml +55 -0
  93. bess_jpl-1.26.1/setup.cfg +4 -0
  94. bess_jpl-1.26.1/test_co2sc.py +102 -0
  95. 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
@@ -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
+ }