voxcity.simulator_gpu.solar.csf.CSFCalculator¶
- class voxcity.simulator_gpu.solar.csf.CSFCalculator(domain, n_azimuth: int = 80, n_elevation: int = 40, max_surfaces: int = 10000)¶
GPU-accelerated Canopy Sink Factor calculator.
CSF represents the fraction of radiation absorbed by each vegetation cell along ray paths from surfaces to sky/sun.
Following PALM’s methodology: - CSF entries have a source index (isurfs): -1 for sky, >= 0 for surfaces - During reflection iterations, canopy absorption is accumulated using CSF - pcbinsw += csf * surfoutsl(isurfsrc) * asrc * grid_volume_inverse
- domain¶
- nx¶
- ny¶
- nz¶
- dx¶
- dy¶
- dz¶
- n_azimuth = 80¶
- n_elevation = 40¶
- ext_coef = 0.6¶
- max_surfaces = 10000¶
- max_dist¶
- csf¶
- csf_sky¶
- lad_path¶
- dsitransc¶
- pc_box_area¶
- pc_abs_eff¶
- grid_volume¶
- grid_volume_inverse¶
- allocate_surface_csf(n_surfaces: int)¶
Allocate surface-to-canopy CSF storage for reflection calculations.
This is called when canopy absorption during reflections is needed.
- Parameters:
n_surfaces – Number of surfaces in the domain
- reset_csf()¶
Reset CSF fields to zero.
- reset_surface_csf(n_surfaces: int)¶
Reset surface-indexed CSF storage.
- compute_canopy_absorption_direct_palm(sun_dir, is_solid, lad, incoming_flux: float, prototype_lad: float = PROTOTYPE_LAD, mc_resolution: int = 60)¶
Compute direct solar canopy absorption using PALM’s method.
This is the main entry point that follows PALM’s approach: 1. Compute box absorption parameters (pc_box_area, pc_abs_eff) 2. Compute dsitransc (transmissivity to each canopy box) 3. Compute absorption per box using PALM’s formula
- Parameters:
sun_dir – Sun direction vector (ti.Vector or list)
is_solid – 3D solid field
lad – 3D LAD field
incoming_flux – Direct solar flux (W/m²)
prototype_lad – Reference LAD for effective coefficient
mc_resolution – Monte Carlo resolution for box_absorb
- compute_canopy_absorption_diffuse_palm(is_solid, lad, diffuse_flux: float, pcbinswdif, n_azimuth: int = None, n_elevation: int = None)¶
Compute diffuse sky canopy absorption using PALM’s method.
This computes: 1. CSF from sky (if not already cached - geometry-dependent, computed once) 2. Diffuse absorption using pcbinswdif = csf_sky * diffuse_flux * grid_volume_inverse
- Parameters:
is_solid – 3D solid field
lad – 3D LAD field
diffuse_flux – Diffuse sky flux (W/m²)
pcbinswdif – Output array for diffuse absorbed (W/m³)
n_azimuth – Number of azimuthal divisions for sky CSF
n_elevation – Number of elevation divisions for sky CSF
- compute_csf_sky_cached(is_solid, lad, n_azim: int, n_elev: int)¶
Compute CSF from sky with caching.
CSF sky is purely geometry-dependent (LAD + is_solid) and does not change with sun position. This wrapper caches the result after first computation.
- Parameters:
is_solid – 3D solid field
lad – 3D LAD field
n_azim – Number of azimuthal divisions
n_elev – Number of elevation divisions
- invalidate_csf_sky_cache()¶
Invalidate the CSF sky cache (call if geometry changes).
- compute_csf_sky(is_solid: ti.template(), lad: ti.template(), n_azim: taichi.i32, n_elev: taichi.i32)¶
Compute canopy sink factors from sky (isurfs = -1 in PALM terminology).
For each canopy cell, traces rays toward the sky hemisphere and computes the fraction of diffuse sky radiation that would be absorbed by this cell.
The result is stored in csf_sky as a view factor × absorption fraction. To get absorbed power: csf_sky[i,j,k] * diffuse_flux * horizontal_area / grid_volume
- Parameters:
is_solid – 3D solid field
lad – 3D LAD field
n_azim – Number of azimuthal divisions
n_elev – Number of elevation divisions
- compute_csf_direct(surf_pos: ti.template(), surf_area: ti.template(), sun_dir: ti.types.vector(3, ti.f32), is_solid: ti.template(), lad: ti.template(), n_surf: taichi.i32, incoming_flux: taichi.f32)¶
Compute CSF for direct solar radiation.
Traces rays from surfaces toward sun and accumulates absorption in each canopy cell along the path.
- Parameters:
surf_pos – Surface positions
surf_area – Surface areas
sun_dir – Sun direction unit vector
is_solid – 3D solid field
lad – 3D Leaf Area Density field
n_surf – Number of surfaces
incoming_flux – Incoming direct solar flux (W/m²)
- compute_csf_diffuse_hemisphere(surf_pos: ti.template(), surf_dir: ti.template(), surf_area: ti.template(), is_solid: ti.template(), lad: ti.template(), n_surf: taichi.i32, diffuse_flux: taichi.f32, n_azim: taichi.i32, n_elev: taichi.i32)¶
Compute CSF for diffuse sky radiation.
Traces rays from surfaces to multiple sky directions.
- compute_canopy_absorption_direct(sun_dir: ti.types.vector(3, ti.f32), is_solid: ti.template(), lad: ti.template(), incoming_flux: taichi.f32)¶
Compute direct solar absorption in canopy by tracing rays from sky.
This traces ONE ray per column from the top of the domain downward, following the sun direction. This correctly computes absorption without overcounting from multiple surfaces.
The result is stored in self.csf as total absorbed power (W) per cell. To convert to PALM-compatible W/m³, divide by grid_volume:
pcbinswdir = csf[i,j,k] * grid_volume_inverse
Note: This is an alternative method to compute_canopy_absorption_direct_palm which directly follows PALM’s box_absorb methodology.
- Parameters:
sun_dir – Sun direction unit vector (pointing toward sun)
is_solid – 3D solid field
lad – 3D Leaf Area Density field
incoming_flux – Incoming direct solar flux (W/m²)
- get_csf_numpy()¶
Get CSF field as numpy array (units depend on computation method).
- get_csf_wm3()¶
Get CSF field as numpy array in W/m³ (PALM-compatible units).
This divides the stored values by grid_volume to ensure consistent units.
- get_total_canopy_absorption() float¶
Get total radiation absorbed by canopy (W).
For PALM-compatible pcbinsw in W/m³, use get_csf_wm3().