ATLAS Offline Software
Loading...
Searching...
No Matches
StandaloneDataIO.h
Go to the documentation of this file.
1//
2// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3//
4// Dear emacs, this is -*- c++ -*-
5//
6
7#ifndef CALORECGPU_STANDALONEDATAIO_H
8#define CALORECGPU_STANDALONEDATAIO_H
9
10#include "Helpers.h"
11
12#include "CUDAFriendlyClasses.h"
13
14#include <fstream>
15#include <string>
16#include <map>
17#include <set>
18#include <iomanip>
19#include <sstream>
20
21#include <filesystem>
22
24{
25 enum class ErrorState
26 {
28 };
29
30 protected:
31
32 inline static void report_error(const std::filesystem::path & file, const std::string & kind, const bool really_report = false)
33 {
34 if (really_report)
35 {
36 std::cerr << "ERROR: when " << kind << " from '" << file << "'." << std::endl;
37 }
38 }
39
40 public:
41
43 {
44 friend struct StandaloneDataIO;
45
46 public:
47
48 inline static ErrorState read_geometry(const std::filesystem::path & file,
50 const bool report = false)
51 {
52 std::ifstream in(file.native(), std::ios_base::binary);
53 geo.binary_input(in);
54 if (in.fail())
55 {
56 report_error(file, "reading geometry", report);
58 }
59 in.close();
60 return ErrorState::OK;
61 }
62
63 inline static ErrorState read_noise(const std::filesystem::path & file,
65 const bool report = false)
66 {
67 std::ifstream in(file.native(), std::ios_base::binary);
68 noise.binary_input(in);
69 if (in.fail())
70 {
71 report_error(file, "reading noise", report);
73 }
74 in.close();
75 return ErrorState::OK;
76 }
77
78 inline static ErrorState write_geometry(std::filesystem::path file,
80 const bool report = false)
81 {
82 file.replace_extension(".geometry");
83 std::ofstream out(file, std::ios_base::binary);
84 geo.binary_output(out);
85 if (out.fail())
86 {
87 report_error(file, "writing geometry", report);
89 }
90 out.close();
91 return ErrorState::OK;
92 }
93
94 inline static ErrorState write_noise(std::filesystem::path file,
96 const bool report = false)
97 {
98 file.replace_extension(".noise");
99 std::ofstream out(file, std::ios_base::binary);
100 noise.binary_output(out);
101 if (out.fail())
102 {
103 report_error(file, "writing noise", report);
105 }
106 out.close();
107 return ErrorState::OK;
108 }
109 };
110
112 {
113 friend struct StandaloneDataIO;
114
115 public:
116 inline static ErrorState read_cluster_info(const std::filesystem::path & file,
118 const bool report = false)
119 {
120 clusters.allocate();
121
122 std::ifstream in(file.native(), std::ios_base::binary);
123
124 auto reader = [&](auto * ptr, const auto & size)
125 {
126 in.read(reinterpret_cast<char *>(ptr), sizeof(*ptr) * size);
127 };
128
129 reader(static_cast<CaloRecGPU::ClusterBaseInfo *>(clusters), 1);
130
131 if (in.fail() || clusters->number < 0 || clusters->number > CaloRecGPU::NMaxClusters)
132 {
133 report_error(file, "reading clusters", report);
135 }
136
137 if (clusters->has_basic_info())
138 {
139 reader(clusters->clusterEnergy, clusters->number);
140 reader(clusters->clusterEt, clusters->number);
141 reader(clusters->clusterEta, clusters->number);
142 reader(clusters->clusterPhi, clusters->number);
143 reader(clusters->seedCellIndex, clusters->number);
144 }
145
146 switch (clusters->state)
147 {
149 [[fallthrough]];
151 reader(clusters->cells.tags, CaloRecGPU::NCaloCells);
152 break;
154 [[fallthrough]];
156 [[fallthrough]];
158 [[fallthrough]];
160 reader(clusters->cellsPrefixSum, clusters->number + 1);
161 reader(clusters->cells.indices, clusters->number_cells);
162 reader(clusters->cellWeights, clusters->number_cells);
163 reader(clusters->clusterIndices, clusters->number_cells);
164 break;
165 default:
166 break;
167 }
168
169 if (clusters->has_moments())
170 {
171 clusters->for_all_moments([&](auto & arr)
172 {
173 unsigned long long base_size;
174 if constexpr (std::is_pointer_v<std::decay_t<decltype(*arr)>>)
175 {
176 base_size = sizeof(**arr) * sizeof(arr)/sizeof(*arr);
177 }
178 else
179 {
180 base_size = sizeof(*arr);
181 }
182 in.read(reinterpret_cast<char *>(arr), base_size * clusters->number);
183 });
184 }
185
186 if (in.fail())
187 {
188 report_error(file, "reading clusters", report);
190 }
191
192 in.close();
193
194 return ErrorState::OK;
195
196 }
197
198 //Let's assume we're dealing with a full cell collection,
199 //as that is going to be the most common case anyway.
200 inline static ErrorState read_cell_info(const std::filesystem::path & file,
202 const bool report = false)
203 {
204 std::ifstream in(file.native(), std::ios_base::binary);
205 cell_info.binary_input(in);
206 if (in.fail())
207 {
208 report_error(file, "reading cell info", report);
210 }
211 in.close();
212 return ErrorState::OK;
213 }
214
215 inline static ErrorState write_cluster_info(std::filesystem::path file,
217 const bool report = false)
218 {
219 file.replace_extension(".clusterinfo");
220 std::ofstream out(file, std::ios_base::binary);
221
222 auto writer = [&](const auto * ptr, const auto & size)
223 {
224 out.write(reinterpret_cast<const char *>(ptr), sizeof(*ptr) * size);
225 };
226
227
228 out.write(reinterpret_cast<const char *>(static_cast<const CaloRecGPU::ClusterBaseInfo *>(clusters)), sizeof(CaloRecGPU::ClusterBaseInfo));
229
230 if (clusters->has_basic_info())
231 {
232 writer(clusters->clusterEnergy, clusters->number);
233 writer(clusters->clusterEt, clusters->number);
234 writer(clusters->clusterEta, clusters->number);
235 writer(clusters->clusterPhi, clusters->number);
236 writer(clusters->seedCellIndex, clusters->number);
237 }
238
239 switch (clusters->state)
240 {
242 [[fallthrough]];
244 writer(clusters->cells.tags, CaloRecGPU::NCaloCells);
245 break;
247 [[fallthrough]];
249 [[fallthrough]];
251 [[fallthrough]];
253 writer(clusters->cellsPrefixSum, clusters->number + 1);
254 writer(clusters->cells.indices, clusters->number_cells);
255 writer(clusters->cellWeights, clusters->number_cells);
256 writer(clusters->clusterIndices, clusters->number_cells);
257 break;
258 default:
259 break;
260 }
261
262 if (clusters->has_moments())
263 {
264 clusters->for_all_moments([&](const auto & arr)
265 {
266 unsigned long long base_size;
267 if constexpr (std::is_pointer_v<std::decay_t<decltype(*arr)>>)
268 {
269 base_size = sizeof(**arr) * sizeof(arr)/sizeof(*arr);
270 }
271 else
272 {
273 base_size = sizeof(*arr);
274 }
275 out.write(reinterpret_cast<const char *>(arr), base_size * clusters->number);
276 });
277 }
278
279 if (out.fail())
280 {
281 report_error(file, "writing clusters", report);
283 }
284 out.close();
285 return ErrorState::OK;
286 }
287
288 //Let's assume we're dealing with a full cell collection,
289 //as that is going to be the most common case anyway.
290 inline static ErrorState write_cell_info(std::filesystem::path file,
292 const bool report = false)
293 {
294 file.replace_extension(".cellinfo");
295 std::ofstream out(file, std::ios_base::binary);
296 cell_info.binary_output(out);
297 if (out.fail())
298 {
299 report_error(file, "writing cell info", report);
301 }
302 out.close();
303 return ErrorState::OK;
304 }
305
306 };
307
308 protected:
309
310 inline static bool create_or_check_folder(const std::filesystem::path & folder, const bool output_errors = true)
311 {
312 if (!std::filesystem::exists(folder))
313 {
314 if (!std::filesystem::create_directory(folder))
315 {
316 if (output_errors)
317 {
318 std::cout << "ERROR: folder '" << folder << "' could not be created." << std::endl;
319 }
320 return false;
321 }
322 }
323 else if (!std::filesystem::is_directory(folder))
324 {
325 if (output_errors)
326 {
327 std::cout << "ERROR: folder '" << folder << "' is not a valid folder." << std::endl;
328 }
329 return false;
330 }
331 return true;
332 }
333
334 public:
335
336 inline static ErrorState prepare_folder_for_output(const std::filesystem::path & folder, const bool output_errors = true)
337 {
338 if (!create_or_check_folder(folder, output_errors))
339 {
341 }
342 return ErrorState::OK;
343 }
344
345 inline static std::string build_filename( const std::string & prefix,
346 const std::string & text,
347 const std::string & suffix,
348 const std::string & ext )
349 {
350 return prefix + (prefix.size() > 0 ? "_" : "") + text +
351 (suffix.size() > 0 ? "_" : "") + suffix + "." + ext;
352 }
353
354 inline static std::string build_filename( const std::string & prefix,
355 const size_t event_number,
356 const std::string & suffix,
357 const std::string & ext,
358 const unsigned int num_width = 9 )
359 {
360 std::ostringstream event_ID_format;
361 event_ID_format << std::setfill('0') << std::setw(num_width) << event_number;
362 const std::string event_ID = event_ID_format.str();
363 return build_filename(prefix, event_ID, suffix, ext);
364 }
365
366
367 inline static ErrorState save_constants_to_folder(const std::filesystem::path & folder,
370 const std::string & prefix = "",
371 const std::string & suffix = "",
372 const bool output_errors = true)
373 {
374 if (!create_or_check_folder(folder, output_errors))
375 {
377 }
378
379 auto filename = [&] (const std::string & text, const std::string & ext)
380 {
381 return folder / build_filename(prefix, text, suffix, ext);
382 };
383
384 if (ConstantInformation::write_geometry(filename("geometry", "geo"), geo) != ErrorState::OK)
385 {
387 }
388 if (ConstantInformation::write_noise(filename("noise", "noise"), noise) != ErrorState::OK)
389 {
391 }
392 return ErrorState::OK;
393 }
394
395 inline static ErrorState save_event_to_folder(const size_t event_number,
396 const std::filesystem::path & folder,
399 const std::string & prefix = "",
400 const std::string & suffix = "",
401 const unsigned int num_width = 9,
402 const bool output_errors = true)
403 {
404 if (!create_or_check_folder(folder, output_errors))
405 {
407 }
408
409 std::ostringstream event_ID_format;
410 event_ID_format << std::setfill('0') << std::setw(num_width) << event_number;
411 const std::string event_ID = event_ID_format.str();
412
413 auto filename = [&] (const std::string & ext)
414 {
415 return folder / build_filename(prefix, event_ID, suffix, ext);
416 };
417
418 if (EventInformation::write_cell_info(filename("cellinfo"), cell_info) != ErrorState::OK)
419 {
421 }
422 if (EventInformation::write_cluster_info(filename("clusterinfo"), clusters) != ErrorState::OK)
423 {
425 }
426 return ErrorState::OK;
427 }
428
429 inline static ErrorState save_cell_info_to_folder(const size_t event_number,
430 const std::filesystem::path & folder,
432 const std::string & prefix = "",
433 const std::string & suffix = "",
434 const unsigned int num_width = 9,
435 const bool output_errors = true)
436 {
437 if (!create_or_check_folder(folder, output_errors))
438 {
440 }
441
442 std::ostringstream event_ID_format;
443 event_ID_format << std::setfill('0') << std::setw(num_width) << event_number;
444 const std::string event_ID = event_ID_format.str();
445
446 auto filename = [&] (const std::string & ext)
447 {
448 return folder / build_filename(prefix, event_ID, suffix, ext);
449 };
450
451 if (EventInformation::write_cell_info(filename("cellinfo"), cell_info) != ErrorState::OK)
452 {
454 }
455 return ErrorState::OK;
456 }
457
458 inline static ErrorState save_clusters_to_folder(const size_t event_number,
459 const std::filesystem::path & folder,
461 const std::string & prefix = "",
462 const std::string & suffix = "",
463 const unsigned int num_width = 9,
464 const bool output_errors = true)
465 {
466 if (!create_or_check_folder(folder, output_errors))
467 {
469 }
470
471 std::ostringstream event_ID_format;
472 event_ID_format << std::setfill('0') << std::setw(num_width) << event_number;
473 const std::string event_ID = event_ID_format.str();
474
475 auto filename = [&] (const std::string & ext)
476 {
477 return folder / build_filename(prefix, event_ID, suffix, ext);
478 };
479
480 if (EventInformation::write_cluster_info(filename("clusters"), clusters) != ErrorState::OK)
481 {
483 }
484 return ErrorState::OK;
485 }
486
488 {
489 std::map<std::string, CaloRecGPU::Helpers::CPU_object<CaloRecGPU::GeometryArr>> geometry;
490 std::map<std::string, CaloRecGPU::Helpers::CPU_object<CaloRecGPU::CellNoiseArr>> noise;
491 std::map<std::string, CaloRecGPU::Helpers::CPU_object<CaloRecGPU::ClusterInfoArr>> cluster_info;
492 std::map<std::string, CaloRecGPU::Helpers::CPU_object<CaloRecGPU::CellInfoArr>> cell_info;
493 };
494
501 {
502 bool load_cluster_info = false,
505 load_noise = false;
506
507 static constexpr FolderLoadOptions None()
508 {
510 return ret;
511 //By design, all options are initialized as false...
512 }
513 static constexpr FolderLoadOptions All()
514 {
515 FolderLoadOptions ret{true, true, true, true};
516 return ret;
517 }
518 };
519
520
524 template <class F>
525 inline static FolderLoad load_folder_filter(F && filter_function,
526 //Receives a std::string (the filename),
527 //returns `true` if the file should be filtered out.
528 const std::filesystem::path & folder,
529 int max_events = -1,
531 const bool output_messages = true)
532 {
533 FolderLoad ret;
534 if (!std::filesystem::is_directory(folder))
535 {
536 if (output_messages)
537 {
538 std::cout << "ERROR: '" << folder << "' is not a valid folder." << std::endl;
539 }
540 return ret;
541 }
542 std::set<std::string> read_one_part_of_v1_cells;
543 int event_count = 0;
544 for (const std::filesystem::path & file : std::filesystem::directory_iterator(folder))
545 {
546 if ( max_events > 0 && event_count >= max_events &&
547 ret.geometry.size() > 0 && ret.noise.size() > 0 )
548 {
549 break;
550 }
551
552 const bool can_load_events = (max_events < 0) || (event_count < max_events);
553 const std::string filename = file.stem().native();
554
555 if (filter_function(filename))
556 {
557 continue;
558 }
559
560 auto check_error = [&](const ErrorState & es, const std::string & str)
561 {
562 if (es == ErrorState::OK)
563 {
564 return false;
565 }
566 if (output_messages)
567 {
568 std::cout << "ERROR: '" << file << "' is not a valid " << str << " file (" << (int) es << ")." << std::endl;
569 }
570 return true;
571 };
572
573 auto output_loading_message = [&](const std::string & str)
574 {
575 if (output_messages)
576 {
577 std::cout << "Loaded " << str << " from '" << file << "'." << std::endl;
578 }
579 };
580
581 if (file.extension() == ".geometry")
582 {
583 if (!flo.load_geometry)
584 {
585 continue;
586 }
588 if (check_error(ConstantInformation::read_geometry(file, tempgeo), "geometry"))
589 {
590 continue;
591 }
592 ret.geometry[filename] = std::move(tempgeo);
593 output_loading_message("geometry");
594 }
595 else if (file.extension() == ".cellinfo")
596 {
597 if (!flo.load_cell_info || !can_load_events)
598 {
599 continue;
600 }
602 if (check_error(EventInformation::read_cell_info(file, tempcellinfo), "cell info"))
603 {
604 continue;
605 }
606 ret.cell_info[filename] = std::move(tempcellinfo);
607 output_loading_message("cell info");
608 if (ret.cluster_info.count(filename) > 0 || !flo.load_cluster_info)
609 {
610 ++event_count;
611 }
612 }
613 else if (file.extension() == ".clusterinfo")
614 {
615 if (!flo.load_cluster_info || !can_load_events)
616 {
617 continue;
618 }
620 if (check_error(EventInformation::read_cluster_info(file, tempclu), "cluster info"))
621 {
622 continue;
623 }
624 ret.cluster_info[filename] = std::move(tempclu);
625 output_loading_message("cluster info");
626 if (ret.cell_info.count(filename) > 0 || !flo.load_cell_info)
627 {
628 ++event_count;
629 }
630 }
631 else if (file.extension() == ".noise")
632 {
633 if (!flo.load_noise)
634 {
635 continue;
636 }
638 if (check_error(ConstantInformation::read_noise(file, tempnois), "noise"))
639 {
640 continue;
641 }
642 ret.noise[filename] = std::move(tempnois);
643 output_loading_message("noise");
644 }
645 }
646 return ret;
647 }
648
649 inline static FolderLoad load_folder(const std::filesystem::path & folder,
650 int max_events = -1,
652 const bool output_messages = true)
653 {
654 return load_folder_filter([&](const std::string &)
655 {
656 return false;
657 },
658 folder, max_events, flo, output_messages);
659 }
660
661};
662
663#endif //CALORECGPU_STANDALONEDATAIO_H
#define F(x, y, z)
Definition MD5.cxx:112
SimpleHolder< T, MemoryContext::CPU, true > CPU_object
Holds an object of type T in CPU memory.
constexpr int NCaloCells
constexpr int NMaxClusters
Contains the fundamental information that allows interacting with ClusterInfoArr so that it is easier...
static ErrorState write_noise(std::filesystem::path file, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellNoiseArr > &noise, const bool report=false)
static ErrorState write_geometry(std::filesystem::path file, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::GeometryArr > &geo, const bool report=false)
static ErrorState read_noise(const std::filesystem::path &file, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellNoiseArr > &noise, const bool report=false)
static ErrorState read_geometry(const std::filesystem::path &file, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::GeometryArr > &geo, const bool report=false)
static ErrorState write_cell_info(std::filesystem::path file, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellInfoArr > &cell_info, const bool report=false)
static ErrorState read_cluster_info(const std::filesystem::path &file, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::ClusterInfoArr > &clusters, const bool report=false)
static ErrorState read_cell_info(const std::filesystem::path &file, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellInfoArr > &cell_info, const bool report=false)
static ErrorState write_cluster_info(std::filesystem::path file, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::ClusterInfoArr > &clusters, const bool report=false)
The members of this structure should all be initialised by default to false.
static constexpr FolderLoadOptions None()
static constexpr FolderLoadOptions All()
std::map< std::string, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellInfoArr > > cell_info
std::map< std::string, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::ClusterInfoArr > > cluster_info
std::map< std::string, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::GeometryArr > > geometry
std::map< std::string, CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellNoiseArr > > noise
static std::string build_filename(const std::string &prefix, const size_t event_number, const std::string &suffix, const std::string &ext, const unsigned int num_width=9)
static FolderLoad load_folder(const std::filesystem::path &folder, int max_events=-1, const FolderLoadOptions &flo=FolderLoadOptions::None(), const bool output_messages=true)
static bool create_or_check_folder(const std::filesystem::path &folder, const bool output_errors=true)
static std::string build_filename(const std::string &prefix, const std::string &text, const std::string &suffix, const std::string &ext)
static ErrorState save_constants_to_folder(const std::filesystem::path &folder, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::GeometryArr > &geo, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellNoiseArr > &noise, const std::string &prefix="", const std::string &suffix="", const bool output_errors=true)
static ErrorState prepare_folder_for_output(const std::filesystem::path &folder, const bool output_errors=true)
static void report_error(const std::filesystem::path &file, const std::string &kind, const bool really_report=false)
static ErrorState save_event_to_folder(const size_t event_number, const std::filesystem::path &folder, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellInfoArr > &cell_info, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::ClusterInfoArr > &clusters, const std::string &prefix="", const std::string &suffix="", const unsigned int num_width=9, const bool output_errors=true)
static FolderLoad load_folder_filter(F &&filter_function, const std::filesystem::path &folder, int max_events=-1, const FolderLoadOptions &flo=FolderLoadOptions::None(), const bool output_messages=true)
static ErrorState save_cell_info_to_folder(const size_t event_number, const std::filesystem::path &folder, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::CellInfoArr > &cell_info, const std::string &prefix="", const std::string &suffix="", const unsigned int num_width=9, const bool output_errors=true)
static ErrorState save_clusters_to_folder(const size_t event_number, const std::filesystem::path &folder, const CaloRecGPU::Helpers::CPU_object< CaloRecGPU::ClusterInfoArr > &clusters, const std::string &prefix="", const std::string &suffix="", const unsigned int num_width=9, const bool output_errors=true)
TFile * file