API Reference

This page is a compact guide to the public entry points of ArchimedLight.jl. For normal use, create a LightSimulation and call run_light.

API Stability

Version 0.1.3 is the compatibility baseline for ArchimedLight's first release in Julia's General registry. Earlier 0.1.x tags were development snapshots and are not covered by this stability promise. Starting with 0.1.3, the supported public API is the set of names exported by ArchimedLight. This includes the high-level simulation workflow, input readers, model helpers, validation helpers, user-facing result containers, attachment/output helpers, visualization helpers, and concrete backend selectors. Patch releases after 0.1.3 are expected to preserve those names; incompatible changes will use a new minor version and include migration notes.

Some lower-level stage functions are available as qualified calls such as ArchimedLight.compute_sky(...). These are intended for debugging, research, and parity work. They are not exported, and their exact arguments, return containers, and cache internals may be refined before 1.0.

LightStepResult and LightBudget are public result containers. It is fine to read their fields in analysis code, but user code should normally construct results through run_light rather than calling result constructors directly.

LightSimulation owns internal preparation and cache state. Use update_scene!, update_models!, update_options!, and cache_summary rather than relying on the cache field or cache object layout.

Main Workflow

File-based run:

using ArchimedLight

repo_root = normpath(joinpath(dirname(pathof(ArchimedLight)), ".."))
config = joinpath(repo_root, "example_2", "config.yml")
sim, meteo = read_simulation(config)
step = run_light(sim, first(meteo))
series = run_light(sim, meteo);
2-element Vector{LightStepResult}:
 LightStepResult(PAR=3.724 MJ, NIR=9.594 MJ, sky=463.139 W m^-2 PAR / 501.734 W m^-2 NIR, sectors=16 [sky=16, sun=0], scattering=13 iters, converged)
 LightStepResult(PAR=3.628 MJ, NIR=9.443 MJ, sky=448.777 W m^-2 PAR / 486.175 W m^-2 NIR, sectors=16 [sky=16, sun=0], scattering=13 iters, converged)

Interactive run. This is a schematic API shape because it assumes that the host application provides plant.opf and meteo_row; see the checked Interactive Workflow page for a fully executable in-memory scene.

using PlantGeom

scene = make_scene(domain=(-1.0, -1.0, 1.0, 1.0)) do s
    add_plant!(s, "plant.opf"; group="coffee", id=1)
    add_ground!(s; group="soil", type="ground")
end

models = models_for(
    "coffee" => ("Leaf" => translucent(par=0.15, nir=0.90),),
    "soil" => ("ground" => translucent(par=0.10, nir=0.40),),
)

sim = LightSimulation(scene, models; options=LightOptions())
step = run_light(sim, meteo_row)

For host-model coupling, this schematic loop assumes your host model provides the meteo rows and a later new_scene:

for row in rows
    light = run_light(sim, row)
end

update_scene!(sim, new_scene)

Input Loading

Use these when your workflow starts from files or existing tables. The names in this block are schematic placeholders for your actual paths and tables.

read_simulation(path)
read_scene(path)
read_models(path_or_paths)
read_options(path)
read_meteo(path_or_table)

Scene And Model Helpers

Use these when inputs are built in Julia. This block lists call signatures and is intentionally schematic.

PlantGeom.make_scene(f; domain, source_path="interactive.scene", kwargs...)
PlantGeom.add_plant!(builder, mtg_or_path; group, id, at=(0, 0, 0), scale=1.0, rotate=(0, 0, 0))
PlantGeom.add_object!(builder, mtg_mesh_or_path; group, id, type="object", at=(0, 0, 0), scale=1.0, rotate=(0, 0, 0))
PlantGeom.add_ground!(builder; z=0.0, nx=9, ny=9, group="pavement", type="Cobblestone")
PlantGeom.prepare_scene(mtg; source_path="interactive.opf", scene_xy_bounds=nothing, relabel_ids=false)
models_for(group => (type => model, ...), ...)
translucent(; par, nir, transparency=0.0)
virtual_sensor()
emitter(; radiance, par=0.48, nir=0.52)

PlantGeom.add_plant! is the plant-named wrapper. PlantGeom.add_object! is the general placement helper for MTGs, GeometryBasics meshes, .opf, and .gwa files. For mesh files such as .obj or .ply, use MeshIO/FileIO to load the mesh first. This snippet is schematic because it depends on your local mesh file and builder:

using FileIO, MeshIO
mesh = load("sensor.obj")
PlantGeom.add_object!(builder, mesh; group="sensor", type="panel", id=10)

Both placement helpers accept at, scale, rotate, deg, and OPS-style rotation, inclination_azimut, and inclination_angle placement keywords.

Tuple rotations use fixed X, then Y, then Z order. This is a schematic call shape:

PlantGeom.add_object!(builder, mesh; group="sensor", type="panel", id=10, rotate=(10, 20, 30), deg=true)

Named-tuple rotations preserve the field order, which is useful when you need a specific Euler sequence. This is a schematic call shape:

PlantGeom.add_object!(builder, mesh; group="sensor", type="panel", id=10, rotate=(y=20, z=30, x=10), deg=true)

PlantGeom.add_ground! and write_scene also work on prepared scenes. This snippet is schematic because it assumes an existing scene and output path:

PlantGeom.add_ground!(scene; z=0.0, nx=9, ny=9, xy_bounds=nothing, group="pavement", type="Cobblestone")
write_scene(path, scene)

Validation

Use these to diagnose inputs before running. This block is schematic and uses placeholder inputs already introduced above:

check_scene(scene)
check_models(scene, models)
check_meteo(meteo; options=LightOptions())
check_simulation(sim)
check_simulation(scene, meteo; models, options=LightOptions())
summarize_scene(scene; models=nothing)
summarize_meteo(meteo; options=LightOptions())

Each function returns a ValidationReport with errors, warnings, and infos. Meteo-aware checks and execution methods accept check_boundaries=false as a one-call override; derivability, duration, and finite-input consistency checks remain enabled.

The summarize_* helpers return structured summaries and print compact diagnostics for humans. Use them when you are not sure what ArchimedLight sees. This schematic snippet assumes scene, models, meteo, and options exist:

summarize_scene(scene; models=models)
summarize_meteo(meteo; options=options)

Simulation Cache

LightSimulation owns preparation and cache state. These helpers update inputs and invalidate cached data. This block is schematic and assumes existing replacement inputs:

update_scene!(sim, scene)
update_models!(sim, models)
update_options!(sim, options)
cache_summary(sim)

update_scene! immediately releases old scene-dependent prepared data and cache entries. The cache object itself is an implementation detail; use cache_summary(sim) when you need to inspect cache behavior. Its node_metadata_count and node_metadata_bytes fields report the size of the current lightweight metadata snapshot independently of the radiation-response cache budget.

Advanced Light Pipeline

The explicit stage API is available as qualified, advanced API for debugging, research, and parity workflows. These calls may return stage containers such as ArchimedLight.TurtleGrid or ArchimedLight.FirstOrderResult, which are not exported in 0.1.x. This block is schematic because it assumes all previous stage inputs have already been prepared:

ArchimedLight.compute_sky(row, options)
ArchimedLight.build_turtle(options, sky)
ArchimedLight.compute_directional_fluxes(row, sky, turtle, options)
ArchimedLight.compute_first_order(scene, models, turtle, fluxes, options)
ArchimedLight.compute_scattering(scene, models, turtle, first, options)
ArchimedLight.integrate_light(scene, models, first, scattering, options; meteo_row=row)

These functions and stage containers are intentionally not exported in 0.1.x. Prefer run_light for application code unless you need to inspect or replace individual pipeline stages.

For interactive synthetic scenes, run_light also accepts a prebuilt sky state. This block is schematic because it assumes an existing scene, models, options, and sky:

sim = LightSimulation(scene, models; options=options)
step = run_light(sim, sky; step_duration_seconds=1800.0)

A vector of sky states runs as a series. Supply either one duration shared by all states or one duration per state:

series = run_light(sim, skies; step_duration_seconds=1800.0)
series = run_light(sim, skies; step_duration_seconds=[900.0, 1800.0, 900.0])

The result order matches skies, and the prepared scene and radiation cache are reused throughout the series.

The low-level cache functions are still available for advanced work, but their cache object layout is internal. This block is schematic and uses placeholders:

cache = ArchimedLight.prepare_light_cache(scene, models, options; ...)
ArchimedLight.run_light_step(cache, meteo_row)
ArchimedLight.run_light_series(cache, meteo)

prepare_light_cache uses a tiered policy internally:

  • :full keeps all seen turtle responses in memory
  • :partial keeps a bounded LRU cache for large moving-sun series
  • :topology_fallback reuses prepared geometry/topology only when a full-response cache would be too large or unsupported

Scene Attachment Helpers

These functions attach computed values back onto the MTG using ARCHIMED attribute names. This block lists schematic call shapes:

attach_node_values!(scene, attr, values; fill_value=nothing)
attach_light_step!(scene, step; fields=[:incident_par_flux], names=Dict(), fill_value=nothing)
attach_light_series!(scene, steps; fields=[:incident_par_flux], names=Dict(), fill_value=NaN)

attach_light_step! attaches scalar values for one step. attach_light_series! attaches Vector{Float64} values, ordered like steps, for each selected field. The supported fields selectors are:

SelectorDefault MTG attribute
:areaarea
:incident_par_initial_fluxRi_PAR_0_f
:incident_nir_initial_fluxRi_NIR_0_f
:incident_par_fluxRi_PAR_f
:incident_nir_fluxRi_NIR_f
:incident_par_initial_energyRi_PAR_0_q
:incident_nir_initial_energyRi_NIR_0_q
:incident_par_energyRi_PAR_q
:incident_nir_energyRi_NIR_q
:absorbed_par_initial_fluxRa_PAR_0_f
:absorbed_nir_initial_fluxRa_NIR_0_f
:absorbed_par_fluxRa_PAR_f
:absorbed_nir_fluxRa_NIR_f
:absorbed_par_initial_energyRa_PAR_0_q
:absorbed_nir_initial_energyRa_NIR_0_q
:absorbed_par_energyRa_PAR_q
:absorbed_nir_energyRa_NIR_q
:sky_fractionsky_fraction

For :area, attach_light_step! attaches one scalar surface area per node, while attach_light_series! repeats that area once per step so the attached attribute has the same vector shape as the light fields.

Use names=Dict(selector => attr) to override default attribute names, for example Dict(:absorbed_nir_flux => :Ra_SW_f).

Scene-Aware Light Queries

Use these functions to select geometric nodes and query a step or complete series without first attaching values to the MTG:

light_node_ids(
    scene_or_sim;
    node_ids=nothing,
    source_topology_id=nothing,
    group=nothing,
    species=nothing,
    object_id=nothing,
    symbol=nothing,
    scale=nothing,
    type=nothing,
    attributes=NamedTuple(),
    inherit_attributes=false,
    where=nothing,
)

light_metric_values(
    scene_or_sim,
    step_or_series,
    selector;
    # the same node filters
    reduce=nothing,
    by=nothing,
    sink=nothing,
)

The default result is a Tables.jl-compatible long-form column table. A reducer without by returns one scalar for a step or one value per timestep for a series. A reducer with by returns a grouped table. Native selectors and ARCHIMED names are interchangeable, for example :absorbed_par_energy and :Ra_PAR_q.

group/species and object_id inherit metadata from scene object roots. Arbitrary attributes are node-local unless inherit_attributes=true. Explicit node_ids are runtime identifiers in one prepared scene. source_topology_id identifies the source topology component; combine it with object_id when the same source plant is instantiated more than once.

Results retain a lightweight metadata snapshot by default. Consequently, light_metric_values(sim, dynamic_series, ...) applies semantic filters to each step's own scene version after update_scene!, even when runtime node ids changed. light_node_ids(step; ...) queries one retained snapshot directly.

Configure retention with:

LightOptions(
    store_node_metadata=true,
    node_metadata_attributes=(:organ_id, :cohort),
)

Extra attributes must be lightweight scalar values. Set store_node_metadata=false to minimize retained results; those results must be queried with their original live scene. A custom where predicate also needs a live MTG, so dynamic-series queries should capture its scalar inputs through node_metadata_attributes and use attributes=(...) instead.

Visualization Helpers

These helpers expose direct mesh coloring and the Makie package extension. This block lists schematic call shapes:

light_render_geometry(scene, models, options)
light_render_geometry(step)
light_render_geometry(steps)
tile_light_geometry(scene, geometry; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)
tile_light_geometry(scene, step; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)
tile_light_geometry(scene, steps; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)
tile_light_geometry(scene, models, options; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)
light_metric_values(step, selector)
light_metric_values(steps, selector; timestep=1)
light_face_values(data; color=:incident_par_flux, timestep=1, fill_value=NaN)
light_vertex_values(data; color=:incident_par_flux, timestep=1, fill_value=NaN)
light_face_values(scene, models, options, data; color=:incident_par_flux, timestep=1, fill_value=NaN)
light_vertex_values(scene, models, options, data; color=:incident_par_flux, timestep=1, fill_value=NaN)
lightplot(geometry, data; color=:incident_par_flux, timestep=1, interpolate=false, ...)
lightplot!(axis, geometry, data; color=:incident_par_flux, timestep=1, interpolate=false, ...)
lightplot(step; color=:incident_par_flux, timestep=1, interpolate=false, ...)
lightplot(steps; color=:incident_par_flux, timestep=1, interpolate=false, ...)
lightplot!(axis, step; color=:incident_par_flux, timestep=1, interpolate=false, ...)
lightplot!(axis, steps; color=:incident_par_flux, timestep=1, interpolate=false, ...)
lightplot(scene, models, options, data; color=:incident_par_flux, timestep=1, interpolate=false, ...)
lightplot!(axis, scene, models, options, data; color=:incident_par_flux, timestep=1, interpolate=false, ...)

For lightplot(steps; colorrange=automatic), the Makie extension keeps a single color range across the whole series so animated timesteps remain comparable.

Backend Types

The current public backend selectors are:

This block lists schematic constructor calls:

RasterCPUBackend()
RaycastScatteringBackend()

They can be passed explicitly to the pipeline helpers when you want to control the implementation used for interception or scattering. Only the concrete selectors are exported in 0.1.x; the backend supertypes are internal, and defining new backend subtypes is not yet a supported extension interface.

  • read Getting Started for the shortest runnable workflow
  • read Composable Stages if you want the stage-by-stage pattern
  • read Outputs for the mapping between LightBudget fields and ARCHIMED attribute names

API List

ArchimedLight.EmitterModelType
EmitterModel(; model="LambertianEmitter", radiance=0.0, gamma=OpticalProperties(0.48, 0.52), extras=...)

Emission model for artificial or diagnostic light sources.

radiance is the Lambertian radiance L emitted by each matching surface, in power per emitting area per steradian (for example W m^-2 sr^-1). gamma contains independent dimensionless spectral coefficients which are applied exactly as configured; they are not normalized to sum to one. PAR and NIR use the named fields, while additional coefficients in gamma.extras retain their uppercased band names. For a component with emitting surface area A, the hemispherical power in band b is pi * A * L * gamma[b]. The current model is one-sided and assumes a horizontal surface emitting into the downward hemisphere.

Most canopy simulations do not need explicit emitters and rely only on sky and sun forcing, but emitters are useful for artificial lighting setups, synthetic tests, or debugging scenes.

source
ArchimedLight.GroupModelType
GroupModel(group; types=OrderedDict(), extras=...)

Model definition for one functional group, keyed by component type.

group should match the functional-group name carried by the prepared scene geometry, for example "coffee" or "pavement".

types maps scene type names such as "Leaf", "Metamer", or "Cobblestone" to TypeModel values.

Wildcard support:

  • an exact type key such as "Leaf" applies only to that type
  • the wildcard key "*" acts as a fallback for any type in the group

This allows compact interactive setups such as:

GroupModel(
    "coffee";
    types=OrderedDict(
        "*" => TypeModel(
            interception=InterceptionModel(
                model="Translucent",
                optical_properties=OpticalProperties(0.15, 0.90),
            ),
        ),
        "Stem" => TypeModel(
            interception=InterceptionModel(
                model="Translucent",
                transparency=0.2,
                optical_properties=OpticalProperties(0.10, 0.50),
            ),
        ),
    ),
)

In that example, all coffee components use the wildcard model except "Stem", which is overridden explicitly.

source
ArchimedLight.InterceptionModelType
InterceptionModel(; model="Translucent", sensor=false, transparency=0.0, optical_properties=nothing, use=nothing, variants=..., extras=...)

Radiative behavior attached to one scene component type.

This stores the interception model name, transparency, optical coefficients, and optional named variants from historical ARCHIMED model files.

Main fields:

  • model: historical ARCHIMED interception model name. The common runtime case is "Translucent".
  • sensor: marks the type as a virtual sensor. Virtual sensors receive light diagnostics but remain transparent in the transfer logic.
  • transparency: first-order transmitted fraction. Typical values are in [0, 1], with 0.0 for fully intercepting surfaces and larger values for partially transmitting components.
  • optical_properties: waveband-dependent scattering coefficients used by the scattering stage.
  • use and variants: preserved support for historical YAML files that define several named parameter sets under one Interception block.

Typical pattern for ordinary canopy elements:

InterceptionModel(model="Translucent", transparency=0.0, optical_properties=OpticalProperties(0.15, 0.90))

source
ArchimedLight.LightBudgetType
LightBudget

Per-node light budget for one simulation step, storing incident and absorbed fluxes and energies for PAR, NIR, and optional extra wavebands. Escaped artificial-emitter energy is stored by waveband and emitting source node.

source
ArchimedLight.LightModelsType
LightModels(groups)

Top-level collection of all functional-group models used by one simulation.

This is the object passed to run_light_step, run_light_series, and the lower level interception/scattering functions.

groups maps functional-group names to GroupModel values. The special group key "*" is also supported as a global fallback.

When the solver resolves a scene node (group, type), it matches models with the following precedence:

  1. exact group and exact type
  2. exact group and wildcard type "*"
  3. wildcard group "*" and exact type
  4. wildcard group "*" and wildcard type "*"

This makes LightModels convenient for:

  • precise canopy parameterizations with several plant groups
  • synthetic scenes where one default model should cover many node types
  • gradual interactive workflows where you start with fallback models and then add explicit overrides

Examples:

  • LightModels([GroupModel("coffee"; ...), GroupModel("pavement"; ...)])
  • LightModels([GroupModel("*"; types=OrderedDict("*" => default_type_model))])
source
ArchimedLight.LightNodeMetadataType
LightNodeMetadata

Lightweight columnar scene-node metadata captured for one prepared scene. Every LightStepResult computed from the same simulation cache shares the same snapshot, so semantic queries remain valid after update_scene!.

attributes stores requested node-local scalar attributes, while inherited_attributes stores their nearest inherited values.

source
ArchimedLight.LightOptionsType
LightOptions

Runtime controls for interception, scattering, and caching.

Fields:

  • all_in_turtle: if false, keep the direct beam as a separate sun sector; if true, redistribute it into the turtle sectors.
  • turtle_sectors: number of diffuse sky sectors. Common values are 16, 46, or denser grids for smoother angular resolution.
  • pixel_size: raster pixel size in meters. Smaller values improve geometric fidelity but increase runtime and memory use.
  • area_ratio: enable the ARCHIMED projected-area correction used for parity with the historical implementation.
  • scattering: enable multiple scattering after first-order interception.
  • scattering_max_iter: maximum number of scattering iterations.
  • scattering_stop_ratio: stop scattering when the current scattered energy is below this fraction of the initial intercepted energy.
  • scattering_coeff_par: fallback PAR scattering coefficient when the model has no PAR OpticalProperties.
  • scattering_coeff_nir: fallback NIR scattering coefficient when the model has no NIR OpticalProperties.
  • cache_radiation: reuse directional responses across series steps when possible.
  • include_sky_fraction: store the per-node sky_fraction map in each LightStepResult. Leave false unless downstream code needs it. When options are read from a config file, this is enabled by requesting sky_fraction in component_variables or opf_variables.
  • store_node_metadata: retain a lightweight per-scene node metadata snapshot shared by all results computed from that scene. This keeps queries valid after update_scene!.
  • node_metadata_attributes: optional scalar MTG attribute names to add to the standard node metadata snapshot. Standard identity and group/type fields are always included when store_node_metadata=true.
  • cache_pixel_table: cache raster pixel tables for repeated projections.
  • pixel_hit_stack_mode: storage mode for per-pixel hit stacks. Supported values are "auto", "small", and "vector".
  • toricity: enable horizontal periodic wrapping of the simulated plot.
  • radiation_timestep_minutes: internal radiative substep used when a meteo row covers a coarser interval.
  • radiation_input_semantics: interpretation of supplied irradiances. :interval_mean preserves the supplied full-timestep mean, while :sunlit_intensity treats it as an intensity that applies only while the sun is above the horizon (the historical Java behavior).
  • scene_rotation_deg: clockwise rotation, in degrees, from geographic north to the scene's local coordinates. The geographic sun is transformed into the fixed local turtle basis before directional weights are computed.
  • check_meteo_boundaries: validate physical ranges for meteorological inputs before preparation or execution. Derivability and conflicting-input checks remain enabled even when this is false.
  • allow_overlapping_meteo_steps: keep overlapping meteo intervals instead of rejecting the series during meteo preparation.
  • nir_interception: include NIR in directional fluxes and first-order interception.
  • nir_scattering: include NIR in the multiple-scattering stage. This has no effect if nir_interception=false.
  • java_logged_turtle_dirs: use the Java-compatibility turtle direction path used in parity/debug workflows.
  • meteo_range: optional historical range selector applied during meteo preparation, for example "2, 5" or a datetime range.
  • debug: enable debug-only compatibility hooks.
  • log_debug: emit additional debug logging where implemented.
  • debug_drop_leading_hit: optional (node_id, x, y) hook used to remove a leading raster hit at one pixel for parity debugging.

Typical starting point for simple runs:

LightOptions(turtle_sectors=46, pixel_size=0.0025, scattering=true)

Constructor keywords are the field names above. LightOptions(old; kwargs...) copies an existing options value and overrides only the supplied keywords.

source
ArchimedLight.LightRenderGeometryType
LightRenderGeometry

Render-ready geometry used to visualize one simulated light result.

This stores the exact face subset and face-to-node mapping used by the light solver after model-dependent filtering has been applied.

source
ArchimedLight.LightSimulationMethod
LightSimulation(scene, models; options=LightOptions(), kwargs...)

Create a reusable light simulation. Expensive geometry preparation and radiation caches are built lazily by run_light.

Arguments:

  • scene: prepared PlantGeom.SceneGeometry used by the solver.
  • models: model specification accepted by prepare_models.

Keywords:

  • options: LightOptions controlling interception, scattering, and caching.
  • interception_backend: interception backend selector or backend instance. The default is :raster_cpu.
  • scattering_mode: scattering algorithm selector. The default is :raycast.
  • scattering_backend: optional scattering backend instance.
  • memory_limit_bytes: optional limit for resident directional-response cache data. nothing uses the package default.
source
ArchimedLight.LightStepResultType
LightStepResult

Complete result of one light simulation step, including the sky state, turtle, directional fluxes, first-order interception, optional scattering, and the integrated LightBudget. When requested, the result can also store a per-node sky_fraction map. Results returned by run_light_step and run_light_series also carry the render geometry needed by lightplot. By default they retain a shared LightNodeMetadata snapshot for scene-aware queries across dynamic scene updates.

source
ArchimedLight.OpticalPropertiesType
OpticalProperties(par=0.0, nir=0.0)

Per-waveband scattering coefficients for a component or emitter.

par and nir are the built-in ARCHIMED bands. Additional coefficients can be stored in extras.

For plant components, these coefficients are typically used as the scattered fraction in each waveband. Expected values are usually in [0, 1].

Typical values:

  • leaves in PAR: often around 0.05-0.25
  • leaves in NIR: often around 0.4-0.9
  • emitters: gamma often uses PAR=0.48, NIR=0.52 as independent spectral coefficients for the built-in bands; the values are not normalized

Examples:

  • OpticalProperties(0.15, 0.90) for a strongly NIR-scattering leaf
  • OpticalProperties(0.48, 0.52) for PAR/NIR emitter coefficients
source
ArchimedLight.SkyStateType
SkyState(sun_azimuth_deg, sun_elevation_deg, ri_par_f, ri_nir_f, direct_fraction, diffuse_fraction)

Radiative forcing state used to build the turtle and directional fluxes for one light step. When produced by compute_sky, its irradiance fields are effective means over the complete meteo interval, after applying radiation_input_semantics.

Arguments:

  • sun_azimuth_deg: sun azimuth in degrees on the horizontal plane. The package uses along +y, 90° along +x, 180° along -y, and 270° along -x. If your scene uses the common x=east, y=north convention, this means 0°=north, 90°=east, 180°=south, 270°=west.
  • sun_elevation_deg: sun elevation in degrees above the horizon. Typical daylight values are between 5 and 80. Use 90 for a sun at zenith; in simple examples, 89 is often a good practical choice when you want a nearly vertical beam.
  • ri_par_f: incident PAR irradiance in W m^-2 on a horizontal plane. Typical daylight values are often in the 100-600 range. Clear midday conditions are often around 300-500.
  • ri_nir_f: incident NIR irradiance in W m^-2 on a horizontal plane. Typical daylight values are often in the 100-700 range, commonly of the same order as or slightly larger than PAR.
  • direct_fraction: fraction of the shortwave forcing treated as direct beam. Expected range is [0, 1]. Typical values are near 0.8-1.0 for clear-sky conditions, around 0.3-0.7 for mixed conditions, and 0.0 for a fully diffuse sky.
  • diffuse_fraction: fraction of the shortwave forcing treated as diffuse sky radiation. Expected range is [0, 1]. In most use cases, it should satisfy direct_fraction + diffuse_fraction == 1.

This six-argument constructor stores ri_sw_f = ri_par_f + ri_nir_f automatically.

Examples:

  • Nearly zenith, mostly direct forcing: SkyState(180.0, 89.0, 350.0, 250.0, 0.95, 0.05)
  • Lower sun with mixed direct and diffuse light: SkyState(135.0, 35.0, 200.0, 180.0, 0.5, 0.5)
  • Fully diffuse overcast step: SkyState(180.0, 45.0, 120.0, 130.0, 0.0, 1.0)
source
ArchimedLight.TypeModelType
TypeModel(; interception=nothing, light_emitter=nothing, extras=...)

Model definition for one component type inside a functional group.

This is the level that corresponds to one entry under the Type: block in a historical YAML model file.

Typical contents:

  • interception: how this component intercepts, transmits, and scatters light
  • light_emitter: optional emission model for artificial sources
  • extras: preserved non-light metadata from input files

Examples:

  • a leaf type with only interception behavior
  • a lamp type with only light_emitter
  • a diagnostic sensor type with interception=InterceptionModel(sensor=true, ...)
source
ArchimedLight.ValidationReportType
ValidationReport(errors, warnings, infos)

Structured validation result returned by check_scene, check_models, check_meteo, and check_simulation.

source
ArchimedLight.attach_light_series!Method
attach_light_series!(scene, steps; fields=[:incident_par_flux], names=Dict(), fill_value=NaN)

Attach a time series of LightStepResult values to the scene MTG.

Arguments:

  • scene: MTG-backed PlantGeom.SceneGeometry to mutate.
  • steps: ordered vector of LightStepResult values to attach.

Keywords:

  • fields: budget or metadata selectors to attach.
  • names: optional mapping from selectors in fields to custom MTG attribute names.
  • fill_value: value stored for geometry nodes absent from a selected step dictionary.

For each selected field, every geometry node receives a vector ordered like steps, which is convenient for downstream plotting or coupled simulations. For example, with the default field, each geometry node gets node[:Ri_PAR_f]::Vector{Float64} with one value per light step.

fields accepts the same selectors as attach_light_step!:

  • :area => area
  • :incident_par_initial_flux => Ri_PAR_0_f
  • :incident_nir_initial_flux => Ri_NIR_0_f
  • :incident_par_flux => Ri_PAR_f
  • :incident_nir_flux => Ri_NIR_f
  • :incident_par_initial_energy => Ri_PAR_0_q
  • :incident_nir_initial_energy => Ri_NIR_0_q
  • :incident_par_energy => Ri_PAR_q
  • :incident_nir_energy => Ri_NIR_q
  • :absorbed_par_initial_flux => Ra_PAR_0_f
  • :absorbed_nir_initial_flux => Ra_NIR_0_f
  • :absorbed_par_flux => Ra_PAR_f
  • :absorbed_nir_flux => Ra_NIR_f
  • :absorbed_par_initial_energy => Ra_PAR_0_q
  • :absorbed_nir_initial_energy => Ra_NIR_0_q
  • :absorbed_par_energy => Ra_PAR_q
  • :absorbed_nir_energy => Ra_NIR_q
  • :sky_fraction => sky_fraction

For :area, series attachment stores the same area value repeated once per step so the result has the same vector shape as the light fields.

Use names to override attached attribute names. This is useful for downstream packages that expect different names:

attach_light_series!(
    scene,
    steps;
    fields=[:area, :absorbed_par_flux, :absorbed_nir_flux, :sky_fraction],
    names=Dict(:absorbed_nir_flux => :Ra_SW_f),
)

fill_value is used for geometry nodes that are missing from a given step dictionary. The default is NaN, so missing values remain visible in the attached vectors.

sky_fraction is only available when each step was produced with LightOptions(include_sky_fraction=true), or from a config that requests sky_fraction: true in component_variables or opf_variables.

source
ArchimedLight.attach_light_step!Method
attach_light_step!(scene, step; fields=[:incident_par_flux], names=Dict(), fill_value=nothing)

Attach one LightStepResult back onto the scene MTG using ARCHIMED-style attribute names such as Ri_PAR_f and Ra_PAR_q.

Arguments:

  • scene: MTG-backed PlantGeom.SceneGeometry to mutate.
  • step: one LightStepResult whose node-level values will be attached.

Keywords:

  • fields: budget or metadata selectors to attach.
  • names: optional mapping from selectors in fields to custom MTG attribute names.
  • fill_value: value written for geometry nodes absent from a selected step dictionary.

fields selects which budget components to export. Each selected field is attached as one scalar MTG attribute per geometry node. Supported selectors are:

  • :incident_par_initial_flux => Ri_PAR_0_f
  • :incident_nir_initial_flux => Ri_NIR_0_f
  • :incident_par_flux => Ri_PAR_f
  • :incident_nir_flux => Ri_NIR_f
  • :incident_par_initial_energy => Ri_PAR_0_q
  • :incident_nir_initial_energy => Ri_NIR_0_q
  • :incident_par_energy => Ri_PAR_q
  • :incident_nir_energy => Ri_NIR_q
  • :absorbed_par_initial_flux => Ra_PAR_0_f
  • :absorbed_nir_initial_flux => Ra_NIR_0_f
  • :absorbed_par_flux => Ra_PAR_f
  • :absorbed_nir_flux => Ra_NIR_f
  • :absorbed_par_initial_energy => Ra_PAR_0_q
  • :absorbed_nir_initial_energy => Ra_NIR_0_q
  • :absorbed_par_energy => Ra_PAR_q
  • :absorbed_nir_energy => Ra_NIR_q
  • :sky_fraction => sky_fraction
  • :area => area

Selector naming follows the budget hierarchy:

  • incident means intercepted radiation, corresponding to historical Ri
  • absorbed means absorbed radiation, corresponding to historical Ra
  • initial means first-order only, corresponding to historical _0_
  • no initial means first-order plus scattering
  • flux means W m^-2, corresponding to historical _f
  • energy means J per component and per step, corresponding to historical _q
  • area means the prepared object surface area in m^2

names is an optional dictionary that remaps those exported fields to custom MTG attribute names. For example:

attach_light_step!(
    scene,
    step;
    fields=[:incident_par_flux, :absorbed_par_energy],
    names=Dict(
        :incident_par_flux => :my_par_flux,
        :absorbed_par_energy => :my_par_energy,
    ),
)

With that override, the values are attached on :my_par_flux and :my_par_energy instead of the default ARCHIMED names.

To expose the sky-view fraction or PlantBiophysics-specific names, you can mix selectors and overrides:

attach_light_step!(
    scene,
    step;
    fields=[:area, :absorbed_par_flux, :absorbed_nir_flux, :sky_fraction],
    names=Dict(:absorbed_nir_flux => :Ra_SW_f),
)

sky_fraction is only available when the step was produced with LightOptions(include_sky_fraction=true), or from a config that requests sky_fraction: true in component_variables or opf_variables.

source
ArchimedLight.attach_node_values!Method
attach_node_values!(scene, attr, values; fill_value=nothing)

Attach a dictionary of per-node values to the MTG stored in scene.

Only geometry nodes present in the prepared scene are updated. Missing node ids receive fill_value.

Arguments:

  • scene: MTG-backed PlantGeom.SceneGeometry to mutate.
  • attr: MTG attribute name to write on each geometry node.
  • values: dictionary keyed by node id, containing values to attach.

Keywords:

  • fill_value: value written for geometry nodes absent from values.
source
ArchimedLight.cache_summaryMethod
cache_summary(sim)

Return a named tuple summarizing the current radiation cache state for a LightSimulation.

Arguments:

  • sim: simulation whose prepared cache should be summarized. If no cache has been prepared yet, the summary reports mode=:unprepared.
source
ArchimedLight.check_meteoMethod
check_meteo(meteo; options=LightOptions(), check_boundaries=options.check_meteo_boundaries)::ValidationReport

Validate meteo rows for required solar geometry, radiation inputs, and timestep duration data.

Arguments:

  • meteo: a meteo row, PlantMeteo.TimeStepTable, or Tables.jl-compatible table.

Keywords:

  • options: LightOptions used for checks that depend on runtime meteo handling.
  • check_boundaries: check physical ranges for used meteo values. Missing, nonfinite, derivability, and conflicting-input checks are always performed.
source
ArchimedLight.check_modelsMethod
check_models(scene, models)::ValidationReport

Validate that models cover the geometric group/type pairs present in scene.

Arguments:

  • scene: PlantGeom.SceneGeometry whose geometric nodes define the required group/type pairs.
  • models: model specification accepted by prepare_models.
source
ArchimedLight.check_sceneMethod
check_scene(scene)::ValidationReport

Validate basic scene readiness for light interception.

Arguments:

  • scene: PlantGeom.SceneGeometry to check for geometry nodes, faces, and a valid xy domain.
source
ArchimedLight.check_simulationMethod
check_simulation(sim)::ValidationReport
check_simulation(scene, meteo; models, options=LightOptions(), check_boundaries=options.check_meteo_boundaries)::ValidationReport

Validate a reusable simulation or the separate inputs needed to build and run one.

Arguments:

  • sim: LightSimulation to validate.
  • scene: PlantGeom.SceneGeometry to validate when checking separate inputs.
  • meteo: meteo row or table to validate when checking separate inputs.

Keywords:

  • models: required model specification when checking separate inputs.
  • options: LightOptions used for meteo validation.
  • check_boundaries: check physical ranges for used meteo values.
source
ArchimedLight.emitterMethod
emitter(; radiance, par=0.48, nir=0.52)

Build a TypeModel for an emitting component.

Keywords:

  • radiance: Lambertian radiance per emitting area per steradian.
  • par: unnormalized PAR spectral coefficient. The default is 0.48.
  • nir: unnormalized NIR spectral coefficient. The default is 0.52.
source
ArchimedLight.light_face_valuesMethod
light_face_values(scene, models, options, data; color=:incident_par_flux, timestep=1, fill_value=NaN)
light_face_values(data; color=:incident_par_flux, timestep=1, fill_value=NaN)

Return one scalar color value per rendered face for direct Makie mesh coloring.

Arguments:

  • geometry: LightRenderGeometry whose faces receive values.
  • scene: prepared PlantGeom.SceneGeometry used when deriving geometry from simulation inputs.
  • models: LightModels used when deriving geometry from simulation inputs.
  • options: LightOptions used when deriving geometry from simulation inputs.
  • data: one LightStepResult, a vector of results, a node-value dictionary, a vector of dictionaries, or explicit numeric color values.

Keywords:

  • color: metric selector, node-value dictionary, or explicit numeric color vector.
  • timestep: one-based index used for series data.
  • fill_value: value used for nodes/faces without finite data.

When data is a LightStepResult or a series of steps returned by run_light_step / run_light_series, the stored render geometry is used and no scene or model inputs are needed.

source
ArchimedLight.light_metric_valuesMethod
light_metric_values(scene_or_sim, step_or_series, metric; filters..., reduce=nothing, by=nothing, sink=nothing)

Return a filtered, Tables.jl-compatible column table for one light metric. metric accepts package selectors such as :absorbed_par_energy and historical ARCHIMED names such as :Ra_PAR_q.

The node filters are the same as light_node_ids. Without reduce, the result contains step_number, scene and output node identifiers, group/type and MTG metadata, requested attribute columns, and value. A series is returned in long form with one-based step numbers.

With reduce=sum, a single step returns a scalar and a series returns one value per timestep. Pass by to obtain a grouped table instead; series grouping always retains step_number. sink optionally materializes table results with a Tables.jl-compatible sink such as DataFrames.DataFrame.

Summing component energy metrics is physically meaningful. Component fluxes are area-normalized, so summing them generally is not a scene-scale energy total.

source
ArchimedLight.light_metric_valuesMethod
light_metric_values(step, selector)
light_metric_values(steps, selector; timestep=1)

Return the per-node metric map selected by selector.

Arguments:

  • step: one LightStepResult to read.
  • steps: vector of LightStepResult values to index with timestep.
  • selector: metric selector symbol, either package-native or ARCHIMED-style.

Keywords:

  • timestep: one-based index used when steps is a series.

selector may be either a runtime budget field such as :incident_par_flux or the corresponding ARCHIMED attribute name such as :Ri_PAR_f.

source
ArchimedLight.light_node_idsMethod
light_node_ids(scene_or_sim; filters...)

Return the sorted runtime node ids of geometric scene components matching all requested filters. Pass the returned ids back through node_ids= to reuse a selection across light metrics or timesteps.

Standard filters are node_ids, source_topology_id, group (or its alias species), object_id, symbol, scale, and type. Scalar filters use equality; collections use membership. attributes accepts a named tuple or dictionary of exact attribute matches. Arbitrary attributes are node-local unless inherit_attributes=true. The optional where predicate receives the corresponding MTG node.

group/species and object_id use inherited scene metadata, matching the way OPS object roots identify their descendant geometry.

source
ArchimedLight.light_render_geometryMethod
light_render_geometry(scene, models, options)
light_render_geometry(step)
light_render_geometry(steps)

Return the render-ready geometry associated with a light simulation.

Arguments:

  • scene: prepared PlantGeom.SceneGeometry used when deriving geometry from simulation inputs.
  • models: LightModels used to apply solver-visible filtering.
  • options: LightOptions used to match the solver geometry.
  • step: one LightStepResult whose stored render geometry is returned.
  • steps: non-empty vector of LightStepResult values. The first step supplies the geometry.

For a scene, this applies the same model-dependent filtering as the solver. For results returned by run_light_step or run_light_series, it returns the stored render geometry directly.

source
ArchimedLight.light_vertex_valuesMethod
light_vertex_values(scene, models, options, data; color=:incident_par_flux, timestep=1, fill_value=NaN)
light_vertex_values(data; color=:incident_par_flux, timestep=1, fill_value=NaN)

Return one scalar color value per rendered vertex, obtained by averaging the values of adjacent faces.

Arguments:

  • geometry: LightRenderGeometry whose vertices receive values.
  • scene: prepared PlantGeom.SceneGeometry used when deriving geometry from simulation inputs.
  • models: LightModels used when deriving geometry from simulation inputs.
  • options: LightOptions used when deriving geometry from simulation inputs.
  • data: one LightStepResult, a vector of results, a node-value dictionary, a vector of dictionaries, or explicit numeric color values.

Keywords:

  • color: metric selector, node-value dictionary, or explicit numeric color vector.
  • timestep: one-based index used for series data.
  • fill_value: value used for nodes/vertices without finite data.

When data is a LightStepResult or a series of steps returned by run_light_step / run_light_series, the stored render geometry is used and no scene or model inputs are needed.

source
ArchimedLight.lightplotFunction
lightplot

Makie plotting entry point provided by the Makie package extension. Load Makie or CairoMakie before calling it. The preferred API is lightplot(step; ...) or lightplot(steps; ...).

Arguments:

  • data: one LightStepResult or a vector of results with stored render geometry.
  • geometry: optional LightRenderGeometry when plotting explicit geometry/data pairs.
  • scene: prepared PlantGeom.SceneGeometry used when deriving geometry from simulation inputs.
  • models: LightModels used when deriving geometry from simulation inputs.
  • options: LightOptions used when deriving geometry from simulation inputs.

Keywords:

  • kwargs...: Makie plot attributes, including ArchimedLight-specific color, timestep, interpolate, and fill_value.
source
ArchimedLight.lightplot!Function
lightplot!

In-place Makie plotting entry point provided by the Makie package extension. Load Makie or CairoMakie before calling it. The preferred API is lightplot!(axis, step; ...) or lightplot!(axis, steps; ...).

Arguments:

  • axis: Makie axis or scene-like parent to plot into.
  • data: one LightStepResult or a vector of results with stored render geometry.
  • geometry: optional LightRenderGeometry when plotting explicit geometry/data pairs.
  • scene: prepared PlantGeom.SceneGeometry used when deriving geometry from simulation inputs.
  • models: LightModels used when deriving geometry from simulation inputs.
  • options: LightOptions used when deriving geometry from simulation inputs.

Keywords:

  • kwargs...: Makie plot attributes, including ArchimedLight-specific color, timestep, interpolate, and fill_value.
source
ArchimedLight.models_forMethod
models_for(group_specs...)::LightModels

Create LightModels from compact (group => (type => model, ...)) pairs. Group and type names are matched against geometric scene nodes.

Arguments:

  • group_specs...: one or more pairs where the left side is a scene group name and the right side is an iterable of type => TypeModel pairs.

Example:

julia> models = models_for(
           "coffee" => (
               "Leaf" => translucent(par=0.15, nir=0.90),
               "Stem" => translucent(par=0.20, nir=0.50),
           ),
           "soil" => (
               "ground" => translucent(par=0.10, nir=0.40),
           ),
       );

julia> (collect(keys(models)), models["coffee"].types["Leaf"].interception.model)
(["coffee", "soil"], "Translucent")
source
ArchimedLight.prepare_meteoMethod
prepare_meteo(meteo, options; check_boundaries=options.check_meteo_boundaries)::PlantMeteo.TimeStepTable

Return the effective meteo table after Java-like meteo controls are applied: sequence validation, optional meteo_range, and optional active filtering.

Arguments:

  • meteo: a PlantMeteo.TimeStepTable or Tables.jl-compatible table of meteo rows.
  • options: LightOptions controlling overlap validation, meteo_range, and active-row filtering.

Keywords:

  • check_boundaries: check physical ranges for used meteo values. Missing, nonfinite, derivability, and conflicting-input checks always remain enabled.
source
ArchimedLight.prepare_modelsMethod
prepare_models(models)

Normalize in-memory model definitions into a LightModels object.

Arguments:

  • models: an in-memory model specification.

Accepted inputs are an existing LightModels, a single GroupModel, a vector of groups, or an OrderedDict{String,GroupModel}.

source
ArchimedLight.read_meteoMethod
read_meteo(path)::PlantMeteo.TimeStepTable
read_meteo(data)::PlantMeteo.TimeStepTable

Read a meteorological forcing table from path and return it as a PlantMeteo.TimeStepTable.

The resulting table keeps available metadata such as latitude, longitude, altitude, and source file path.

Arguments:

  • path: path to a meteorological forcing file readable by PlantMeteo.
  • data: alternatively, a Tables.jl-compatible table or an existing PlantMeteo.TimeStepTable.
source
ArchimedLight.read_modelsMethod
read_models(path_or_paths)::LightModels

Read one or more ARCHIMED model YAML files and return them as a LightModels collection.

Arguments:

  • path_or_paths: a model source to read.

path_or_paths can be:

  • the path to a single model YAML file containing a Group
  • the path to a config YAML file containing a models: list
  • a vector of explicit model-file paths
source
ArchimedLight.read_optionsMethod
read_options(path)::LightOptions

Read runtime light options from a config YAML file.

This parses the ARCHIMED configuration keys such as sky_sectors, pixel_size, toricity, scattering controls, and meteo-range options into a LightOptions instance.

Arguments:

  • path: path to an ARCHIMED-style configuration YAML file.
source
ArchimedLight.read_sceneMethod
read_scene(path)::PlantGeom.SceneGeometry

Read a scene file (.ops, .opf, or .gwa) and return a prepared PlantGeom.SceneGeometry.

The scene is relabelled into a dense node-id space and immediately converted to the merged-mesh representation expected by the interception pipeline.

Arguments:

  • path: path to an .ops, .opf, or .gwa scene file.

Keywords:

  • plantgeom_backend: reserved PlantGeom backend selector. The current default is :auto.
source
ArchimedLight.read_simulationMethod
read_simulation(path; plot_paving_override=nothing, check_boundaries=nothing, kwargs...)

Read a complete file-based light simulation and return (sim, meteo), where sim is a LightSimulation.

Arguments:

  • path: path to the ARCHIMED-style configuration YAML file.

Keywords:

  • plot_paving_override: optional replacement paving count used when materializing model-declared ground geometry.
  • check_boundaries: optional boundary-validation policy applied while reading meteo and stored in the returned simulation. Derivability and conflict checks are always performed.
  • kwargs...: keyword arguments forwarded to LightSimulation, such as interception_backend, scattering_mode, scattering_backend, and memory_limit_bytes.

This smoke example uses coarse, non-scattering options so it remains quick:

julia> repo_root = normpath(joinpath(dirname(pathof(ArchimedLight)), ".."));

julia> config = joinpath(repo_root, "example_2", "config.yml");

julia> sim, meteo = read_simulation(config; plot_paving_override=0);

julia> update_options!(
           sim,
           LightOptions(
               sim.options;
               turtle_sectors=1,
               pixel_size=0.1,
               area_ratio=false,
               scattering=false,
               toricity=false,
           ),
       );

julia> step = run_light(sim, first(meteo));

julia> println(step)
LightStepResult(PAR=291.777 kJ, NIR=316.092 kJ, sky=463.139 W m^-2 PAR / 501.734 W m^-2 NIR, sectors=1 [sky=1, sun=0], scattering=off)
source
ArchimedLight.run_lightMethod
run_light(sim, skies::AbstractVector{<:SkyState}; step_duration_seconds)

Run a series of already computed sky states. The step duration is required because sky states do not contain timing metadata.

step_duration_seconds may be either one positive duration shared by every state or a vector of positive durations with the same length as skies. The results are returned as a Vector{LightStepResult} in input order, while the simulation's prepared scene and radiation cache are reused across the series.

Examples

series = run_light(sim, skies; step_duration_seconds=1800.0)
series = run_light(sim, skies; step_duration_seconds=[900.0, 1800.0, 900.0])
source
ArchimedLight.run_lightMethod
run_light(sim, meteo_or_row; check_boundaries=sim.options.check_meteo_boundaries)

Run one light step for a meteo row, or a full series for a meteo table.

Arguments:

  • sim: LightSimulation containing the scene, models, options, and lazy cache.
  • meteo_or_row: either a single meteo row for one step, or a PlantMeteo.TimeStepTable/Tables.jl-compatible table for a series.

Keywords:

  • check_boundaries: check physical ranges for used meteo values. Derivability and conflicting-input checks are always performed.
source
ArchimedLight.run_lightMethod
run_light(sim, sky::SkyState; step_duration_seconds)

Run one light step from an already computed sky state. The step duration is required because there is no meteo row from which to infer it.

Arguments:

  • sim: LightSimulation containing the scene, models, options, and lazy cache.
  • sky: precomputed SkyState used for one light step.

Keywords:

  • step_duration_seconds: duration of the step in seconds. This is required for energy integration.
source
ArchimedLight.summarize_meteoMethod
summarize_meteo(meteo; options=LightOptions(), check_boundaries=options.check_meteo_boundaries)

Return a MeteoSummary describing row count, columns, timestep duration, radiation inputs, and the detected solar-geometry path for a meteo table or row.

Arguments:

  • meteo: a meteo row, PlantMeteo.TimeStepTable, or Tables.jl-compatible table.

Keywords:

  • options: LightOptions used for checks that depend on runtime meteo handling.
  • check_boundaries: check physical ranges while resolving the summary.
source
ArchimedLight.summarize_sceneMethod
summarize_scene(scene; models=nothing)

Return a SceneSummary describing the prepared scene domain, geometric nodes, faces, group/type pairs, object ids, and missing model pairs.

Pass models to include a model coverage check in the summary.

Arguments:

  • scene: PlantGeom.SceneGeometry to summarize.

Keywords:

  • models: optional model specification used to report missing group/type coverage.
source
ArchimedLight.tile_light_geometryMethod
tile_light_geometry(scene, geometry; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)
tile_light_geometry(scene, step; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)
tile_light_geometry(scene, steps; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)
tile_light_geometry(scene, models, options; nx=1, ny=1, centered=true, xperiod=nothing, yperiod=nothing)

Repeat a render geometry nx times along x and ny times along y for visualizing toric or repeated scenes.

Arguments:

  • scene: prepared PlantGeom.SceneGeometry used to infer tile spacing when periods are not provided.
  • geometry: LightRenderGeometry to repeat.
  • step: one LightStepResult whose stored geometry is repeated.
  • steps: non-empty vector of LightStepResult values whose first step supplies the geometry.
  • models: LightModels used when deriving geometry from simulation inputs.
  • options: LightOptions used when deriving geometry from simulation inputs.

Keywords:

  • nx: number of repetitions along x.
  • ny: number of repetitions along y.
  • centered: center tile offsets around the original geometry when true.
  • xperiod: optional explicit x tile period.
  • yperiod: optional explicit y tile period.

By default, the tile period comes from the scene xy bounds, so the visual repetition matches the simulation plot box. Pass xperiod and yperiod explicitly to override that spacing.

source
ArchimedLight.translucentMethod
translucent(; par, nir, transparency=0.0)

Build a TypeModel for an ordinary translucent component.

Keywords:

  • par: PAR scattering fraction for the component.
  • nir: NIR scattering fraction for the component.
  • transparency: intercepted-light transparency fraction. The default 0.0 makes the component opaque to interception.

par and nir are scattering fractions for the built-in ARCHIMED wavebands. The absorbed fraction is therefore 1 - scattering_fraction.

julia> model = translucent(par=0.15, nir=0.90, transparency=0.1);

julia> (model.interception.model, model.interception.transparency, model.interception.optical_properties.par)
("Translucent", 0.1, 0.15)
source
ArchimedLight.update_scene!Method
update_scene!(sim, new_scene)

Replace the scene and immediately release all prepared data tied to the old scene. The next run_light call prepares the new scene lazily.

Arguments:

  • sim: LightSimulation to update in place.
  • new_scene: replacement PlantGeom.SceneGeometry.
source
ArchimedLight.virtual_sensorMethod
virtual_sensor()

Build a TypeModel for virtual sensors. Virtual sensors receive light diagnostics while remaining transparent in interception and scattering logic.

Arguments: none.

source
ArchimedLight.write_component_valuesMethod
write_component_values(path::AbstractString, sim::LightSimulation, series; step_index_base::Integer=1)

Write an ARCHIMED-style component_values.csv file from already-computed LightStepResult values.

series may be a single LightStepResult or a collection of them. The function serializes the supplied results only; it does not run the simulation. Step numbers are 1-based by default. Use step_index_base=0 only for historical harness compatibility.

Arguments:

  • path: destination CSV file path.
  • sim: LightSimulation that supplies scene, model, and option context for component rows.
  • series: one LightStepResult or a collection of results to serialize.

Keywords:

  • step_index_base: first step number written to the CSV. The default is 1.
source
ArchimedLight.write_sceneMethod
write_scene(path, scene)

Write an MTG-backed PlantGeom.SceneGeometry to path.

Supported output formats are .ops, .opf, and .gwa. The function refreshes the reference-mesh registry and normalizes topology ids before export.

Arguments:

  • path: output path ending in .ops, .opf, or .gwa.
  • scene: MTG-backed PlantGeom.SceneGeometry to write.
source