2High-level LeafOptics interface for PyHelios.
4This module provides a user-friendly interface to the PROSPECT leaf optical model
5for computing spectral reflectance and transmittance of plant leaves.
10from contextlib
import contextmanager
11from dataclasses
import dataclass, field
12from pathlib
import Path
13from typing
import List, Optional, Tuple, Union
15from .plugins.registry
import get_plugin_registry
16from .wrappers
import ULeafOpticsWrapper
as leafoptics_wrapper
17from .Context
import Context, check_context_alive
18from .exceptions
import HeliosError
19from .assets
import get_asset_manager
21logger = logging.getLogger(__name__)
25 """Exception raised for LeafOptics-specific errors."""
49 Data class for PROSPECT leaf optical model parameters.
51 These parameters define the physical and biochemical properties of a leaf
52 that determine its spectral reflectance and transmittance.
55 numberlayers: Number of mesophyll layers in the leaf (typically 1-3)
56 brownpigments: Brown pigment content (arbitrary units, typically 0)
57 chlorophyllcontent: Chlorophyll a+b content in micrograms per square cm
58 carotenoidcontent: Carotenoid content in micrograms per square cm
59 anthocyancontent: Anthocyanin content in micrograms per square cm
60 watermass: Equivalent water thickness in grams per square cm
61 drymass: Dry matter content (leaf mass per area) in grams per square cm
62 protein: Protein content in grams per square cm (PROSPECT-PRO mode)
63 carbonconstituents: Carbon-based constituents in grams per square cm (PROSPECT-PRO mode)
64 V2Z: Violaxanthin-to-zeaxanthin de-epoxidation state, [0, 1]. Used by the
65 radiation plugin's solar-induced fluorescence (SIF) pipeline; ignored by
66 the pure PROSPECT reflectance/transmittance calculation. Default 0
67 (dark-adapted, all violaxanthin).
68 fqe: Intrinsic fluorescence quantum efficiency scalar applied on top of the
69 per-leaf Phi_F at SIF emission time (radiation plugin only). Ignored by
70 PROSPECT. Default 1.0.
73 - If protein > 0 OR carbonconstituents > 0, the model uses PROSPECT-PRO mode
74 which ignores drymass and uses protein + carbonconstituents instead.
75 - Otherwise, the model uses PROSPECT-D mode which uses drymass.
76 - V2Z and fqe are inert unless the radiation plugin's SIF camera is in use.
78 numberlayers: float = 1.5
79 brownpigments: float = 0.0
80 chlorophyllcontent: float = 30.0
81 carotenoidcontent: float = 7.0
82 anthocyancontent: float = 1.0
83 watermass: float = 0.015
86 carbonconstituents: float = 0.0
90 def to_list(self) -> List[float]:
91 """Convert properties to a list in the order expected by the C++ interface."""
107 def from_list(cls, values: List[float]) ->
'LeafOpticsProperties':
108 """Create LeafOpticsProperties from a list of values.
110 Accepts the legacy 9-float layout (without V2Z/fqe) for backward
111 compatibility with serialized data; missing fields fall back to
112 defaults and a ``DeprecationWarning`` is emitted so callers can
113 migrate to the 11-element layout.
115 if len(values)
not in (9, 11):
116 raise ValueError(f
"Expected 9 or 11 values, got {len(values)}")
120 "LeafOpticsProperties.from_list received a 9-element legacy "
121 "array (pre-helios-core 1.3.72). V2Z and fqe will default to "
122 "0.0 and 1.0 respectively. Migrate serialized data to the "
123 "11-element layout to silence this warning.",
128 numberlayers=values[0],
129 brownpigments=values[1],
130 chlorophyllcontent=values[2],
131 carotenoidcontent=values[3],
132 anthocyancontent=values[4],
136 carbonconstituents=values[8],
137 V2Z=values[9]
if len(values) > 9
else 0.0,
138 fqe=values[10]
if len(values) > 10
else 1.0,
145 Parameters for nitrogen-based automatic leaf optics.
147 Passed to :meth:`LeafOptics.run` (without a label) to derive each leaf's PROSPECT
148 chlorophyll and carotenoid content from its ``"leaf_nitrogen_gN_m2"`` object data
149 (g N/m^2, typically written by the PlantArchitecture nitrogen model):
151 - Cab (ug/cm^2) = N_area (g/m^2) * 100 * f_photosynthetic * N_to_Cab_coefficient,
153 - Car (ug/cm^2) = Cab * Car_to_Cab_ratio
155 All other PROSPECT parameters are fixed at the values given here. Leaves are grouped
156 into ``num_bins`` spectrum bins spaced evenly across the nitrogen range, so at most
157 ``num_bins`` spectra are generated (labelled ``"Nauto_0"``, ``"Nauto_1"``, ...).
160 f_photosynthetic: Fraction of leaf nitrogen in photosynthetic machinery [0-1]
161 N_to_Cab_coefficient: Empirical nitrogen-to-chlorophyll coefficient
162 Car_to_Cab_ratio: Carotenoid to chlorophyll ratio
163 numberlayers: Leaf structure parameter N (must be >= 1)
164 anthocyancontent: Anthocyanin content in micrograms per square cm
165 brownpigments: Brown pigment content (senescence indicator)
166 watermass: Equivalent water thickness in grams per square cm
167 drymass: Leaf mass per area in grams per square cm
168 protein: Protein content in grams per square cm (PROSPECT-PRO mode)
169 carbonconstituents: Carbon constituents in grams per square cm (PROSPECT-PRO mode)
170 V2Z: Violaxanthin-to-zeaxanthin state [0, 1] for the SIF pipeline (fixed across bins)
171 fqe: Intrinsic fluorescence quantum efficiency scalar for the SIF pipeline (fixed across bins)
172 num_bins: Number of spectrum bins (a single bin is used when all leaves share one nitrogen value)
173 reassignment_threshold: Relative nitrogen change (fraction of bin centre) a leaf must
174 exceed before it is reassigned to another bin; 0 disables the relative test
175 min_reassignment_change: Minimum absolute nitrogen change (g/m^2) before a leaf is
176 reassigned; the new bin must also be closer by at least half this amount (hysteresis)
178 f_photosynthetic: float = 0.50
179 N_to_Cab_coefficient: float = 0.40
180 Car_to_Cab_ratio: float = 0.25
181 numberlayers: float = 1.5
182 anthocyancontent: float = 1.0
183 brownpigments: float = 0.0
184 watermass: float = 0.015
185 drymass: float = 0.006
187 carbonconstituents: float = 0.0
191 reassignment_threshold: float = 0.0
192 min_reassignment_change: float = 0.05
195 "f_photosynthetic",
"N_to_Cab_coefficient",
"Car_to_Cab_ratio",
"numberlayers",
196 "anthocyancontent",
"brownpigments",
"watermass",
"drymass",
"protein",
197 "carbonconstituents",
"V2Z",
"fqe",
"reassignment_threshold",
"min_reassignment_change",
201 """Raise ValueError if any field has the wrong type or an unphysical value."""
203 value = getattr(self, name)
204 if isinstance(value, bool)
or not isinstance(value, (int, float)):
205 raise ValueError(f
"{name} must be a number, got {type(value).__name__}")
206 if value != value
or value
in (float(
"inf"), float(
"-inf")):
207 raise ValueError(f
"{name} must be finite, got {value}")
209 raise ValueError(f
"{name} must be non-negative, got {value}")
211 raise ValueError(f
"numberlayers must be >= 1, got {self.numberlayers}")
213 raise ValueError(f
"f_photosynthetic must be in [0, 1], got {self.f_photosynthetic}")
215 raise ValueError(f
"V2Z must be in [0, 1], got {self.V2Z}")
217 raise ValueError(f
"num_bins must be an int, got {type(self.num_bins).__name__}")
219 raise ValueError(f
"num_bins must be at least 1, got {self.num_bins}")
221 def to_list(self) -> List[float]:
222 """Convert the float fields to a list in the order expected by the C++ interface (num_bins excluded)."""
223 return [float(getattr(self, name))
for name
in self.
_FLOAT_FIELDS]
229 Context manager that temporarily changes working directory to where LeafOptics assets are located.
231 LeafOptics C++ code uses relative paths like "plugins/leafoptics/spectral_data/"
232 expecting assets relative to working directory. This manager temporarily changes to the build
233 directory where assets are actually located.
236 asset_manager = get_asset_manager()
237 working_dir = asset_manager._get_helios_build_path()
239 if working_dir
and working_dir.exists():
240 leafoptics_assets = working_dir /
'plugins' /
'leafoptics' /
'spectral_data'
243 current_dir = Path(__file__).parent
244 repo_root = current_dir.parent
245 build_lib_dir = repo_root /
'pyhelios_build' /
'build' /
'lib'
246 working_dir = build_lib_dir.parent
247 leafoptics_assets = working_dir /
'plugins' /
'leafoptics' /
'spectral_data'
249 if not build_lib_dir.exists():
251 f
"PyHelios build directory not found at {build_lib_dir}. "
252 f
"LeafOptics requires native libraries to be built. "
253 f
"Run: build_scripts/build_helios --plugins leafoptics"
257 spectral_file = leafoptics_assets /
'prospect_spectral_library.xml'
258 if not spectral_file.exists():
260 f
"LeafOptics spectral data not found at {spectral_file}. "
261 f
"Build system failed to copy LeafOptics assets. "
262 f
"Run: build_scripts/build_helios --clean --plugins leafoptics"
266 file_size = spectral_file.stat().st_size
267 if file_size < 400000:
269 f
"LeafOptics spectral data file appears corrupted (size: {file_size} bytes, expected ~475KB). "
270 f
"Run: build_scripts/build_helios --clean --plugins leafoptics"
274 original_dir = os.getcwd()
276 os.chdir(working_dir)
277 logger.debug(f
"Changed working directory to {working_dir} for LeafOptics asset access")
280 os.chdir(original_dir)
281 logger.debug(f
"Restored working directory to {original_dir}")
286 High-level interface for PROSPECT leaf optical model.
288 This class provides a user-friendly wrapper around the native Helios
289 LeafOptics plugin for computing spectral reflectance and transmittance
290 of plant leaves based on their biochemical properties.
292 The PROSPECT model computes spectral optical properties for wavelengths
293 from 400 nm to 2500 nm at 1 nm resolution (2101 data points).
296 - Cross-platform support (Windows, Linux, macOS)
298 - Requires spectral_data assets (~475KB XML file)
299 - LeafOptics plugin compiled into PyHelios
302 >>> from pyhelios import Context, LeafOptics, LeafOpticsProperties
304 >>> with Context() as context:
305 ... with LeafOptics(context) as leafoptics:
306 ... # Get properties for a known species
307 ... props = leafoptics.getPropertiesFromLibrary("sunflower")
308 ... print(f"Sunflower chlorophyll: {props.chlorophyllcontent} ug/cm^2")
310 ... # Compute spectra
311 ... wavelengths, reflectance, transmittance = leafoptics.getLeafSpectra(props)
312 ... print(f"Spectral range: {wavelengths[0]}-{wavelengths[-1]} nm")
314 ... # Apply to geometry
315 ... leaf_uuid = context.addPatch(center=[0, 0, 1], size=[0.1, 0.1])
316 ... leafoptics.run([leaf_uuid], props, "sunflower_leaf")
319 def __init__(self, context: Context):
321 Initialize LeafOptics with graceful plugin handling.
324 context: Helios Context instance
327 TypeError: If context is not a Context instance
328 LeafOpticsError: If LeafOptics plugin is not available or spectral data missing
331 if not (hasattr(context,
'__class__')
and
332 (isinstance(context, Context)
or
333 context.__class__.__name__ ==
'Context')):
334 raise TypeError(f
"LeafOptics requires a Context instance, got {type(context).__name__}")
336 self.context = context
337 self._leafoptics_ptr =
None
340 registry = get_plugin_registry()
342 if not registry.is_plugin_available(
'leafoptics'):
344 available_plugins = registry.get_available_plugins()
347 "LeafOptics requires the 'leafoptics' plugin which is not available.\n\n"
348 "The LeafOptics plugin implements the PROSPECT leaf optical model which computes:\n"
349 "- Spectral reflectance (400-2500 nm at 1 nm resolution)\n"
350 "- Spectral transmittance\n"
351 "- Based on leaf biochemical properties (chlorophyll, water, dry matter, etc.)\n\n"
353 "- Cross-platform support (Windows, Linux, macOS)\n"
354 "- No GPU required\n"
355 "- Built-in species library with 12 plant species\n"
356 "- Supports both PROSPECT-D and PROSPECT-PRO modes\n\n"
357 "To enable LeafOptics modeling:\n"
358 "1. Build PyHelios with LeafOptics plugin:\n"
359 " build_scripts/build_helios --plugins leafoptics\n"
360 "2. Or build with radiation plugins for full spectral modeling:\n"
361 " build_scripts/build_helios --plugins leafoptics,radiation\n"
362 f
"\nCurrently available plugins: {available_plugins}"
370 self._leafoptics_ptr = leafoptics_wrapper.createLeafOptics(context.getNativePtr())
371 if self._leafoptics_ptr
is None:
373 "Failed to create LeafOptics instance. "
374 "This may indicate a problem with the spectral data files."
376 logger.info(
"LeafOptics created successfully")
378 except LeafOpticsError:
380 except Exception
as e:
384 """Raise if the owning Context has been destroyed (see Context.check_context_alive)."""
385 check_context_alive(getattr(self,
"context",
None),
"LeafOptics")
388 """Context manager entry."""
391 def __exit__(self, exc_type, exc_value, traceback):
392 """Context manager exit with proper cleanup."""
396 logger.debug(
"LeafOptics destroyed successfully")
397 except Exception
as e:
398 logger.warning(f
"Error destroying LeafOptics: {e}")
403 """Destructor to ensure C++ resources freed even without 'with' statement."""
404 if hasattr(self,
'_leafoptics_ptr')
and self.
_leafoptics_ptr is not None:
408 except Exception
as e:
410 warnings.warn(f
"Error in LeafOptics.__del__: {e}")
412 def run(self, UUIDs: List[int],
413 leafproperties: Union[LeafOpticsProperties, LeafOpticsProperties_Nauto],
414 label: Optional[str] =
None) ->
None:
416 Run the LeafOptics model to generate spectra and assign them to primitives.
418 Two modes, selected by the type of ``leafproperties``:
420 - :class:`LeafOpticsProperties` with a ``label``: computes one reflectance and
421 transmittance spectrum, stores it as global data ``"leaf_reflectivity_<label>"`` /
422 ``"leaf_transmissivity_<label>"``, and assigns it to every primitive.
423 - :class:`LeafOpticsProperties_Nauto` without a label (nitrogen mode): groups the
424 primitives by parent object, reads ``"leaf_nitrogen_gN_m2"`` object data from each,
425 derives chlorophyll and carotenoid content from it, and assigns each object the
426 spectrum of its nitrogen bin (global data ``"leaf_reflectivity_Nauto_<i>"`` etc.).
427 The first nitrogen-mode call creates the bins and fixes the parameters; later calls
428 track added/removed primitives, reassign leaves whose nitrogen changed, and rebuild
429 the bins if nitrogen moves outside their range. Parameters passed on later calls are
430 ignored. Primitives without a parent object are skipped with a warning.
433 UUIDs: List of primitive UUIDs to assign spectra to
434 leafproperties: LeafOpticsProperties or LeafOpticsProperties_Nauto
435 label: Spectrum label (required for LeafOpticsProperties, must be omitted for
436 LeafOpticsProperties_Nauto)
439 ValueError: If parameters are invalid
440 LeafOpticsError: If computation fails (e.g. an object lacks "leaf_nitrogen_gN_m2")
443 >>> props = LeafOpticsProperties(chlorophyllcontent=40.0, watermass=0.02)
444 >>> leafoptics.run([leaf_uuid], props, "my_leaf")
445 >>> # Creates: "leaf_reflectivity_my_leaf" and "leaf_transmissivity_my_leaf"
447 >>> context.setObjectDataFloat(leaf_objID, "leaf_nitrogen_gN_m2", 2.0)
448 >>> leafoptics.run(context.getObjectPrimitiveUUIDs(leaf_objID), LeafOpticsProperties_Nauto())
451 raise ValueError(
"UUIDs list cannot be empty")
453 if isinstance(leafproperties, LeafOpticsProperties_Nauto):
454 if label
is not None:
455 raise ValueError(
"label must not be given in nitrogen mode (LeafOpticsProperties_Nauto); "
456 "spectra are labelled 'Nauto_<bin>' automatically")
457 leafproperties.validate()
460 leafoptics_wrapper.leafOpticsRunNitrogen(
463 leafproperties.to_list(),
464 leafproperties.num_bins
466 except Exception
as e:
467 raise LeafOpticsError(f
"Failed to run nitrogen-based LeafOptics model: {e}")
470 if not isinstance(leafproperties, LeafOpticsProperties):
471 raise ValueError(
"leafproperties must be a LeafOpticsProperties or LeafOpticsProperties_Nauto instance, "
472 f
"got {type(leafproperties).__name__}")
474 raise ValueError(
"Label cannot be empty")
478 leafoptics_wrapper.leafOpticsRun(
481 leafproperties.to_list(),
484 except Exception
as e:
489 Re-read leaf nitrogen and reassign spectra for the primitives tracked in nitrogen mode.
491 Faster than calling :meth:`run` again with the same UUIDs when only nitrogen values
492 have changed (e.g. after advancing the PlantArchitecture nitrogen model): it skips
493 primitive grouping and add/remove processing. A leaf is moved to another bin only when
494 its nitrogen has moved past the configured reassignment thresholds. Bins are not
495 rebuilt here; use :meth:`run` if nitrogen may have left the original range.
498 LeafOpticsError: If nitrogen mode has not been initialized with
499 ``run(UUIDs, LeafOpticsProperties_Nauto(...))``
503 leafoptics_wrapper.leafOpticsUpdateNitrogenBasedSpectra(self.
_leafoptics_ptr)
504 except Exception
as e:
507 def runNoUUIDs(self, leafproperties: LeafOpticsProperties, label: str) ->
None:
509 Run the LeafOptics model without assigning to primitives.
511 This method computes reflectance and transmittance spectra based on the given
512 leaf properties and creates global data entries, but does not assign them to
516 leafproperties: LeafOpticsProperties with biochemical parameters
517 label: Label for the spectra (appended to "leaf_reflectivity_" and "leaf_transmissivity_")
520 ValueError: If parameters are invalid
521 LeafOpticsError: If computation fails
523 if not isinstance(leafproperties, LeafOpticsProperties):
524 raise ValueError(
"leafproperties must be a LeafOpticsProperties instance")
526 raise ValueError(
"Label cannot be empty")
530 leafoptics_wrapper.leafOpticsRunNoUUIDs(
532 leafproperties.to_list(),
535 except Exception
as e:
538 def getLeafSpectra(self, leafproperties: LeafOpticsProperties) -> Tuple[List[float], List[float], List[float]]:
540 Compute leaf reflectance and transmittance spectra.
542 This method computes spectral properties without creating global data entries
543 or assigning to primitives.
546 leafproperties: LeafOpticsProperties with biochemical parameters
549 Tuple of (wavelengths, reflectivities, transmissivities):
550 - wavelengths: List of wavelengths in nm (400-2500 at 1nm resolution, 2101 points)
551 - reflectivities: List of reflectance values (0-1) at each wavelength
552 - transmissivities: List of transmittance values (0-1) at each wavelength
555 ValueError: If parameters are invalid
556 LeafOpticsError: If computation fails
559 >>> props = LeafOpticsProperties(chlorophyllcontent=40.0)
560 >>> wavelengths, refl, trans = leafoptics.getLeafSpectra(props)
561 >>> # Find reflectance at 550 nm (green peak)
562 >>> idx_550 = wavelengths.index(550.0)
563 >>> print(f"Reflectance at 550 nm: {refl[idx_550]:.3f}")
565 if not isinstance(leafproperties, LeafOpticsProperties):
566 raise ValueError(
"leafproperties must be a LeafOpticsProperties instance")
570 return leafoptics_wrapper.leafOpticsGetLeafSpectra(
572 leafproperties.to_list()
574 except Exception
as e:
577 def setProperties(self, UUIDs: List[int], leafproperties: LeafOpticsProperties) ->
None:
579 Set leaf optical properties for primitives as Context primitive data.
581 This assigns the biochemical properties as primitive data using labels:
582 "chlorophyll", "carotenoid", "anthocyanin", "brown", "water", "drymass"
583 (or "protein" + "cellulose" in PROSPECT-PRO mode).
586 UUIDs: List of primitive UUIDs
587 leafproperties: LeafOpticsProperties with biochemical parameters
590 ValueError: If parameters are invalid
591 LeafOpticsError: If operation fails
594 raise ValueError(
"UUIDs list cannot be empty")
595 if not isinstance(leafproperties, LeafOpticsProperties):
596 raise ValueError(
"leafproperties must be a LeafOpticsProperties instance")
600 leafoptics_wrapper.leafOpticsSetProperties(
603 leafproperties.to_list()
605 except Exception
as e:
610 Get PROSPECT parameters from reflectivity spectrum for primitives.
612 This method retrieves the "reflectivity_spectrum" primitive data for each
613 primitive and checks if it matches a spectrum generated by this LeafOptics
614 instance. If a match is found, the corresponding PROSPECT model parameters
615 are assigned as primitive data.
618 UUIDs: List of primitive UUIDs to query
621 Primitives without matching spectra are silently skipped.
624 raise ValueError(
"UUIDs list cannot be empty")
628 leafoptics_wrapper.leafOpticsGetPropertiesFromSpectrum(
632 except Exception
as e:
637 Get leaf optical properties from the built-in species library.
639 The library contains PROSPECT-D parameters fitted from the LOPEX93 dataset
640 for common plant species.
643 species: Name of the species (case-insensitive). Available species:
644 "default", "garden_lettuce", "alfalfa", "corn", "sunflower",
645 "english_walnut", "rice", "soybean", "wine_grape", "tomato",
646 "common_bean", "cowpea"
649 LeafOpticsProperties populated with the species-specific parameters
652 ValueError: If species name is empty
655 If species is not found, default properties are used and a warning is issued.
658 >>> props = leafoptics.getPropertiesFromLibrary("sunflower")
659 >>> print(f"Chlorophyll: {props.chlorophyllcontent} ug/cm^2")
662 raise ValueError(
"Species name cannot be empty")
666 properties_list = leafoptics_wrapper.leafOpticsGetPropertiesFromLibrary(
670 return LeafOpticsProperties.from_list(properties_list)
671 except Exception
as e:
675 """Disable command-line output messages from LeafOptics."""
679 except Exception
as e:
683 """Enable command-line output messages from LeafOptics."""
687 except Exception
as e:
692 Selectively output specific biochemical properties as primitive data.
694 By default, LeafOptics writes all biochemical properties to primitive data.
695 Use this method to specify only the properties you need for improved performance.
698 label: Biochemical property to output. Valid values:
699 - "chlorophyll": Chlorophyll content
700 - "carotenoid": Carotenoid content
701 - "anthocyanin": Anthocyanin content
702 - "brown": Brown pigment content
703 - "water": Water content
704 - "drymass": Dry mass content
705 - "protein": Protein content
706 - "cellulose": Cellulose content
709 ValueError: If label is empty or invalid
710 LeafOpticsError: If operation fails
713 Added in helios-core v1.3.59 for performance optimization when only
714 specific biochemical properties are needed for analysis.
717 >>> with LeafOptics(context) as leaf:
718 ... # Only output chlorophyll and water content
719 ... leaf.optionalOutputPrimitiveData("chlorophyll")
720 ... leaf.optionalOutputPrimitiveData("water")
721 ... leaf.run(uuids, properties, "leaf_spectra")
724 raise ValueError(
"Label cannot be empty")
726 valid_labels = [
"chlorophyll",
"carotenoid",
"anthocyanin",
"brown",
727 "water",
"drymass",
"protein",
"cellulose"]
728 if label
not in valid_labels:
729 raise ValueError(f
"Invalid label '{label}'. Must be one of: {', '.join(valid_labels)}")
733 leafoptics_wrapper.leafOpticsOptionalOutputPrimitiveData(self.
_leafoptics_ptr, label)
734 except Exception
as e:
735 raise LeafOpticsError(f
"Failed to set optional output for '{label}': {e}")
740 Get list of available species in the built-in library.
743 List of species names that can be used with getPropertiesFromLibrary()
745 return AVAILABLE_SPECIES.copy()
750 Check if LeafOptics plugin is available in the current build.
753 True if LeafOptics is available, False otherwise
755 return leafoptics_wrapper.is_leafoptics_available()
Exception raised for LeafOptics-specific errors.
Parameters for nitrogen-based automatic leaf optics.
int num_bins
Number of spectrum bins (a single bin is used when all leaves share one nitrogen value)
List[float] to_list(self)
Convert the float fields to a list in the order expected by the C++ interface (num_bins excluded).
float f_photosynthetic
Fraction of leaf nitrogen in photosynthetic machinery [0-1].
float V2Z
Violaxanthin-to-zeaxanthin state [0, 1] for the SIF pipeline (fixed across bins)
float numberlayers
Leaf structure parameter N (must be >= 1)
None validate(self)
Raise ValueError if any field has the wrong type or an unphysical value.
Data class for PROSPECT leaf optical model parameters.
float anthocyancontent
Anthocyanin content in micrograms per square cm.
float watermass
Equivalent water thickness in grams per square cm.
float drymass
Dry matter content (leaf mass per area) in grams per square cm.
float numberlayers
Number of mesophyll layers in the leaf (typically 1-3)
float carbonconstituents
Carbon-based constituents in grams per square cm (PROSPECT-PRO mode)
float protein
Protein content in grams per square cm (PROSPECT-PRO mode)
float carotenoidcontent
Carotenoid content in micrograms per square cm.
'LeafOpticsProperties' from_list(cls, List[float] values)
Create LeafOpticsProperties from a list of values.
float brownpigments
Brown pigment content (arbitrary units, typically 0)
float chlorophyllcontent
Chlorophyll a+b content in micrograms per square cm.
List[float] to_list(self)
Convert properties to a list in the order expected by the C++ interface.
float V2Z
Violaxanthin-to-zeaxanthin de-epoxidation state, [0, 1].
float fqe
Intrinsic fluorescence quantum efficiency scalar applied on top of the.
High-level interface for PROSPECT leaf optical model.
None setProperties(self, List[int] UUIDs, LeafOpticsProperties leafproperties)
Set leaf optical properties for primitives as Context primitive data.
__del__(self)
Destructor to ensure C++ resources freed even without 'with' statement.
List[str] getAvailableSpecies()
Get list of available species in the built-in library.
LeafOpticsProperties getPropertiesFromLibrary(self, str species)
Get leaf optical properties from the built-in species library.
None updateNitrogenBasedSpectra(self)
Re-read leaf nitrogen and reassign spectra for the primitives tracked in nitrogen mode.
__exit__(self, exc_type, exc_value, traceback)
Context manager exit with proper cleanup.
Tuple[List[float], List[float], List[float]] getLeafSpectra(self, LeafOpticsProperties leafproperties)
Compute leaf reflectance and transmittance spectra.
None disableMessages(self)
Disable command-line output messages from LeafOptics.
None optionalOutputPrimitiveData(self, str label)
Selectively output specific biochemical properties as primitive data.
bool isAvailable()
Check if LeafOptics plugin is available in the current build.
None runNoUUIDs(self, LeafOpticsProperties leafproperties, str label)
Run the LeafOptics model without assigning to primitives.
None enableMessages(self)
Enable command-line output messages from LeafOptics.
None run(self, List[int] UUIDs, Union[LeafOpticsProperties, LeafOpticsProperties_Nauto] leafproperties, Optional[str] label=None)
Run the LeafOptics model to generate spectra and assign them to primitives.
__enter__(self)
Context manager entry.
None getPropertiesFromSpectrum(self, List[int] UUIDs)
Get PROSPECT parameters from reflectivity spectrum for primitives.
_check_context_alive(self)
Raise if the owning Context has been destroyed (see Context.check_context_alive).
Exception classes for PyHelios library.
_leafoptics_working_directory()
Context manager that temporarily changes working directory to where LeafOptics assets are located.