0.1.26
Loading...
Searching...
No Matches
PhotosynthesisModel.py
Go to the documentation of this file.
1"""
2PhotosynthesisModel Plugin for PyHelios.
3
4This module provides a high-level interface to the Helios photosynthesis modeling
5plugin, enabling simulation of plant photosynthesis processes using both empirical
6and mechanistic models.
7"""
8
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,
19 get_species_aliases
20)
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
26)
27
28
29class PhotosynthesisModelError(Exception):
30 """Exception raised by PhotosynthesisModel operations."""
31 pass
32
33
34#: Species available in the helios-core C4 photosynthesis library (von Caemmerer 2021).
35#: Lookups via :meth:`PhotosynthesisModel.setC4CoefficientsFromLibrary` are case-insensitive
36#: but otherwise exact — unknown species raise ``helios_runtime_error`` from the C++ side.
37AVAILABLE_C4_SPECIES = [
38 "SetariaViridis_vC2021",
39 "GenericC4_vC2000",
40 "Maize_Massad2007",
41]
42
43
45 """
46 High-level interface for Helios photosynthesis modeling.
47
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.
51
52 Features:
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
57
58 Example:
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 (W/m²)
69 ... )
70 ... photosynthesis.setEmpiricalModelCoefficients(coeffs)
71 ... photosynthesis.run()
72
73 Available species can be queried using:
74 >>> PhotosynthesisModel.get_available_species()
75 ['ALMOND', 'APPLE', 'AVOCADO', ...]
76 """
77
78 def __init__(self, context: Context):
79 """
80 Initialize PhotosynthesisModel.
81
82 Args:
83 context: PyHelios Context instance containing the 3D geometry
84
85 Raises:
86 PhotosynthesisModelError: If plugin is not available or initialization fails
87 """
88 if not isinstance(context, Context):
90 f"Context parameter must be a Context instance, got {type(context).__name__}"
91 )
92
93 self.context = context
94 self._native_ptr = None
95
96 try:
97 # Get the native context pointer
98 context_ptr = self.context.getNativePtr()
99 if context_ptr is None:
100 raise PhotosynthesisModelError("Context has no native pointer - context may not be properly initialized")
101
102 # Create the photosynthesis model
103 self._native_ptr = photosynthesis_wrapper.createPhotosynthesisModel(context_ptr)
104 if self._native_ptr is None:
105 raise PhotosynthesisModelError("Failed to create photosynthesis model")
106
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"
113 ) from e
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"
119 ) from e
120 else:
121 raise PhotosynthesisModelError(f"Failed to initialize PhotosynthesisModel: {e}") from e
122
123 def _check_context_alive(self):
124 """Raise if the owning Context has been destroyed (see Context.check_context_alive)."""
125 check_context_alive(getattr(self, "context", None), "PhotosynthesisModel")
127 def __enter__(self):
128 """Context manager entry."""
129 return self
131 def __exit__(self, exc_type, exc_value, traceback):
132 """Context manager exit with cleanup."""
133 self.cleanup()
135 def cleanup(self):
136 """Clean up native resources."""
137 if hasattr(self, '_native_ptr') and self._native_ptr is not None:
138 try:
139 photosynthesis_wrapper.destroyPhotosynthesisModel(self._native_ptr)
140 except Exception:
141 pass # Ignore cleanup errors
142 finally:
143 self._native_ptr = None
144
145 def get_native_ptr(self):
146 """Get the native C++ pointer for advanced operations."""
147 return self._native_ptr
149 def __del__(self):
150 """Destructor to ensure cleanup."""
151 self.cleanup()
153 # Model Configuration
154 def setModelTypeEmpirical(self):
155 """
156 Set the photosynthesis model type to empirical.
157
158 The empirical model uses light response curves with saturation kinetics.
159 """
161 photosynthesis_wrapper.setModelTypeEmpirical(self._native_ptr)
162
163 def setModelTypeFarquhar(self):
164 """
165 Set the photosynthesis model type to Farquhar-von Caemmerer-Berry.
166
167 The FvCB model is a mechanistic model accounting for biochemical
168 limitations of C3 photosynthesis.
169 """
171 photosynthesis_wrapper.setModelTypeFarquhar(self._native_ptr)
172
173 def setModelTypeC4(self):
174 """
175 Set the photosynthesis model type to the von Caemmerer (2021) steady-state C4 model.
176
177 Pair with :meth:`setC4CoefficientsFromLibrary` (e.g. ``"SetariaViridis_vC2021"``,
178 ``"Maize_Massad2007"``) or :meth:`setC4ModelCoefficients` to populate parameters.
179
180 Note:
181 Requires helios-core v1.3.72 or newer.
182
183 Raises:
184 NotImplementedError: If running against an older helios-core that does not
185 support the C4 bindings — rebuild with ``build_scripts/build_helios --clean``.
186 """
188 photosynthesis_wrapper.setModelTypeC4(self._native_ptr)
189
190 def setFarquharMesophyllConductance(self, gm_at_25c: float,
191 dha: float = -1.0,
192 topt: float = -1.0,
193 dhd: float = -1.0,
194 uuids: Optional[List[int]] = None):
195 """
196 Set Farquhar mesophyll conductance ``gm`` (mol CO2 / m² / s / bar) for selected primitives.
197
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``).
202
203 Args:
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.).
210
211 Raises:
212 ValueError: If ``uuids`` is None or empty.
213 NotImplementedError: If running against helios-core older than v1.3.72.
214 """
215 if not uuids:
216 raise ValueError(
217 "setFarquharMesophyllConductance requires explicit UUIDs. "
218 "To configure all primitives use setFarquharModelCoefficients() with a populated coefficient set."
219 )
221 photosynthesis_wrapper.setFarquharMesophyllConductance(
222 self._native_ptr, gm_at_25c, dha, topt, dhd, uuids,
223 )
224
225 def setC4CoefficientsFromLibrary(self, species: str, uuids: Optional[List[int]] = None,
226 material_label: Optional[str] = None):
227 """
228 Set C4 model coefficients from the von Caemmerer (2021) species library.
229
230 Args:
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``.
237
238 Raises:
239 ValueError: If both ``uuids`` and ``material_label`` are provided.
240 NotImplementedError: If running against helios-core older than v1.3.72.
241 """
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(
247 self._native_ptr, species, material_label,
248 )
249 else:
251 photosynthesis_wrapper.setC4CoefficientsFromLibrary(self._native_ptr, species, uuids)
252
253 def getC4CoefficientsFromLibrary(self, species: str) -> List[float]:
254 """
255 Return the 43-float C4 coefficient array for ``species``.
256
257 See ``native/include/pyhelios_wrapper_photosynthesis.h`` for the per-index meaning.
258 """
260 return photosynthesis_wrapper.getC4CoefficientsFromLibrary(self._native_ptr, species)
261
262 def setC4ModelCoefficients(self, coefficients: List[float],
263 uuids: Optional[List[int]] = None,
264 material_label: Optional[str] = None):
265 """
266 Apply a 43-float C4 coefficient array.
267
268 Pair with :meth:`getC4CoefficientsFromLibrary` to round-trip a species' defaults.
269
270 Args:
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``.
277
278 Raises:
279 ValueError: If both ``uuids`` and ``material_label`` are provided.
280 """
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(
286 self._native_ptr, material_label, coefficients,
287 )
288 else:
290 photosynthesis_wrapper.setC4ModelCoefficients(self._native_ptr, coefficients, uuids)
291
292 def getC4ModelCoefficients(self, uuid: int) -> List[float]:
293 """Return the 43-float C4 coefficient array for a single primitive."""
295 return photosynthesis_wrapper.getC4ModelCoefficients(self._native_ptr, uuid)
296
297 def setCm(self, cm: float, uuids: List[int]):
298 """
299 Manually prescribe the mesophyll cytosolic CO2 partial pressure (Cm) for the C4 model.
300
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.
304
305 Args:
306 cm: Mesophyll cytosolic CO2 partial pressure in ubar.
307 uuids: Primitive UUIDs to set. Must be non-empty.
308
309 Raises:
310 ValueError: If ``uuids`` is empty.
311 NotImplementedError: If running against helios-core older than v1.3.72.
312 """
313 if not uuids:
314 raise ValueError("setCm requires a non-empty list of UUIDs.")
316 photosynthesis_wrapper.setCm(self._native_ptr, cm, uuids)
317
318 # Model Execution
319 def run(self):
320 """
321 Run photosynthesis calculations for all primitives in the context.
322
323 The model must be configured with appropriate coefficients before running.
324 """
326 photosynthesis_wrapper.run(self._native_ptr)
327
328 @validate_photosynthesis_uuid_params
329 def runForPrimitives(self, uuids: Union[List[int], int]):
330 """
331 Run photosynthesis calculations for specific primitives.
332
333 Args:
334 uuids: Single UUID (integer) or list of UUIDs for primitives
335 """
336 if isinstance(uuids, int):
337 uuids = [uuids]
339 photosynthesis_wrapper.runForUUIDs(self._native_ptr, uuids)
340
341 # Species Configuration
342 @validate_photosynthesis_species_params
343 def setSpeciesCoefficients(self, species: str, uuids: Optional[List[int]] = None):
344 """
345 Set Farquhar model coefficients from built-in species library.
346
347 Args:
348 species: Species name from the built-in library
349 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
350
351 Example:
352 >>> model.setSpeciesCoefficients("APPLE")
353 >>> model.setSpeciesCoefficients("SOYBEAN", [uuid1, uuid2])
354 """
355 if uuids is None:
357 photosynthesis_wrapper.setFarquharCoefficientsFromLibrary(self._native_ptr, species)
358 else:
360 photosynthesis_wrapper.setFarquharCoefficientsFromLibraryForUUIDs(self._native_ptr, species, uuids)
361
362 def setFarquharCoefficientsFromLibrary(self, species: str, uuids: Optional[List[int]] = None):
363 """
364 Set Farquhar model coefficients from built-in species library.
365
366 This method matches the C++ API naming: setFarquharCoefficientsFromLibrary()
367
368 Args:
369 species: Species name from the built-in library
370 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
371
372 Example:
373 >>> model.setFarquharCoefficientsFromLibrary("APPLE")
374 >>> model.setFarquharCoefficientsFromLibrary("SOYBEAN", [uuid1, uuid2])
375 """
376 if uuids is None:
378 photosynthesis_wrapper.setFarquharCoefficientsFromLibrary(self._native_ptr, species)
379 else:
381 photosynthesis_wrapper.setFarquharCoefficientsFromLibraryForUUIDs(self._native_ptr, species, uuids)
382
383 def getSpeciesCoefficients(self, species: str) -> List[float]:
384 """
385 Get Farquhar model coefficients for a species from the library.
386
387 Args:
388 species: Species name
389
390 Returns:
391 List of Farquhar model coefficients for the species
392 """
393 species = validate_species_name(species)
395 return photosynthesis_wrapper.getFarquharCoefficientsFromLibrary(self._native_ptr, species)
396
397 @staticmethod
398 def get_available_species() -> List[str]:
399 """
400 Static method to get available species without creating a model instance.
401
402 Returns:
403 List of species names available in the photosynthesis library
404 """
405 return get_available_species()
407 @staticmethod
408 def get_species_aliases() -> dict:
409 """
410 Static method to get species aliases mapping.
411
412 Returns:
413 Dictionary mapping aliases to canonical species names
414 """
415 return get_species_aliases()
417 # Model Coefficient Configuration
418 @validate_empirical_model_params
419 def setEmpiricalModelCoefficients(self, coefficients: EmpiricalModelCoefficients,
420 uuids: Optional[List[int]] = None):
421 """
422 Set empirical model coefficients.
423
424 Args:
425 coefficients: EmpiricalModelCoefficients instance with model parameters
426 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
427 """
428 # Convert to list format expected by C++ interface
429 coeff_list = coefficients.to_array()
430
431 if uuids is None:
433 photosynthesis_wrapper.setEmpiricalModelCoefficients(self._native_ptr, coeff_list)
434 else:
436 photosynthesis_wrapper.setEmpiricalModelCoefficientsForUUIDs(self._native_ptr, coeff_list, uuids)
437
438 @validate_farquhar_model_params
439 def setFarquharModelCoefficients(self, coefficients: FarquharModelCoefficients,
440 uuids: Optional[List[int]] = None):
441 """
442 Set Farquhar model coefficients.
443
444 Args:
445 coefficients: FarquharModelCoefficients instance with FvCB parameters
446 uuids: Optional list of primitive UUIDs. If None, applies to all primitives.
447 """
448 # Convert to list format expected by C++ interface
449 coeff_list = coefficients.to_array()
450
451 if uuids is None:
453 photosynthesis_wrapper.setFarquharModelCoefficients(self._native_ptr, coeff_list)
454 else:
456 photosynthesis_wrapper.setFarquharModelCoefficientsForUUIDs(self._native_ptr, coeff_list, uuids)
457
458 # Individual Farquhar Parameter Setting
459 def setVcmax(self, vcmax: float, uuids: List[int], dha: Optional[float] = None,
460 topt: Optional[float] = None, dhd: Optional[float] = None):
461 """
462 Set maximum carboxylation rate for Farquhar model.
463
464 This method modifies only the Vcmax parameter while preserving all
465 other existing Farquhar model parameters for each primitive.
466
467 Args:
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)
473
474 Note:
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.
479 """
480 from .types import FarquharModelCoefficients
481
482 # For each UUID, get existing coefficients, modify Vcmax, then set back
483 for uuid in uuids:
484 # Get existing coefficients as raw array
485 existing_array = self.getFarquharModelCoefficients(uuid)
486
487 # Create new coefficient object from existing values
488 existing_coeffs = FarquharModelCoefficients.from_array(existing_array)
489
490 # Modify only Vcmax parameter using the temperature response
491 if dha is None:
492 existing_coeffs.Vcmax = vcmax
493 else:
494 # Create temperature response object and set it
495 from .types import PhotosyntheticTemperatureResponseParameters
496 if dhd is None and topt is None:
497 temp_response = PhotosyntheticTemperatureResponseParameters(vcmax, dha)
498 elif dhd is None:
499 temp_response = PhotosyntheticTemperatureResponseParameters(vcmax, dha, topt)
500 else:
501 temp_response = PhotosyntheticTemperatureResponseParameters(vcmax, dha, topt, dhd)
502
503 # Set the temperature response values
504 existing_coeffs.Vcmax = temp_response.value_at_25C
505 # Note: Temperature response parameters would need to be stored separately
506 # For now, just set the basic value
507 existing_coeffs.Vcmax = vcmax
508
509 # Set the modified coefficients back for this UUID
510 self.setFarquharModelCoefficients(existing_coeffs, [uuid])
511
512 def setJmax(self, jmax: float, uuids: List[int], dha: Optional[float] = None,
513 topt: Optional[float] = None, dhd: Optional[float] = None):
514 """
515 Set maximum electron transport rate for Farquhar model.
516
517 This method modifies only the Jmax parameter while preserving all
518 other existing Farquhar model parameters for each primitive.
519
520 Args:
521 jmax: Maximum electron transport rate at 25°C (μmol m⁻² s⁻¹)
522 uuids: List of primitive UUIDs to modify (required)
523 dha: Activation energy (optional, kJ/mol)
524 topt: Optimal temperature (optional, °C)
525 dhd: Deactivation energy (optional, kJ/mol)
526
527 Note:
528 Primitives must have existing Farquhar model coefficients set before
529 calling this method. Use setFarquharCoefficientsFromLibrary() first
530 if needed. To modify all primitives, use setFarquharModelCoefficients()
531 with complete coefficient objects.
532 """
533 from .types import FarquharModelCoefficients
534
535 # For each UUID, get existing coefficients, modify Jmax, then set back
536 for uuid in uuids:
537 # Get existing coefficients as raw array
538 existing_array = self.getFarquharModelCoefficients(uuid)
539
540 # Create new coefficient object from existing values
541 existing_coeffs = FarquharModelCoefficients.from_array(existing_array)
542
543 # Modify only Jmax parameter
544 existing_coeffs.Jmax = jmax
545
546 # Set the modified coefficients back for this UUID
547 self.setFarquharModelCoefficients(existing_coeffs, [uuid])
548
549 def setDarkRespiration(self, respiration: float, uuids: List[int], dha: Optional[float] = None,
550 topt: Optional[float] = None, dhd: Optional[float] = None):
551 """
552 Set dark respiration rate.
553
554 This method modifies only the Rd parameter while preserving all
555 other existing Farquhar model parameters for each primitive.
556
557 Args:
558 respiration: Dark respiration rate at 25°C (μmol m⁻² s⁻¹)
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)
563
564 Note:
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.
569 """
570 from .types import FarquharModelCoefficients
571
572 # For each UUID, get existing coefficients, modify Rd, then set back
573 for uuid in uuids:
574 # Get existing coefficients as raw array
575 existing_array = self.getFarquharModelCoefficients(uuid)
576
577 # Create new coefficient object from existing values
578 existing_coeffs = FarquharModelCoefficients.from_array(existing_array)
579
580 # Modify only Rd parameter
581 existing_coeffs.Rd = respiration
582
583 # Set the modified coefficients back for this UUID
584 self.setFarquharModelCoefficients(existing_coeffs, [uuid])
585
586 def setQuantumEfficiency(self, efficiency: float, uuids: List[int], dha: Optional[float] = None,
587 topt: Optional[float] = None, dhd: Optional[float] = None):
588 """
589 Set quantum efficiency of photosystem II.
590
591 This method modifies only the alpha parameter while preserving all
592 other existing Farquhar model parameters for each primitive.
593
594 Args:
595 efficiency: Quantum efficiency at 25°C (dimensionless, 0-1)
596 uuids: List of primitive UUIDs to modify (required)
597 dha: Activation energy (optional, kJ/mol)
598 topt: Optimal temperature (optional, °C)
599 dhd: Deactivation energy (optional, kJ/mol)
600
601 Note:
602 Primitives must have existing Farquhar model coefficients set before
603 calling this method. Use setFarquharCoefficientsFromLibrary() first
604 if needed. To modify all primitives, use setFarquharModelCoefficients()
605 with complete coefficient objects.
606 """
607 from .types import FarquharModelCoefficients
608
609 # For each UUID, get existing coefficients, modify alpha, then set back
610 for uuid in uuids:
611 # Get existing coefficients as raw array
612 existing_array = self.getFarquharModelCoefficients(uuid)
613
614 # Create new coefficient object from existing values
615 existing_coeffs = FarquharModelCoefficients.from_array(existing_array)
616
617 # Modify only alpha parameter
618 existing_coeffs.alpha = efficiency
619
620 # Set the modified coefficients back for this UUID
621 self.setFarquharModelCoefficients(existing_coeffs, [uuid])
622
623 def setLightResponseCurvature(self, curvature: float, uuids: List[int], dha: Optional[float] = None,
624 topt: Optional[float] = None, dhd: Optional[float] = None):
625 """
626 Set light response curvature parameter.
627
628 This method modifies only the theta parameter while preserving all
629 other existing Farquhar model parameters for each primitive.
630
631 Args:
632 curvature: Light response curvature at 25°C (dimensionless)
633 uuids: List of primitive UUIDs to modify (required)
634 dha: Activation energy (optional, kJ/mol)
635 topt: Optimal temperature (optional, °C)
636 dhd: Deactivation energy (optional, kJ/mol)
637
638 Note:
639 Primitives must have existing Farquhar model coefficients set before
640 calling this method. Use setFarquharCoefficientsFromLibrary() first
641 if needed. To modify all primitives, use setFarquharModelCoefficients()
642 with complete coefficient objects.
643
644 Note:
645 The theta parameter is stored in the coefficient array but may not be
646 directly exposed in the current FarquharModelCoefficients structure.
647 This method sets the basic curvature value.
648 """
649 from .types import FarquharModelCoefficients
650
651 # For each UUID, get existing coefficients, modify theta/curvature, then set back
652 for uuid in uuids:
653 # Get existing coefficients as raw array
654 existing_array = self.getFarquharModelCoefficients(uuid)
655
656 # Create new coefficient object from existing values
657 existing_coeffs = FarquharModelCoefficients.from_array(existing_array)
658
659 # Note: theta/curvature parameter mapping would need to be checked
660 # For now, this is a placeholder - the actual field mapping needs verification
661 # existing_coeffs.theta = curvature # This field may not exist
662
663 # Set the modified coefficients back for this UUID
664 self.setFarquharModelCoefficients(existing_coeffs, [uuid])
665
666 # Results and Output
667 def getEmpiricalModelCoefficients(self, uuid: int) -> List[float]:
668 """
669 Get empirical model coefficients for a specific primitive.
670
671 Args:
672 uuid: Primitive UUID
673
674 Returns:
675 List of empirical model coefficients
676 """
678 return photosynthesis_wrapper.getEmpiricalModelCoefficients(self._native_ptr, uuid)
679
680 def getFarquharModelCoefficients(self, uuid: int) -> List[float]:
681 """
682 Get Farquhar model coefficients for a specific primitive.
683
684 Args:
685 uuid: Primitive UUID
686
687 Returns:
688 List of Farquhar model coefficients
689 """
691 return photosynthesis_wrapper.getFarquharModelCoefficients(self._native_ptr, uuid)
692
693 def exportResults(self, label: str):
694 """
695 Export photosynthesis results with optional label.
696
697 Args:
698 label: Data label for export
699 """
701 photosynthesis_wrapper.optionalOutputPrimitiveData(self._native_ptr, label)
702
703 # Model Information and Utilities
704 def enableMessages(self):
705 """Enable photosynthesis model status messages."""
707 photosynthesis_wrapper.enableMessages(self._native_ptr)
708
709 def disableMessages(self):
710 """Disable photosynthesis model status messages."""
712 photosynthesis_wrapper.disableMessages(self._native_ptr)
713
714 def printModelReport(self, uuids: Optional[List[int]] = None):
715 """
716 Print model configuration report.
717
718 Args:
719 uuids: Optional list of UUIDs. If None, prints report for all primitives.
720 """
721 if uuids is None:
723 photosynthesis_wrapper.printDefaultValueReport(self._native_ptr)
724 else:
726 photosynthesis_wrapper.printDefaultValueReportForUUIDs(self._native_ptr, uuids)
727
728 # Utility Methods
729 def validateConfiguration(self) -> bool:
730 """
731 Basic validation that model has been configured.
732
733 Returns:
734 True if model appears to be configured (has native pointer)
735 """
736 return self._native_ptr is not None
738 def resetModel(self):
739 """
740 Reset the model by recreating it.
741 Note: This will clear all configured parameters.
742 """
743 if self._native_ptr is not None:
744 old_ptr = self._native_ptr
745 try:
746 context_ptr = self.context.getNativePtr()
747 self._native_ptr = photosynthesis_wrapper.createPhotosynthesisModel(context_ptr)
748 finally:
749 # Clean up old pointer
750 try:
751 photosynthesis_wrapper.destroyPhotosynthesisModel(old_ptr)
752 except Exception:
753 pass
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.
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.
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.
setLightResponseCurvature(self, float curvature, List[int] uuids, Optional[float] dha=None, Optional[float] topt=None, Optional[float] dhd=None)
Set light response curvature parameter.
Temperature response parameters for photosynthetic processes.