2Ctypes wrapper for LeafOptics C++ bindings.
4This module provides low-level ctypes bindings to interface with
5the native Helios LeafOptics plugin (PROSPECT model) via the C++ wrapper layer.
9from typing
import List, Tuple
11from ..plugins
import helios_lib
12from ..exceptions
import check_helios_error
16 """Opaque structure for LeafOptics C++ class"""
20from .UContextWrapper
import UContext
23LEAF_OPTICS_PROPERTIES_COUNT = 9
26LEAF_OPTICS_SPECTRAL_POINTS = 2101
30 """Automatic error checking for all leaf optics functions"""
31 check_helios_error(helios_lib.getLastErrorCode, helios_lib.getLastErrorMessage)
37 helios_lib.createLeafOptics.argtypes = [ctypes.POINTER(UContext)]
38 helios_lib.createLeafOptics.restype = ctypes.POINTER(ULeafOptics)
39 helios_lib.createLeafOptics.errcheck = _check_error
41 helios_lib.destroyLeafOptics.argtypes = [ctypes.POINTER(ULeafOptics)]
42 helios_lib.destroyLeafOptics.restype =
None
45 helios_lib.leafOpticsRun.argtypes = [
46 ctypes.POINTER(ULeafOptics),
47 ctypes.POINTER(ctypes.c_uint),
49 ctypes.POINTER(ctypes.c_float),
52 helios_lib.leafOpticsRun.restype =
None
53 helios_lib.leafOpticsRun.errcheck = _check_error
55 helios_lib.leafOpticsRunNoUUIDs.argtypes = [
56 ctypes.POINTER(ULeafOptics),
57 ctypes.POINTER(ctypes.c_float),
60 helios_lib.leafOpticsRunNoUUIDs.restype =
None
61 helios_lib.leafOpticsRunNoUUIDs.errcheck = _check_error
64 helios_lib.leafOpticsGetLeafSpectra.argtypes = [
65 ctypes.POINTER(ULeafOptics),
66 ctypes.POINTER(ctypes.c_float),
67 ctypes.POINTER(ctypes.c_float),
68 ctypes.POINTER(ctypes.c_float),
69 ctypes.POINTER(ctypes.c_float),
70 ctypes.POINTER(ctypes.c_uint)
72 helios_lib.leafOpticsGetLeafSpectra.restype =
None
73 helios_lib.leafOpticsGetLeafSpectra.errcheck = _check_error
76 helios_lib.leafOpticsSetProperties.argtypes = [
77 ctypes.POINTER(ULeafOptics),
78 ctypes.POINTER(ctypes.c_uint),
80 ctypes.POINTER(ctypes.c_float)
82 helios_lib.leafOpticsSetProperties.restype =
None
83 helios_lib.leafOpticsSetProperties.errcheck = _check_error
85 helios_lib.leafOpticsGetPropertiesFromSpectrum.argtypes = [
86 ctypes.POINTER(ULeafOptics),
87 ctypes.POINTER(ctypes.c_uint),
90 helios_lib.leafOpticsGetPropertiesFromSpectrum.restype =
None
91 helios_lib.leafOpticsGetPropertiesFromSpectrum.errcheck = _check_error
93 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.argtypes = [
94 ctypes.POINTER(ULeafOptics),
97 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.restype =
None
98 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.errcheck = _check_error
101 helios_lib.leafOpticsGetPropertiesFromLibrary.argtypes = [
102 ctypes.POINTER(ULeafOptics),
104 ctypes.POINTER(ctypes.c_float)
106 helios_lib.leafOpticsGetPropertiesFromLibrary.restype =
None
107 helios_lib.leafOpticsGetPropertiesFromLibrary.errcheck = _check_error
110 helios_lib.leafOpticsDisableMessages.argtypes = [ctypes.POINTER(ULeafOptics)]
111 helios_lib.leafOpticsDisableMessages.restype =
None
112 helios_lib.leafOpticsDisableMessages.errcheck = _check_error
114 helios_lib.leafOpticsEnableMessages.argtypes = [ctypes.POINTER(ULeafOptics)]
115 helios_lib.leafOpticsEnableMessages.restype =
None
116 helios_lib.leafOpticsEnableMessages.errcheck = _check_error
119 helios_lib.leafOpticsOptionalOutputPrimitiveData.argtypes = [ctypes.POINTER(ULeafOptics), ctypes.c_char_p]
120 helios_lib.leafOpticsOptionalOutputPrimitiveData.restype =
None
121 helios_lib.leafOpticsOptionalOutputPrimitiveData.errcheck = _check_error
123 _LEAFOPTICS_FUNCTIONS_AVAILABLE =
True
125except AttributeError:
126 _LEAFOPTICS_FUNCTIONS_AVAILABLE =
False
131def createLeafOptics(context: ctypes.POINTER(UContext)) -> ctypes.POINTER(ULeafOptics):
132 """Create LeafOptics instance
135 context: Pointer to the Helios Context
138 Pointer to the created LeafOptics instance
141 NotImplementedError: If LeafOptics functions not available
142 ValueError: If context is None
144 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
145 raise NotImplementedError(
146 "LeafOptics functions not available in current Helios library. "
147 "Rebuild PyHelios with 'leafoptics' enabled:\n"
148 " build_scripts/build_helios --plugins leafoptics"
152 raise ValueError(
"Context instance is None.")
154 return helios_lib.createLeafOptics(context)
158 """Destroy LeafOptics instance"""
159 if leafoptics
and _LEAFOPTICS_FUNCTIONS_AVAILABLE:
160 helios_lib.destroyLeafOptics(leafoptics)
165 properties: List[float],
167 """Run LeafOptics model and assign spectra to primitives
170 leafoptics: Pointer to LeafOptics instance
171 uuids: List of primitive UUIDs
172 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
173 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
174 label: Label for the spectra (appended to "leaf_reflectivity_" and "leaf_transmissivity_")
176 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
177 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
179 raise ValueError(
"LeafOptics instance is None.")
181 raise ValueError(
"UUIDs list cannot be empty.")
182 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
183 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
185 raise ValueError(
"Label cannot be empty.")
187 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
188 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
189 label_bytes = label.encode(
'utf-8')
191 helios_lib.leafOpticsRun(leafoptics, uuid_array, len(uuids), properties_array, label_bytes)
195 properties: List[float],
197 """Run LeafOptics model without assigning to primitives
200 leafoptics: Pointer to LeafOptics instance
201 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
202 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
203 label: Label for the spectra
205 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
206 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
208 raise ValueError(
"LeafOptics instance is None.")
209 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
210 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
212 raise ValueError(
"Label cannot be empty.")
214 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
215 label_bytes = label.encode(
'utf-8')
217 helios_lib.leafOpticsRunNoUUIDs(leafoptics, properties_array, label_bytes)
221 properties: List[float]) -> Tuple[List[float], List[float], List[float]]:
222 """Get leaf reflectance and transmittance spectra
225 leafoptics: Pointer to LeafOptics instance
226 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
227 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
230 Tuple of (wavelengths, reflectivities, transmissivities) as lists of floats
231 - wavelengths: 400-2500 nm at 1nm resolution (2101 points)
232 - reflectivities: reflectance values at each wavelength
233 - transmissivities: transmittance values at each wavelength
235 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
236 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
238 raise ValueError(
"LeafOptics instance is None.")
239 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
240 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
242 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
243 reflectivities = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
244 transmissivities = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
245 wavelengths = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
246 size = ctypes.c_uint()
248 helios_lib.leafOpticsGetLeafSpectra(
249 leafoptics, properties_array, reflectivities, transmissivities, wavelengths, ctypes.byref(size)
255 list(wavelengths[:n]),
256 list(reflectivities[:n]),
257 list(transmissivities[:n])
263 properties: List[float]) ->
None:
264 """Set leaf optical properties for primitives
267 leafoptics: Pointer to LeafOptics instance
268 uuids: List of primitive UUIDs
269 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
270 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
272 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
273 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
275 raise ValueError(
"LeafOptics instance is None.")
277 raise ValueError(
"UUIDs list cannot be empty.")
278 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
279 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
281 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
282 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
284 helios_lib.leafOpticsSetProperties(leafoptics, uuid_array, len(uuids), properties_array)
288 uuids: List[int]) ->
None:
289 """Get PROSPECT parameters from reflectivity spectrum for primitives
292 leafoptics: Pointer to LeafOptics instance
293 uuids: List of primitive UUIDs to query
296 Primitives without matching spectra are silently skipped
298 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
299 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
301 raise ValueError(
"LeafOptics instance is None.")
303 raise ValueError(
"UUIDs list cannot be empty.")
305 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
307 helios_lib.leafOpticsGetPropertiesFromSpectrum(leafoptics, uuid_array, len(uuids))
312 """Get PROSPECT parameters from reflectivity spectrum for a single primitive
315 leafoptics: Pointer to LeafOptics instance
316 uuid: Single primitive UUID to query
319 If no matching spectrum is found, the primitive is silently skipped
321 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
322 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
324 raise ValueError(
"LeafOptics instance is None.")
326 raise ValueError(
"UUID must be non-negative.")
328 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle(leafoptics, ctypes.c_uint(uuid))
332 species: str) -> List[float]:
333 """Get leaf optical properties from the built-in species library
336 leafoptics: Pointer to LeafOptics instance
337 species: Name of the species (case-insensitive). Available species:
338 "default", "garden_lettuce", "alfalfa", "corn", "sunflower",
339 "english_walnut", "rice", "soybean", "wine_grape", "tomato",
340 "common_bean", "cowpea"
343 List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
344 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
347 If species is not found, default properties are used and a warning is issued
349 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
350 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
352 raise ValueError(
"LeafOptics instance is None.")
354 raise ValueError(
"Species name cannot be empty.")
356 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)()
357 species_bytes = species.encode(
'utf-8')
359 helios_lib.leafOpticsGetPropertiesFromLibrary(leafoptics, species_bytes, properties_array)
361 return list(properties_array)
365 """Disable command-line output messages from LeafOptics"""
366 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
367 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
369 raise ValueError(
"LeafOptics instance is None.")
371 helios_lib.leafOpticsDisableMessages(leafoptics)
375 """Enable command-line output messages from LeafOptics"""
376 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
377 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
379 raise ValueError(
"LeafOptics instance is None.")
381 helios_lib.leafOpticsEnableMessages(leafoptics)
385 """Selectively output primitive data for specific biochemical properties
387 By default, all biochemical properties are written as primitive data. Use this method
388 to select only needed properties for better performance.
391 leafoptics: LeafOptics instance pointer
392 label: Property label - one of: "chlorophyll", "carotenoid", "anthocyanin",
393 "brown", "water", "drymass", "protein", "cellulose"
396 Added in helios-core v1.3.59
398 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
399 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
401 raise ValueError(
"LeafOptics instance is None.")
403 raise ValueError(
"Label cannot be empty.")
405 label_encoded = label.encode(
'utf-8')
406 helios_lib.leafOpticsOptionalOutputPrimitiveData(leafoptics, label_encoded)
410 """Check if LeafOptics functions are available in the current library"""
411 return _LEAFOPTICS_FUNCTIONS_AVAILABLE
415if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
418 "Mock mode: LeafOptics not available. "
419 "This would create a plugin instance with native library."
424 "Mock mode: LeafOptics method not available. "
425 "This would execute plugin computation with native library."
429 createLeafOptics = mock_create
430 leafOpticsRun = mock_method
431 leafOpticsRunNoUUIDs = mock_method
432 leafOpticsGetLeafSpectra = mock_method
433 leafOpticsSetProperties = mock_method
434 leafOpticsGetPropertiesFromSpectrum = mock_method
435 leafOpticsGetPropertiesFromSpectrumSingle = mock_method
436 leafOpticsGetPropertiesFromLibrary = mock_method
Opaque structure for LeafOptics C++ class.
mock_method(*args, **kwargs)
None leafOpticsOptionalOutputPrimitiveData(ctypes.POINTER(ULeafOptics) leafoptics, str label)
Selectively output primitive data for specific biochemical properties.
leafOpticsGetPropertiesFromLibrary
None destroyLeafOptics(ctypes.POINTER(ULeafOptics) leafoptics)
Destroy LeafOptics instance.
leafOpticsGetPropertiesFromSpectrumSingle
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.
mock_create(*args, **kwargs)
leafOpticsGetPropertiesFromSpectrum
bool is_leafoptics_available()
Check if LeafOptics functions are available in the current library.