Skip to content

Commit b70d77b

Browse files
committed
[df] Enable snapshotting RNTuple cardinality cols
1 parent cb54a79 commit b70d77b

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

tree/dataframe/src/RDFSnapshotHelpers.cxx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,18 @@ void ROOT::Internal::RDF::UntypedSnapshotRNTupleHelper::Initialize()
912912
? ROOT::Internal::RDF::GetTypeNameWithOpts(*fInputLoopManager->GetDataSource(),
913913
fInputFieldNames[i], fOptions.fVector2RVec)
914914
: ROOT::Internal::RDF::TypeID2TypeName(*fInputColumnTypeIDs[i]);
915-
model->AddField(ROOT::RFieldBase::Create(fOutputFieldNames[i], typeName).Unwrap());
915+
916+
// Cardinality fields are read-only, so instead we snapshot them as their inner type.
917+
if (typeName.substr(0, 24) == "ROOT::RNTupleCardinality") {
918+
// Get "T" from "ROOT::RNTupleCardinality<T>".
919+
std::string cardinalityType = typeName.substr(25, typeName.size() - 26);
920+
Warning("Snapshot",
921+
"Column \"%s\" is a read-only \"%s\" column. It will be snapshot as its inner type \"%s\" instead.",
922+
fInputFieldNames[i].c_str(), typeName.c_str(), cardinalityType.c_str());
923+
model->AddField(ROOT::RFieldBase::Create(fOutputFieldNames[i], cardinalityType).Unwrap());
924+
} else {
925+
model->AddField(ROOT::RFieldBase::Create(fOutputFieldNames[i], typeName).Unwrap());
926+
}
916927
fFieldTokens[i] = model->GetToken(fOutputFieldNames[i]);
917928
}
918929
model->Freeze();

tree/dataframe/test/dataframe_snapshot_ntuple.cxx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,40 @@ TEST(RDFSnapshotRNTuple, TDirectory)
538538
EXPECT_EQ(expected, sdf.GetColumnNames());
539539
}
540540

541+
TEST(RDFSnapshotRNTuple, CardinalityColumns)
542+
{
543+
FileRAII fileGuard{"RDFSnapshotRNTuple_cardinality_columns.root"};
544+
545+
{
546+
auto model = ROOT::RNTupleModel::Create();
547+
548+
model->MakeField<std::vector<Electron>>("electron");
549+
550+
auto cardinalityFld = std::make_unique<ROOT::RField<ROOT::RNTupleCardinality<std::uint32_t>>>("nElectrons");
551+
model->AddProjectedField(std::move(cardinalityFld), [](const std::string &) { return "electron"; });
552+
553+
auto writer = ROOT::RNTupleWriter::Recreate(std::move(model), "ntuple", fileGuard.GetPath());
554+
auto electron = writer->GetModel().GetDefaultEntry().GetPtr<std::vector<Electron>>("electron");
555+
556+
for (unsigned i = 0; i < 5; ++i) {
557+
*electron = {Electron{1.f * i}, Electron{2.f * i}, Electron{3.f * i}};
558+
writer->Fill();
559+
}
560+
}
561+
562+
ROOT::RDF::RSnapshotOptions opts;
563+
opts.fMode = "UPDATE";
564+
opts.fOutputFormat = ROOT::RDF::ESnapshotOutputFormat::kRNTuple;
565+
ROOT::RDataFrame df("ntuple", fileGuard.GetPath());
566+
567+
ROOT_EXPECT_WARNING(df.Snapshot("ntuple_snap", fileGuard.GetPath(), "", opts), "Snapshot",
568+
"Column \"nElectrons\" is a read-only \"ROOT::RNTupleCardinality<std::uint32_t>\" column. It "
569+
"will be snapshot as its inner type \"std::uint32_t\" instead.");
570+
571+
ROOT::RDataFrame sdf("ntuple_snap", fileGuard.GetPath());
572+
EXPECT_EQ("std::uint32_t", sdf.GetColumnType("nElectrons"));
573+
}
574+
541575
class RDFSnapshotRNTupleFromTTreeTest : public ::testing::Test {
542576
protected:
543577
const std::string fFileName = "RDFSnapshotRNTuple_ttree_fixture.root";

0 commit comments

Comments
 (0)