0.1.22
Loading...
Searching...
No Matches
LeafOptics.py
Go to the documentation of this file.
1"""
2High-level LeafOptics interface for PyHelios.
3
4This module provides a user-friendly interface to the PROSPECT leaf optical model
5for computing spectral reflectance and transmittance of plant leaves.
6"""
7
8import logging
9import os
10from contextlib import contextmanager
11from dataclasses import dataclass, field
12from pathlib import Path
13from typing import List, Optional, Tuple
14
15from .plugins.registry import get_plugin_registry
16from .wrappers import ULeafOpticsWrapper as leafoptics_wrapper
17from .Context import Context
18from .exceptions import HeliosError
19from .assets import get_asset_manager
20
21logger = logging.getLogger(__name__)
22
23
25 """Exception raised for LeafOptics-specific errors."""
26 pass
27
28
29# Available species in the built-in library
30AVAILABLE_SPECIES = [
31 "default",
32 "garden_lettuce",
33 "alfalfa",
34 "corn",
35 "sunflower",
36 "english_walnut",
37 "rice",
38 "soybean",
39 "wine_grape",
40 "tomato",
41 "common_bean",
42 "cowpea"
43]
44
45
46@dataclass
48 """
49 Data class for PROSPECT leaf optical model parameters.
50
51 These parameters define the physical and biochemical properties of a leaf
52 that determine its spectral reflectance and transmittance.
53
54 Attributes:
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.
71
72 Note:
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.
77 """
78 numberlayers: float = 1.5
79 brownpigments: float = 0.0
80 chlorophyllcontent: float = 30.0 # micrograms/cm^2
81 carotenoidcontent: float = 7.0 # micrograms/cm^2
82 anthocyancontent: float = 1.0 # micrograms/cm^2
83 watermass: float = 0.015 # g/cm^2
84 drymass: float = 0.09 # g/cm^2
85 protein: float = 0.0 # g/cm^2 (PROSPECT-PRO mode)
86 carbonconstituents: float = 0.0 # g/cm^2 (PROSPECT-PRO mode)
87 V2Z: float = 0.0 # SIF: violaxanthin↔zeaxanthin state, [0, 1]
88 fqe: float = 1.0 # SIF: intrinsic fluorescence quantum efficiency scalar
89
90 def to_list(self) -> List[float]:
91 """Convert properties to a list in the order expected by the C++ interface."""
92 return [
93 self.numberlayers,
94 self.brownpigments,
98 self.watermass,
99 self.drymass,
100 self.protein,
102 self.V2Z,
103 self.fqe,
106 @classmethod
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.
114 """
115 if len(values) not in (9, 11):
116 raise ValueError(f"Expected 9 or 11 values, got {len(values)}")
117 if len(values) == 9:
118 import warnings
119 warnings.warn(
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.",
124 DeprecationWarning,
125 stacklevel=2,
126 )
127 return cls(
128 numberlayers=values[0],
129 brownpigments=values[1],
130 chlorophyllcontent=values[2],
131 carotenoidcontent=values[3],
132 anthocyancontent=values[4],
133 watermass=values[5],
134 drymass=values[6],
135 protein=values[7],
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,
140
141
142@contextmanager
144 """
145 Context manager that temporarily changes working directory to where LeafOptics assets are located.
146
147 LeafOptics C++ code uses relative paths like "plugins/leafoptics/spectral_data/"
148 expecting assets relative to working directory. This manager temporarily changes to the build
149 directory where assets are actually located.
150 """
151 # Find the build directory containing LeafOptics assets
152 asset_manager = get_asset_manager()
153 working_dir = asset_manager._get_helios_build_path()
154
155 if working_dir and working_dir.exists():
156 leafoptics_assets = working_dir / 'plugins' / 'leafoptics' / 'spectral_data'
157 else:
158 # Fallback to development paths
159 current_dir = Path(__file__).parent
160 repo_root = current_dir.parent
161 build_lib_dir = repo_root / 'pyhelios_build' / 'build' / 'lib'
162 working_dir = build_lib_dir.parent
163 leafoptics_assets = working_dir / 'plugins' / 'leafoptics' / 'spectral_data'
164
165 if not build_lib_dir.exists():
166 raise LeafOpticsError(
167 f"PyHelios build directory not found at {build_lib_dir}. "
168 f"LeafOptics requires native libraries to be built. "
169 f"Run: build_scripts/build_helios --plugins leafoptics"
170 )
171
172 # Validate spectral data file exists
173 spectral_file = leafoptics_assets / 'prospect_spectral_library.xml'
174 if not spectral_file.exists():
175 raise LeafOpticsError(
176 f"LeafOptics spectral data not found at {spectral_file}. "
177 f"Build system failed to copy LeafOptics assets. "
178 f"Run: build_scripts/build_helios --clean --plugins leafoptics"
179 )
180
181 # Validate file size (should be ~475KB)
182 file_size = spectral_file.stat().st_size
183 if file_size < 400000: # Less than 400KB indicates corruption
184 raise LeafOpticsError(
185 f"LeafOptics spectral data file appears corrupted (size: {file_size} bytes, expected ~475KB). "
186 f"Run: build_scripts/build_helios --clean --plugins leafoptics"
187 )
188
189 # Change to the build directory temporarily
190 original_dir = os.getcwd()
191 try:
192 os.chdir(working_dir)
193 logger.debug(f"Changed working directory to {working_dir} for LeafOptics asset access")
194 yield working_dir
195 finally:
196 os.chdir(original_dir)
197 logger.debug(f"Restored working directory to {original_dir}")
198
199
200class LeafOptics:
201 """
202 High-level interface for PROSPECT leaf optical model.
203
204 This class provides a user-friendly wrapper around the native Helios
205 LeafOptics plugin for computing spectral reflectance and transmittance
206 of plant leaves based on their biochemical properties.
207
208 The PROSPECT model computes spectral optical properties for wavelengths
209 from 400 nm to 2500 nm at 1 nm resolution (2101 data points).
210
211 System requirements:
212 - Cross-platform support (Windows, Linux, macOS)
213 - No GPU required
214 - Requires spectral_data assets (~475KB XML file)
215 - LeafOptics plugin compiled into PyHelios
216
217 Example:
218 >>> from pyhelios import Context, LeafOptics, LeafOpticsProperties
219 >>>
220 >>> with Context() as context:
221 ... with LeafOptics(context) as leafoptics:
222 ... # Get properties for a known species
223 ... props = leafoptics.getPropertiesFromLibrary("sunflower")
224 ... print(f"Sunflower chlorophyll: {props.chlorophyllcontent} ug/cm^2")
225 ...
226 ... # Compute spectra
227 ... wavelengths, reflectance, transmittance = leafoptics.getLeafSpectra(props)
228 ... print(f"Spectral range: {wavelengths[0]}-{wavelengths[-1]} nm")
229 ...
230 ... # Apply to geometry
231 ... leaf_uuid = context.addPatch(center=[0, 0, 1], size=[0.1, 0.1])
232 ... leafoptics.run([leaf_uuid], props, "sunflower_leaf")
233 """
234
235 def __init__(self, context: Context):
236 """
237 Initialize LeafOptics with graceful plugin handling.
238
239 Args:
240 context: Helios Context instance
241
242 Raises:
243 TypeError: If context is not a Context instance
244 LeafOpticsError: If LeafOptics plugin is not available or spectral data missing
245 """
246 # Validate context type - use duck typing to handle import state issues during testing
247 if not (hasattr(context, '__class__') and
248 (isinstance(context, Context) or
249 context.__class__.__name__ == 'Context')):
250 raise TypeError(f"LeafOptics requires a Context instance, got {type(context).__name__}")
251
252 self.context = context
253 self._leafoptics_ptr = None
254
255 # Check plugin availability using registry
256 registry = get_plugin_registry()
257
258 if not registry.is_plugin_available('leafoptics'):
259 # Get helpful information about the missing plugin
260 available_plugins = registry.get_available_plugins()
261
262 error_msg = (
263 "LeafOptics requires the 'leafoptics' plugin which is not available.\n\n"
264 "The LeafOptics plugin implements the PROSPECT leaf optical model which computes:\n"
265 "- Spectral reflectance (400-2500 nm at 1 nm resolution)\n"
266 "- Spectral transmittance\n"
267 "- Based on leaf biochemical properties (chlorophyll, water, dry matter, etc.)\n\n"
268 "Features:\n"
269 "- Cross-platform support (Windows, Linux, macOS)\n"
270 "- No GPU required\n"
271 "- Built-in species library with 12 plant species\n"
272 "- Supports both PROSPECT-D and PROSPECT-PRO modes\n\n"
273 "To enable LeafOptics modeling:\n"
274 "1. Build PyHelios with LeafOptics plugin:\n"
275 " build_scripts/build_helios --plugins leafoptics\n"
276 "2. Or build with radiation plugins for full spectral modeling:\n"
277 " build_scripts/build_helios --plugins leafoptics,radiation\n"
278 f"\nCurrently available plugins: {available_plugins}"
281 raise LeafOpticsError(error_msg)
282
283 # Plugin is available - create LeafOptics with asset-aware working directory
284 try:
286 self._leafoptics_ptr = leafoptics_wrapper.createLeafOptics(context.getNativePtr())
287 if self._leafoptics_ptr is None:
288 raise LeafOpticsError(
289 "Failed to create LeafOptics instance. "
290 "This may indicate a problem with the spectral data files."
291 )
292 logger.info("LeafOptics created successfully")
293
294 except LeafOpticsError:
295 raise
296 except Exception as e:
297 raise LeafOpticsError(f"Failed to initialize LeafOptics: {e}")
298
299 def __enter__(self):
300 """Context manager entry."""
301 return self
302
303 def __exit__(self, exc_type, exc_value, traceback):
304 """Context manager exit with proper cleanup."""
305 if self._leafoptics_ptr is not None:
306 try:
307 leafoptics_wrapper.destroyLeafOptics(self._leafoptics_ptr)
308 logger.debug("LeafOptics destroyed successfully")
309 except Exception as e:
310 logger.warning(f"Error destroying LeafOptics: {e}")
311 finally:
312 self._leafoptics_ptr = None
313
314 def __del__(self):
315 """Destructor to ensure C++ resources freed even without 'with' statement."""
316 if hasattr(self, '_leafoptics_ptr') and self._leafoptics_ptr is not None:
317 try:
318 leafoptics_wrapper.destroyLeafOptics(self._leafoptics_ptr)
319 self._leafoptics_ptr = None
320 except Exception as e:
321 import warnings
322 warnings.warn(f"Error in LeafOptics.__del__: {e}")
323
324 def run(self, UUIDs: List[int], leafproperties: LeafOpticsProperties, label: str) -> None:
325 """
326 Run the LeafOptics model to generate spectra and assign to primitives.
328 This method computes reflectance and transmittance spectra based on the given
329 leaf properties, creates global data entries, and assigns them to the specified
330 primitives.
332 Args:
333 UUIDs: List of primitive UUIDs to assign spectra to
334 leafproperties: LeafOpticsProperties with biochemical parameters
335 label: Label for the spectra (appended to "leaf_reflectivity_" and "leaf_transmissivity_")
336
337 Raises:
338 ValueError: If parameters are invalid
339 LeafOpticsError: If computation fails
340
341 Example:
342 >>> props = LeafOpticsProperties(chlorophyllcontent=40.0, watermass=0.02)
343 >>> leafoptics.run([leaf_uuid], props, "my_leaf")
344 >>> # Creates: "leaf_reflectivity_my_leaf" and "leaf_transmissivity_my_leaf"
345 """
346 if not UUIDs:
347 raise ValueError("UUIDs list cannot be empty")
348 if not isinstance(leafproperties, LeafOpticsProperties):
349 raise ValueError("leafproperties must be a LeafOpticsProperties instance")
350 if not label:
351 raise ValueError("Label cannot be empty")
352
353 try:
354 leafoptics_wrapper.leafOpticsRun(
355 self._leafoptics_ptr,
356 UUIDs,
357 leafproperties.to_list(),
358 label
359 )
360 except Exception as e:
361 raise LeafOpticsError(f"Failed to run LeafOptics model: {e}")
362
363 def runNoUUIDs(self, leafproperties: LeafOpticsProperties, label: str) -> None:
364 """
365 Run the LeafOptics model without assigning to primitives.
366
367 This method computes reflectance and transmittance spectra based on the given
368 leaf properties and creates global data entries, but does not assign them to
369 any primitives.
370
371 Args:
372 leafproperties: LeafOpticsProperties with biochemical parameters
373 label: Label for the spectra (appended to "leaf_reflectivity_" and "leaf_transmissivity_")
374
375 Raises:
376 ValueError: If parameters are invalid
377 LeafOpticsError: If computation fails
378 """
379 if not isinstance(leafproperties, LeafOpticsProperties):
380 raise ValueError("leafproperties must be a LeafOpticsProperties instance")
381 if not label:
382 raise ValueError("Label cannot be empty")
383
384 try:
385 leafoptics_wrapper.leafOpticsRunNoUUIDs(
386 self._leafoptics_ptr,
387 leafproperties.to_list(),
388 label
389 )
390 except Exception as e:
391 raise LeafOpticsError(f"Failed to run LeafOptics model: {e}")
392
393 def getLeafSpectra(self, leafproperties: LeafOpticsProperties) -> Tuple[List[float], List[float], List[float]]:
394 """
395 Compute leaf reflectance and transmittance spectra.
396
397 This method computes spectral properties without creating global data entries
398 or assigning to primitives.
399
400 Args:
401 leafproperties: LeafOpticsProperties with biochemical parameters
402
403 Returns:
404 Tuple of (wavelengths, reflectivities, transmissivities):
405 - wavelengths: List of wavelengths in nm (400-2500 at 1nm resolution, 2101 points)
406 - reflectivities: List of reflectance values (0-1) at each wavelength
407 - transmissivities: List of transmittance values (0-1) at each wavelength
408
409 Raises:
410 ValueError: If parameters are invalid
411 LeafOpticsError: If computation fails
412
413 Example:
414 >>> props = LeafOpticsProperties(chlorophyllcontent=40.0)
415 >>> wavelengths, refl, trans = leafoptics.getLeafSpectra(props)
416 >>> # Find reflectance at 550 nm (green peak)
417 >>> idx_550 = wavelengths.index(550.0)
418 >>> print(f"Reflectance at 550 nm: {refl[idx_550]:.3f}")
419 """
420 if not isinstance(leafproperties, LeafOpticsProperties):
421 raise ValueError("leafproperties must be a LeafOpticsProperties instance")
422
423 try:
424 return leafoptics_wrapper.leafOpticsGetLeafSpectra(
425 self._leafoptics_ptr,
426 leafproperties.to_list()
427 )
428 except Exception as e:
429 raise LeafOpticsError(f"Failed to get leaf spectra: {e}")
430
431 def setProperties(self, UUIDs: List[int], leafproperties: LeafOpticsProperties) -> None:
432 """
433 Set leaf optical properties for primitives as Context primitive data.
434
435 This assigns the biochemical properties as primitive data using labels:
436 "chlorophyll", "carotenoid", "anthocyanin", "brown", "water", "drymass"
437 (or "protein" + "cellulose" in PROSPECT-PRO mode).
438
439 Args:
440 UUIDs: List of primitive UUIDs
441 leafproperties: LeafOpticsProperties with biochemical parameters
442
443 Raises:
444 ValueError: If parameters are invalid
445 LeafOpticsError: If operation fails
446 """
447 if not UUIDs:
448 raise ValueError("UUIDs list cannot be empty")
449 if not isinstance(leafproperties, LeafOpticsProperties):
450 raise ValueError("leafproperties must be a LeafOpticsProperties instance")
451
452 try:
453 leafoptics_wrapper.leafOpticsSetProperties(
454 self._leafoptics_ptr,
455 UUIDs,
456 leafproperties.to_list()
457 )
458 except Exception as e:
459 raise LeafOpticsError(f"Failed to set properties: {e}")
460
461 def getPropertiesFromSpectrum(self, UUIDs: List[int]) -> None:
462 """
463 Get PROSPECT parameters from reflectivity spectrum for primitives.
464
465 This method retrieves the "reflectivity_spectrum" primitive data for each
466 primitive and checks if it matches a spectrum generated by this LeafOptics
467 instance. If a match is found, the corresponding PROSPECT model parameters
468 are assigned as primitive data.
469
470 Args:
471 UUIDs: List of primitive UUIDs to query
472
473 Note:
474 Primitives without matching spectra are silently skipped.
475 """
476 if not UUIDs:
477 raise ValueError("UUIDs list cannot be empty")
478
479 try:
480 leafoptics_wrapper.leafOpticsGetPropertiesFromSpectrum(
481 self._leafoptics_ptr,
482 UUIDs
483 )
484 except Exception as e:
485 raise LeafOpticsError(f"Failed to get properties from spectrum: {e}")
486
487 def getPropertiesFromLibrary(self, species: str) -> LeafOpticsProperties:
488 """
489 Get leaf optical properties from the built-in species library.
490
491 The library contains PROSPECT-D parameters fitted from the LOPEX93 dataset
492 for common plant species.
493
494 Args:
495 species: Name of the species (case-insensitive). Available species:
496 "default", "garden_lettuce", "alfalfa", "corn", "sunflower",
497 "english_walnut", "rice", "soybean", "wine_grape", "tomato",
498 "common_bean", "cowpea"
499
500 Returns:
501 LeafOpticsProperties populated with the species-specific parameters
503 Raises:
504 ValueError: If species name is empty
505
506 Note:
507 If species is not found, default properties are used and a warning is issued.
508
509 Example:
510 >>> props = leafoptics.getPropertiesFromLibrary("sunflower")
511 >>> print(f"Chlorophyll: {props.chlorophyllcontent} ug/cm^2")
512 """
513 if not species:
514 raise ValueError("Species name cannot be empty")
515
516 try:
517 properties_list = leafoptics_wrapper.leafOpticsGetPropertiesFromLibrary(
518 self._leafoptics_ptr,
519 species
520 )
521 return LeafOpticsProperties.from_list(properties_list)
522 except Exception as e:
523 raise LeafOpticsError(f"Failed to get properties from library: {e}")
524
525 def disableMessages(self) -> None:
526 """Disable command-line output messages from LeafOptics."""
527 try:
528 leafoptics_wrapper.leafOpticsDisableMessages(self._leafoptics_ptr)
529 except Exception as e:
530 raise LeafOpticsError(f"Failed to disable messages: {e}")
531
532 def enableMessages(self) -> None:
533 """Enable command-line output messages from LeafOptics."""
534 try:
535 leafoptics_wrapper.leafOpticsEnableMessages(self._leafoptics_ptr)
536 except Exception as e:
537 raise LeafOpticsError(f"Failed to enable messages: {e}")
538
539 def optionalOutputPrimitiveData(self, label: str) -> None:
540 """
541 Selectively output specific biochemical properties as primitive data.
542
543 By default, LeafOptics writes all biochemical properties to primitive data.
544 Use this method to specify only the properties you need for improved performance.
545
546 Args:
547 label: Biochemical property to output. Valid values:
548 - "chlorophyll": Chlorophyll content
549 - "carotenoid": Carotenoid content
550 - "anthocyanin": Anthocyanin content
551 - "brown": Brown pigment content
552 - "water": Water content
553 - "drymass": Dry mass content
554 - "protein": Protein content
555 - "cellulose": Cellulose content
556
557 Raises:
558 ValueError: If label is empty or invalid
559 LeafOpticsError: If operation fails
561 Note:
562 Added in helios-core v1.3.59 for performance optimization when only
563 specific biochemical properties are needed for analysis.
564
565 Example:
566 >>> with LeafOptics(context) as leaf:
567 ... # Only output chlorophyll and water content
568 ... leaf.optionalOutputPrimitiveData("chlorophyll")
569 ... leaf.optionalOutputPrimitiveData("water")
570 ... leaf.run(uuids, properties, "leaf_spectra")
571 """
572 if not label:
573 raise ValueError("Label cannot be empty")
574
575 valid_labels = ["chlorophyll", "carotenoid", "anthocyanin", "brown",
576 "water", "drymass", "protein", "cellulose"]
577 if label not in valid_labels:
578 raise ValueError(f"Invalid label '{label}'. Must be one of: {', '.join(valid_labels)}")
579
580 try:
581 leafoptics_wrapper.leafOpticsOptionalOutputPrimitiveData(self._leafoptics_ptr, label)
582 except Exception as e:
583 raise LeafOpticsError(f"Failed to set optional output for '{label}': {e}")
584
585 @staticmethod
586 def getAvailableSpecies() -> List[str]:
587 """
588 Get list of available species in the built-in library.
589
590 Returns:
591 List of species names that can be used with getPropertiesFromLibrary()
592 """
593 return AVAILABLE_SPECIES.copy()
594
595 @staticmethod
596 def isAvailable() -> bool:
597 """
598 Check if LeafOptics plugin is available in the current build.
599
600 Returns:
601 True if LeafOptics is available, False otherwise
602 """
603 return leafoptics_wrapper.is_leafoptics_available()
Exception raised for LeafOptics-specific errors.
Definition LeafOptics.py:25
Data class for PROSPECT leaf optical model parameters.
Definition LeafOptics.py:63
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.
__exit__(self, exc_type, exc_value, traceback)
Context manager exit with proper cleanup.
None run(self, List[int] UUIDs, LeafOpticsProperties leafproperties, str label)
Run the LeafOptics model to generate spectra and assign to primitives.
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.
__enter__(self)
Context manager entry.
None getPropertiesFromSpectrum(self, List[int] UUIDs)
Get PROSPECT parameters from reflectivity spectrum for primitives.
Exception classes for PyHelios library.
Definition exceptions.py:10
_leafoptics_working_directory()
Context manager that temporarily changes working directory to where LeafOptics assets are located.