2PhotosynthesisModel Plugin for PyHelios.
4This module provides a high-level interface to the Helios photosynthesis modeling
5plugin, enabling simulation of plant photosynthesis processes using both empirical
9from typing
import List, Optional, Union
10from .Context
import Context, check_context_alive
11from .wrappers
import UPhotosynthesisWrapper
as photosynthesis_wrapper
12from .types.photosynthesis
import (
13 PhotosyntheticTemperatureResponseParameters,
14 EmpiricalModelCoefficients,
15 FarquharModelCoefficients,
16 PHOTOSYNTHESIS_SPECIES,
17 validate_species_name,
18 get_available_species,
21from .validation.plugin_decorators
import (
22 validate_photosynthesis_species_params,
23 validate_empirical_model_params,
24 validate_farquhar_model_params,
25 validate_photosynthesis_uuid_params
30 """Exception raised by PhotosynthesisModel operations."""
37AVAILABLE_C4_SPECIES = [
38 "SetariaViridis_vC2021",
46 High-level interface for Helios photosynthesis modeling.
48 The PhotosynthesisModel provides methods for configuring and running
49 photosynthesis simulations using various models including empirical
50 and mechanistic (Farquhar-von Caemmerer-Berry) approaches.
53 - Support for empirical and FvCB photosynthesis models
54 - Built-in species library with 21+ plant species
55 - Comprehensive parameter validation
56 - Context manager support for proper cleanup
59 >>> from pyhelios import Context, PhotosynthesisModel
60 >>> from pyhelios.types import EmpiricalModelCoefficients
61 >>> context = Context()
62 >>> with PhotosynthesisModel(context) as photosynthesis:
63 ... # Configure empirical model
64 ... coeffs = EmpiricalModelCoefficients(
65 ... Tref=298.0, # Reference temperature (K)
66 ... Ci_ref=290.0, # Reference CO2 concentration (μmol/mol)
67 ... Asat=20.0, # Light-saturated photosynthesis rate (μmol/m²/s)
68 ... theta=65.0 # Light response curvature (µmol/m²·s PPFD)
70 ... photosynthesis.setEmpiricalModelCoefficients(coeffs)
71 ... photosynthesis.run()
73 Available species can be queried using:
74 >>> PhotosynthesisModel.get_available_species()
75 ['ALMOND', 'APPLE', 'AVOCADO', ...]
78 def __init__(self, context: Context):
80 Initialize PhotosynthesisModel.
83 context: PyHelios Context instance containing the 3D geometry
86 PhotosynthesisModelError: If plugin is not available or initialization fails
88 if not isinstance(context, Context):
90 f
"Context parameter must be a Context instance, got {type(context).__name__}"
98 context_ptr = self.
context.getNativePtr()
99 if context_ptr
is None:
103 self.
_native_ptr = photosynthesis_wrapper.createPhotosynthesisModel(context_ptr)
107 except Exception
as e:
108 if "photosynthesis plugin is not available" in str(e).lower():
110 "Photosynthesis plugin is not available. "
111 "Please rebuild PyHelios with photosynthesis plugin enabled:\n"
112 " build_scripts/build_helios --plugins photosynthesis"
114 elif "mock mode" in str(e).lower():
116 "PhotosynthesisModel requires native Helios libraries. "
117 "Currently running in mock mode. Please build native libraries:\n"
118 " build_scripts/build_helios --plugins photosynthesis"
124 """Raise if the owning Context has been destroyed (see Context.check_context_alive)."""
125 check_context_alive(getattr(self,
"context",
None),
"PhotosynthesisModel")
128 """Context manager entry."""
131 def __exit__(self, exc_type, exc_value, traceback):
132 """Context manager exit with cleanup."""
136 """Clean up native resources."""
137 if hasattr(self,
'_native_ptr')
and self.
_native_ptr is not None:
139 photosynthesis_wrapper.destroyPhotosynthesisModel(self.
_native_ptr)
146 """Get the native C++ pointer for advanced operations."""
150 """Destructor to ensure cleanup."""
156 Set the photosynthesis model type to empirical.
158 The empirical model uses light response curves with saturation kinetics.
165 Set the photosynthesis model type to Farquhar-von Caemmerer-Berry.
167 The FvCB model is a mechanistic model accounting for biochemical
168 limitations of C3 photosynthesis.
175 Set the photosynthesis model type to the von Caemmerer (2021) steady-state C4 model.
177 Pair with :meth:`setC4CoefficientsFromLibrary` (e.g. ``"SetariaViridis_vC2021"``,
178 ``"Maize_Massad2007"``) or :meth:`setC4ModelCoefficients` to populate parameters.
181 Requires helios-core v1.3.72 or newer.
184 NotImplementedError: If running against an older helios-core that does not
185 support the C4 bindings — rebuild with ``build_scripts/build_helios --clean``.
194 uuids: Optional[List[int]] =
None):
196 Set Farquhar mesophyll conductance ``gm`` (mol CO2 / m² / s / bar) for selected primitives.
198 Pass ``dha`` < 0 (the default) to apply ``gm`` with no temperature response. Pass a
199 positive ``dha`` and leave ``topt``/``dhd`` at -1 to use a monotonic Arrhenius response.
200 Set ``topt`` (in °C) for a peaked Arrhenius response, and ``dhd`` to override the
201 deactivation energy (defaults to ``10*dha``).
204 gm_at_25c: ``gm`` at the 25 °C reference, mol CO2 / m² / s / bar.
205 dha: Activation energy (kJ/mol). -1 disables temperature response.
206 topt: Optimum temperature in °C. -1 keeps Arrhenius monotonic.
207 dhd: Deactivation energy (kJ/mol). -1 picks a default.
208 uuids: Primitive UUIDs to update. ``None`` is rejected; the underlying
209 wrapper requires explicit UUIDs (matching ``setVcmax`` etc.).
212 ValueError: If ``uuids`` is None or empty.
213 NotImplementedError: If running against helios-core older than v1.3.72.
217 "setFarquharMesophyllConductance requires explicit UUIDs. "
218 "To configure all primitives use setFarquharModelCoefficients() with a populated coefficient set."
221 photosynthesis_wrapper.setFarquharMesophyllConductance(
222 self.
_native_ptr, gm_at_25c, dha, topt, dhd, uuids,
226 material_label: Optional[str] =
None):
228 Set C4 model coefficients from the von Caemmerer (2021) species library.
231 species: Species name (case-insensitive). See :data:`AVAILABLE_C4_SPECIES`.
232 uuids: Optional list of primitive UUIDs. If None and ``material_label`` is
233 also None, applies to all primitives in the Context.
234 material_label: Optional material label. When set, applies the coefficients
235 to every primitive that references this material at run() time. Mutually
236 exclusive with ``uuids``.
239 ValueError: If both ``uuids`` and ``material_label`` are provided.
240 NotImplementedError: If running against helios-core older than v1.3.72.
242 if uuids
is not None and material_label
is not None:
243 raise ValueError(
"setC4CoefficientsFromLibrary: pass either uuids or material_label, not both.")
244 if material_label
is not None:
246 photosynthesis_wrapper.setC4CoefficientsFromLibraryForMaterial(
251 photosynthesis_wrapper.setC4CoefficientsFromLibrary(self.
_native_ptr, species, uuids)
255 Return the 43-float C4 coefficient array for ``species``.
257 See ``native/include/pyhelios_wrapper_photosynthesis.h`` for the per-index meaning.
260 return photosynthesis_wrapper.getC4CoefficientsFromLibrary(self.
_native_ptr, species)
263 uuids: Optional[List[int]] =
None,
264 material_label: Optional[str] =
None):
266 Apply a 43-float C4 coefficient array.
268 Pair with :meth:`getC4CoefficientsFromLibrary` to round-trip a species' defaults.
271 coefficients: 43-float C4 coefficient array.
272 uuids: Optional list of primitive UUIDs. If None and ``material_label`` is
273 also None, applies to all primitives in the Context.
274 material_label: Optional material label. When set, applies the coefficients
275 to every primitive that references this material at run() time. Mutually
276 exclusive with ``uuids``.
279 ValueError: If both ``uuids`` and ``material_label`` are provided.
281 if uuids
is not None and material_label
is not None:
282 raise ValueError(
"setC4ModelCoefficients: pass either uuids or material_label, not both.")
283 if material_label
is not None:
285 photosynthesis_wrapper.setC4ModelCoefficientsForMaterial(
290 photosynthesis_wrapper.setC4ModelCoefficients(self.
_native_ptr, coefficients, uuids)
293 """Return the 43-float C4 coefficient array for a single primitive."""
295 return photosynthesis_wrapper.getC4ModelCoefficients(self.
_native_ptr, uuid)
297 def setCm(self, cm: float, uuids: List[int]):
299 Manually prescribe the mesophyll cytosolic CO2 partial pressure (Cm) for the C4 model.
301 Bypasses the ``Cm = Ci - A/gm`` fixed-point iteration and the stomatal balance
302 on Ci. Primarily intended for testing and validation against the von Caemmerer 2021
303 reference spreadsheet.
306 cm: Mesophyll cytosolic CO2 partial pressure in ubar.
307 uuids: Primitive UUIDs to set. Must be non-empty.
310 ValueError: If ``uuids`` is empty.
311 NotImplementedError: If running against helios-core older than v1.3.72.
314 raise ValueError(
"setCm requires a non-empty list of UUIDs.")
316 photosynthesis_wrapper.setCm(self.
_native_ptr, cm, uuids)
321 Run photosynthesis calculations for all primitives in the context.
323 The model must be configured with appropriate coefficients before running.
328 @validate_photosynthesis_uuid_params
331 Run photosynthesis calculations for specific primitives.
334 uuids: Single UUID (integer) or list of UUIDs for primitives
336 if isinstance(uuids, int):
339 photosynthesis_wrapper.runForUUIDs(self.
_native_ptr, uuids)
342 @validate_photosynthesis_species_params
345 Set Farquhar model coefficients from built-in species library.
348 species: Species name from the built-in library
349 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
352 >>> model.setSpeciesCoefficients("APPLE")
353 >>> model.setSpeciesCoefficients("SOYBEAN", [uuid1, uuid2])
357 photosynthesis_wrapper.setFarquharCoefficientsFromLibrary(self.
_native_ptr, species)
360 photosynthesis_wrapper.setFarquharCoefficientsFromLibraryForUUIDs(self.
_native_ptr, species, uuids)
364 Set Farquhar model coefficients from built-in species library.
366 This method matches the C++ API naming: setFarquharCoefficientsFromLibrary()
369 species: Species name from the built-in library
370 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
373 >>> model.setFarquharCoefficientsFromLibrary("APPLE")
374 >>> model.setFarquharCoefficientsFromLibrary("SOYBEAN", [uuid1, uuid2])
378 photosynthesis_wrapper.setFarquharCoefficientsFromLibrary(self.
_native_ptr, species)
381 photosynthesis_wrapper.setFarquharCoefficientsFromLibraryForUUIDs(self.
_native_ptr, species, uuids)
385 Get Farquhar model coefficients for a species from the library.
388 species: Species name
391 List of Farquhar model coefficients for the species
393 species = validate_species_name(species)
395 return photosynthesis_wrapper.getFarquharCoefficientsFromLibrary(self.
_native_ptr, species)
400 Static method to get available species without creating a model instance.
403 List of species names available in the photosynthesis library
410 Static method to get species aliases mapping.
413 Dictionary mapping aliases to canonical species names
418 @validate_empirical_model_params
420 uuids: Optional[List[int]] =
None):
422 Set empirical model coefficients.
425 coefficients: EmpiricalModelCoefficients instance with model parameters
426 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
429 coeff_list = coefficients.to_array()
433 photosynthesis_wrapper.setEmpiricalModelCoefficients(self.
_native_ptr, coeff_list)
436 photosynthesis_wrapper.setEmpiricalModelCoefficientsForUUIDs(self.
_native_ptr, coeff_list, uuids)
438 @validate_farquhar_model_params
440 uuids: Optional[List[int]] =
None):
442 Set Farquhar model coefficients.
445 coefficients: FarquharModelCoefficients instance with FvCB parameters
446 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
449 coeff_list = coefficients.to_array()
453 photosynthesis_wrapper.setFarquharModelCoefficients(self.
_native_ptr, coeff_list)
456 photosynthesis_wrapper.setFarquharModelCoefficientsForUUIDs(self.
_native_ptr, coeff_list, uuids)
459 def setVcmax(self, vcmax: float, uuids: List[int], dha: Optional[float] =
None,
460 topt: Optional[float] =
None, dhd: Optional[float] =
None):
462 Set maximum carboxylation rate for Farquhar model.
464 This method modifies only the Vcmax parameter while preserving all
465 other existing Farquhar model parameters for each primitive.
468 vcmax: Maximum carboxylation rate at 25°C (μmol m⁻² s⁻¹)
469 uuids: List of primitive UUIDs to modify (required)
470 dha: Activation energy (optional, kJ/mol)
471 topt: Optimal temperature (optional, °C)
472 dhd: Deactivation energy (optional, kJ/mol)
475 Primitives must have existing Farquhar model coefficients set before
476 calling this method. Use setFarquharCoefficientsFromLibrary() first
477 if needed. To modify all primitives, use setFarquharModelCoefficients()
478 with complete coefficient objects.
481 photosynthesis_wrapper.setFarquharVcmax(
483 -1.0
if dha
is None else dha,
484 -1.0
if topt
is None else topt,
485 -1.0
if dhd
is None else dhd,
489 def setJmax(self, jmax: float, uuids: List[int], dha: Optional[float] =
None,
490 topt: Optional[float] =
None, dhd: Optional[float] =
None):
492 Set maximum electron transport rate for Farquhar model.
494 This method modifies only the Jmax parameter while preserving all
495 other existing Farquhar model parameters for each primitive.
498 jmax: Maximum electron transport rate at 25°C (μmol m⁻² s⁻¹)
499 uuids: List of primitive UUIDs to modify (required)
500 dha: Activation energy (optional, kJ/mol)
501 topt: Optimal temperature (optional, °C)
502 dhd: Deactivation energy (optional, kJ/mol)
505 Primitives must have existing Farquhar model coefficients set before
506 calling this method. Use setFarquharCoefficientsFromLibrary() first
507 if needed. To modify all primitives, use setFarquharModelCoefficients()
508 with complete coefficient objects.
511 photosynthesis_wrapper.setFarquharJmax(
513 -1.0
if dha
is None else dha,
514 -1.0
if topt
is None else topt,
515 -1.0
if dhd
is None else dhd,
519 def setDarkRespiration(self, respiration: float, uuids: List[int], dha: Optional[float] =
None,
520 topt: Optional[float] =
None, dhd: Optional[float] =
None):
522 Set dark respiration rate.
524 This method modifies only the Rd parameter while preserving all
525 other existing Farquhar model parameters for each primitive.
528 respiration: Dark respiration rate at 25°C (μmol m⁻² s⁻¹)
529 uuids: List of primitive UUIDs to modify (required)
530 dha: Activation energy (optional, kJ/mol)
531 topt: Optimal temperature (optional, °C)
532 dhd: Deactivation energy (optional, kJ/mol)
535 Primitives must have existing Farquhar model coefficients set before
536 calling this method. Use setFarquharCoefficientsFromLibrary() first
537 if needed. To modify all primitives, use setFarquharModelCoefficients()
538 with complete coefficient objects.
541 photosynthesis_wrapper.setFarquharRd(
543 -1.0
if dha
is None else dha,
544 -1.0
if topt
is None else topt,
545 -1.0
if dhd
is None else dhd,
549 def setQuantumEfficiency(self, efficiency: float, uuids: List[int], dha: Optional[float] =
None,
550 topt: Optional[float] =
None, dhd: Optional[float] =
None):
552 Set quantum efficiency of photosystem II.
554 This method modifies only the alpha parameter while preserving all
555 other existing Farquhar model parameters for each primitive.
558 efficiency: Quantum efficiency at 25°C (dimensionless, 0-1)
559 uuids: List of primitive UUIDs to modify (required)
560 dha: Activation energy (optional, kJ/mol)
561 topt: Optimal temperature (optional, °C)
562 dhd: Deactivation energy (optional, kJ/mol)
565 Primitives must have existing Farquhar model coefficients set before
566 calling this method. Use setFarquharCoefficientsFromLibrary() first
567 if needed. To modify all primitives, use setFarquharModelCoefficients()
568 with complete coefficient objects.
571 photosynthesis_wrapper.setFarquharQuantumEfficiency(
573 -1.0
if dha
is None else dha,
574 -1.0
if topt
is None else topt,
575 -1.0
if dhd
is None else dhd,
580 topt: Optional[float] =
None, dhd: Optional[float] =
None):
582 Set light response curvature parameter.
584 This method modifies only the theta parameter while preserving all
585 other existing Farquhar model parameters for each primitive.
588 curvature: Light response curvature at 25°C (dimensionless)
589 uuids: List of primitive UUIDs to modify (required)
590 dha: Activation energy (optional, kJ/mol)
591 topt: Optimal temperature (optional, °C)
592 dhd: Deactivation energy (optional, kJ/mol)
595 Primitives must have existing Farquhar model coefficients set before
596 calling this method. Use setFarquharCoefficientsFromLibrary() first
597 if needed. To modify all primitives, use setFarquharModelCoefficients()
598 with complete coefficient objects.
602 photosynthesis_wrapper.setFarquharLightResponseCurvature(
604 -1.0
if dha
is None else dha,
605 -1.0
if topt
is None else topt,
606 -1.0
if dhd
is None else dhd,
612 Get the light response curvature (theta) at 25 degrees C for a primitive.
615 uuid: Primitive UUID to query
618 Light response curvature at 25 degrees C (dimensionless)
624 Get the full light response curvature (theta) temperature response for a primitive.
627 uuid: Primitive UUID to query
630 PhotosyntheticTemperatureResponseParameters for theta
632 from .types
import FarquharModelCoefficients
635 return FarquharModelCoefficients.from_array(
641 Get empirical model coefficients for a specific primitive.
647 List of empirical model coefficients
650 return photosynthesis_wrapper.getEmpiricalModelCoefficients(self.
_native_ptr, uuid)
654 Get Farquhar model coefficients for a specific primitive.
660 List of Farquhar model coefficients
663 return photosynthesis_wrapper.getFarquharModelCoefficients(self.
_native_ptr, uuid)
667 Export photosynthesis results with optional label.
670 label: Data label for export
673 photosynthesis_wrapper.optionalOutputPrimitiveData(self.
_native_ptr, label)
677 """Enable photosynthesis model status messages."""
682 """Disable photosynthesis model status messages."""
688 Print model configuration report.
691 uuids: Optional list of UUIDs. If None, prints report for all primitives.
695 photosynthesis_wrapper.printDefaultValueReport(self.
_native_ptr)
698 photosynthesis_wrapper.printDefaultValueReportForUUIDs(self.
_native_ptr, uuids)
703 Basic validation that model has been configured.
706 True if model appears to be configured (has native pointer)
712 Reset the model by recreating it.
713 Note: This will clear all configured parameters.
718 context_ptr = self.
context.getNativePtr()
719 self.
_native_ptr = photosynthesis_wrapper.createPhotosynthesisModel(context_ptr)
723 photosynthesis_wrapper.destroyPhotosynthesisModel(old_ptr)
Exception raised by PhotosynthesisModel operations.
High-level interface for Helios photosynthesis modeling.
setC4CoefficientsFromLibrary(self, str species, Optional[List[int]] uuids=None, Optional[str] material_label=None)
Set C4 model coefficients from the von Caemmerer (2021) species library.
disableMessages(self)
Disable photosynthesis model status messages.
printModelReport(self, Optional[List[int]] uuids=None)
Print model configuration report.
enableMessages(self)
Enable photosynthesis model status messages.
bool validateConfiguration(self)
Basic validation that model has been configured.
List[float] getC4ModelCoefficients(self, int uuid)
Return the 43-float C4 coefficient array for a single primitive.
setFarquharMesophyllConductance(self, float gm_at_25c, float dha=-1.0, float topt=-1.0, float dhd=-1.0, Optional[List[int]] uuids=None)
Set Farquhar mesophyll conductance gm (mol CO2 / m² / s / bar) for selected primitives.
setFarquharCoefficientsFromLibrary(self, str species, Optional[List[int]] uuids=None)
Set Farquhar model coefficients from built-in species library.
setJmax(self, float jmax, List[int] uuids, Optional[float] dha=None, Optional[float] topt=None, Optional[float] dhd=None)
Set maximum electron transport rate for Farquhar model.
cleanup(self)
Clean up native resources.
__enter__(self)
Context manager entry.
float getLightResponseCurvature(self, int uuid)
Get the light response curvature (theta) at 25 degrees C for a primitive.
List[float] getFarquharModelCoefficients(self, int uuid)
Get Farquhar model coefficients for a specific primitive.
get_native_ptr(self)
Get the native C++ pointer for advanced operations.
setDarkRespiration(self, float respiration, List[int] uuids, Optional[float] dha=None, Optional[float] topt=None, Optional[float] dhd=None)
Set dark respiration rate.
setModelTypeFarquhar(self)
Set the photosynthesis model type to Farquhar-von Caemmerer-Berry.
List[float] getC4CoefficientsFromLibrary(self, str species)
Return the 43-float C4 coefficient array for species.
setVcmax(self, float vcmax, List[int] uuids, Optional[float] dha=None, Optional[float] topt=None, Optional[float] dhd=None)
Set maximum carboxylation rate for Farquhar model.
setModelTypeC4(self)
Set the photosynthesis model type to the von Caemmerer (2021) steady-state C4 model.
setModelTypeEmpirical(self)
Set the photosynthesis model type to empirical.
exportResults(self, str label)
Export photosynthesis results with optional label.
getLightResponseCurvatureTempResponse(self, int uuid)
Get the full light response curvature (theta) temperature response for a primitive.
resetModel(self)
Reset the model by recreating it.
setQuantumEfficiency(self, float efficiency, List[int] uuids, Optional[float] dha=None, Optional[float] topt=None, Optional[float] dhd=None)
Set quantum efficiency of photosystem II.
setCm(self, float cm, List[int] uuids)
Manually prescribe the mesophyll cytosolic CO2 partial pressure (Cm) for the C4 model.
setEmpiricalModelCoefficients(self, EmpiricalModelCoefficients coefficients, Optional[List[int]] uuids=None)
Set empirical model coefficients.
dict get_species_aliases()
Static method to get species aliases mapping.
run(self)
Run photosynthesis calculations for all primitives in the context.
__init__(self, Context context)
Initialize PhotosynthesisModel.
runForPrimitives(self, Union[List[int], int] uuids)
Run photosynthesis calculations for specific primitives.
setFarquharModelCoefficients(self, FarquharModelCoefficients coefficients, Optional[List[int]] uuids=None)
Set Farquhar model coefficients.
_check_context_alive(self)
Raise if the owning Context has been destroyed (see Context.check_context_alive).
List[str] get_available_species()
Static method to get available species without creating a model instance.
List[float] getEmpiricalModelCoefficients(self, int uuid)
Get empirical model coefficients for a specific primitive.
setC4ModelCoefficients(self, List[float] coefficients, Optional[List[int]] uuids=None, Optional[str] material_label=None)
Apply a 43-float C4 coefficient array.
List[float] getSpeciesCoefficients(self, str species)
Get Farquhar model coefficients for a species from the library.
setSpeciesCoefficients(self, str species, Optional[List[int]] uuids=None)
Set Farquhar model coefficients from built-in species library.
__exit__(self, exc_type, exc_value, traceback)
Context manager exit with cleanup.
__del__(self)
Destructor to ensure cleanup.
setLightResponseCurvature(self, float curvature, List[int] uuids, Optional[float] dha=None, Optional[float] topt=None, Optional[float] dhd=None)
Set light response curvature parameter.