Skip to content

Commit 46c2f15

Browse files
committed
[v0.1.20] 2026-05-08
- Updated helios-core to v1.3.72 - Added scalar existence and metadata queries: `doesObjectExist()`, `doesObjectContainPrimitive()`, `doesMaterialDataExist()`, `objectHasTexture()`, `isPrimitiveDirty()`, `areObjectPrimitivesComplete()`, `getJulianDate()`, `getMaterialCount()`, `getObjectArea()`, `getObjectPrimitiveCount()`, `getPolymeshObjectVolume()`, `getMaterialIDFromLabel()`, `getPrimitiveMaterialID()`, `getGlobalDataVersion()`, `getPrimitiveParentObjectID()`, `getObjectTextureFile()`, `listAllPrimitiveDataLabels()`, `getLoadedXMLFiles()`, `printObjectInfo()`, `printPrimitiveInfo()`, `setObjectDataFromPrimitiveDataMean()`, `renameMaterial()`, `renamePrimitiveData()`, `clearMaterialData()`, plus `enable/disablePrimitiveDataValueCaching()` and `enable/disableObjectDataValueCaching()` - Added vector-return queries and geometry mutators: `getDeletedUUIDs()`, `getDirtyUUIDs()`, `getUniquePrimitiveParentObjectIDs()`, `getObjectAverageNormal()`, plus `setObjectAverageNormal()`, `setObjectOrigin()`, `setPrimitiveAzimuth()`, `setPrimitiveElevation()`, `setTriangleVertices()`, `setPrimitiveNormal()` (single/batch), and `setPrimitiveParentObjectID()` (single/batch) - Added a complete material-data API spanning all 11 Helios data types (`int`, `uint`, `float`, `double`, `string`, `vec2`, `vec3`, `vec4`, `int2`, `int3`, `int4`): per-type explicit `setMaterialData<Type>()` and `getMaterialData<Type>()` methods, a unified `setMaterialData()`/`getMaterialData()` dispatcher with auto-detection via `getMaterialDataType()`, and `getUniquePrimitiveDataValues()`/`getUniqueObjectDataValues()` (`int`/`uint`/`str`) - Added 4×4 transformation matrix accessors as numpy `(4,4) float32` ndarrays (also accepting nested lists or flat 16-float lists): `get/setObjectTransformationMatrix()` and `get/setPrimitiveTransformationMatrix()` with single/batch dispatch, plus domain-level `getDomainBoundingBox()` and `getDomainBoundingSphere()` with optional UUID filtering - Added tube/polymesh/object mutators: `setTubeNodes()`, `setTubeRadii()`, `scaleTubeGirth()`, `scaleTubeLength()`, `pruneTubeNodes()`, `appendTubeSegment()` (color or texture+uv kwargs), `addPolymeshObject()`, `setObjectColor()` (RGB/RGBA, single/batch), `overrideObjectTextureColor()`/`useObjectTextureColor()`, `markPrimitiveDirty()`/`markPrimitiveClean()`, `setTileObjectSubdivisionCount()`, and `setTileObjectSubdivisionByAreaRatio()` - Added `cleanDeletedUUIDs()` and `cleanDeletedObjectIDs()` (returning new lists, not mutating input), `writeXML()`/`writeXML_byobject()` for XML export with optional UUID filtering, `randu()`/`randn()` random-number draws (uniform with optional float or int range; normal with optional mean/stddev), and geographic `setLocation()`/`getLocation()` returning the new `Location` dataclass (latitude, longitude, UTC offset) - Added colormap and texture-transparency helpers: `generateColormap(name, n_colors)` returning an `RGBcolor` list, `generateTexturesFromColormap()` returning generated file paths, and `getPrimitiveTextureTransparencyData()` returning an `Optional[np.ndarray]` 2D bool mask - Added `deleteTimeseriesVariable(label)` to remove a single timeseries variable and all of its data points (complements the existing `clearTimeseriesData()` and `updateTimeseriesData()`). - Extended `LeafOpticsProperties` with two optional Fluspect-B SIF parameters: `V2Z` (violaxanthin↔zeaxanthin de-epoxidation state, default 0.0) and `fqe` (intrinsic fluorescence quantum-efficiency scalar, default 1.0). They are ignored by the pure PROSPECT reflectance/transmittance calculation; the radiation plugin's SIF pipeline reads them when active. The flat float-array layout grew from 9 to 11 entries; `LeafOpticsProperties.from_list()` still accepts both lengths for backward compatibility with serialized data. - Added `setModelTypeC4()` and the von Caemmerer (2021) steady-state C4 model — `setC4CoefficientsFromLibrary()` / `getC4CoefficientsFromLibrary()` (species: `SetariaViridis_vC2021`, `GenericC4_vC2000`, `Maize_Massad2007`), `setC4ModelCoefficients()` / `getC4ModelCoefficients()` over a 43-float coefficient array (5 temperature-responsive rates × 4 floats: Vpmax/Vcmax/Jmax/Rd/gm; 5 K-25 + 5 dH kinetic constants; 13 user-tunable scalars), and `setCm()` for direct mesophyll CO₂ prescription (testing/validation). Both `setC4CoefficientsFromLibrary()` and `setC4ModelCoefficients()` accept a `material_label` keyword to apply coefficients per-material rather than per-UUID. - Added `setFarquharMesophyllConductance()` to configure C3 mesophyll conductance `gm` (mol CO₂ / m² / s / bar) with optional temperature response. Default behaviour unchanged: `gm = +∞` reduces `Cc` to `Ci` (legacy Farquhar). - `FarquharModelCoefficients` flat array round-trip (`to_array()` / `from_array()` and the corresponding `getFarquharModelCoefficients` / `setFarquharModelCoefficients` C wrappers) grew from 18 to 22 floats: slots 18–21 carry `(gm_at_25C, dHa, Topt_C, dHd)` for the gm temperature response. `from_array` still accepts the legacy 18-float layout for back-compat (gm defaults to `+∞`); the C wrapper still accepts 18-float buffers and only consumes the gm slots when the buffer is at least 22 elements. - C4 `limitation_state` uses the convention `1 = enzyme-limited`, `2 = electron-transport-limited` (vs. C3's `0/1`). New optional output primitive data labels for the C4 model: `Cm` (mesophyll cytosolic CO₂) and `Vp` (PEP carboxylation rate). - Added `addSIFCamera()` (vec3 lookat and SphericalCoord overloads) plus the new `SIFCameraProperties` (extends `CameraProperties` with `excitation_bin_width_nm` and `excitation_scattering_depth`) and the `isSIFCamera()` query. SIF cameras source per-band emission from the Fluspect-B kernel rather than Stefan-Boltzmann; Helios auto-creates internal excitation bands covering 400–750 nm at the requested bin width.
1 parent 156ec89 commit 46c2f15

33 files changed

Lines changed: 8516 additions & 87 deletions

docs/CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
# Changelog
22

3+
# [v0.1.20] 2026-05-08
4+
5+
- Updated helios-core to v1.3.72
6+
7+
## Context
8+
- Added scalar existence and metadata queries: `doesObjectExist()`, `doesObjectContainPrimitive()`, `doesMaterialDataExist()`, `objectHasTexture()`, `isPrimitiveDirty()`, `areObjectPrimitivesComplete()`, `getJulianDate()`, `getMaterialCount()`, `getObjectArea()`, `getObjectPrimitiveCount()`, `getPolymeshObjectVolume()`, `getMaterialIDFromLabel()`, `getPrimitiveMaterialID()`, `getGlobalDataVersion()`, `getPrimitiveParentObjectID()`, `getObjectTextureFile()`, `listAllPrimitiveDataLabels()`, `getLoadedXMLFiles()`, `printObjectInfo()`, `printPrimitiveInfo()`, `setObjectDataFromPrimitiveDataMean()`, `renameMaterial()`, `renamePrimitiveData()`, `clearMaterialData()`, plus `enable/disablePrimitiveDataValueCaching()` and `enable/disableObjectDataValueCaching()`
9+
- Added vector-return queries and geometry mutators: `getDeletedUUIDs()`, `getDirtyUUIDs()`, `getUniquePrimitiveParentObjectIDs()`, `getObjectAverageNormal()`, plus `setObjectAverageNormal()`, `setObjectOrigin()`, `setPrimitiveAzimuth()`, `setPrimitiveElevation()`, `setTriangleVertices()`, `setPrimitiveNormal()` (single/batch), and `setPrimitiveParentObjectID()` (single/batch)
10+
- Added a complete material-data API spanning all 11 Helios data types (`int`, `uint`, `float`, `double`, `string`, `vec2`, `vec3`, `vec4`, `int2`, `int3`, `int4`): per-type explicit `setMaterialData<Type>()` and `getMaterialData<Type>()` methods, a unified `setMaterialData()`/`getMaterialData()` dispatcher with auto-detection via `getMaterialDataType()`, and `getUniquePrimitiveDataValues()`/`getUniqueObjectDataValues()` (`int`/`uint`/`str`)
11+
- Added 4×4 transformation matrix accessors as numpy `(4,4) float32` ndarrays (also accepting nested lists or flat 16-float lists): `get/setObjectTransformationMatrix()` and `get/setPrimitiveTransformationMatrix()` with single/batch dispatch, plus domain-level `getDomainBoundingBox()` and `getDomainBoundingSphere()` with optional UUID filtering
12+
- Added tube/polymesh/object mutators: `setTubeNodes()`, `setTubeRadii()`, `scaleTubeGirth()`, `scaleTubeLength()`, `pruneTubeNodes()`, `appendTubeSegment()` (color or texture+uv kwargs), `addPolymeshObject()`, `setObjectColor()` (RGB/RGBA, single/batch), `overrideObjectTextureColor()`/`useObjectTextureColor()`, `markPrimitiveDirty()`/`markPrimitiveClean()`, `setTileObjectSubdivisionCount()`, and `setTileObjectSubdivisionByAreaRatio()`
13+
- Added `cleanDeletedUUIDs()` and `cleanDeletedObjectIDs()` (returning new lists, not mutating input), `writeXML()`/`writeXML_byobject()` for XML export with optional UUID filtering, `randu()`/`randn()` random-number draws (uniform with optional float or int range; normal with optional mean/stddev), and geographic `setLocation()`/`getLocation()` returning the new `Location` dataclass (latitude, longitude, UTC offset)
14+
- Added colormap and texture-transparency helpers: `generateColormap(name, n_colors)` returning an `RGBcolor` list, `generateTexturesFromColormap()` returning generated file paths, and `getPrimitiveTextureTransparencyData()` returning an `Optional[np.ndarray]` 2D bool mask
15+
- Added `deleteTimeseriesVariable(label)` to remove a single timeseries variable and all of its data points (complements the existing `clearTimeseriesData()` and `updateTimeseriesData()`).
16+
17+
## LeafOptics
18+
- Extended `LeafOpticsProperties` with two optional Fluspect-B SIF parameters: `V2Z` (violaxanthin↔zeaxanthin de-epoxidation state, default 0.0) and `fqe` (intrinsic fluorescence quantum-efficiency scalar, default 1.0). They are ignored by the pure PROSPECT reflectance/transmittance calculation; the radiation plugin's SIF pipeline reads them when active. The flat float-array layout grew from 9 to 11 entries; `LeafOpticsProperties.from_list()` still accepts both lengths for backward compatibility with serialized data.
19+
20+
## Photosynthesis
21+
- Added `setModelTypeC4()` and the von Caemmerer (2021) steady-state C4 model — `setC4CoefficientsFromLibrary()` / `getC4CoefficientsFromLibrary()` (species: `SetariaViridis_vC2021`, `GenericC4_vC2000`, `Maize_Massad2007`), `setC4ModelCoefficients()` / `getC4ModelCoefficients()` over a 43-float coefficient array (5 temperature-responsive rates × 4 floats: Vpmax/Vcmax/Jmax/Rd/gm; 5 K-25 + 5 dH kinetic constants; 13 user-tunable scalars), and `setCm()` for direct mesophyll CO₂ prescription (testing/validation). Both `setC4CoefficientsFromLibrary()` and `setC4ModelCoefficients()` accept a `material_label` keyword to apply coefficients per-material rather than per-UUID.
22+
- Added `setFarquharMesophyllConductance()` to configure C3 mesophyll conductance `gm` (mol CO₂ / m² / s / bar) with optional temperature response. Default behaviour unchanged: `gm = +∞` reduces `Cc` to `Ci` (legacy Farquhar).
23+
- `FarquharModelCoefficients` flat array round-trip (`to_array()` / `from_array()` and the corresponding `getFarquharModelCoefficients` / `setFarquharModelCoefficients` C wrappers) grew from 18 to 22 floats: slots 18–21 carry `(gm_at_25C, dHa, Topt_C, dHd)` for the gm temperature response. `from_array` still accepts the legacy 18-float layout for back-compat (gm defaults to `+∞`); the C wrapper still accepts 18-float buffers and only consumes the gm slots when the buffer is at least 22 elements.
24+
- C4 `limitation_state` uses the convention `1 = enzyme-limited`, `2 = electron-transport-limited` (vs. C3's `0/1`). New optional output primitive data labels for the C4 model: `Cm` (mesophyll cytosolic CO₂) and `Vp` (PEP carboxylation rate).
25+
26+
## Radiation
27+
- Added `addSIFCamera()` (vec3 lookat and SphericalCoord overloads) plus the new `SIFCameraProperties` (extends `CameraProperties` with `excitation_bin_width_nm` and `excitation_scattering_depth`) and the `isSIFCamera()` query. SIF cameras source per-band emission from the Fluspect-B kernel rather than Stefan-Boltzmann; Helios auto-creates internal excitation bands covering 400–750 nm at the requested bin width.
28+
329
# [v0.1.19] 2026-04-16
430

531
- Updated helios-core to v1.3.71

docs/file_io.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,17 @@ context = Context()
257257
# The context will now contain a default patch, with primitive data "somedata" equal to 10.2
258258
context.loadXML("file.xml")
259259
```
260+
261+
To export only a subset of primitives, pass a list of UUIDs to `writeXML()`:
262+
263+
```python
264+
context.writeXML("subset.xml", uuids=[uuid1, uuid2], quiet=True)
265+
```
266+
267+
To export a list of compound objects (and the primitives they contain), use `writeXML_byobject()`:
268+
269+
```python
270+
context.writeXML_byobject("objects.xml", [objID1, objID2], quiet=True)
271+
```
272+
273+
The `quiet` flag (defaults to `False`) suppresses informational console output during export.

docs/plugin_leafoptics.md

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,73 @@ model.
9292
<tr><td>drymass</td><td>g&nbsp;cm\f$^{-2}\f$</td><td>Dry matter mass</td><td>0.09</td></tr>
9393
<tr><td>protein</td><td>g&nbsp;cm\f$^{-2}\f$</td><td>Protein mass</td><td>0</td></tr>
9494
<tr><td>carbonconstituents</td><td>g&nbsp;cm\f$^{-2}\f$</td><td>Cellulose and other carbon compounds</td><td>0</td></tr>
95+
<tr><td>V2Z</td><td>unitless, [0,1]</td><td>Violaxanthin↔zeaxanthin de-epoxidation state. Used by the radiation plugin's solar-induced fluorescence (SIF) pipeline; ignored by PROSPECT.</td><td>0</td></tr>
96+
<tr><td>fqe</td><td>unitless</td><td>Intrinsic fluorescence quantum-efficiency scalar applied on top of the per-leaf Phi_F at SIF emission time. Ignored by PROSPECT.</td><td>1</td></tr>
9597
</table>
9698

99+
> **SIF parameters (helios-core v1.3.72+):** `V2Z` and `fqe` are inert for the pure
100+
> reflectance/transmittance calculation. They are written to `fluspect_biochem_<label>`
101+
> global data on every `run()` so the radiation plugin's SIF camera can look them up
102+
> per primitive when building Fluspect-B emission kernels.
103+
104+
## Integration with the Radiation SIF Pipeline {#LOSIFIntegration}
105+
106+
The radiation plugin includes a Fluspect-B / van der Tol pipeline for simulating solar-induced chlorophyll fluorescence (SIF) — see [SIF camera](plugin_radiation.md#sif-camera) in the radiation docs. LeafOptics is the canonical way to author the per-leaf biochemistry that pipeline needs.
107+
108+
### What LeafOptics Writes for SIF {#LOSIFData}
109+
110+
Every `run(uuids, props, label)` call emits one extra global-data entry and one extra primitive-data label, in addition to the reflectance and transmittance outputs:
111+
112+
| Output | Type | Description |
113+
|---|---|---|
114+
| Global data `fluspect_biochem_<label>` | `std::vector<float>` (11 elements) | Fluspect-B biochemistry vector in fixed field order: `[Cab, Cca, Cw, Cdm, Cs, Cant, Cp, Cbc, N, V2Z, fqe]`. |
115+
| Primitive data `fluspect_spectrum` | `string` | Stamped on every UUID — value is `"fluspect_biochem_<label>"`. The radiation plugin reads this per primitive to identify fluorescing leaves; primitives without it are silently treated as non-fluorescing (stems, soil, etc.). |
116+
117+
The biochemistry vector is keyed by label, so leaves sharing a spectrum label share a single Fluspect-B kernel in the radiation plugin's per-label kernel cache. This is automatic — no extra API to enable.
118+
119+
### Field Mapping (LeafOpticsProperties → Fluspect-B) {#LOSIFFields}
120+
121+
| `LeafOpticsProperties` Member | Fluspect-B Field | Notes |
122+
|---|---|---|
123+
| `chlorophyllcontent` | C<sub>ab</sub> | Drives the dominant red-edge absorption that emits at 685 nm. |
124+
| `carotenoidcontent` | C<sub>ca</sub> | Combined with V2Z controls absorption in the 400–550 nm excitation range. |
125+
| `watermass` | C<sub>w</sub> | Equivalent water thickness (cm). |
126+
| `drymass` | C<sub>dm</sub> | PROSPECT-D dry matter (g/cm²). Set to 0 in PROSPECT-PRO mode. |
127+
| `brownpigments` | C<sub>s</sub> | Senescence/brown-pigment content. |
128+
| `anthocyancontent` | C<sub>ant</sub> | |
129+
| `protein` | C<sub>p</sub> | PROSPECT-PRO only. |
130+
| `carbonconstituents` | C<sub>bc</sub> | PROSPECT-PRO only. |
131+
| `numberlayers` | N | Mesophyll layer parameter. |
132+
| `V2Z` | V2Z | SIF-only field; ignored by PROSPECT. |
133+
| `fqe` | f<sub>qe</sub> | SIF-only field; ignored by PROSPECT. |
134+
135+
### Minimal SIF Wiring Example {#LOSIFExample}
136+
137+
```python
138+
from pyhelios import Context, LeafOptics
139+
from pyhelios.LeafOptics import LeafOpticsProperties
140+
from pyhelios.types import vec3, vec2
141+
142+
with Context() as context:
143+
leaf_uuids = [context.addPatch(center=vec3(0, 0, 1), size=vec2(0.1, 0.1))]
144+
with LeafOptics(context) as leafoptics:
145+
props = LeafOpticsProperties()
146+
props.chlorophyllcontent = 40.0 # Cab, ug/cm^2
147+
props.carotenoidcontent = 10.0 # Cca, ug/cm^2
148+
props.numberlayers = 1.5
149+
props.watermass = 0.009 # cm
150+
props.drymass = 0.012 # g/cm^2
151+
props.V2Z = 0.0 # dark-adapted; SIF-only
152+
props.fqe = 1.0 # no calibration scalar; SIF-only
153+
leafoptics.run(leaf_uuids, props, "myleaf")
154+
155+
# Now the radiation plugin's SIF pipeline can find every leaf in leaf_uuids via the
156+
# "fluspect_spectrum" primitive data and look up its biochemistry from the
157+
# "fluspect_biochem_myleaf" global data — no further wiring required.
158+
```
159+
160+
> **Note:** the reverse path `getPropertiesFromSpectrum()` does not currently populate `V2Z` or `fqe` as primitive data — those fields are SIF-only and are read by the radiation plugin directly from the `fluspect_biochem_*` global-data vector.
161+
97162
## Using the LeafOptics Plug-in {#LOUse}
98163

99164
The model can be run to produce global spectra and, optionally, assign those
@@ -147,7 +212,7 @@ with Context() as context:
147212
leafoptics.run(leafIDs, props, "example")
148213
```
149214

150-
The method returns a \ref pyhelios.LeafOptics.LeafOpticsProperties "LeafOpticsProperties" structure with all nine parameters populated (numberlayers, chlorophyllcontent, carotenoidcontent, anthocyancontent, brownpigments, watermass, drymass, protein, carbonconstituents).
215+
The method returns a \ref pyhelios.LeafOptics.LeafOpticsProperties "LeafOpticsProperties" structure with the nine PROSPECT biochemistry parameters populated (numberlayers, chlorophyllcontent, carotenoidcontent, anthocyancontent, brownpigments, watermass, drymass, protein, carbonconstituents). The optional Fluspect-B SIF fields (`V2Z`, `fqe`) keep their dataclass defaults (0.0 and 1.0); set them on the returned object if you intend to use the radiation plugin's SIF camera.
151216

152217
### Available Species {#LOLibrarySpecies}
153218

0 commit comments

Comments
 (0)