0.1.39
Loading...
Searching...
No Matches
ULeafOpticsWrapper.py
Go to the documentation of this file.
1"""
2Ctypes wrapper for LeafOptics C++ bindings.
3
4This module provides low-level ctypes bindings to interface with
5the native Helios LeafOptics plugin (PROSPECT model) via the C++ wrapper layer.
6"""
7
8import ctypes
9from typing import List, Tuple
10
11from ..plugins import helios_lib
12from ..exceptions import check_helios_error
13
14# Define the ULeafOptics struct
15class ULeafOptics(ctypes.Structure):
16 """Opaque structure for LeafOptics C++ class"""
17 pass
18
19# Import UContext from main wrapper to avoid type conflicts
20from .UContextWrapper import UContext
21
22# Number of properties in LeafOpticsProperties struct.
23# Order: [numberlayers, brownpigments, chlorophyllcontent, carotenoidcontent,
24# anthocyancontent, watermass, drymass, protein, carbonconstituents, V2Z, fqe]
25LEAF_OPTICS_PROPERTIES_COUNT = 11
26
27# Number of spectral points (400-2500 nm at 1nm resolution)
28LEAF_OPTICS_SPECTRAL_POINTS = 2101
29
30# Number of float fields in LeafOpticsProperties_Nauto (num_bins is passed separately as uint).
31# Order: [f_photosynthetic, N_to_Cab_coefficient, Car_to_Cab_ratio, numberlayers,
32# anthocyancontent, brownpigments, watermass, drymass, protein, carbonconstituents,
33# V2Z, fqe, reassignment_threshold, min_reassignment_change]
34LEAF_OPTICS_NAUTO_FLOAT_COUNT = 14
35
36# Error checking callback
37def _check_error(result, func, args):
38 """Automatic error checking for all leaf optics functions"""
39 check_helios_error(helios_lib.getLastErrorCode, helios_lib.getLastErrorMessage, helios_lib.clearError)
40 return result
41
42# Try to set up LeafOptics function prototypes
43try:
44 # LeafOptics creation and destruction
45 helios_lib.createLeafOptics.argtypes = [ctypes.POINTER(UContext)]
46 helios_lib.createLeafOptics.restype = ctypes.POINTER(ULeafOptics)
47 helios_lib.createLeafOptics.errcheck = _check_error
49 helios_lib.destroyLeafOptics.argtypes = [ctypes.POINTER(ULeafOptics)]
50 helios_lib.destroyLeafOptics.restype = None
51
52 # Model execution
53 helios_lib.leafOpticsRun.argtypes = [
54 ctypes.POINTER(ULeafOptics),
55 ctypes.POINTER(ctypes.c_uint),
56 ctypes.c_uint,
57 ctypes.POINTER(ctypes.c_float),
58 ctypes.c_char_p
59 ]
60 helios_lib.leafOpticsRun.restype = None
61 helios_lib.leafOpticsRun.errcheck = _check_error
62
63 helios_lib.leafOpticsRunNoUUIDs.argtypes = [
64 ctypes.POINTER(ULeafOptics),
65 ctypes.POINTER(ctypes.c_float),
66 ctypes.c_char_p
67 ]
68 helios_lib.leafOpticsRunNoUUIDs.restype = None
69 helios_lib.leafOpticsRunNoUUIDs.errcheck = _check_error
70
71 # Spectral data retrieval
72 helios_lib.leafOpticsGetLeafSpectra.argtypes = [
73 ctypes.POINTER(ULeafOptics),
74 ctypes.POINTER(ctypes.c_float),
75 ctypes.POINTER(ctypes.c_float),
76 ctypes.POINTER(ctypes.c_float),
77 ctypes.POINTER(ctypes.c_float),
78 ctypes.POINTER(ctypes.c_uint)
79 ]
80 helios_lib.leafOpticsGetLeafSpectra.restype = None
81 helios_lib.leafOpticsGetLeafSpectra.errcheck = _check_error
82
83 # Property management
84 helios_lib.leafOpticsSetProperties.argtypes = [
85 ctypes.POINTER(ULeafOptics),
86 ctypes.POINTER(ctypes.c_uint),
87 ctypes.c_uint,
88 ctypes.POINTER(ctypes.c_float)
89 ]
90 helios_lib.leafOpticsSetProperties.restype = None
91 helios_lib.leafOpticsSetProperties.errcheck = _check_error
92
93 helios_lib.leafOpticsGetPropertiesFromSpectrum.argtypes = [
94 ctypes.POINTER(ULeafOptics),
95 ctypes.POINTER(ctypes.c_uint),
96 ctypes.c_uint
97 ]
98 helios_lib.leafOpticsGetPropertiesFromSpectrum.restype = None
99 helios_lib.leafOpticsGetPropertiesFromSpectrum.errcheck = _check_error
100
101 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.argtypes = [
102 ctypes.POINTER(ULeafOptics),
103 ctypes.c_uint
104 ]
105 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.restype = None
106 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.errcheck = _check_error
107
108 # Species library
109 helios_lib.leafOpticsGetPropertiesFromLibrary.argtypes = [
110 ctypes.POINTER(ULeafOptics),
111 ctypes.c_char_p,
112 ctypes.POINTER(ctypes.c_float)
113 ]
114 helios_lib.leafOpticsGetPropertiesFromLibrary.restype = None
115 helios_lib.leafOpticsGetPropertiesFromLibrary.errcheck = _check_error
116
117 # Message control
118 helios_lib.leafOpticsDisableMessages.argtypes = [ctypes.POINTER(ULeafOptics)]
119 helios_lib.leafOpticsDisableMessages.restype = None
120 helios_lib.leafOpticsDisableMessages.errcheck = _check_error
121
122 helios_lib.leafOpticsEnableMessages.argtypes = [ctypes.POINTER(ULeafOptics)]
123 helios_lib.leafOpticsEnableMessages.restype = None
124 helios_lib.leafOpticsEnableMessages.errcheck = _check_error
125
126 # Optional output primitive data (v1.3.59)
127 helios_lib.leafOpticsOptionalOutputPrimitiveData.argtypes = [ctypes.POINTER(ULeafOptics), ctypes.c_char_p]
128 helios_lib.leafOpticsOptionalOutputPrimitiveData.restype = None
129 helios_lib.leafOpticsOptionalOutputPrimitiveData.errcheck = _check_error
130
131 _LEAFOPTICS_FUNCTIONS_AVAILABLE = True
132
133except AttributeError:
134 _LEAFOPTICS_FUNCTIONS_AVAILABLE = False
135
136# Nitrogen-based automatic mode (set up separately so an older library without these
137# symbols keeps the rest of LeafOptics usable)
138try:
139 helios_lib.leafOpticsRunNitrogen.argtypes = [
140 ctypes.POINTER(ULeafOptics),
141 ctypes.POINTER(ctypes.c_uint),
142 ctypes.c_uint,
143 ctypes.POINTER(ctypes.c_float),
144 ctypes.c_uint
145 ]
146 helios_lib.leafOpticsRunNitrogen.restype = None
147 helios_lib.leafOpticsRunNitrogen.errcheck = _check_error
148
149 helios_lib.leafOpticsUpdateNitrogenBasedSpectra.argtypes = [ctypes.POINTER(ULeafOptics)]
150 helios_lib.leafOpticsUpdateNitrogenBasedSpectra.restype = None
151 helios_lib.leafOpticsUpdateNitrogenBasedSpectra.errcheck = _check_error
152
153 _LEAFOPTICS_NITROGEN_FUNCTIONS_AVAILABLE = True
154
155except AttributeError:
156 _LEAFOPTICS_NITROGEN_FUNCTIONS_AVAILABLE = False
157
158_NITROGEN_NOT_AVAILABLE_MSG = (
159 "LeafOptics nitrogen-mode functions not available in current Helios library. "
160 "Rebuild PyHelios to include them:\n"
161 " build_scripts/build_helios"
162)
163
165# Wrapper functions
166
167def createLeafOptics(context: ctypes.POINTER(UContext)) -> ctypes.POINTER(ULeafOptics):
168 """Create LeafOptics instance
169
170 Args:
171 context: Pointer to the Helios Context
172
173 Returns:
174 Pointer to the created LeafOptics instance
176 Raises:
177 NotImplementedError: If LeafOptics functions not available
178 ValueError: If context is None
179 """
180 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
181 raise NotImplementedError(
182 "LeafOptics functions not available in current Helios library. "
183 "Rebuild PyHelios with 'leafoptics' enabled:\n"
184 " build_scripts/build_helios --plugins leafoptics"
185 )
186
187 if not context:
188 raise ValueError("Context instance is None.")
189
190 return helios_lib.createLeafOptics(context)
191
192
193def destroyLeafOptics(leafoptics: ctypes.POINTER(ULeafOptics)) -> None:
194 """Destroy LeafOptics instance"""
195 if leafoptics and _LEAFOPTICS_FUNCTIONS_AVAILABLE:
196 helios_lib.destroyLeafOptics(leafoptics)
197
198
199def leafOpticsRun(leafoptics: ctypes.POINTER(ULeafOptics),
200 uuids: List[int],
201 properties: List[float],
202 label: str) -> None:
203 """Run LeafOptics model and assign spectra to primitives
204
205 Args:
206 leafoptics: Pointer to LeafOptics instance
207 uuids: List of primitive UUIDs
208 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
209 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
210 label: Label for the spectra (appended to "leaf_reflectivity_" and "leaf_transmissivity_")
211 """
212 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
213 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
214 if not leafoptics:
215 raise ValueError("LeafOptics instance is None.")
216 if not uuids:
217 raise ValueError("UUIDs list cannot be empty.")
218 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
219 raise ValueError(f"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
220 if not label:
221 raise ValueError("Label cannot be empty.")
222
223 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
224 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
225 label_bytes = label.encode('utf-8')
226
227 helios_lib.leafOpticsRun(leafoptics, uuid_array, len(uuids), properties_array, label_bytes)
228
229
230def leafOpticsRunNoUUIDs(leafoptics: ctypes.POINTER(ULeafOptics),
231 properties: List[float],
232 label: str) -> None:
233 """Run LeafOptics model without assigning to primitives
234
235 Args:
236 leafoptics: Pointer to LeafOptics instance
237 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
238 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
239 label: Label for the spectra
240 """
241 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
242 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
243 if not leafoptics:
244 raise ValueError("LeafOptics instance is None.")
245 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
246 raise ValueError(f"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
247 if not label:
248 raise ValueError("Label cannot be empty.")
249
250 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
251 label_bytes = label.encode('utf-8')
252
253 helios_lib.leafOpticsRunNoUUIDs(leafoptics, properties_array, label_bytes)
254
256def leafOpticsGetLeafSpectra(leafoptics: ctypes.POINTER(ULeafOptics),
257 properties: List[float]) -> Tuple[List[float], List[float], List[float]]:
258 """Get leaf reflectance and transmittance spectra
259
260 Args:
261 leafoptics: Pointer to LeafOptics instance
262 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
263 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
264
265 Returns:
266 Tuple of (wavelengths, reflectivities, transmissivities) as lists of floats
267 - wavelengths: 400-2500 nm at 1nm resolution (2101 points)
268 - reflectivities: reflectance values at each wavelength
269 - transmissivities: transmittance values at each wavelength
270 """
271 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
272 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
273 if not leafoptics:
274 raise ValueError("LeafOptics instance is None.")
275 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
276 raise ValueError(f"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
277
278 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
279 reflectivities = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
280 transmissivities = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
281 wavelengths = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
282 size = ctypes.c_uint()
283
284 helios_lib.leafOpticsGetLeafSpectra(
285 leafoptics, properties_array, reflectivities, transmissivities, wavelengths, ctypes.byref(size)
287
288 # Convert to Python lists
289 n = size.value
290 return (
291 list(wavelengths[:n]),
292 list(reflectivities[:n]),
293 list(transmissivities[:n])
294 )
295
296
297def leafOpticsSetProperties(leafoptics: ctypes.POINTER(ULeafOptics),
298 uuids: List[int],
299 properties: List[float]) -> None:
300 """Set leaf optical properties for primitives
301
302 Args:
303 leafoptics: Pointer to LeafOptics instance
304 uuids: List of primitive UUIDs
305 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
306 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
307 """
308 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
309 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
310 if not leafoptics:
311 raise ValueError("LeafOptics instance is None.")
312 if not uuids:
313 raise ValueError("UUIDs list cannot be empty.")
314 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
315 raise ValueError(f"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
316
317 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
318 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
319
320 helios_lib.leafOpticsSetProperties(leafoptics, uuid_array, len(uuids), properties_array)
321
323def leafOpticsGetPropertiesFromSpectrum(leafoptics: ctypes.POINTER(ULeafOptics),
324 uuids: List[int]) -> None:
325 """Get PROSPECT parameters from reflectivity spectrum for primitives
326
327 Args:
328 leafoptics: Pointer to LeafOptics instance
329 uuids: List of primitive UUIDs to query
330
331 Note:
332 Primitives without matching spectra are silently skipped
333 """
334 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
335 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
336 if not leafoptics:
337 raise ValueError("LeafOptics instance is None.")
338 if not uuids:
339 raise ValueError("UUIDs list cannot be empty.")
340
341 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
342
343 helios_lib.leafOpticsGetPropertiesFromSpectrum(leafoptics, uuid_array, len(uuids))
344
345
346def leafOpticsGetPropertiesFromSpectrumSingle(leafoptics: ctypes.POINTER(ULeafOptics),
347 uuid: int) -> None:
348 """Get PROSPECT parameters from reflectivity spectrum for a single primitive
350 Args:
351 leafoptics: Pointer to LeafOptics instance
352 uuid: Single primitive UUID to query
353
354 Note:
355 If no matching spectrum is found, the primitive is silently skipped
356 """
357 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
358 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
359 if not leafoptics:
360 raise ValueError("LeafOptics instance is None.")
361 if uuid < 0:
362 raise ValueError("UUID must be non-negative.")
363
364 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle(leafoptics, ctypes.c_uint(uuid))
365
366
367def leafOpticsGetPropertiesFromLibrary(leafoptics: ctypes.POINTER(ULeafOptics),
368 species: str) -> List[float]:
369 """Get leaf optical properties from the built-in species library
370
371 Args:
372 leafoptics: Pointer to LeafOptics instance
373 species: Name of the species (case-insensitive). Available species:
374 "default", "garden_lettuce", "alfalfa", "corn", "sunflower",
375 "english_walnut", "rice", "soybean", "wine_grape", "tomato",
376 "common_bean", "cowpea"
377
378 Returns:
379 List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
380 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
381
382 Note:
383 If species is not found, default properties are used and a warning is issued
384 """
385 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
386 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
387 if not leafoptics:
388 raise ValueError("LeafOptics instance is None.")
389 if not species:
390 raise ValueError("Species name cannot be empty.")
391
392 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)()
393 species_bytes = species.encode('utf-8')
394
395 helios_lib.leafOpticsGetPropertiesFromLibrary(leafoptics, species_bytes, properties_array)
396
397 return list(properties_array)
398
399
400def leafOpticsDisableMessages(leafoptics: ctypes.POINTER(ULeafOptics)) -> None:
401 """Disable command-line output messages from LeafOptics"""
402 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
403 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
404 if not leafoptics:
405 raise ValueError("LeafOptics instance is None.")
406
407 helios_lib.leafOpticsDisableMessages(leafoptics)
408
409
410def leafOpticsEnableMessages(leafoptics: ctypes.POINTER(ULeafOptics)) -> None:
411 """Enable command-line output messages from LeafOptics"""
412 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
413 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
414 if not leafoptics:
415 raise ValueError("LeafOptics instance is None.")
416
417 helios_lib.leafOpticsEnableMessages(leafoptics)
419
420def leafOpticsOptionalOutputPrimitiveData(leafoptics: ctypes.POINTER(ULeafOptics), label: str) -> None:
421 """Selectively output primitive data for specific biochemical properties
422
423 By default, all biochemical properties are written as primitive data. Use this method
424 to select only needed properties for better performance.
425
426 Args:
427 leafoptics: LeafOptics instance pointer
428 label: Property label - one of: "chlorophyll", "carotenoid", "anthocyanin",
429 "brown", "water", "drymass", "protein", "cellulose"
430
431 Note:
432 Added in helios-core v1.3.59
433 """
434 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
435 raise NotImplementedError("LeafOptics functions not available. Rebuild with leafoptics enabled.")
436 if not leafoptics:
437 raise ValueError("LeafOptics instance is None.")
438 if not label:
439 raise ValueError("Label cannot be empty.")
440
441 label_encoded = label.encode('utf-8')
442 helios_lib.leafOpticsOptionalOutputPrimitiveData(leafoptics, label_encoded)
443
444
445def leafOpticsRunNitrogen(leafoptics: ctypes.POINTER(ULeafOptics),
446 uuids: List[int],
447 params: List[float],
448 num_bins: int) -> None:
449 """Run nitrogen-based automatic leaf optics for leaf primitives
451 Args:
452 leafoptics: Pointer to LeafOptics instance
453 uuids: List of leaf primitive UUIDs (must belong to objects with "leaf_nitrogen_gN_m2" data)
454 params: List of LEAF_OPTICS_NAUTO_FLOAT_COUNT floats [f_photosynthetic, N_to_Cab_coefficient,
455 Car_to_Cab_ratio, numberlayers, anthocyancontent, brownpigments, watermass, drymass,
456 protein, carbonconstituents, V2Z, fqe, reassignment_threshold, min_reassignment_change]
457 num_bins: Number of spectrum bins
458 """
459 if not _LEAFOPTICS_NITROGEN_FUNCTIONS_AVAILABLE:
460 raise NotImplementedError(_NITROGEN_NOT_AVAILABLE_MSG)
461 if not leafoptics:
462 raise ValueError("LeafOptics instance is None.")
463 if not uuids:
464 raise ValueError("UUIDs list cannot be empty.")
465 if len(params) != LEAF_OPTICS_NAUTO_FLOAT_COUNT:
466 raise ValueError(f"Nitrogen parameters must have exactly {LEAF_OPTICS_NAUTO_FLOAT_COUNT} elements.")
467 if num_bins < 1:
468 raise ValueError("num_bins must be at least 1.")
469
470 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
471 params_array = (ctypes.c_float * LEAF_OPTICS_NAUTO_FLOAT_COUNT)(*params)
473 helios_lib.leafOpticsRunNitrogen(leafoptics, uuid_array, len(uuids), params_array, ctypes.c_uint(num_bins))
474
475
476def leafOpticsUpdateNitrogenBasedSpectra(leafoptics: ctypes.POINTER(ULeafOptics)) -> None:
477 """Re-read leaf nitrogen for tracked primitives and reassign spectra where it changed"""
478 if not _LEAFOPTICS_NITROGEN_FUNCTIONS_AVAILABLE:
479 raise NotImplementedError(_NITROGEN_NOT_AVAILABLE_MSG)
480 if not leafoptics:
481 raise ValueError("LeafOptics instance is None.")
482
483 helios_lib.leafOpticsUpdateNitrogenBasedSpectra(leafoptics)
484
485
487 """Check if the LeafOptics nitrogen-mode functions are available in the current library"""
488 return _LEAFOPTICS_NITROGEN_FUNCTIONS_AVAILABLE
489
490
491def is_leafoptics_available() -> bool:
492 """Check if LeafOptics functions are available in the current library"""
493 return _LEAFOPTICS_FUNCTIONS_AVAILABLE
495
496# Mock mode functions
497if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
498 def mock_create(*args, **kwargs):
499 raise RuntimeError(
500 "Mock mode: LeafOptics not available. "
501 "This would create a plugin instance with native library."
502 )
503
504 def mock_method(*args, **kwargs):
505 raise RuntimeError(
506 "Mock mode: LeafOptics method not available. "
507 "This would execute plugin computation with native library."
508 )
510 # Replace functions with mocks for development
511 createLeafOptics = mock_create
512 leafOpticsRun = mock_method
513 leafOpticsRunNoUUIDs = mock_method
514 leafOpticsGetLeafSpectra = mock_method
515 leafOpticsSetProperties = mock_method
516 leafOpticsGetPropertiesFromSpectrum = mock_method
517 leafOpticsGetPropertiesFromSpectrumSingle = mock_method
518 leafOpticsGetPropertiesFromLibrary = mock_method
519 leafOpticsRunNitrogen = mock_method
520 leafOpticsUpdateNitrogenBasedSpectra = mock_method
Opaque structure for LeafOptics C++ class.
None leafOpticsOptionalOutputPrimitiveData(ctypes.POINTER(ULeafOptics) leafoptics, str label)
Selectively output primitive data for specific biochemical properties.
None destroyLeafOptics(ctypes.POINTER(ULeafOptics) leafoptics)
Destroy LeafOptics instance.
bool is_leafoptics_nitrogen_available()
Check if the LeafOptics nitrogen-mode functions are available in the current library.
None leafOpticsEnableMessages(ctypes.POINTER(ULeafOptics) leafoptics)
Enable command-line output messages from LeafOptics.
None leafOpticsDisableMessages(ctypes.POINTER(ULeafOptics) leafoptics)
Disable command-line output messages from LeafOptics.
_check_error(result, func, args)
Automatic error checking for all leaf optics functions.
bool is_leafoptics_available()
Check if LeafOptics functions are available in the current library.