77 TTree
t1(
"t1",
"a simple Tree with simple variables");
83 t1.Branch(
"px", &px,
"px/F");
84 t1.Branch(
"py", &py,
"py/F");
85 t1.Branch(
"pz", &pz,
"pz/F");
86 t1.Branch(
"random", &random,
"random/D");
87 t1.Branch(
"ev", &ev,
"ev/I");
88 t1.Branch(
"xyz", xyz,
"xyz[3]/F");
89 t1.Branch(
"ij", ij,
"ij[2]/I");
91 for (Int_t
i = 0;
i < 1000;
i++) {
95 gRandom->Rannor(px, py);
96 pz = px * px + py * py;
100 random = gRandom->Rndm();
104 file->WriteObjectAny(&
t1,
t1.Class());
105 auto* fileRead =
new TBufferFile(TBuffer::kRead, file->BufferSize(), file->Buffer(),
false,
nullptr);
107 std::vector<char const*> capabilitiesSpecs = {
108 "O2Framework:RNTupleObjectReadingCapability",
109 "O2Framework:TTreeObjectReadingCapability",
112 std::vector<LoadablePlugin> plugins;
113 for (
auto spec : capabilitiesSpecs) {
115 for (
auto& extra : morePlugins) {
116 plugins.push_back(extra);
119 REQUIRE(plugins.size() == 2);
122 std::vector<char const*> configDiscoverySpec = {};
123 PluginManager::loadFromPlugin<RootObjectReadingCapability, RootObjectReadingCapabilityPlugin>(plugins, factory.
capabilities);
131 auto fs = std::make_shared<TBufferFileFS>(fileRead, factory);
133 arrow::dataset::FileSource
source(
"p", fs);
136 REQUIRE(schemaOpt.ok());
138 REQUIRE(
schema->num_fields() == 7);
139 REQUIRE(
schema->field(0)->type()->id() == arrow::float32()->id());
140 REQUIRE(
schema->field(1)->type()->id() == arrow::float32()->id());
141 REQUIRE(
schema->field(2)->type()->id() == arrow::float32()->id());
142 REQUIRE(
schema->field(3)->type()->id() == arrow::float64()->id());
143 REQUIRE(
schema->field(4)->type()->id() == arrow::int32()->id());
144 REQUIRE(
schema->field(5)->type()->id() == arrow::fixed_size_list(arrow::float32(), 3)->id());
145 REQUIRE(
schema->field(6)->type()->id() == arrow::fixed_size_list(arrow::int32(), 2)->id());
147 REQUIRE(fragment.ok());
148 auto options = std::make_shared<arrow::dataset::ScanOptions>();
149 options->dataset_schema =
schema;
150 auto scanner =
format->ScanBatchesAsync(options, *fragment);
151 REQUIRE(scanner.ok());
152 auto batches = (*scanner)();
153 auto result = batches.result();
155 REQUIRE((*result)->columns().size() == 7);
156 REQUIRE((*result)->num_rows() == 1000);
162 auto int_array = std::static_pointer_cast<arrow::Int32Array>(batch->GetColumnByName(
"ev"));
163 REQUIRE(int_array->length() == 100);
164 for (
int64_t j = 0;
j < int_array->length();
j++) {
165 REQUIRE(int_array->Value(
j) ==
j + 1);
170 auto list_array = std::static_pointer_cast<arrow::FixedSizeListArray>(batch->GetColumnByName(
"xyz"));
172 REQUIRE(list_array->length() == 100);
174 for (
int64_t i = 0;
i < list_array->length();
i++) {
175 auto value_slice = list_array->value_slice(
i);
176 auto float_array = std::static_pointer_cast<arrow::FloatArray>(value_slice);
178 REQUIRE(float_array->Value(0) == 1);
179 REQUIRE(float_array->Value(1) == 2);
180 REQUIRE(float_array->Value(2) ==
i + 1);
185 auto list_array = std::static_pointer_cast<arrow::FixedSizeListArray>(batch->GetColumnByName(
"ij"));
187 REQUIRE(list_array->length() == 100);
189 for (
int64_t i = 0;
i < list_array->length();
i++) {
190 auto value_slice = list_array->value_slice(
i);
191 auto int_array = std::static_pointer_cast<arrow::Int32Array>(value_slice);
192 REQUIRE(int_array->Value(0) ==
i);
193 REQUIRE(int_array->Value(1) ==
i + 1);
198 auto bool_array = std::static_pointer_cast<arrow::BooleanArray>(batch->GetColumnByName(
"bools"));
200 REQUIRE(bool_array->length() == 100);
201 for (
int64_t j = 0;
j < bool_array->length();
j++) {
202 REQUIRE(bool_array->Value(
j) == (
j % 3 == 0));
207 auto list_array = std::static_pointer_cast<arrow::FixedSizeListArray>(batch->GetColumnByName(
"manyBools"));
209 REQUIRE(list_array->length() == 100);
210 for (
int64_t i = 0;
i < list_array->length();
i++) {
211 auto value_slice = list_array->value_slice(
i);
212 auto bool_array = std::static_pointer_cast<arrow::BooleanArray>(value_slice);
213 REQUIRE(bool_array->Value(0) == (
i % 4 == 0));
214 REQUIRE(bool_array->Value(1) == (
i % 5 == 0));
219 auto list_array = std::static_pointer_cast<arrow::ListArray>(batch->GetColumnByName(
"vla"));
221 REQUIRE(list_array->length() == 100);
222 for (
int64_t i = 0;
i < list_array->length();
i++) {
223 auto value_slice = list_array->value_slice(
i);
224 REQUIRE(value_slice->length() == (
i % 10));
225 auto int_array = std::static_pointer_cast<arrow::Int32Array>(value_slice);
226 for (
size_t j = 0;
j < value_slice->length();
j++) {
227 REQUIRE(int_array->Value(
j) ==
j);
275 auto*
f =
new TMemFile(
"foo",
"RECREATE");
280 auto* t =
new TTree(
"tracks",
"a simple Tree with simple variables");
284 Float_t px = 0, py = 1, pz = 2;
287 t->Branch(
"px", &px,
"px/F");
288 t->Branch(
"py", &py,
"py/F");
289 t->Branch(
"pz", &pz,
"pz/F");
290 t->Branch(
"random", &random,
"random/D");
291 t->Branch(
"ev", &ev,
"ev/I");
292 t->Branch(
"xyz", xyz,
"xyz[3]/F");
293 t->Branch(
"ij", ij,
"ij[2]/I");
295 for (Int_t
i = 0;
i < 1000;
i++) {
299 gRandom->Rannor(px, py);
300 pz = px * px + py * py;
304 random = gRandom->Rndm();
311 t =
new TTree(
"tracks",
"a simple Tree with simple variables");
315 Float_t px = 0, py = 1, pz = 2;
320 int vla[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
324 t->Branch(
"px", &px,
"px/F");
325 t->Branch(
"py", &py,
"py/F");
326 t->Branch(
"pz", &pz,
"pz/F");
327 t->Branch(
"random", &random,
"random/D");
328 t->Branch(
"ev", &ev,
"ev/I");
329 t->Branch(
"xyz", xyz,
"xyz[3]/F");
330 t->Branch(
"ij", ij,
"ij[2]/I");
331 t->Branch(
"bools", &oneBool,
"bools/O");
332 t->Branch(
"manyBools", &manyBool,
"manyBools[2]/O");
333 t->Branch(
"vla_size", &vlaSize,
"vla_size/I");
334 t->Branch(
"vla", vla,
"vla[vla_size]/I");
335 t->Branch(
"byte", &
byte,
"byte/B");
337 for (Int_t
i = 0;
i < 100;
i++) {
341 gRandom->Rannor(px, py);
342 pz = px * px + py * py;
346 random = gRandom->Rndm();
348 oneBool = (
i % 3 == 0);
349 manyBool[0] = (
i % 4 == 0);
350 manyBool[1] = (
i % 5 == 0);
358 std::vector<char const*> capabilitiesSpecs = {
359 "O2Framework:RNTupleObjectReadingCapability",
360 "O2Framework:TTreeObjectReadingCapability",
365 std::vector<LoadablePlugin> plugins;
366 for (
auto spec : capabilitiesSpecs) {
368 for (
auto& extra : morePlugins) {
369 plugins.push_back(extra);
372 REQUIRE(plugins.size() == 2);
374 PluginManager::loadFromPlugin<RootObjectReadingCapability, RootObjectReadingCapabilityPlugin>(plugins, factory.
capabilities);
381 auto rNtupleFormat = factory.
capabilities[0].factory().format();
384 auto fs = std::make_shared<TFileFileSystem>(
f, 50 * 1024 * 1024, factory);
386 arrow::dataset::FileSource
source(
"DF_2/tracks", fs);
389 REQUIRE(physicalSchema.ok());
392 std::vector<std::shared_ptr<arrow::Field>>
fields;
393 for (
auto& field : (*(physicalSchema))->fields()) {
394 if (field->name().ends_with(
"_size")) {
399 std::shared_ptr<arrow::Schema>
schema = std::make_shared<arrow::Schema>(
fields);
403 auto fragment =
format->MakeFragment(
source, {}, *physicalSchema);
404 REQUIRE(fragment.ok());
405 auto options = std::make_shared<arrow::dataset::ScanOptions>();
406 options->dataset_schema =
schema;
407 auto scanner =
format->ScanBatchesAsync(options, *fragment);
408 REQUIRE(scanner.ok());
412 std::shared_ptr<arrow::RecordBatch> batch;
414 auto batches = (*scanner)();
415 auto result = batches.result();
417 REQUIRE((*result)->columns().size() == 11);
418 REQUIRE((*result)->num_rows() == 100);
419 std::shared_ptr<arrow::ResizableBuffer>
buffer = *arrow::AllocateResizableBuffer(1000, 64);
420 auto deferredWriterStream = factory.
capabilities[1].factory().deferredOutputStreamer(*fragment,
buffer);
421 auto outBatch = arrow::ipc::MakeStreamWriter(deferredWriterStream.get(),
schema);
422 auto status = outBatch.ValueOrDie()->WriteRecordBatch(**
result);
423 std::shared_ptr<arrow::io::InputStream> bufferReader = std::make_shared<arrow::io::BufferReader>(
buffer);
424 auto readerResult = arrow::ipc::RecordBatchStreamReader::Open(bufferReader);
425 auto batchReader = readerResult.ValueOrDie();
427 auto next = batchReader->ReadNext(&batch);
428 REQUIRE(batch !=
nullptr);
432 auto*
output =
new TMemFile(
"foo",
"RECREATE");
433 auto outFs = std::make_shared<TFileFileSystem>(
output, 0, factory);
436 auto destination = outFs->OpenOutputStream(
"/", {});
437 REQUIRE(destination.ok());
440 arrow::fs::FileLocator locator{outFs,
"/DF_3"};
441 auto writer =
format->MakeWriter(*destination,
schema, {}, locator);
442 auto success = writer->get()->Write(batch);
443 REQUIRE(batch->schema()->field(0)->name() ==
"px");
444 auto rootDestination = std::dynamic_pointer_cast<TDirectoryFileOutputStream>(*destination);
448 REQUIRE(success.ok());
450 auto tfileFs = std::dynamic_pointer_cast<TFileFileSystem>(outFs);
451 REQUIRE(tfileFs.get());
452 REQUIRE(tfileFs->GetFile());
453 auto*
tree = (TTree*)tfileFs->GetFile()->GetObjectChecked(
"/DF_3", TClass::GetClass(
"TTree"));
454 REQUIRE(
tree !=
nullptr);
455 REQUIRE(((TBranch*)
tree->GetListOfBranches()->At(0))->GetEntries() == 100);
456 REQUIRE(((TBranch*)
tree->GetListOfBranches()->At(0))->GetName() == std::string(
"px"));
458 arrow::dataset::FileSource source2(
"/DF_3", outFs);
460 REQUIRE(
format->IsSupported(source2) ==
true);
461 tfileFs = std::dynamic_pointer_cast<TFileFileSystem>(source2.filesystem());
462 REQUIRE(tfileFs.get());
463 REQUIRE(tfileFs->GetFile());
464 REQUIRE(tfileFs->GetFile()->GetObjectChecked(
"/DF_3", TClass::GetClass(
"TTree")));
466 tree = (TTree*)tfileFs->GetFile()->GetObjectChecked(
"/DF_3", TClass::GetClass(
"TTree"));
467 REQUIRE(
tree !=
nullptr);
468 REQUIRE(((TBranch*)
tree->GetListOfBranches()->At(0))->GetEntries() == 100);
470 auto schemaOptWritten =
format->Inspect(source2);
471 tfileFs = std::dynamic_pointer_cast<TFileFileSystem>(source2.filesystem());
472 REQUIRE(tfileFs.get());
473 REQUIRE(tfileFs->GetFile());
474 REQUIRE(tfileFs->GetFile()->GetObjectChecked(
"/DF_3", TClass::GetClass(
"TTree")));
475 REQUIRE(schemaOptWritten.ok());
476 auto schemaWritten = *schemaOptWritten;
478 tree = (TTree*)tfileFs->GetFile()->GetObjectChecked(
"/DF_3", TClass::GetClass(
"TTree"));
479 REQUIRE(
tree !=
nullptr);
480 REQUIRE(((TBranch*)
tree->GetListOfBranches()->At(0))->GetEntries() == 100);
483 std::vector<std::shared_ptr<arrow::Field>>
fields;
484 for (
auto& field : schemaWritten->fields()) {
485 if (field->name().ends_with(
"_size")) {
490 std::shared_ptr<arrow::Schema>
schema = std::make_shared<arrow::Schema>(
fields);
493 auto fragmentWritten =
format->MakeFragment(source2, {}, *physicalSchema);
494 REQUIRE(fragmentWritten.ok());
495 auto optionsWritten = std::make_shared<arrow::dataset::ScanOptions>();
496 optionsWritten->dataset_schema =
schema;
497 auto scannerWritten =
format->ScanBatchesAsync(optionsWritten, *fragmentWritten);
498 REQUIRE(scannerWritten.ok());
499 tree = (TTree*)tfileFs->GetFile()->GetObjectChecked(
"/DF_3", TClass::GetClass(
"TTree"));
500 REQUIRE(
tree !=
nullptr);
501 REQUIRE(((TBranch*)
tree->GetListOfBranches()->At(0))->GetEntries() == 100);
502 auto batchesWritten = (*scannerWritten)();
503 auto resultWritten = batchesWritten.result();
504 REQUIRE(resultWritten.ok());
505 REQUIRE((*resultWritten)->columns().size() == 11);
506 REQUIRE((*resultWritten)->num_rows() == 100);
508 std::shared_ptr<arrow::ResizableBuffer>
buffer = *arrow::AllocateResizableBuffer(1000, 64);
509 auto deferredWriterStream2 = factory.
capabilities[1].factory().deferredOutputStreamer(*fragmentWritten,
buffer);
510 auto outBatch = arrow::ipc::MakeStreamWriter(deferredWriterStream2.get(),
schema);
511 auto status = outBatch.ValueOrDie()->WriteRecordBatch(**resultWritten);
512 std::shared_ptr<arrow::io::InputStream> bufferReader = std::make_shared<arrow::io::BufferReader>(
buffer);
513 auto readerResult = arrow::ipc::RecordBatchStreamReader::Open(bufferReader);
514 auto batchReader = readerResult.ValueOrDie();
516 auto next = batchReader->ReadNext(&batch);
517 REQUIRE(batch !=
nullptr);
521#if __has_include(<ROOT/RFieldBase.hxx>)
522 arrow::fs::FileLocator rnTupleLocator{outFs,
"rntuple"};
524 arrow::fs::FileLocator rnTupleLocator{outFs,
"/rntuple"};
527 auto rntupleDestination = std::dynamic_pointer_cast<TDirectoryFileOutputStream>(*destination);
530 auto rNtupleWriter = rNtupleFormat->MakeWriter(*destination,
schema, {}, rnTupleLocator);
531 auto rNtupleSuccess = rNtupleWriter->get()->Write(batch);
532 REQUIRE(rNtupleSuccess.ok());
536#if __has_include(<ROOT/RFieldBase.hxx>)
537 arrow::dataset::FileSource writtenRntupleSource(
"rntuple", outFs);
539 arrow::dataset::FileSource writtenRntupleSource(
"/rntuple", outFs);
542 REQUIRE(rNtupleFormat->IsSupported(writtenRntupleSource) ==
true);
544 auto rntupleSchemaOpt = rNtupleFormat->Inspect(writtenRntupleSource);
545 REQUIRE(rntupleSchemaOpt.ok());
546 auto rntupleSchemaWritten = *rntupleSchemaOpt;
549 auto rntupleFragmentWritten = rNtupleFormat->MakeFragment(writtenRntupleSource, {}, rntupleSchemaWritten);
550 REQUIRE(rntupleFragmentWritten.ok());
551 auto rntupleOptionsWritten = std::make_shared<arrow::dataset::ScanOptions>();
552 rntupleOptionsWritten->dataset_schema = rntupleSchemaWritten;
553 auto rntupleScannerWritten = rNtupleFormat->ScanBatchesAsync(rntupleOptionsWritten, *rntupleFragmentWritten);
554 REQUIRE(rntupleScannerWritten.ok());
555 auto rntupleBatchesWritten = (*rntupleScannerWritten)();
556 auto rntupleResultWritten = rntupleBatchesWritten.result();
557 REQUIRE(rntupleResultWritten.ok());
558 REQUIRE((*rntupleResultWritten)->columns().size() == 11);
560 REQUIRE((*rntupleResultWritten)->num_rows() == 100);