voxcity.simulator_gpu.solar.csf.CSFCalculator ============================================= .. py: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 .. py:attribute:: domain .. py:attribute:: nx .. py:attribute:: ny .. py:attribute:: nz .. py:attribute:: dx .. py:attribute:: dy .. py:attribute:: dz .. py:attribute:: n_azimuth :value: 80 .. py:attribute:: n_elevation :value: 40 .. py:attribute:: ext_coef :value: 0.6 .. py:attribute:: max_surfaces :value: 10000 .. py:attribute:: max_dist .. py:attribute:: csf .. py:attribute:: csf_sky .. py:attribute:: lad_path .. py:attribute:: dsitransc .. py:attribute:: pc_box_area .. py:attribute:: pc_abs_eff .. py:attribute:: grid_volume .. py:attribute:: grid_volume_inverse .. py:method:: 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. :param n_surfaces: Number of surfaces in the domain .. py:method:: reset_csf() Reset CSF fields to zero. .. py:method:: reset_surface_csf(n_surfaces: int) Reset surface-indexed CSF storage. .. py:method:: 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 :param sun_dir: Sun direction vector (ti.Vector or list) :param is_solid: 3D solid field :param lad: 3D LAD field :param incoming_flux: Direct solar flux (W/m²) :param prototype_lad: Reference LAD for effective coefficient :param mc_resolution: Monte Carlo resolution for box_absorb .. py:method:: 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 :param is_solid: 3D solid field :param lad: 3D LAD field :param diffuse_flux: Diffuse sky flux (W/m²) :param pcbinswdif: Output array for diffuse absorbed (W/m³) :param n_azimuth: Number of azimuthal divisions for sky CSF :param n_elevation: Number of elevation divisions for sky CSF .. py:method:: 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. :param is_solid: 3D solid field :param lad: 3D LAD field :param n_azim: Number of azimuthal divisions :param n_elev: Number of elevation divisions .. py:method:: invalidate_csf_sky_cache() Invalidate the CSF sky cache (call if geometry changes). .. py:method:: 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 :param is_solid: 3D solid field :param lad: 3D LAD field :param n_azim: Number of azimuthal divisions :param n_elev: Number of elevation divisions .. py:method:: 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. :param surf_pos: Surface positions :param surf_area: Surface areas :param sun_dir: Sun direction unit vector :param is_solid: 3D solid field :param lad: 3D Leaf Area Density field :param n_surf: Number of surfaces :param incoming_flux: Incoming direct solar flux (W/m²) .. py:method:: 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. .. py:method:: 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. :param sun_dir: Sun direction unit vector (pointing toward sun) :param is_solid: 3D solid field :param lad: 3D Leaf Area Density field :param incoming_flux: Incoming direct solar flux (W/m²) .. py:method:: get_csf_numpy() Get CSF field as numpy array (units depend on computation method). .. py: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. .. py:method:: get_total_canopy_absorption() -> float Get total radiation absorbed by canopy (W). For PALM-compatible pcbinsw in W/m³, use get_csf_wm3().