artist.raytracing ================= .. py:module:: artist.raytracing Submodules ---------- .. toctree:: :maxdepth: 1 /autoapi/artist/raytracing/blocking/index /autoapi/artist/raytracing/geometry/index /autoapi/artist/raytracing/heliostat_ray_tracer/index /autoapi/artist/raytracing/sampling/index Classes ------- .. autoapisummary:: artist.raytracing.HeliostatRayTracer artist.raytracing.DistortionsDataset artist.raytracing.RestrictedDistributedSampler Functions --------- .. autoapisummary:: artist.raytracing.line_cylinder_intersections artist.raytracing.line_plane_intersections artist.raytracing.reflect Package Contents ---------------- .. py:function:: line_cylinder_intersections(rays: artist.scene.rays.Rays, points_at_ray_origins: torch.Tensor, target_areas: artist.field.tower_target_areas_cylindrical.TowerTargetAreasCylindrical, target_area_indices: torch.Tensor | None = None, bitmap_resolution: torch.Tensor = torch.tensor([256, 256]), device: torch.device | None = None) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor] Compute ray intersections with cylindrical receiver target areas and map hits into bitmap coordinates. This routine transforms rays from world space into each target cylinder's local frame, computes intersections with the infinite cylinder side surface, filters intersections to the finite cylinder sector (height + opening angle), and returns per-ray bitmap coordinates, intersection distances, and Lambert-weighted intensities. Pipeline: 1. Select target area per heliostat (or default to index 0). 2. Build local cylinder frame and transform ray origins/directions into that frame. 3. Solve quadratic for intersections with the infinite cylinder (x^2 + y^2 = r^2). 4. Select the smallest strictly positive intersection distance per ray. 5. Compute local intersection points, surface normals, and cosine-based intensity factor. 6. Filter to finite cylinder patch bounds: - height range [0, h] - angle range [0, opening_angle] 7. Convert valid local coordinates to continuous bitmap coordinates. Parameters ---------- rays : Rays Rays with directions and magnitudes, the directions must be normalized. points_at_ray_origins : torch.Tensor Ray origins in world space. Shape is ``[number_of_active_heliostats, number_of_combined_surface_points_all_facets, 4]``. target_areas : TowerTargetAreasCylindrical Cylindrical receiver definitions (centers, axes, normals, radii, heights, opening angles). target_area_indices : torch.Tensor | None Indices of target areas corresponding to each heliostat (default is None). If none are provided, the first target area of the scenario will be linked to all heliostats. Shape is ``[number_of_active_heliostats]``. bitmap_resolution : torch.Tensor Bitmap resolution (default is ``torch.tensor([256,256])``). device : torch.device | None The device on which to perform computations or load tensors and models (default is None). If None, ``ARTIST`` will automatically select the most appropriate device (CUDA or CPU) based on availability and OS. Returns ------- torch.Tensor Continuous E (horizontal/unwrapped-angle) bitmap coordinates in pixel units. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. Invalid rays are 0. torch.Tensor Continuous U (vertical/height) bitmap coordinates in pixel units. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. Invalid rays are 0. torch.Tensor Ray parameter distance t to the selected cylinder intersection. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. Invalid rays are 0. torch.Tensor Lambert-weighted hit intensities: ray_magnitudes * max(0, -dot(ray_dir_local, normal_local)). Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. Invalid rays are 0. .. py:function:: line_plane_intersections(rays: artist.scene.rays.Rays, points_at_ray_origins: torch.Tensor, target_areas: artist.field.tower_target_areas_planar.TowerTargetAreasPlanar, target_area_indices: torch.Tensor | None = None, bitmap_resolution: torch.Tensor = torch.tensor([256, 256]), device: torch.device | None = None) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor] Compute line-plane intersections of the rays (lines) and the target areas (planes). Parameters ---------- rays : Rays Rays with directions and magnitudes, the directions must be normalized. points_at_ray_origins : torch.Tensor Origins of the rays, which coincide with the surface points of the heliostats. Shape is ``[number_of_active_heliostats, number_of_combined_surface_points_all_facets, 4]``. target_areas : TowerTargetAreas All planar tower target areas. target_area_indices : torch.Tensor | None Indices of target areas corresponding to each heliostat (default is None). If none are provided, the first target area of the scenario will be linked to all heliostats. Shape is ``[number_of_active_heliostats]``. bitmap_resolution : torch.Tensor | None Bitmap resolution (default is ``torch.tensor([256,256])``). device : torch.device | None The device on which to perform computations or load tensors and models (default is None). If None, ``ARTIST`` will automatically select the most appropriate device (CUDA or CPU) based on availability and OS. Returns ------- torch.Tensor East components of the bitmap intersections. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. torch.Tensor Up components of the bitmap intersections. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. torch.Tensor Intersection distances. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. torch.Tensor Absolute intensities of the rays hitting the target planes. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_points_all_facets]``. .. py:function:: reflect(incident_ray_directions: torch.Tensor, reflection_surface_normals: torch.Tensor) -> torch.Tensor Reflect incoming rays given the normals of reflective surfaces. Parameters ---------- incident_ray_directions : torch.Tensor Direction of the incident ray as seen from the heliostats. Shape is ``[number_of_active_heliostats, 1, 4]``. reflection_surface_normals : torch.Tensor Normals of the reflective surfaces. Shape is ``[number_of_active_heliostats, number_of_combined_surface_normals_all_facets, 4]``. Returns ------- torch.Tensor Reflected rays. Shape is ``[number_of_active_heliostats, number_of_combined_surface_normals_all_facets, 4]``. .. py:class:: HeliostatRayTracer(scenario: artist.scenario.scenario.Scenario, heliostat_group: artist.field.heliostat_group.HeliostatGroup, blocking_active: bool = True, world_size: int = 1, rank: int = 0, batch_size: int = 100, random_seed: int = 7, bitmap_resolution: torch.Tensor = torch.tensor([indices.bitmap_resolution, indices.bitmap_resolution]), dni: float | None = None) Initialize the heliostat ray tracer. "Heliostat"-tracing is one kind of ray tracing applied in ``ARTIST``. For this kind of ray tracing, the rays are initialized on the heliostats. The rays originate in the discrete surface points. There they are multiplied, distorted, and scattered, and then they are sent to the aim points. Letting the rays originate on the heliostats, drastically reduces the number of rays that need to be traced. Parameters ---------- scenario : Scenario The scenario used to perform ray tracing. heliostat_group : HeliostatGroup The selected heliostat group containing active heliostats. blocking_active : bool Flag indicating whether blocking is activated (default is True). world_size : int The world size, i.e., the overall number of processes (default is 1). rank : int The rank, i.e., individual process ID (default is 0). batch_size : int The number of samples (heliostats) processed in parallel within a single rank (default is 100). random_seed : int The random seed used for generating the distortions (default is 7). bitmap_resolution : torch.Tensor The resolution of the bitmap in both directions. (default is torch.tensor([256,256])). Shape is ``[2]``. dni : float | None Direct normal irradiance in W/m^2 (default is None -> ray magnitude = 1.0). .. py:attribute:: scenario .. py:attribute:: heliostat_group .. py:attribute:: blocking_active :value: True .. py:attribute:: world_size :value: 1 .. py:attribute:: rank :value: 0 .. py:attribute:: batch_size :value: 100 .. py:attribute:: light_source .. py:attribute:: distortions_dataset .. py:attribute:: distortions_sampler .. py:attribute:: distortions_loader .. py:attribute:: bitmap_resolution .. py:method:: get_sampler_indices() -> torch.Tensor Get the indices assigned to the current rank by the distributed sampler. Returns ------- torch.Tensor Indices of the distortions dataset that are assigned to this rank. Shape is ``[number_of_samples_assigned_to_current_rank]``. .. py:method:: trace_rays(incident_ray_directions: torch.Tensor, active_heliostats_mask: torch.Tensor, target_area_indices: torch.Tensor, ray_extinction_factor: float = 0.0, mirror_reflectivity: float = 0.935, device: torch.device | None = None) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor] Perform heliostat ray tracing. Scatter the rays according to the distortions, calculate the intersections with the target planes, and sample the resulting bitmaps on the target areas. The bitmaps are generated separately for each active heliostat and are accessed individually. If blocking is activated in the ``HeliostatRayTracer``, rays that are blocked by other heliostats are filtered out. Parameters ---------- incident_ray_directions : torch.Tensor The direction of the incident rays as seen from the heliostats. Shape is ``[number_of_active_heliostats, 4]``. active_heliostats_mask : torch.Tensor A mask where 0 indicates a deactivated heliostat and 1 an activated one. An integer greater than 1 indicates that this heliostat is regarded multiple times. Shape is ``[number_of_heliostats]``. target_area_indices : torch.Tensor The indices of the target areas for each active heliostat. Shape is ``[number_of_active_heliostats]``. ray_extinction_factor : float Amount of global ray extinction, responsible for shading (default is 0.0 -> no extinction). mirror_reflectivity : float Fraction of incident ray intensity reflected by the mirror surface (default is 0.935). device : torch.device | None The device on which to perform computations or load tensors and models (default is None). If None, ``ARTIST`` will automatically select the most appropriate device (CUDA or CPU) based on availability and OS. Raises ------ ValueError If not all heliostats used for ray tracing have been aligned. Returns ------- torch.Tensor The resulting bitmaps per heliostat. Shape is ``[number_of_active_heliostats, bitmap_resolution_e, bitmap_resolution_u]``. torch.Tensor The fraction of rays hitting the target, neglecting blocking effects. Shape is ``[number_of_active_heliostats]``. torch.Tensor The fraction of rays not being blocked. Shape is ``[number_of_active_heliostats]``. torch.Tensor The fraction of rays actually hitting the target, taking into account blocking effects. Shape is ``[number_of_active_heliostats]``. .. py:method:: scatter_rays(distortion_u: torch.Tensor, distortion_e: torch.Tensor, original_ray_direction: torch.Tensor, device: torch.device | None = None) -> artist.scene.rays.Rays Scatter the reflected rays around the preferred ray directions for each heliostat. Parameters ---------- distortion_u : torch.Tensor The distortions in up direction (angles for scattering). Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_normals_all_facets]``. distortion_e : torch.Tensor The distortions in east direction (angles for scattering). Shape is ``[number_of_active_heliostats, number_of_rays, number_of_combined_surface_normals_all_facets]``. original_ray_direction : torch.Tensor The ray direction around which to scatter. Shape is ``[number_of_active_heliostats, number_of_combined_surface_normals_all_facets, 4]``. device : torch.device | None The device on which to perform computations or load tensors and models (default is None). If None, ``ARTIST`` will automatically select the most appropriate device (CUDA or CPU) based on availability and OS. Returns ------- Rays Scattered rays around the preferred reflection directions. .. py:method:: get_bitmaps_per_target(bitmaps_per_heliostat: torch.Tensor, target_area_indices: torch.Tensor, device: torch.device | None = None) -> torch.Tensor Transform bitmaps per heliostat to bitmaps per target area. Parameters ---------- bitmaps_per_heliostat : torch.Tensor Bitmaps per heliostat. Shape is ``[number_of_active_heliostats, bitmap_resolution_e, bitmap_resolution_u]``. target_area_indices : torch.Tensor The mapping from heliostat to target area. Shape is ``[number_of_active_heliostats]``. device : torch.device | None The device on which to perform computations or load tensors and models (default is None). If None, ``ARTIST`` will automatically select the most appropriate device (CUDA or CPU) based on availability and OS. Returns ------- torch.Tensor Bitmaps per target area. Shape is ``[number_of_target_areas, bitmap_resolution_e, bitmap_resolution_u]``. .. py:method:: bilinear_splatting(bitmap_intersections_e: torch.Tensor, bitmap_intersections_u: torch.Tensor, absolute_intensities: torch.Tensor, device: torch.device | None) -> torch.Tensor Distribute ray intensities onto bitmap pixels using bilinear splatting. Each ray intersection with the target area is treated as a continuously positioned value between four neighboring discrete pixels (east/west and up/down neighbors). The intensity is split among these four pixels proportionally to their proximity to the intersection point, yielding a differentiable approximation of the discrete binning operation. Parameters ---------- bitmap_intersections_e : torch.Tensor The east-component bitmap coordinates of ray intersections. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_surface_points]``. bitmap_intersections_u : torch.Tensor The up-component bitmap coordinates of ray intersections. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_surface_points]``. absolute_intensities : torch.Tensor The intensity of each ray at its intersection point. Shape is ``[number_of_active_heliostats, number_of_rays, number_of_surface_points]``. device : torch.device | None The device on which to perform computations or load tensors and models. If None, ``ARTIST`` will automatically select the most appropriate device (CUDA or CPU) based on availability and OS. Returns ------- torch.Tensor The flux density bitmaps, one per active heliostat. Shape is ``[number_of_active_heliostats, bitmap_resolution_u, bitmap_resolution_e]``. .. py:class:: DistortionsDataset(light_source: artist.scene.light_source.LightSource, number_of_points_per_heliostat: int, number_of_active_heliostats: int, random_seed: int = 7) Bases: :py:obj:`torch.utils.data.Dataset` Initialize the dataset. This class implements a custom dataset according to the ``torch`` interface. The content of this dataset are the distortions. The distortions are used in our version of "heliostat"-tracing to indicate how each incoming ray must be multiplied and scattered on the heliostat. According to ``torch``, this dataset must implement a function to return the length of the dataset and one function to retrieve an element through an index. Parameters ---------- light_source : LightSource The light source used to model the distortions. number_of_points_per_heliostat : int The number of points on the heliostats for which distortions are created. number_of_active_heliostats : int The number of active heliostats in the scenario. random_seed : int The random seed used for generating the distortions (default is 7). .. py:method:: __len__() -> int Calculate the length of the dataset, i.e., the number of items contained. Returns ------- int The length of the dataset. .. py:method:: __getitem__(idx: int) -> tuple[torch.Tensor, torch.Tensor] Select an item from the dataset. Parameters ---------- idx : int The index of the item to select. Returns ------- torch.Tensor The distortions in the up direction for the given index. torch.Tensor The distortions in the east direction for the given index. .. py:class:: RestrictedDistributedSampler(number_of_samples: int, number_of_active_heliostats: int, world_size: int = 1, rank: int = 0) Bases: :py:obj:`torch.utils.data.Sampler` Set up a custom distributed sampler to assign data to each rank or leave them idle. Parameters ---------- number_of_samples : int Length of the dataset or total number of samples. number_of_active_heliostats : int Number of active heliostats. world_size : int World size or total number of processes (default is 1). rank : int Rank of the current process (default is 0). .. py:attribute:: rank_indices :value: [] .. py:method:: __iter__() -> Iterator[int] Generate a sequence of indices for the current rank's portion of the dataset. Returns ------- Iterator[int] An iterator over indices for the current rank.