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
25LEAF_OPTICS_PROPERTIES_COUNT = 11
28LEAF_OPTICS_SPECTRAL_POINTS = 2101
32 """Automatic error checking for all leaf optics functions"""
33 check_helios_error(helios_lib.getLastErrorCode, helios_lib.getLastErrorMessage)
39 helios_lib.createLeafOptics.argtypes = [ctypes.POINTER(UContext)]
40 helios_lib.createLeafOptics.restype = ctypes.POINTER(ULeafOptics)
41 helios_lib.createLeafOptics.errcheck = _check_error
43 helios_lib.destroyLeafOptics.argtypes = [ctypes.POINTER(ULeafOptics)]
44 helios_lib.destroyLeafOptics.restype =
None
47 helios_lib.leafOpticsRun.argtypes = [
48 ctypes.POINTER(ULeafOptics),
49 ctypes.POINTER(ctypes.c_uint),
51 ctypes.POINTER(ctypes.c_float),
54 helios_lib.leafOpticsRun.restype =
None
55 helios_lib.leafOpticsRun.errcheck = _check_error
57 helios_lib.leafOpticsRunNoUUIDs.argtypes = [
58 ctypes.POINTER(ULeafOptics),
59 ctypes.POINTER(ctypes.c_float),
62 helios_lib.leafOpticsRunNoUUIDs.restype =
None
63 helios_lib.leafOpticsRunNoUUIDs.errcheck = _check_error
66 helios_lib.leafOpticsGetLeafSpectra.argtypes = [
67 ctypes.POINTER(ULeafOptics),
68 ctypes.POINTER(ctypes.c_float),
69 ctypes.POINTER(ctypes.c_float),
70 ctypes.POINTER(ctypes.c_float),
71 ctypes.POINTER(ctypes.c_float),
72 ctypes.POINTER(ctypes.c_uint)
74 helios_lib.leafOpticsGetLeafSpectra.restype =
None
75 helios_lib.leafOpticsGetLeafSpectra.errcheck = _check_error
78 helios_lib.leafOpticsSetProperties.argtypes = [
79 ctypes.POINTER(ULeafOptics),
80 ctypes.POINTER(ctypes.c_uint),
82 ctypes.POINTER(ctypes.c_float)
84 helios_lib.leafOpticsSetProperties.restype =
None
85 helios_lib.leafOpticsSetProperties.errcheck = _check_error
87 helios_lib.leafOpticsGetPropertiesFromSpectrum.argtypes = [
88 ctypes.POINTER(ULeafOptics),
89 ctypes.POINTER(ctypes.c_uint),
92 helios_lib.leafOpticsGetPropertiesFromSpectrum.restype =
None
93 helios_lib.leafOpticsGetPropertiesFromSpectrum.errcheck = _check_error
95 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.argtypes = [
96 ctypes.POINTER(ULeafOptics),
99 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.restype =
None
100 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle.errcheck = _check_error
103 helios_lib.leafOpticsGetPropertiesFromLibrary.argtypes = [
104 ctypes.POINTER(ULeafOptics),
106 ctypes.POINTER(ctypes.c_float)
108 helios_lib.leafOpticsGetPropertiesFromLibrary.restype =
None
109 helios_lib.leafOpticsGetPropertiesFromLibrary.errcheck = _check_error
112 helios_lib.leafOpticsDisableMessages.argtypes = [ctypes.POINTER(ULeafOptics)]
113 helios_lib.leafOpticsDisableMessages.restype =
None
114 helios_lib.leafOpticsDisableMessages.errcheck = _check_error
116 helios_lib.leafOpticsEnableMessages.argtypes = [ctypes.POINTER(ULeafOptics)]
117 helios_lib.leafOpticsEnableMessages.restype =
None
118 helios_lib.leafOpticsEnableMessages.errcheck = _check_error
121 helios_lib.leafOpticsOptionalOutputPrimitiveData.argtypes = [ctypes.POINTER(ULeafOptics), ctypes.c_char_p]
122 helios_lib.leafOpticsOptionalOutputPrimitiveData.restype =
None
123 helios_lib.leafOpticsOptionalOutputPrimitiveData.errcheck = _check_error
125 _LEAFOPTICS_FUNCTIONS_AVAILABLE =
True
127except AttributeError:
128 _LEAFOPTICS_FUNCTIONS_AVAILABLE =
False
133def createLeafOptics(context: ctypes.POINTER(UContext)) -> ctypes.POINTER(ULeafOptics):
134 """Create LeafOptics instance
137 context: Pointer to the Helios Context
140 Pointer to the created LeafOptics instance
143 NotImplementedError: If LeafOptics functions not available
144 ValueError: If context is None
146 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
147 raise NotImplementedError(
148 "LeafOptics functions not available in current Helios library. "
149 "Rebuild PyHelios with 'leafoptics' enabled:\n"
150 " build_scripts/build_helios --plugins leafoptics"
154 raise ValueError(
"Context instance is None.")
156 return helios_lib.createLeafOptics(context)
160 """Destroy LeafOptics instance"""
161 if leafoptics
and _LEAFOPTICS_FUNCTIONS_AVAILABLE:
162 helios_lib.destroyLeafOptics(leafoptics)
167 properties: List[float],
169 """Run LeafOptics model and assign spectra to primitives
172 leafoptics: Pointer to LeafOptics instance
173 uuids: List of primitive UUIDs
174 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
175 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
176 label: Label for the spectra (appended to "leaf_reflectivity_" and "leaf_transmissivity_")
178 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
179 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
181 raise ValueError(
"LeafOptics instance is None.")
183 raise ValueError(
"UUIDs list cannot be empty.")
184 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
185 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
187 raise ValueError(
"Label cannot be empty.")
189 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
190 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
191 label_bytes = label.encode(
'utf-8')
193 helios_lib.leafOpticsRun(leafoptics, uuid_array, len(uuids), properties_array, label_bytes)
197 properties: List[float],
199 """Run LeafOptics model without assigning to primitives
202 leafoptics: Pointer to LeafOptics instance
203 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
204 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
205 label: Label for the spectra
207 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
208 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
210 raise ValueError(
"LeafOptics instance is None.")
211 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
212 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
214 raise ValueError(
"Label cannot be empty.")
216 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
217 label_bytes = label.encode(
'utf-8')
219 helios_lib.leafOpticsRunNoUUIDs(leafoptics, properties_array, label_bytes)
223 properties: List[float]) -> Tuple[List[float], List[float], List[float]]:
224 """Get leaf reflectance and transmittance spectra
227 leafoptics: Pointer to LeafOptics instance
228 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
229 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
232 Tuple of (wavelengths, reflectivities, transmissivities) as lists of floats
233 - wavelengths: 400-2500 nm at 1nm resolution (2101 points)
234 - reflectivities: reflectance values at each wavelength
235 - transmissivities: transmittance values at each wavelength
237 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
238 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
240 raise ValueError(
"LeafOptics instance is None.")
241 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
242 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
244 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
245 reflectivities = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
246 transmissivities = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
247 wavelengths = (ctypes.c_float * LEAF_OPTICS_SPECTRAL_POINTS)()
248 size = ctypes.c_uint()
250 helios_lib.leafOpticsGetLeafSpectra(
251 leafoptics, properties_array, reflectivities, transmissivities, wavelengths, ctypes.byref(size)
257 list(wavelengths[:n]),
258 list(reflectivities[:n]),
259 list(transmissivities[:n])
265 properties: List[float]) ->
None:
266 """Set leaf optical properties for primitives
269 leafoptics: Pointer to LeafOptics instance
270 uuids: List of primitive UUIDs
271 properties: List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
272 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
274 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
275 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
277 raise ValueError(
"LeafOptics instance is None.")
279 raise ValueError(
"UUIDs list cannot be empty.")
280 if len(properties) != LEAF_OPTICS_PROPERTIES_COUNT:
281 raise ValueError(f
"Properties must have exactly {LEAF_OPTICS_PROPERTIES_COUNT} elements.")
283 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
284 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)(*properties)
286 helios_lib.leafOpticsSetProperties(leafoptics, uuid_array, len(uuids), properties_array)
290 uuids: List[int]) ->
None:
291 """Get PROSPECT parameters from reflectivity spectrum for primitives
294 leafoptics: Pointer to LeafOptics instance
295 uuids: List of primitive UUIDs to query
298 Primitives without matching spectra are silently skipped
300 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
301 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
303 raise ValueError(
"LeafOptics instance is None.")
305 raise ValueError(
"UUIDs list cannot be empty.")
307 uuid_array = (ctypes.c_uint * len(uuids))(*uuids)
309 helios_lib.leafOpticsGetPropertiesFromSpectrum(leafoptics, uuid_array, len(uuids))
314 """Get PROSPECT parameters from reflectivity spectrum for a single primitive
317 leafoptics: Pointer to LeafOptics instance
318 uuid: Single primitive UUID to query
321 If no matching spectrum is found, the primitive is silently skipped
323 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
324 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
326 raise ValueError(
"LeafOptics instance is None.")
328 raise ValueError(
"UUID must be non-negative.")
330 helios_lib.leafOpticsGetPropertiesFromSpectrumSingle(leafoptics, ctypes.c_uint(uuid))
334 species: str) -> List[float]:
335 """Get leaf optical properties from the built-in species library
338 leafoptics: Pointer to LeafOptics instance
339 species: Name of the species (case-insensitive). Available species:
340 "default", "garden_lettuce", "alfalfa", "corn", "sunflower",
341 "english_walnut", "rice", "soybean", "wine_grape", "tomato",
342 "common_bean", "cowpea"
345 List of 9 floats [numberlayers, brownpigments, chlorophyllcontent,
346 carotenoidcontent, anthocyancontent, watermass, drymass, protein, carbonconstituents]
349 If species is not found, default properties are used and a warning is issued
351 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
352 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
354 raise ValueError(
"LeafOptics instance is None.")
356 raise ValueError(
"Species name cannot be empty.")
358 properties_array = (ctypes.c_float * LEAF_OPTICS_PROPERTIES_COUNT)()
359 species_bytes = species.encode(
'utf-8')
361 helios_lib.leafOpticsGetPropertiesFromLibrary(leafoptics, species_bytes, properties_array)
363 return list(properties_array)
367 """Disable command-line output messages from LeafOptics"""
368 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
369 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
371 raise ValueError(
"LeafOptics instance is None.")
373 helios_lib.leafOpticsDisableMessages(leafoptics)
377 """Enable command-line output messages from LeafOptics"""
378 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
379 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
381 raise ValueError(
"LeafOptics instance is None.")
383 helios_lib.leafOpticsEnableMessages(leafoptics)
387 """Selectively output primitive data for specific biochemical properties
389 By default, all biochemical properties are written as primitive data. Use this method
390 to select only needed properties for better performance.
393 leafoptics: LeafOptics instance pointer
394 label: Property label - one of: "chlorophyll", "carotenoid", "anthocyanin",
395 "brown", "water", "drymass", "protein", "cellulose"
398 Added in helios-core v1.3.59
400 if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
401 raise NotImplementedError(
"LeafOptics functions not available. Rebuild with leafoptics enabled.")
403 raise ValueError(
"LeafOptics instance is None.")
405 raise ValueError(
"Label cannot be empty.")
407 label_encoded = label.encode(
'utf-8')
408 helios_lib.leafOpticsOptionalOutputPrimitiveData(leafoptics, label_encoded)
412 """Check if LeafOptics functions are available in the current library"""
413 return _LEAFOPTICS_FUNCTIONS_AVAILABLE
417if not _LEAFOPTICS_FUNCTIONS_AVAILABLE:
420 "Mock mode: LeafOptics not available. "
421 "This would create a plugin instance with native library."
426 "Mock mode: LeafOptics method not available. "
427 "This would execute plugin computation with native library."
431 createLeafOptics = mock_create
432 leafOpticsRun = mock_method
433 leafOpticsRunNoUUIDs = mock_method
434 leafOpticsGetLeafSpectra = mock_method
435 leafOpticsSetProperties = mock_method
436 leafOpticsGetPropertiesFromSpectrum = mock_method
437 leafOpticsGetPropertiesFromSpectrumSingle = mock_method
438 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.