51 std::shared_ptr<HighFive::File> file_;
52 std::string group_name_;
53 std::optional<HighFive::Group> group_;
54 std::optional<HighFive::DataSet> readouts_, cues_, weights_, normalizations_;
55 std::vector<uint32_t> cue_values_;
56 std::vector<uint64_t> normalization_values_;
57 std::optional<DetectorType> detector_{std::nullopt};
58 std::optional<ReadoutType> sendable_{std::nullopt};
59 std::optional<std::string> description_{std::nullopt};
60 std::optional<std::string> efu_address_{std::nullopt};
61 std::optional<uint16_t> efu_port_{std::nullopt};
63 [[nodiscard]] std::pair<size_t, size_t> point_bounds(
const size_t point)
const {
64 if (point >= cue_values_.size()) {
65 throw std::runtime_error(
"Out of bounds point requested");
67 const auto end =
static_cast<size_t>(cue_values_.at(point));
68 const auto start = point > 0 ?
static_cast<size_t>(cue_values_.at(point - 1)) : 0u;
69 if (end < start || end > size()) {
70 throw std::runtime_error(
"Invalid cue values in collector group");
76 RL_API
explicit Reader(std::shared_ptr<HighFive::File> file,
const std::string & collector_name): file_{std::move(file)}, group_name_{collector_name} {
78 throw std::runtime_error(
"Reader requires an open file");
80 if (!file_->exist(group_name_)) {
82 s <<
"Collector group \"" << group_name_ <<
"\" not found in file";
83 throw std::runtime_error(s.str());
85 group_ = file_->getGroup(group_name_);
86 if (
const auto result = validate_collector_group(group_.value()); !result.empty()) {
88 s <<
"Collector group \"" << group_name_ <<
"\" is invalid: " << result;
89 throw std::runtime_error(s.str());
92 readouts_ = group_->getDataSet(CollectorSink::readout_dataset_name());
93 cues_ = group_->getDataSet(CollectorSink::cue_dataset_name());
94 weights_ = group_->getDataSet(CollectorSink::weight_dataset_name());
95 normalizations_ = group_->getDataSet(CollectorSink::normalization_dataset_name());
104 if (readouts_->hasAttribute(CollectorSink::parameter_description_attribute_name())) {
105 description_ = readouts_->getAttribute(CollectorSink::parameter_description_attribute_name()).read<std::string>();
109 const auto stored = readouts_->getDataType();
110 for (
const auto rt : {ReadoutType::CAEN, ReadoutType::TTLMonitor, ReadoutType::CDT, ReadoutType::VMM3,
111 ReadoutType::BM0, ReadoutType::BM2, ReadoutType::BMI}) {
112 if (stored == hdf_compound_type(rt)) {
118 if (group_->hasAttribute(CollectorSink::efu_address_attribute_name())) {
119 efu_address_ = group_->getAttribute(CollectorSink::efu_address_attribute_name()).read<std::string>();
121 if (group_->hasAttribute(CollectorSink::efu_port_attribute_name())) {
122 const auto port = group_->getAttribute(CollectorSink::efu_port_attribute_name()).read<int>();
123 if (port > 0 && port <= 65535) {
124 efu_port_ =
static_cast<uint16_t
>(port);
128 cues_->read(cue_values_);
129 if (cue_values_.empty()) {
130 throw std::runtime_error(
"Collector cues dataset is empty");
132 if (!std::ranges::is_sorted(cue_values_)) {
133 throw std::runtime_error(
"Collector cues dataset must be monotonically non-decreasing");
135 if (cue_values_.back() != size()) {
136 throw std::runtime_error(
"Collector cues end value does not match readout dataset size");
138 normalizations_->read(normalization_values_);
139 if (weights_->getDimensions().back() != cue_values_.size() || normalization_values_.size() != cue_values_.size()) {
140 throw std::runtime_error(
"Collector point datasets (cues, weights, normalizations) have mismatched dimensions");
146 RL_API [[nodiscard]]
const std::string & collector_name()
const {
return group_name_; }
148 RL_API [[nodiscard]] DetectorType
detector_type()
const {
return detector_.value_or(DetectorType::Reserved); }
151 if (sendable_.has_value()) {
return sendable_.value(); }
152 throw std::runtime_error(
"Collector group has no readout type: it stores user-described records");
158 RL_API [[nodiscard]]
const std::optional<std::string> &
type_description()
const {
return description_; }
159 RL_API [[nodiscard]]
size_t size()
const {
return readouts_->getDimensions().back(); }
160 RL_API [[nodiscard]]
size_t points()
const {
return cue_values_.size(); }
161 RL_API [[nodiscard]] HighFive::DataType datatype()
const {
return readouts_->getDataType(); }
162 RL_API [[nodiscard]]
size_t record_size()
const {
return readouts_->getDataType().getSize(); }
167 if (point >= cue_values_.size()) {
168 throw std::runtime_error(
"Out of bounds point requested");
170 return weights_->select({point}, {1}).read<double>();
176 if (point >= normalization_values_.size()) {
177 throw std::runtime_error(
"Out of bounds point requested");
179 return normalization_values_[point];
184 RL_API [[nodiscard]] std::vector<uint8_t>
get_raw(
const size_t index,
const size_t count)
const {
185 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds record requested"); }
186 const auto datatype = readouts_->getDataType();
187 std::vector<uint8_t> buffer(count * datatype.getSize());
188 readouts_->select({index}, {count}).read_raw(buffer.data(), datatype);
193 RL_API [[nodiscard]] std::optional<std::string>
efu_address()
const {
return efu_address_; }
195 RL_API [[nodiscard]] std::optional<uint16_t>
efu_port()
const {
return efu_port_; }
197 RL_API [[nodiscard]]
size_t point_offset(
const size_t point)
const {
198 return point_bounds(point).first;
200 RL_API [[nodiscard]]
size_t point_size(
const size_t point)
const {
201 const auto [start, end] = point_bounds(point);
205 RL_API
auto get_CAEN(
const size_t index,
const size_t count)
const {
206 if (sendable_ != ReadoutType::CAEN){
throw std::runtime_error(
"Non CAEN readout type"); }
207 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds event requested");}
208 std::vector<CAEN_event> event(count);
209 const auto datatype = readouts_->getDataType();
210 readouts_->select({index}, {count}).read_raw(event.data(), datatype);
213 RL_API
auto get_TTLMonitor(
const size_t index,
const size_t count)
const {
214 if (sendable_ != ReadoutType::TTLMonitor){
throw std::runtime_error(
"Non TTLMonitor readout type"); }
215 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds event requested");}
216 std::vector<TTLMonitor_event> event(count);
217 const auto datatype = readouts_->getDataType();
218 readouts_->select({index}, {count}).read_raw(event.data(), datatype);
221 RL_API
auto get_VMM3(
const size_t index,
const size_t count)
const{
222 if (sendable_ != ReadoutType::VMM3) {
throw std::runtime_error(
"Non VMM3 readout type"); }
223 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds event requested");}
224 std::vector<VMM3_event> event(count);
225 const auto datatype = readouts_->getDataType();
226 readouts_->select({index}, {count}).read_raw(event.data(), datatype);
229 RL_API
auto get_CDT(
const size_t index,
const size_t count)
const{
230 if (sendable_ != ReadoutType::CDT) {
throw std::runtime_error(
"Non CDT readout type"); }
231 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds event requested");}
232 std::vector<CDT_event> event(count);
233 const auto datatype = readouts_->getDataType();
234 readouts_->select({index}, {count}).read_raw(event.data(), datatype);
237 RL_API
auto get_BM0(
const size_t index,
const size_t count)
const{
238 if (sendable_ != ReadoutType::BM0) {
throw std::runtime_error(
"Non BM0 readout type"); }
239 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds event requested");}
240 std::vector<BM0_event> event(count);
241 const auto datatype = readouts_->getDataType();
242 readouts_->select({index}, {count}).read_raw(event.data(), datatype);
245 RL_API
auto get_BM2(
const size_t index,
const size_t count)
const{
246 if (sendable_ != ReadoutType::BM2) {
throw std::runtime_error(
"Non BM2 readout type"); }
247 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds event requested");}
248 std::vector<BM2_event> event(count);
249 const auto datatype = readouts_->getDataType();
250 readouts_->select({index}, {count}).read_raw(event.data(), datatype);
253 RL_API
auto get_BMI(
const size_t index,
const size_t count)
const {
254 if (sendable_ != ReadoutType::BMI) {
throw std::runtime_error(
"Non BMI readout type"); }
255 if (index >= size() || index + count > size()) {
throw std::runtime_error(
"Out of bounds event requested");}
256 std::vector<BMI_event> event(count);
257 const auto datatype = readouts_->getDataType();
258 readouts_->select({index}, {count}).read_raw(event.data(), datatype);
262 RL_API
auto get_point_CAEN(
const size_t point)
const {
263 const auto [start, end] = point_bounds(point);
264 return get_CAEN(start, end - start);
266 RL_API
auto get_point_TTLMonitor(
const size_t point)
const {
267 const auto [start, end] = point_bounds(point);
268 return get_TTLMonitor(start, end - start);
270 RL_API
auto get_point_VMM3(
const size_t point)
const {
271 const auto [start, end] = point_bounds(point);
272 return get_VMM3(start, end - start);
274 RL_API
auto get_point_CDT(
const size_t point)
const {
275 const auto [start, end] = point_bounds(point);
276 return get_CDT(start, end - start);
278 RL_API
auto get_point_BM0(
const size_t point)
const {
279 const auto [start, end] = point_bounds(point);
280 return get_BM0(start, end - start);
282 RL_API
auto get_point_BM2(
const size_t point)
const {
283 const auto [start, end] = point_bounds(point);
284 return get_BM2(start, end - start);
286 RL_API
auto get_point_BMI(
const size_t point)
const {
287 const auto [start, end] = point_bounds(point);
288 return get_BMI(start, end - start);
298 std::string filename_;
299 std::shared_ptr<HighFive::File> file_;
300 std::optional<HighFive::Group> parameters_;
301 std::vector<Reader> readers_;
302 std::vector<std::string> parameter_names_;
303 std::vector<ParameterDatasetView> parameter_views_;
306 static bool is_parameter_group(
const HighFive::Group & group) {
307 return group.hasAttribute(CollectorSink::type_attribute())
308 && group.getAttribute(CollectorSink::type_attribute()).read<std::string>() == CollectorSink::parameter_group_type();
311 static bool is_collector_group(
const HighFive::Group & group) {
312 return group.hasAttribute(CollectorSink::type_attribute())
313 && group.getAttribute(CollectorSink::type_attribute()).read<std::string>() == CollectorSink::collector_group_type();
317 RL_API
explicit ReaderSource(
const std::string& filename): filename_{filename} {
319 file_ = std::make_shared<HighFive::File>(filename, HighFive::File::ReadOnly);
320 }
catch (HighFive::Exception & ex) {
322 s <<
"Error opening file " << filename <<
":\n" << ex.what();
323 throw std::runtime_error(s.str());
327 if (file_->hasAttribute(CollectorSink::program_attribute_name())) {
328 file_->getAttribute(CollectorSink::program_attribute_name()).read(program);
330 if (program != CollectorSink::program_attribute_value()) {
331 throw std::runtime_error(
"The provided HDF file was not produced using libreadout Collector output");
333 if (!file_->hasAttribute(CollectorSink::version_attribute_name()) || !file_->hasAttribute(CollectorSink::revision_attribute_name())) {
334 throw std::runtime_error(
"Collector file is missing required version attributes");
337 const auto version = file_->getAttribute(CollectorSink::version_attribute_name()).read<std::string>();
338 const auto this_version = std::string(
reinterpret_cast<const char *
>(libreadout::version::version_number));
339 if (version != this_version){
340 std::cout <<
"The file was produced using libreadout " << version;
341 std::cout <<
" not current " << this_version << std::endl;
344 const auto root = file_->getGroup(
"/");
345 std::vector<std::string> collector_names;
346 for (
size_t i=0; i<root.getNumberObjects(); ++i) {
347 const auto name = root.getObjectName(i);
348 if (root.getObjectType(name) != HighFive::ObjectType::Group) {
351 const auto group = root.getGroup(name);
352 if (name == CollectorSink::parameter_group_name() || is_parameter_group(group)) {
354 }
else if (is_collector_group(group)) {
355 collector_names.push_back(name);
359 if (collector_names.empty()) {
360 throw std::runtime_error(
"Collector file has no collector groups. Legacy flat readout files are not supported.");
362 std::ranges::sort(collector_names);
363 readers_.reserve(collector_names.size());
364 for (
const auto & name : collector_names) {
365 readers_.emplace_back(file_, name);
368 points_ = readers_.front().points();
369 for (
const auto & reader : readers_) {
370 if (reader.points() != points_) {
371 throw std::runtime_error(
"Collector groups have inconsistent point counts");
375 if (parameters_.has_value()) {
376 for (
size_t i=0; i<parameters_->getNumberObjects(); ++i) {
377 const auto name = parameters_->getObjectName(i);
378 if (parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
381 const auto ds = parameters_->getDataSet(name);
382 if (
const auto dims = ds.getDimensions(); dims.size() != 1u || dims.back() != points_) {
383 throw std::runtime_error(
"Parameter datasets must be 1-D and match collector point count");
385 parameter_names_.push_back(name);
387 if (ds.hasAttribute(CollectorSink::parameter_unit_attribute_name())) {
388 view.unit = ds.getAttribute(CollectorSink::parameter_unit_attribute_name()).read<std::string>();
390 if (ds.hasAttribute(CollectorSink::parameter_description_attribute_name())) {
391 view.description = ds.getAttribute(CollectorSink::parameter_description_attribute_name()).read<std::string>();
393 parameter_views_.push_back(std::move(view));
395 std::ranges::sort(parameter_names_);
396 std::ranges::sort(parameter_views_, [](
const auto & a,
const auto & b){
return a.name < b.name; });
400 RL_API [[nodiscard]]
size_t points()
const {
return points_; }
401 RL_API [[nodiscard]]
const std::vector<Reader> & readers()
const {
return readers_; }
402 RL_API [[nodiscard]]
bool has_parameters()
const {
return parameters_.has_value(); }
403 RL_API [[nodiscard]]
const std::vector<std::string> & parameter_names()
const {
return parameter_names_; }
404 RL_API [[nodiscard]]
const std::vector<ParameterDatasetView> & parameter_views()
const {
return parameter_views_; }
406 RL_API [[nodiscard]]
const Reader & reader(
const std::string & collector_name)
const {
407 for (
const auto & reader : readers_) {
408 if (reader.collector_name() == collector_name) {
412 throw std::runtime_error(
"Requested collector reader does not exist");
415 RL_API [[nodiscard]] std::vector<uint8_t> parameter_value(
const std::string & name,
const size_t point)
const {
416 if (!parameters_.has_value()) {
417 throw std::runtime_error(
"Collector file does not contain a parameters group");
419 if (point >= points_) {
420 throw std::runtime_error(
"Out of bounds parameter point requested");
422 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
423 throw std::runtime_error(
"Requested parameter dataset does not exist");
425 const auto ds = parameters_->getDataSet(name);
426 const auto type = ds.getDataType();
427 std::vector<uint8_t> buffer(type.getSize());
428 ds.select({point}, {1}).read_raw(buffer.data(), type);
432 RL_API [[nodiscard]]
bool parameter_is_double(
const std::string & name)
const {
433 for (
const auto & parameter_view : parameter_views_) {
434 if (parameter_view.name == name) {
435 return parameter_view.datatype == HighFive::AtomicType<double>();
441 RL_API [[nodiscard]]
double parameter_double_value(
const std::string & name,
const size_t point)
const {
442 if (!parameters_.has_value()) {
443 throw std::runtime_error(
"Collector file does not contain a parameters group");
445 if (point >= points_) {
446 throw std::runtime_error(
"Out of bounds parameter point requested");
448 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
449 throw std::runtime_error(
"Requested parameter dataset does not exist");
451 const auto ds = parameters_->getDataSet(name);
452 const auto type = ds.getDataType();
453 if (type != HighFive::AtomicType<double>()) {
454 throw std::runtime_error(
"Requested parameter dataset does not have type double");
456 return ds.select({point}, {1}).read<double>();
459 RL_API [[nodiscard]]
bool parameter_is_float(
const std::string & name)
const {
460 for (
const auto & parameter_view : parameter_views_) {
461 if (parameter_view.name == name) {
462 return parameter_view.datatype == HighFive::AtomicType<float>();
467 RL_API [[nodiscard]]
float parameter_float_value(
const std::string & name,
const size_t point)
const {
468 if (!parameters_.has_value()) {
469 throw std::runtime_error(
"Collector file does not contain a parameters group");
471 if (point >= points_) {
472 throw std::runtime_error(
"Out of bounds parameter point requested");
474 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
475 throw std::runtime_error(
"Requested parameter dataset does not exist");
477 const auto ds = parameters_->getDataSet(name);
478 const auto type = ds.getDataType();
479 if (type != HighFive::AtomicType<float>()) {
480 throw std::runtime_error(
"Requested parameter dataset does not have type float");
482 return ds.select({point}, {1}).read<float>();
486 RL_API [[nodiscard]]
bool parameter_is_char(
const std::string & name)
const {
487 for (
const auto & parameter_view : parameter_views_) {
488 if (parameter_view.name == name) {
489 return parameter_view.datatype == HighFive::AtomicType<char>();
494 RL_API [[nodiscard]]
char parameter_char_value(
const std::string & name,
const size_t point)
const {
495 if (!parameters_.has_value()) {
496 throw std::runtime_error(
"Collector file does not contain a parameters group");
498 if (point >= points_) {
499 throw std::runtime_error(
"Out of bounds parameter point requested");
501 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
502 throw std::runtime_error(
"Requested parameter dataset does not exist");
504 const auto ds = parameters_->getDataSet(name);
505 const auto type = ds.getDataType();
506 if (type != HighFive::AtomicType<char>()) {
507 throw std::runtime_error(
"Requested parameter dataset does not have type char");
509 return ds.select({point}, {1}).read<char>();
512 RL_API [[nodiscard]]
bool parameter_is_int(
const std::string & name)
const {
513 for (
const auto & parameter_view : parameter_views_) {
514 if (parameter_view.name == name) {
515 return parameter_view.datatype == HighFive::AtomicType<int>();
520 RL_API [[nodiscard]]
int parameter_int_value(
const std::string & name,
const size_t point)
const {
521 if (!parameters_.has_value()) {
522 throw std::runtime_error(
"Collector file does not contain a parameters group");
524 if (point >= points_) {
525 throw std::runtime_error(
"Out of bounds parameter point requested");
527 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
528 throw std::runtime_error(
"Requested parameter dataset does not exist");
530 const auto ds = parameters_->getDataSet(name);
531 const auto type = ds.getDataType();
532 if (type != HighFive::AtomicType<int>()) {
533 throw std::runtime_error(
"Requested parameter dataset does not have type int");
535 return ds.select({point}, {1}).read<int>();
538 RL_API [[nodiscard]]
bool parameter_is_int32(
const std::string & name)
const {
539 for (
const auto & parameter_view : parameter_views_) {
540 if (parameter_view.name == name) {
541 return parameter_view.datatype == HighFive::AtomicType<int32_t>();
546 RL_API [[nodiscard]] int32_t parameter_int32_value(
const std::string & name,
const size_t point)
const {
547 if (!parameters_.has_value()) {
548 throw std::runtime_error(
"Collector file does not contain a parameters group");
550 if (point >= points_) {
551 throw std::runtime_error(
"Out of bounds parameter point requested");
553 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
554 throw std::runtime_error(
"Requested parameter dataset does not exist");
556 const auto ds = parameters_->getDataSet(name);
557 const auto type = ds.getDataType();
558 if (type != HighFive::AtomicType<int32_t>()) {
559 throw std::runtime_error(
"Requested parameter dataset does not have type int32_t");
561 return ds.select({point}, {1}).read<int32_t>();
564 RL_API [[nodiscard]]
bool parameter_is_int64(
const std::string & name)
const {
565 for (
const auto & parameter_view : parameter_views_) {
566 if (parameter_view.name == name) {
567 return parameter_view.datatype == HighFive::AtomicType<int64_t>();
572 RL_API [[nodiscard]] int64_t parameter_int64_value(
const std::string & name,
const size_t point)
const {
573 if (!parameters_.has_value()) {
574 throw std::runtime_error(
"Collector file does not contain a parameters group");
576 if (point >= points_) {
577 throw std::runtime_error(
"Out of bounds parameter point requested");
579 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
580 throw std::runtime_error(
"Requested parameter dataset does not exist");
582 const auto ds = parameters_->getDataSet(name);
583 const auto type = ds.getDataType();
584 if (type != HighFive::AtomicType<int64_t>()) {
585 throw std::runtime_error(
"Requested parameter dataset does not have type int64_t");
587 return ds.select({point}, {1}).read<int64_t>();
590 RL_API [[nodiscard]]
bool parameter_is_uint(
const std::string & name)
const {
591 for (
const auto & parameter_view : parameter_views_) {
592 if (parameter_view.name == name) {
593 return parameter_view.datatype == HighFive::AtomicType<unsigned int>();
598 RL_API [[nodiscard]]
unsigned int parameter_uint_value(
const std::string & name,
const size_t point)
const {
599 if (!parameters_.has_value()) {
600 throw std::runtime_error(
"Collector file does not contain a parameters group");
602 if (point >= points_) {
603 throw std::runtime_error(
"Out of bounds parameter point requested");
605 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
606 throw std::runtime_error(
"Requested parameter dataset does not exist");
608 const auto ds = parameters_->getDataSet(name);
609 const auto type = ds.getDataType();
610 if (type != HighFive::AtomicType<unsigned int>()) {
611 throw std::runtime_error(
"Requested parameter dataset does not have type unsigned int");
613 return ds.select({point}, {1}).read<unsigned int>();
616 RL_API [[nodiscard]]
bool parameter_is_uint32(
const std::string & name)
const {
617 for (
const auto & parameter_view : parameter_views_) {
618 if (parameter_view.name == name) {
619 return parameter_view.datatype == HighFive::AtomicType<uint32_t>();
624 RL_API [[nodiscard]] uint32_t parameter_uint32_value(
const std::string & name,
const size_t point)
const {
625 if (!parameters_.has_value()) {
626 throw std::runtime_error(
"Collector file does not contain a parameters group");
628 if (point >= points_) {
629 throw std::runtime_error(
"Out of bounds parameter point requested");
631 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
632 throw std::runtime_error(
"Requested parameter dataset does not exist");
634 const auto ds = parameters_->getDataSet(name);
635 const auto type = ds.getDataType();
636 if (type != HighFive::AtomicType<uint32_t>()) {
637 throw std::runtime_error(
"Requested parameter dataset does not have type uint32_t");
639 return ds.select({point}, {1}).read<uint32_t>();
642 RL_API [[nodiscard]]
bool parameter_is_uint64(
const std::string & name)
const {
643 for (
const auto & parameter_view : parameter_views_) {
644 if (parameter_view.name == name) {
645 return parameter_view.datatype == HighFive::AtomicType<uint64_t>();
650 RL_API [[nodiscard]] uint64_t parameter_uint64_value(
const std::string & name,
const size_t point)
const {
651 if (!parameters_.has_value()) {
652 throw std::runtime_error(
"Collector file does not contain a parameters group");
654 if (point >= points_) {
655 throw std::runtime_error(
"Out of bounds parameter point requested");
657 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
658 throw std::runtime_error(
"Requested parameter dataset does not exist");
660 const auto ds = parameters_->getDataSet(name);
661 const auto type = ds.getDataType();
662 if (type != HighFive::AtomicType<uint64_t>()) {
663 throw std::runtime_error(
"Requested parameter dataset does not have type uint64_t");
665 return ds.select({point}, {1}).read<uint64_t>();
668 RL_API [[nodiscard]]
bool parameter_is_string(
const std::string & name)
const {
669 for (
const auto & parameter_view : parameter_views_) {
670 if (parameter_view.name == name) {
671 return parameter_view.datatype.isFixedLenStr() || parameter_view.datatype.isVariableStr();
676 RL_API [[nodiscard]] std::string parameter_string_value(
const std::string & name,
const size_t point)
const {
677 if (!parameters_.has_value()) {
678 throw std::runtime_error(
"Collector file does not contain a parameters group");
680 if (point >= points_) {
681 throw std::runtime_error(
"Out of bounds parameter point requested");
683 if (!parameters_->exist(name) || parameters_->getObjectType(name) != HighFive::ObjectType::Dataset) {
684 throw std::runtime_error(
"Requested parameter dataset does not exist");
686 const auto ds = parameters_->getDataSet(name);
687 const auto type = ds.getDataType();
688 if (!type.isFixedLenStr() && !type.isVariableStr()) {
689 throw std::runtime_error(
"Requested parameter dataset does not have a string type");
691 return ds.select({point}, {1}).read<std::string>();