Skip to content

Commit 3f72333

Browse files
committed
examples
1 parent df17cf2 commit 3f72333

2 files changed

Lines changed: 108 additions & 76 deletions

File tree

examples/field_optimizations/generate_results.py

Lines changed: 36 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ def create_distributions(
8989
9090
Parameters
9191
----------
92+
resolution : torch.Tensor
93+
The bitmap resolution.
9294
measured_data_dir : pathlib.Path
9395
Path to the measured baseline data.
9496
results_path : pathlib.Path
@@ -623,6 +625,8 @@ def aim_point_plots(
623625
The aim point.
624626
dni : float
625627
Direct normal irradiance in W/m^2.
628+
bitmap_resolution : torch.Tensor
629+
The bitmap resolution.
626630
label : str
627631
Identifier fluxes.
628632
batch_size : int
@@ -638,7 +642,7 @@ def aim_point_plots(
638642
-------
639643
torch.Tensor
640644
Total flux distribution on the selected target.
641-
Shape is ``[bitmap_resolution_e, bitmap_resolution_u]``.
645+
Shape is ``[bitmap_resolution_u, bitmap_resolution_e]``.
642646
"""
643647
with torch.no_grad():
644648
device = get_device(device)
@@ -705,30 +709,6 @@ def aim_point_plots(
705709
target_area_indices=target_area_indices,
706710
device=device,
707711
)
708-
# ###########
709-
# import matplotlib.pyplot as plt
710-
711-
# aim_point_measured_bitmap = 256 - torch.tensor([112.9362, 111.4531])
712-
# for i in range(bitmaps_per_heliostat.shape[0]):
713-
# total_f = bitmaps_per_heliostat[i].sum()
714-
# if total_f > 0:
715-
# h, w = bitmaps_per_heliostat[i].shape
716-
# y_grid = torch.arange(h, device=device).unsqueeze(1).expand(h, w)
717-
# x_grid = torch.arange(w, device=device).unsqueeze(0).expand(h, w)
718-
# cy_f = (y_grid * bitmaps_per_heliostat[i]).sum() / total_f
719-
# cx_f = (x_grid * bitmaps_per_heliostat[i]).sum() / total_f
720-
# plt.imshow(bitmaps_per_heliostat[i].cpu().detach())
721-
# plt.scatter(
722-
# x=aim_point_measured_bitmap[0],
723-
# y=aim_point_measured_bitmap[1],
724-
# c="r",
725-
# s=30,
726-
# )
727-
# plt.scatter(cx_f.cpu().detach(), cy_f.cpu().detach(), c="g", s=30)
728-
# plt.scatter(x=w / 2, y=h / 2, c="black", s=30, marker="x")
729-
# plt.savefig(f"./bitmaps/aim_points/{label}_{i}")
730-
# plt.close()
731-
# ###########
732712
flux_distribution_on_target = ray_tracer.get_bitmaps_per_target(
733713
bitmaps_per_heliostat=bitmaps_per_heliostat,
734714
target_area_indices=target_area_indices,
@@ -801,7 +781,9 @@ def full_field_optimizations(
801781
device=device,
802782
) as ddp_setup:
803783
device = ddp_setup["device"]
804-
control_points_path = results_path.parent / "reconstructed_nurbs_control_points.pt"
784+
control_points_path = (
785+
results_path.parent / "reconstructed_nurbs_control_points.pt"
786+
)
805787

806788
assert data_mappings is not None, "data_mappings must be provided."
807789
assert surface_config is not None, "surface_config must be provided."
@@ -998,9 +980,9 @@ def full_field_optimizations(
998980
batch = heliostat_data[i : i + batch_size]
999981
data_surfaces.append(
1000982
{
1001-
config_dictionary.data_parser: data_mappings[
1002-
"surface_training"
1003-
][config_dictionary.data_parser],
983+
config_dictionary.data_parser: data_mappings["surface_training"][
984+
config_dictionary.data_parser
985+
],
1004986
config_dictionary.heliostat_data_mapping: batch,
1005987
}
1006988
)
@@ -1062,14 +1044,16 @@ def full_field_optimizations(
10621044
loss_history_surface.append(loss_history_surface_part)
10631045
if ddp_setup["is_distributed"]:
10641046
torch.distributed.barrier()
1065-
1047+
10661048
reconstructed_nurbs_control_points = [
10671049
heliostat_group.nurbs_control_points.detach()
10681050
for heliostat_group in scenario_surface.heliostat_field.heliostat_groups
10691051
]
10701052
torch.save(reconstructed_nurbs_control_points, control_points_path)
10711053
else:
1072-
reconstructed_nurbs_control_points = torch.load(control_points_path, weights_only=False)
1054+
reconstructed_nurbs_control_points = torch.load(
1055+
control_points_path, weights_only=False
1056+
)
10731057
for heliostat_group, control_points in zip(
10741058
scenario_surface.heliostat_field.heliostat_groups,
10751059
reconstructed_nurbs_control_points,
@@ -1352,7 +1336,7 @@ def create_heliostat_data_mappings(
13521336
The mappings from heliostat name to data files and data parsers for each task.
13531337
"""
13541338
with open(dataset_splits_file, "r") as f:
1355-
dataset_splits_file = json.load(f)
1339+
dataset_splits = json.load(f)
13561340

13571341
data_parser_surface = PaintCalibrationDataParser(
13581342
sample_limit=sample_limit_surfaces,
@@ -1372,7 +1356,9 @@ def create_heliostat_data_mappings(
13721356
| list[tuple[str, list[pathlib.Path], list[pathlib.Path]]],
13731357
] = {
13741358
config_dictionary.data_parser: data_parser_plots,
1375-
config_dictionary.heliostat_data_mapping: dataset_splits_file["kinematics_reconstruction"]["plot"],
1359+
config_dictionary.heliostat_data_mapping: dataset_splits[
1360+
"kinematics_reconstruction"
1361+
]["plot"],
13761362
}
13771363

13781364
data_kinematics_training: dict[
@@ -1381,7 +1367,9 @@ def create_heliostat_data_mappings(
13811367
| list[tuple[str, list[pathlib.Path], list[pathlib.Path]]],
13821368
] = {
13831369
config_dictionary.data_parser: data_parser_kinematics,
1384-
config_dictionary.heliostat_data_mapping: dataset_splits_file["kinematics_reconstruction"]["training"],
1370+
config_dictionary.heliostat_data_mapping: dataset_splits[
1371+
"kinematics_reconstruction"
1372+
]["training"],
13851373
}
13861374

13871375
data_kinematics_validation: dict[
@@ -1390,7 +1378,9 @@ def create_heliostat_data_mappings(
13901378
| list[tuple[str, list[pathlib.Path], list[pathlib.Path]]],
13911379
] = {
13921380
config_dictionary.data_parser: data_parser_kinematics,
1393-
config_dictionary.heliostat_data_mapping: dataset_splits_file["kinematics_reconstruction"]["validation"],
1381+
config_dictionary.heliostat_data_mapping: dataset_splits[
1382+
"kinematics_reconstruction"
1383+
]["validation"],
13941384
}
13951385

13961386
data_surface_plot: dict[
@@ -1399,7 +1389,9 @@ def create_heliostat_data_mappings(
13991389
| list[tuple[str, list[pathlib.Path], list[pathlib.Path]]],
14001390
] = {
14011391
config_dictionary.data_parser: data_parser_plots,
1402-
config_dictionary.heliostat_data_mapping: dataset_splits_file["surface_reconstruction"]["plot"],
1392+
config_dictionary.heliostat_data_mapping: dataset_splits[
1393+
"surface_reconstruction"
1394+
]["plot"],
14031395
}
14041396

14051397
data_surface_training: dict[
@@ -1408,15 +1400,19 @@ def create_heliostat_data_mappings(
14081400
| list[tuple[str, list[pathlib.Path], list[pathlib.Path]]],
14091401
] = {
14101402
config_dictionary.data_parser: data_parser_surface,
1411-
config_dictionary.heliostat_data_mapping: dataset_splits_file["surface_reconstruction"]["training"],
1403+
config_dictionary.heliostat_data_mapping: dataset_splits[
1404+
"surface_reconstruction"
1405+
]["training"],
14121406
}
14131407
data_surface_validation: dict[
14141408
str,
14151409
CalibrationDataParser
14161410
| list[tuple[str, list[pathlib.Path], list[pathlib.Path]]],
14171411
] = {
14181412
config_dictionary.data_parser: data_parser_surface,
1419-
config_dictionary.heliostat_data_mapping: dataset_splits_file["surface_reconstruction"]["validation"],
1413+
config_dictionary.heliostat_data_mapping: dataset_splits[
1414+
"surface_reconstruction"
1415+
]["validation"],
14201416
}
14211417

14221418
data_mappings = {
@@ -1608,7 +1604,7 @@ def main() -> None:
16081604
results_number = get_incremented_path_number(
16091605
base_path=results_dir / "results.pt"
16101606
)
1611-
results_path = results_dir / f"results_{0}.pt"
1607+
results_path = results_dir / f"results_{results_number}.pt"
16121608

16131609
measured_data_dir = pathlib.Path(args.measured_data_dir)
16141610
measured_data_dir.mkdir(parents=True, exist_ok=True)
@@ -1642,9 +1638,7 @@ def main() -> None:
16421638
f"The deflectometry scenario located at {scenario_path_deflectometry} could not be found! Please run the ``generate_scenarios.py`` to generate this scenario, or adjust the file path and try again."
16431639
)
16441640

1645-
dataset_splits = (
1646-
pathlib.Path(args.results_dir) / case / "dataset_splits.json"
1647-
)
1641+
dataset_splits = pathlib.Path(args.results_dir) / case / "dataset_splits.json"
16481642
if not dataset_splits.exists():
16491643
raise FileNotFoundError(
16501644
f"The viable heliostat list located at {dataset_splits} could not be not found! Please run the ``generate_viable_heliostats_list.py`` script to generate this list, or adjust the file path and try again."

examples/field_optimizations/generate_viable_heliostats_list.py

Lines changed: 72 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
11
import argparse
22
import json
33
import pathlib
4+
import random
45
import warnings
6+
from typing import Any
57

68
import pandas as pd
79
import yaml
8-
import paint.util.paint_mappings as paint_mappings
9-
10-
import random
11-
import pathlib
12-
from typing import Any
13-
14-
from artist.data_parser.paint_calibration_parser import PaintCalibrationDataParser
15-
from artist.util import config_dictionary
16-
17-
1810

1911

2012
def find_calibration_data(
@@ -76,8 +68,8 @@ def find_calibration_data(
7668
df = df[~df["HeliostatId"].isin(excluded_heliostats)]
7769

7870
if heliostat_names is not None:
79-
df = df[df["HeliostatId"].isin(heliostat_names)]
80-
71+
df = df[df["HeliostatId"].isin(heliostat_names)]
72+
8173
target_date = pd.to_datetime(date, utc=True)
8274
df["time_diff"] = (df["DateTime"] - target_date).abs()
8375

@@ -92,7 +84,6 @@ def find_calibration_data(
9284
valid_ids = []
9385

9486
for id_ in sub_df["Id"]:
95-
9687
calibration_properties_path = (
9788
data_dir
9889
/ heliostat_id
@@ -149,25 +140,44 @@ def find_calibration_data(
149140

150141

151142
def split_single_heliostat_all_tasks(
152-
heliostat: dict,
143+
heliostat_data: dict[str, Any],
153144
random_generator: random.Random,
154145
ratio: float,
155-
):
146+
) -> tuple[
147+
tuple[str, list[pathlib.Path], list[pathlib.Path], list[pathlib.Path]],
148+
tuple[str, list[pathlib.Path], list[pathlib.Path], list[pathlib.Path]],
149+
tuple[str, list[pathlib.Path], list[pathlib.Path], list[pathlib.Path]],
150+
]:
156151
"""
157-
Splits ONE heliostat consistently across:
158-
- kinematics reconstruction
159-
- surface reconstruction
160-
- (shared calibration alignment)
152+
Split calibration data for a single heliostat into training, validation and plot sets.
153+
154+
Parameters
155+
----------
156+
heliostat_data : dict[str, Any]
157+
Dictionary containing heliostat data with the following keys.
158+
random_generator : random.Random
159+
Random number generator used to shuffle the data indices.
160+
ratio : float
161+
Fraction of samples to include in the training set.
161162
162-
Uses ONE permutation → guarantees alignment across tasks.
163+
Returns
164+
-------
165+
tuple[str, list[pathlib.Path], list[pathlib.Path], list[pathlib.Path]]
166+
Data mapping for the training.
167+
tuple[str, list[pathlib.Path], list[pathlib.Path], list[pathlib.Path]]
168+
Data mapping for the validation.
169+
tuple[str, list[pathlib.Path], list[pathlib.Path], list[pathlib.Path]]
170+
Data mapping for the plots.
163171
"""
164-
name = heliostat["name"]
172+
name = heliostat_data["name"]
165173

166-
calibration_properties = heliostat["calibrations"]
167-
kinematics_fluxes = heliostat["kinematics_reconstruction_flux_images"]
168-
surface_fluxes = heliostat["surface_reconstruction_flux_images"]
174+
calibration_properties = heliostat_data["calibrations"]
175+
kinematics_fluxes = heliostat_data["kinematics_reconstruction_flux_images"]
176+
surface_fluxes = heliostat_data["surface_reconstruction_flux_images"]
169177

170-
assert len(calibration_properties) == len(kinematics_fluxes) == len(surface_fluxes), "Mismatch in amounts of calibration files!"
178+
assert (
179+
len(calibration_properties) == len(kinematics_fluxes) == len(surface_fluxes)
180+
), "Mismatch in amounts of calibration files!"
171181

172182
plot_samples = (
173183
name,
@@ -205,8 +215,26 @@ def create_heliostat_data_mappings(
205215
heliostats_for_plots: list[str],
206216
ratio: float,
207217
file_path: pathlib.Path,
208-
) -> dict[str, Any]:
218+
) -> None:
219+
"""
220+
Create train, validation, and plot data mappings for heliostat reconstruction tasks.
209221
222+
For each heliostat, calibration measurements are split into training and validation
223+
subsets using a consistent random permutation across calibration properties,
224+
kinematics flux images, and surface flux images. Additionally, a single fixed
225+
sample (the first measurement before shuffling) is selected for plotting.
226+
227+
Parameters
228+
----------
229+
viable_heliostats : list[dict[str, Any]]
230+
List of heliostat data dictionaries. Each dictionary must contain:
231+
heliostats_for_plots : list[str]
232+
List of heliostat names for which plot samples should be generated.
233+
ratio : float
234+
Fraction of samples used for training.
235+
file_path : pathlib.Path
236+
Output path where the resulting mappings will be saved as a JSON file.
237+
"""
210238
random_generator = random.Random()
211239

212240
training_kinematics_mappings = []
@@ -218,22 +246,32 @@ def create_heliostat_data_mappings(
218246

219247
for heliostat in viable_heliostats:
220248
training, validation, plot_sample = split_single_heliostat_all_tasks(
221-
heliostat=heliostat,
249+
heliostat_data=heliostat,
222250
random_generator=random_generator,
223251
ratio=ratio,
224252
)
225253

226254
name = heliostat["name"]
227255

228256
_, training_calibration, training_kinematics, training_surfaces = training
229-
_, validation_calibration, validation_kinematics, validation_surfaces = validation
257+
_, validation_calibration, validation_kinematics, validation_surfaces = (
258+
validation
259+
)
230260
_, plot_calibration, plot_kinematics, plot_surfaces = plot_sample
231261

232-
training_kinematics_mappings.append((name, training_calibration, training_kinematics))
233-
validation_kinematics_mappings.append((name, validation_calibration, validation_kinematics))
262+
training_kinematics_mappings.append(
263+
(name, training_calibration, training_kinematics)
264+
)
265+
validation_kinematics_mappings.append(
266+
(name, validation_calibration, validation_kinematics)
267+
)
234268

235-
training_surfaces_mappings.append((name, training_calibration, training_surfaces))
236-
validation_surfaces_mappings.append((name, validation_calibration, validation_surfaces))
269+
training_surfaces_mappings.append(
270+
(name, training_calibration, training_surfaces)
271+
)
272+
validation_surfaces_mappings.append(
273+
(name, validation_calibration, validation_surfaces)
274+
)
237275

238276
if name in heliostats_for_plots:
239277
kinematics_plot_mappings.append((name, plot_calibration, plot_kinematics))
@@ -467,5 +505,5 @@ def create_heliostat_data_mappings(
467505
viable_heliostats=serializable_data,
468506
heliostats_for_plots=args.heliostats_for_plots,
469507
ratio=0.9,
470-
file_path=pathlib.Path(args.results_dir) / case / "dataset_splits.json"
471-
)
508+
file_path=pathlib.Path(args.results_dir) / case / "dataset_splits.json",
509+
)

0 commit comments

Comments
 (0)