@@ -35,6 +35,15 @@ class FileRAII {
35
35
std::string GetPath () const { return fPath ; }
36
36
};
37
37
38
+ template <typename T>
39
+ void expect_vec_eq (const ROOT::RVec<T> &v1, const ROOT::RVec<T> &v2)
40
+ {
41
+ ASSERT_EQ (v1.size (), v2.size ()) << " Vectors 'v1' and 'v2' are of unequal length" ;
42
+ for (std::size_t i = 0ull ; i < v1.size (); ++i) {
43
+ EXPECT_EQ (v1[i], v2[i]) << " Vectors 'v1' and 'v2' differ at index " << i;
44
+ }
45
+ }
46
+
38
47
TEST (RDFSnapshotRNTuple, FromScratch)
39
48
{
40
49
FileRAII fileGuard{" RDFSnapshotRNTuple_from_scratch.root" };
@@ -444,16 +453,36 @@ void WriteTestTree(const std::string &tname, const std::string &fname)
444
453
{
445
454
TFile file (fname.c_str (), " RECREATE" );
446
455
TTree t (tname.c_str (), tname.c_str ());
447
- float pt;
456
+
457
+ float pt = 42 .f ;
458
+ std::vector<float > photons{1 .f , 2 .f , 3 .f };
459
+ Electron electron{137 .f };
460
+ Jet jets;
461
+ jets.electrons .emplace_back (Electron{122 .f });
462
+ jets.electrons .emplace_back (Electron{125 .f });
463
+ jets.electrons .emplace_back (Electron{129 .f });
464
+
465
+ Int_t nmuons = 1 ;
466
+ float muon_pt[3 ] = {10 .f , 20 .f , 30 .f };
467
+
468
+ struct {
469
+ Int_t x = 1 ;
470
+ Int_t y = 2 ;
471
+ } point;
472
+
448
473
t.Branch (" pt" , &pt);
474
+ t.Branch (" photons" , &photons);
475
+ t.Branch (" electron" , &electron);
476
+ t.Branch (" jets" , &jets);
477
+ t.Branch (" nmuons" , &nmuons);
478
+ t.Branch (" muon_pt" , muon_pt, " muon_pt[nmuons]" );
479
+ t.Branch (" point" , &point, " x/I:y/I" );
449
480
450
- pt = 42.0 ;
451
481
t.Fill ();
452
-
453
482
t.Write ();
454
483
}
455
484
456
- TEST (RDFSnapshotRNTuple, DisallowFromTTree )
485
+ TEST (RDFSnapshotRNTuple, FromTTree )
457
486
{
458
487
const auto treename = " tree" ;
459
488
FileRAII fileGuard{" RDFSnapshotRNTuple_disallow_from_ttree.root" };
@@ -465,13 +494,68 @@ TEST(RDFSnapshotRNTuple, DisallowFromTTree)
465
494
RSnapshotOptions opts;
466
495
opts.fOutputFormat = ROOT::RDF::ESnapshotOutputFormat::kRNTuple ;
467
496
468
- try {
469
- auto sdf = df.Define (" x" , [] { return 10 ; }).Snapshot (" ntuple" , fileGuard.GetPath (), {" pt" , " x" }, opts);
470
- FAIL () << " snapshotting from RNTuple to TTree is not (yet) possible" ;
471
- } catch (const std::runtime_error &err) {
472
- EXPECT_STREQ (err.what (), " Snapshotting from TTree to RNTuple is not yet supported. The current recommended way "
473
- " to convert TTrees to RNTuple is through the RNTupleImporter." );
497
+ {
498
+ // FIXME(fdegeus): snapshotting leaflist branches as-is (i.e. without explicitly providing their leafs) is not
499
+ // supported, because we have no way of reconstructing the memory layout of the branch itself from only the
500
+ // TTree's on-disk information without JITting. For RNTuple, we would be able to do this using anonymous record
501
+ // fields, however. Once this is implemented, this test should be changed to check the result of snapshotting
502
+ // "point" fully.
503
+ auto sdf = df.Define (" x" , [] { return 10 ; })
504
+ .Snapshot (" ntuple" , fileGuard.GetPath (),
505
+ {" x" , " pt" , " photons" , " electron" , " jets" , " muon_pt" , " point.x" , " point.y" }, opts);
506
+
507
+ auto x = sdf->Take <int >(" x" );
508
+ auto pt = sdf->Take <float >(" pt" );
509
+ auto photons = sdf->Take <ROOT::RVec<float >>(" photons" );
510
+ auto electron = sdf->Take <Electron>(" electron" );
511
+ auto jet_electrons = sdf->Take <ROOT::RVec<Electron>>(" jets.electrons" );
512
+ auto nMuons = sdf->Take <int >(" nmuons" );
513
+ auto muonPt = sdf->Take <ROOT::RVec<float >>(" muon_pt" );
514
+ auto pointX = sdf->Take <int >(" point_x" );
515
+ auto pointY = sdf->Take <int >(" point_y" );
516
+
517
+ ASSERT_EQ (1UL , x->size ());
518
+ ASSERT_EQ (1UL , pt->size ());
519
+ ASSERT_EQ (1UL , photons->size ());
520
+ ASSERT_EQ (1UL , electron->size ());
521
+ ASSERT_EQ (1UL , jet_electrons->size ());
522
+ ASSERT_EQ (1UL , nMuons->size ());
523
+ ASSERT_EQ (1UL , muonPt->size ());
524
+ ASSERT_EQ (1UL , pointX->size ());
525
+ ASSERT_EQ (1UL , pointY->size ());
526
+
527
+ EXPECT_EQ (10 , x->front ());
528
+ EXPECT_EQ (42 .f , pt->front ());
529
+ expect_vec_eq<float >({1 .f , 2 .f , 3 .f }, photons->front ());
530
+ EXPECT_EQ (Electron{137 .f }, electron->front ());
531
+ expect_vec_eq ({Electron{122 .f }, Electron{125 .f }, Electron{129 .f }}, jet_electrons->front ());
532
+ EXPECT_EQ (1 , nMuons->front ());
533
+ expect_vec_eq ({10 .f }, muonPt->front ());
534
+ EXPECT_EQ (1 , pointX->front ());
535
+ EXPECT_EQ (2 , pointY->front ());
474
536
}
537
+
538
+ auto reader = RNTupleReader::Open (" ntuple" , fileGuard.GetPath ());
539
+
540
+ auto x = reader->GetView <int >(" x" );
541
+ auto pt = reader->GetView <float >(" pt" );
542
+ auto photons = reader->GetView <ROOT::RVec<float >>(" photons" );
543
+ auto electron = reader->GetView <Electron>(" electron" );
544
+ auto jet_electrons = reader->GetView <ROOT::RVec<Electron>>(" jets.electrons" );
545
+ auto nMuons = reader->GetView <int >(" nmuons" );
546
+ auto muonPt = reader->GetView <ROOT::RVec<float >>(" muon_pt" );
547
+ auto pointX = reader->GetView <int >(" point_x" );
548
+ auto pointY = reader->GetView <int >(" point_y" );
549
+
550
+ EXPECT_EQ (10 , x (0 ));
551
+ EXPECT_EQ (42 .f , pt (0 ));
552
+ expect_vec_eq<float >({1 .f , 2 .f , 3 .f }, photons (0 ));
553
+ EXPECT_EQ (Electron{137 .f }, electron (0 ));
554
+ expect_vec_eq ({Electron{122 .f }, Electron{125 .f }, Electron{129 .f }}, jet_electrons (0 ));
555
+ EXPECT_EQ (1 , nMuons (0 ));
556
+ expect_vec_eq ({10 .f }, muonPt (0 ));
557
+ EXPECT_EQ (1 , pointX (0 ));
558
+ EXPECT_EQ (2 , pointY (0 ));
475
559
}
476
560
477
561
#ifdef R__USE_IMT
0 commit comments