@@ -456,113 +456,155 @@ TEST(RDFSnapshotRNTuple, TDirectory)
456456 EXPECT_EQ (expected, sdf.GetColumnNames ());
457457}
458458
459- void WriteTestTree (const std::string &tname, const std::string &fname)
460- {
461- TFile file (fname.c_str (), " RECREATE" );
462- TTree t (tname.c_str (), tname.c_str ());
463-
464- float pt = 42 .f ;
465- std::vector<float > photons{1 .f , 2 .f , 3 .f };
466- Electron electron{137 .f };
467- Jet jets;
468- jets.electrons .emplace_back (Electron{122 .f });
469- jets.electrons .emplace_back (Electron{125 .f });
470- jets.electrons .emplace_back (Electron{129 .f });
471-
472- Int_t nmuons = 1 ;
473- float muon_pt[3 ] = {10 .f , 20 .f , 30 .f };
474-
475- struct {
476- Int_t x = 1 ;
477- Int_t y = 2 ;
478- } point;
479-
480- t.Branch (" pt" , &pt);
481- t.Branch (" photons" , &photons);
482- t.Branch (" electron" , &electron);
483- t.Branch (" jets" , &jets);
484- t.Branch (" nmuons" , &nmuons);
485- t.Branch (" muon_pt" , muon_pt, " muon_pt[nmuons]" );
486- t.Branch (" point" , &point, " x/I:y/I" );
487-
488- t.Fill ();
489- t.Write ();
490- }
459+ class RDFSnapshotRNTupleFromTTreeTest : public ::testing::Test {
460+ protected:
461+ const std::string fFileName = " RDFSnapshotRNTuple_ttree_fixture.root" ;
462+ const std::string fTreeName = " tree" ;
491463
492- TEST (RDFSnapshotRNTuple, FromTTree)
493- {
494- const auto treename = " tree" ;
495- FileRAII fileGuard{" RDFSnapshotRNTuple_from_ttree.root" };
464+ void SetUp () override
465+ {
466+ TFile file (fFileName .c_str (), " RECREATE" );
467+ TTree t (fTreeName .c_str (), fTreeName .c_str ());
468+
469+ float pt = 42 .f ;
470+ std::vector<float > photons{1 .f , 2 .f , 3 .f };
471+ Electron electron{137 .f };
472+ Jet jets;
473+ jets.electrons .emplace_back (Electron{122 .f });
474+ jets.electrons .emplace_back (Electron{125 .f });
475+ jets.electrons .emplace_back (Electron{129 .f });
476+
477+ Int_t nmuons = 1 ;
478+ float muon_pt[3 ] = {10 .f , 20 .f , 30 .f };
479+
480+ struct {
481+ Int_t x = 1 ;
482+ Int_t y = 2 ;
483+ } point;
484+
485+ t.Branch (" pt" , &pt);
486+ t.Branch (" photons" , &photons);
487+ t.Branch (" electron" , &electron);
488+ t.Branch (" jets" , &jets);
489+ t.Branch (" nmuons" , &nmuons);
490+ t.Branch (" muon_pt" , muon_pt, " muon_pt[nmuons]" );
491+ t.Branch (" point" , &point, " x/I:y/I" );
492+
493+ t.Fill ();
494+ t.Write ();
495+ }
496496
497- WriteTestTree (treename, fileGuard. GetPath ());
497+ void TearDown () override { gSystem -> Unlink ( fFileName . c_str ()); }
498498
499- auto df = ROOT::RDataFrame (treename, fileGuard.GetPath ());
499+ void TestFromTTree (const std::string &fname, bool vector2RVec = false )
500+ {
501+ FileRAII fileGuard{fname};
500502
501- RSnapshotOptions opts;
502- opts.fOutputFormat = ROOT::RDF::ESnapshotOutputFormat::kRNTuple ;
503+ auto df = ROOT::RDataFrame (fTreeName , fFileName );
503504
504- {
505- // FIXME(fdegeus): snapshotting leaflist branches as-is (i.e. without explicitly providing their leafs) is not
506- // supported, because we have no way of reconstructing the memory layout of the branch itself from only the
507- // TTree's on-disk information without JITting. For RNTuple, we would be able to do this using anonymous record
508- // fields, however. Once this is implemented, this test should be changed to check the result of snapshotting
509- // "point" fully.
510- auto sdf = df.Define (" x" , [] { return 10 ; })
511- .Snapshot (" ntuple" , fileGuard.GetPath (),
512- {" x" , " pt" , " photons" , " electron" , " jets" , " muon_pt" , " point.x" , " point.y" }, opts);
513-
514- auto x = sdf->Take <int >(" x" );
515- auto pt = sdf->Take <float >(" pt" );
516- auto photons = sdf->Take <ROOT::RVec<float >>(" photons" );
517- auto electron = sdf->Take <Electron>(" electron" );
518- auto jet_electrons = sdf->Take <ROOT::RVec<Electron>>(" jets.electrons" );
519- auto nMuons = sdf->Take <int >(" nmuons" );
520- auto muonPt = sdf->Take <ROOT::RVec<float >>(" muon_pt" );
521- auto pointX = sdf->Take <int >(" point_x" );
522- auto pointY = sdf->Take <int >(" point_y" );
523-
524- ASSERT_EQ (1UL , x->size ());
525- ASSERT_EQ (1UL , pt->size ());
526- ASSERT_EQ (1UL , photons->size ());
527- ASSERT_EQ (1UL , electron->size ());
528- ASSERT_EQ (1UL , jet_electrons->size ());
529- ASSERT_EQ (1UL , nMuons->size ());
530- ASSERT_EQ (1UL , muonPt->size ());
531- ASSERT_EQ (1UL , pointX->size ());
532- ASSERT_EQ (1UL , pointY->size ());
533-
534- EXPECT_EQ (10 , x->front ());
535- EXPECT_EQ (42 .f , pt->front ());
536- expect_vec_eq<float >({1 .f , 2 .f , 3 .f }, photons->front ());
537- EXPECT_EQ (Electron{137 .f }, electron->front ());
538- expect_vec_eq ({Electron{122 .f }, Electron{125 .f }, Electron{129 .f }}, jet_electrons->front ());
539- EXPECT_EQ (1 , nMuons->front ());
540- expect_vec_eq ({10 .f }, muonPt->front ());
541- EXPECT_EQ (1 , pointX->front ());
542- EXPECT_EQ (2 , pointY->front ());
543- }
505+ {
506+ RSnapshotOptions opts;
507+ opts.fOutputFormat = ROOT::RDF::ESnapshotOutputFormat::kRNTuple ;
508+ opts.fVector2RVec = vector2RVec;
509+
510+ // FIXME(fdegeus): snapshotting leaflist branches as-is (i.e. without explicitly providing their leafs) is not
511+ // supported, because we have no way of reconstructing the memory layout of the branch itself from only the
512+ // TTree's on-disk information without JITting. For RNTuple, we would be able to do this using anonymous record
513+ // fields, however. Once this is implemented, this test should be changed to check the result of snapshotting
514+ // "point" fully.
515+ auto sdf = df.Define (" x" , [] { return 10 ; })
516+ .Snapshot (" ntuple" , fileGuard.GetPath (),
517+ {" x" , " pt" , " photons" , " electron" , " jets" , " muon_pt" , " point.x" , " point.y" }, opts);
518+
519+ auto x = sdf->Take <int >(" x" );
520+ auto pt = sdf->Take <float >(" pt" );
521+ auto photons = sdf->Take <ROOT::RVec<float >>(" photons" );
522+ auto electron = sdf->Take <Electron>(" electron" );
523+ auto jet_electrons = sdf->Take <ROOT::RVec<Electron>>(" jets.electrons" );
524+ auto nMuons = sdf->Take <int >(" nmuons" );
525+ auto muonPt = sdf->Take <ROOT::RVec<float >>(" muon_pt" );
526+ auto pointX = sdf->Take <int >(" point_x" );
527+ auto pointY = sdf->Take <int >(" point_y" );
528+
529+ ASSERT_EQ (1UL , x->size ());
530+ ASSERT_EQ (1UL , pt->size ());
531+ ASSERT_EQ (1UL , photons->size ());
532+ ASSERT_EQ (1UL , electron->size ());
533+ ASSERT_EQ (1UL , jet_electrons->size ());
534+ ASSERT_EQ (1UL , nMuons->size ());
535+ ASSERT_EQ (1UL , muonPt->size ());
536+ ASSERT_EQ (1UL , pointX->size ());
537+ ASSERT_EQ (1UL , pointY->size ());
538+
539+ EXPECT_EQ (10 , x->front ());
540+ EXPECT_EQ (42 .f , pt->front ());
541+ expect_vec_eq<float >({1 .f , 2 .f , 3 .f }, photons->front ());
542+ EXPECT_EQ (Electron{137 .f }, electron->front ());
543+ expect_vec_eq ({Electron{122 .f }, Electron{125 .f }, Electron{129 .f }}, jet_electrons->front ());
544+ EXPECT_EQ (1 , nMuons->front ());
545+ expect_vec_eq ({10 .f }, muonPt->front ());
546+ EXPECT_EQ (1 , pointX->front ());
547+ EXPECT_EQ (2 , pointY->front ());
548+ }
544549
545- auto reader = RNTupleReader::Open (" ntuple" , fileGuard.GetPath ());
550+ auto reader = RNTupleReader::Open (" ntuple" , fileGuard.GetPath ());
546551
547- auto x = reader->GetView <int >(" x" );
548- auto pt = reader->GetView <float >(" pt" );
549- auto photons = reader->GetView <ROOT::RVec<float >>(" photons" );
550- auto electron = reader->GetView <Electron>(" electron" );
551- auto jet_electrons = reader->GetView <ROOT::RVec<Electron>>(" jets.electrons" );
552- auto nMuons = reader->GetView <int >(" nmuons" );
553- auto muonPt = reader->GetView <ROOT::RVec<float >>(" muon_pt" );
554- auto pointX = reader->GetView <int >(" point_x" );
555- auto pointY = reader->GetView <int >(" point_y" );
552+ auto &descriptor = reader->GetDescriptor ();
556553
557- EXPECT_EQ (10 , x (0 ));
558- EXPECT_EQ (42 .f , pt (0 ));
559- expect_vec_eq<float >({1 .f , 2 .f , 3 .f }, photons (0 ));
560- EXPECT_EQ (Electron{137 .f }, electron (0 ));
561- expect_vec_eq ({Electron{122 .f }, Electron{125 .f }, Electron{129 .f }}, jet_electrons (0 ));
562- EXPECT_EQ (1 , nMuons (0 ));
563- expect_vec_eq ({10 .f }, muonPt (0 ));
564- EXPECT_EQ (1 , pointX (0 ));
565- EXPECT_EQ (2 , pointY (0 ));
554+ int nTopLevelFields = std::distance (descriptor.GetTopLevelFields ().begin (), descriptor.GetTopLevelFields ().end ());
555+ EXPECT_EQ (9 , nTopLevelFields);
556+ EXPECT_EQ (" std::int32_t" , descriptor.GetFieldDescriptor (descriptor.FindFieldId (" x" )).GetTypeName ());
557+ EXPECT_EQ (" float" , descriptor.GetFieldDescriptor (descriptor.FindFieldId (" pt" )).GetTypeName ());
558+ if (vector2RVec) {
559+ EXPECT_EQ (" ROOT::VecOps::RVec<float>" ,
560+ descriptor.GetFieldDescriptor (descriptor.FindFieldId (" photons" )).GetTypeName ());
561+ } else {
562+ EXPECT_EQ (" std::vector<float>" ,
563+ descriptor.GetFieldDescriptor (descriptor.FindFieldId (" photons" )).GetTypeName ());
564+ }
565+ EXPECT_EQ (" Electron" , descriptor.GetFieldDescriptor (descriptor.FindFieldId (" electron" )).GetTypeName ());
566+ auto jetsId = descriptor.FindFieldId (" jets" );
567+ EXPECT_EQ (" Jet" , descriptor.GetFieldDescriptor (jetsId).GetTypeName ());
568+ auto electronsId = descriptor.FindFieldId (" electrons" , jetsId);
569+ EXPECT_EQ (" std::vector<Electron>" , descriptor.GetFieldDescriptor (electronsId).GetTypeName ());
570+ EXPECT_EQ (" std::int32_t" , descriptor.GetFieldDescriptor (descriptor.FindFieldId (" nmuons" )).GetTypeName ());
571+ EXPECT_EQ (" ROOT::VecOps::RVec<float>" ,
572+ descriptor.GetFieldDescriptor (descriptor.FindFieldId (" muon_pt" )).GetTypeName ());
573+ EXPECT_EQ (" std::int32_t" , descriptor.GetFieldDescriptor (descriptor.FindFieldId (" point_x" )).GetTypeName ());
574+ EXPECT_EQ (" std::int32_t" , descriptor.GetFieldDescriptor (descriptor.FindFieldId (" point_y" )).GetTypeName ());
575+ // sanity check to make sure we don't snapshot the internal RDF size columns
576+ EXPECT_EQ (ROOT::kInvalidDescriptorId , descriptor.FindFieldId (" R_rdf_sizeof_photons" ));
577+
578+ auto x = reader->GetView <int >(" x" );
579+ auto pt = reader->GetView <float >(" pt" );
580+ auto photons = reader->GetView <ROOT::RVec<float >>(" photons" );
581+ auto electron = reader->GetView <Electron>(" electron" );
582+ auto jet_electrons = reader->GetView <ROOT::RVec<Electron>>(" jets.electrons" );
583+ auto nMuons = reader->GetView <int >(" nmuons" );
584+ auto muonPt = reader->GetView <ROOT::RVec<float >>(" muon_pt" );
585+ auto pointX = reader->GetView <int >(" point_x" );
586+ auto pointY = reader->GetView <int >(" point_y" );
587+
588+ EXPECT_EQ (10 , x (0 ));
589+ EXPECT_EQ (42 .f , pt (0 ));
590+ expect_vec_eq<float >({1 .f , 2 .f , 3 .f }, photons (0 ));
591+ EXPECT_EQ (Electron{137 .f }, electron (0 ));
592+ expect_vec_eq ({Electron{122 .f }, Electron{125 .f }, Electron{129 .f }}, jet_electrons (0 ));
593+ EXPECT_EQ (1 , nMuons (0 ));
594+ expect_vec_eq ({10 .f }, muonPt (0 ));
595+ EXPECT_EQ (1 , pointX (0 ));
596+ EXPECT_EQ (2 , pointY (0 ));
597+ }
598+ };
599+
600+ TEST_F (RDFSnapshotRNTupleFromTTreeTest, FromTTree)
601+ {
602+ TestFromTTree (" RDFSnapshotRNTuple_from_ttree.root" );
603+ }
604+
605+ TEST_F (RDFSnapshotRNTupleFromTTreeTest, FromTTreeNoVector2RVec)
606+ {
607+ TestFromTTree (" RDFSnapshotRNTuple_from_ttree_novec2rvec.root" , /* vector2RVec=*/ false );
566608}
567609
568610#ifdef R__USE_IMT
0 commit comments