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().