Skip to content

Commit d4a4b01

Browse files
authored
Maintenance/docs and tutorials (#188)
2 parents 1a49130 + 3a151d6 commit d4a4b01

53 files changed

Lines changed: 1489 additions & 1240 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<img src="https://raw.githubusercontent.com/ARTIST-Association/ARTIST/main/logos/artist_logo.svg" alt="logo" width="500"/>
33
</p>
44

5-
# AI-enhanced differentiable Ray Tracer for Irradiation Prediction in Solar Tower Digital Twins
5+
# AI-Enhanced Differentiable Ray Tracer for Irradiation Prediction in Solar Tower Digital Twins
66

77
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.17381222.svg)](https://doi.org/10.5281/zenodo.17381222)
88
![PyPI](https://img.shields.io/pypi/v/artist-csp)
@@ -20,37 +20,47 @@
2020

2121
## What ``ARTIST`` can do for you
2222

23-
The ``ARTIST`` package provides an implementation of a differentiable ray tracer using the `PyTorch` machine-learning
24-
framework in `Python`. Leveraging automatic differentiation and GPU computation, it facilitates the optimization of
25-
heliostats, towers, and camera parameters within a solar field by combining gradient-based optimization methods with
26-
smooth parametric descriptions of heliostats.
23+
The ``ARTIST`` package provides an implementation of a fully differentiable ray tracer using the ``PyTorch``
24+
machine-learning framework in ``Python``. Leveraging automatic differentiation and GPU computation, ``ARTIST`` enables
25+
gradient-based optimization within a differentiable solar tower power plant model using smooth parametric descriptions
26+
of heliostats. While the underlying framework is designed to support the optimization of arbitrary plant components,
27+
including towers and receivers, the current implementation focuses on data-driven heliostat surface reconstruction and
28+
alignment.
2729

2830
**Our contributions include:**
2931

30-
- **Efficient heliostat calibration:** We develop a parallelized geometric kinematics model that enables efficient
31-
calibration via either ray tracing-based or motor position data. This offers a flexible and robust approach to
32-
heliostat calibration.
32+
- **Efficient heliostat calibration:** ``ARTIST`` combines a differentiable geometric model of heliostat kinematics with
33+
parallelized computation to enable efficient heliostat reconstruction from receiver flux measurements. This results in
34+
a flexible and robust calibration approach.
3335

34-
- **Surface reconstruction and flux density prediction:** Leveraging learning Non-Uniform Rational B-Splines (NURBS),
35-
`ARTIST` reconstructs heliostat surfaces accurately using calibration images commonly available in solar thermal power plants.
36-
Thus, we can achieve sub-millimeter accuracy in mirror reconstruction from focal spot images, contributing to improved
37-
operational safety and efficiency. The reconstructed surfaces can be used for predicting unique heliostat flux densities
38-
with state-of-the-art accuracy. Check out [this paper](https://doi.org/10.21203/rs.3.rs-2554998/v1) for more details.
36+
- **Accurate surface reconstruction and flux density prediction:** Leveraging learning Non-Uniform Rational B-Splines (NURBS),
37+
`ARTIST` reconstructs heliostat surfaces accurately using calibration images commonly available in solar thermal power
38+
plants. Thus, we can achieve sub-millimeter accuracy in mirror reconstruction from focal spot images, contributing to
39+
improved operational safety and efficiency. The reconstructed surfaces can be used for predicting unique heliostat
40+
flux densities with state-of-the-art accuracy. Check out [this paper](https://doi.org/10.1038/s41467-024-51019-z) for
41+
more details:
3942

40-
- **Immediate deployment**: `ARTIST` enables deployment at the beginning of a solar thermal plant's operation,
41-
allowing for in situ calibration and subsequent improvements in energy efficiencies and cost reductions.
43+
> M. Pargmann, J. Ebert, M. Götz et al. Automatic heliostat learning for in situ concentrating solar power plant
44+
metrology with differentiable ray tracing. Nat Commun 15, 6997 (2024). https://doi.org/10.1038/s41467-024-51019-z
4245

43-
- **Optimized flux density:** ``ARTIST`` enables flux density optimization across an entire heliostat field by optimizing
44-
the motor positions of all heliostats to distribute the flux optimally over the receiver.
46+
- **Immediate deployment**: `ARTIST` can be deployed from the beginning of a solar thermal power plant's operation,
47+
enabling in situ calibration and subsequent improvements in energy efficiency and cost reduction..
48+
49+
- **Optimized flux density:** ``ARTIST`` enables flux density optimization across an entire heliostat field by adjusting
50+
heliostat motor positions to obtain an optimal flux distribution on the receiver.
4551

4652

4753
## Installation
48-
We heavily recommend installing the `ARTIST` package in a dedicated `Python3.10+` virtual environment. You can
49-
install ``ARTIST`` directly from the GitHub repository via:
54+
We recommend installing the `ARTIST` package in a dedicated `Python3.10+` virtual environment. You can install the
55+
latest stable release from [PyPI](https://pypi.org/project/artist-csp/):
56+
```bash
57+
pip install artist-csp
58+
```
59+
If you need the latest updates, you can also install ``ARTIST`` directly from the main branch via:
5060
```bash
51-
pip install artist
61+
pip install git+https://github.com/ARTIST-Association/ARTIST.git
5262
```
53-
Alternatively, you can install ``ARTIST`` locally. To achieve this, there are two steps you need to follow:
63+
To install `ARTIST` locally, there are two steps you need to follow:
5464
1. Clone the `ARTIST` repository:
5565
```bash
5666
git clone https://github.com/ARTIST-Association/ARTIST.git
@@ -66,24 +76,24 @@ The ``ARTIST`` repository is structured as shown below:
6676
.
6777
├── artist # Parent package
6878
│ ├── core # Core functionality of ARTIST, e.g. raytracing, optimizers etc.
69-
│ ├── data_loader # Deals with loading data into ARTIST from different sources.
70-
│ ├── field # Objects in the field, e.g. heliostats and target areas like receivers and calibration targets.
79+
│ ├── data_loader # Deals with loading data into ARTIST from different sources
80+
│ ├── field # Objects in the field, e.g. heliostats and target areas like receivers and calibration targets
7181
│ ├── scenario # Functionality to create and load scenarios in ARTIST.
72-
│ ├── scene # Light sources and factors influencing the surroundings.
82+
│ ├── scene # Light sources and factors influencing the surroundings
7383
│ └── util
7484
├── tests
7585
│ ├── data
76-
│ │ ├── field_data # Real measurements from the PAINT database and STRAL that can be used in ARTIST.
77-
│ │ ├── scenarios # Scenarios describing an environment that can be loaded by ARTIST.
86+
│ │ ├── field_data # Real measurements from the PAINT database and STRAL that can be used in ARTIST
87+
│ │ ├── scenarios # Scenarios describing an environment that can be loaded by ARTIST
7888
│ │ └── ...
7989
│ ├── core
8090
│ ├── data_loader
8191
│ └── ...
82-
└── tutorials # Tutorials to help you get started with ARTIST.
83-
├── data # Data accessed in the tutorials.
84-
│ ├── paint # Real measurements from the PAINT database.
85-
│ ├── scenarios # Scenarios describing an environment that can be loaded by ARTIST.
86-
│ └── stral Real # Measurements from STRAL.
92+
└── tutorials # Tutorials to help you get started with ARTIST
93+
├── data # Data accessed in the tutorials
94+
│ ├── paint # Real measurements from the PAINT database
95+
│ ├── scenarios # Scenarios describing an environment that can be loaded by ARTIST
96+
│ └── stral Real # Measurements from STRAL
8797
└── ...
8898
```
8999

artist/core/heliostat_ray_tracer.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ def trace_rays(
370370
self,
371371
incident_ray_directions: torch.Tensor,
372372
active_heliostats_mask: torch.Tensor,
373-
target_area_mask: torch.Tensor,
373+
target_area_indices: torch.Tensor,
374374
ray_extinction_factor: float = 0.0,
375375
device: torch.device | None = None,
376376
) -> torch.Tensor:
@@ -392,7 +392,7 @@ def trace_rays(
392392
A mask where 0 indicates a deactivated heliostat and 1 an activated one.
393393
An integer greater than 1 indicates that this heliostat is regarded multiple times.
394394
Tensor of shape [number_of_heliostats].
395-
target_area_mask : torch.Tensor
395+
target_area_indices : torch.Tensor
396396
The indices of the target areas for each active heliostat.
397397
Tensor of shape [number_of_active_heliostats].
398398
ray_extinction_factor : float
@@ -467,7 +467,9 @@ def trace_rays(
467467
active_heliostats_mask_batch
468468
],
469469
target_areas=self.scenario.target_areas,
470-
target_area_mask=target_area_mask[active_heliostats_mask_batch],
470+
target_area_indices=target_area_indices[
471+
active_heliostats_mask_batch
472+
],
471473
device=device,
472474
)
473475
)
@@ -534,7 +536,7 @@ def trace_rays(
534536
intersections=intersections,
535537
absolute_intensities=intensities,
536538
active_heliostats_mask=active_heliostats_mask_batch,
537-
target_area_mask=target_area_mask[active_heliostats_mask_batch],
539+
target_area_indices=target_area_indices[active_heliostats_mask_batch],
538540
device=device,
539541
)
540542

@@ -602,7 +604,7 @@ def sample_bitmaps(
602604
intersections: torch.Tensor,
603605
absolute_intensities: torch.Tensor,
604606
active_heliostats_mask: torch.Tensor,
605-
target_area_mask: torch.Tensor,
607+
target_area_indices: torch.Tensor,
606608
device: torch.device | None = None,
607609
) -> torch.Tensor:
608610
"""
@@ -621,8 +623,8 @@ def sample_bitmaps(
621623
active_heliostats_mask : torch.Tensor
622624
Used to map bitmaps per heliostat to correct index.
623625
Tensor of shape [number_of_heliostats].
624-
target_area_mask : torch.Tensor
625-
The indices of target areas on which each heliostat is raytraced.
626+
target_area_indices : torch.Tensor
627+
The indices of target areas on which each heliostat is ray-traced.
626628
Tensor of shape [number_of_active_heliostats].
627629
device : torch.device | None
628630
The device on which to perform computations or load tensors and models (default is None).
@@ -644,28 +646,28 @@ def sample_bitmaps(
644646

645647
# Extract widths and heights of target planes, along with corresponding centers in E and U direction.
646648
plane_widths = (
647-
self.scenario.target_areas.dimensions[target_area_mask][
649+
self.scenario.target_areas.dimensions[target_area_indices][
648650
:, index_mapping.target_area_width
649651
]
650652
.unsqueeze(index_mapping.number_rays_per_point)
651653
.unsqueeze(index_mapping.points_dimension)
652654
)
653655
plane_heights = (
654-
self.scenario.target_areas.dimensions[target_area_mask][
656+
self.scenario.target_areas.dimensions[target_area_indices][
655657
:, index_mapping.target_area_height
656658
]
657659
.unsqueeze(index_mapping.number_rays_per_point)
658660
.unsqueeze(index_mapping.points_dimension)
659661
)
660662
plane_centers_e = (
661-
self.scenario.target_areas.centers[target_area_mask][
663+
self.scenario.target_areas.centers[target_area_indices][
662664
:, index_mapping.target_area_center_e
663665
]
664666
.unsqueeze(index_mapping.number_rays_per_point)
665667
.unsqueeze(index_mapping.points_dimension)
666668
)
667669
plane_centers_u = (
668-
self.scenario.target_areas.centers[target_area_mask][
670+
self.scenario.target_areas.centers[target_area_indices][
669671
:, index_mapping.target_area_center_u
670672
]
671673
.unsqueeze(index_mapping.number_rays_per_point)
@@ -856,7 +858,7 @@ def sample_bitmaps(
856858
def get_bitmaps_per_target(
857859
self,
858860
bitmaps_per_heliostat: torch.Tensor,
859-
target_area_mask: torch.Tensor,
861+
target_area_indices: torch.Tensor,
860862
device: torch.device | None = None,
861863
) -> torch.Tensor:
862864
"""
@@ -867,7 +869,7 @@ def get_bitmaps_per_target(
867869
bitmaps_per_heliostat : torch.Tensor
868870
Bitmaps per heliostat.
869871
Tensor of shape [number_of_active_heliostats, bitmap_resolution_e, bitmap_resolution_u].
870-
target_area_mask : torch.Tensor
872+
target_area_indices : torch.Tensor
871873
The mapping from heliostat to target area.
872874
Tensor of shape [number_of_active_heliostats].
873875
device : torch.device | None
@@ -892,7 +894,7 @@ def get_bitmaps_per_target(
892894
device=device,
893895
)
894896
for index in range(self.scenario.target_areas.number_of_target_areas):
895-
mask = target_area_mask == index
897+
mask = target_area_indices == index
896898
if mask.any():
897899
group_bitmaps_per_target[index] = bitmaps_per_heliostat[mask].sum(
898900
dim=index_mapping.heliostat_dimension

artist/core/kinematics_reconstructor.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def _reconstruct_kinematics_parameters_with_raytracing(
202202
incident_ray_directions,
203203
_,
204204
active_heliostats_mask,
205-
target_area_mask,
205+
target_area_indices,
206206
) = parser.parse_data_for_reconstruction(
207207
heliostat_data_mapping=heliostat_mapping,
208208
heliostat_group=heliostat_group,
@@ -266,7 +266,9 @@ def _reconstruct_kinematics_parameters_with_raytracing(
266266

267267
# Align heliostats.
268268
heliostat_group.align_surfaces_with_incident_ray_directions(
269-
aim_points=self.scenario.target_areas.centers[target_area_mask],
269+
aim_points=self.scenario.target_areas.centers[
270+
target_area_indices
271+
],
270272
incident_ray_directions=incident_ray_directions,
271273
active_heliostats_mask=active_heliostats_mask,
272274
device=device,
@@ -291,7 +293,7 @@ def _reconstruct_kinematics_parameters_with_raytracing(
291293
flux_distributions = ray_tracer.trace_rays(
292294
incident_ray_directions=incident_ray_directions,
293295
active_heliostats_mask=active_heliostats_mask,
294-
target_area_mask=target_area_mask,
296+
target_area_indices=target_area_indices,
295297
device=device,
296298
)
297299

@@ -302,7 +304,7 @@ def _reconstruct_kinematics_parameters_with_raytracing(
302304
ground_truth=focal_spots_measured[
303305
sample_indices_for_local_rank
304306
],
305-
target_area_mask=target_area_mask[
307+
target_area_indices=target_area_indices[
306308
sample_indices_for_local_rank
307309
],
308310
reduction_dimensions=(index_mapping.focal_spots,),

artist/core/loss_functions.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ def __call__(
168168
Tensor of shape [number_of_samples, 4].
169169
\*\*kwargs : Any
170170
Keyword arguments.
171-
The ``reduction_dimensions``, ``target_area_mask`` and ``device`` are expected keyword arguments for the focal spot loss.
171+
The ``reduction_dimensions``, ``target_area_indices`` and ``device`` are expected keyword arguments for the focal spot loss.
172172
173173
Raises
174174
------
@@ -181,7 +181,7 @@ def __call__(
181181
The focal spot loss.
182182
Tensor of shape [number_of_samples].
183183
"""
184-
expected_kwargs = ["reduction_dimensions", "device", "target_area_mask"]
184+
expected_kwargs = ["reduction_dimensions", "device", "target_area_indices"]
185185
errors = []
186186
for key in expected_kwargs:
187187
if key not in kwargs:
@@ -194,15 +194,15 @@ def __call__(
194194

195195
device = get_device(device=kwargs["device"])
196196

197-
target_area_mask = kwargs["target_area_mask"]
197+
target_area_indices = kwargs["target_area_indices"]
198198

199199
focal_spot = utils.get_center_of_mass(
200200
bitmaps=prediction,
201-
target_centers=self.scenario.target_areas.centers[target_area_mask],
202-
target_widths=self.scenario.target_areas.dimensions[target_area_mask][
201+
target_centers=self.scenario.target_areas.centers[target_area_indices],
202+
target_widths=self.scenario.target_areas.dimensions[target_area_indices][
203203
:, index_mapping.target_area_width
204204
],
205-
target_heights=self.scenario.target_areas.dimensions[target_area_mask][
205+
target_heights=self.scenario.target_areas.dimensions[target_area_indices][
206206
:, index_mapping.target_area_height
207207
],
208208
device=device,
@@ -263,7 +263,7 @@ def __call__(
263263
Tensor of shape [number_of_samples, bitmap_resolution_e, bitmap_resolution_u].
264264
\*\*kwargs : Any
265265
Keyword arguments.
266-
The ``reduction_dimensions``, ``target_area_mask`` and optionally ``device`` are expected keyword arguments for the pixel loss.
266+
The ``reduction_dimensions``, ``target_area_indices`` and optionally ``device`` are expected keyword arguments for the pixel loss.
267267
268268
Raises
269269
------
@@ -276,7 +276,7 @@ def __call__(
276276
The summed MSE pixel loss reduced along the specified dimensions.
277277
Tensor of shape [number_of_samples].
278278
"""
279-
expected_kwargs = ["reduction_dimensions", "device", "target_area_mask"]
279+
expected_kwargs = ["reduction_dimensions", "device", "target_area_indices"]
280280
errors = []
281281
for key in expected_kwargs:
282282
if key not in kwargs:

0 commit comments

Comments
 (0)