I am trying to ignore (i.e. don’t bother loading the data into memory) specific fields of an RNTuple when reading a file. I can do this if I already know the type of all the fields I want by creating my own RNTupleModel and giving that model to the RNTupleReader, but I’m wondering if there is a way to ignore fields without needing to specify the types of all of the other fields.
Context: I am working on updaing the LDMX-Software/ldmx-sw Framework to use RNTuple instead of TTree (mock-up framework on Codeberg) and one feature that I would like to carry forward is ignoring branches/fields to (hopefully) improve reading performance without needing to create a separate copy/skim of the data. To be honest, I’m not even certain that the current TTree Framework correctly implements this “ignoring”, but I’d like to try to mimic the idea if possible with RNTuple.
ROOT Version: 6.38.00
Built for linuxx8664gcc on Nov 27 2025, 09:05:19
From tags/v6-38-00@v6-38-00
I’ve uploaded the source code I’m using to try to mock-up this “ignoring” feature separate from the rest of the framework. It is a copy of src/ignore.cxx in the mock-up framework linked above. ignore.cxx (3.3 KB)
In that code, I test various different reading methods and then printout the number of bytes read (szReadPayload + szReadOverhead) to check how much data was actually “looked at” by the reader. I test reading a single 10-entry RNTuple with two fields: "to_keep" and "to_ignore". In the discussion below, I am omitting all of the instrumentation code for brevity.
naive
The naive reading method is to only GetPtr for the fields I care about. In this example, that is the field "to_keep". This is effectively what is done in the RNTuple skim example.
auto reader = ROOT::RNTupleReader::Open(TUPLENAME, FILEPATH);
auto keep = reader->GetModel().GetDefaultEntry().GetPtr<int>("to_keep");
for (auto i: *reader) {
reader->LoadEntry(i);
}
This reads 96B which I guess is the amount for both “to_keep” and “to_ignore” which I deduce from below.
own model
If I construct my own model and provide that model to the RNTupleReader, then I can half the number of bytes read.
auto model = ROOT::RNTupleModel::Create();
auto to_keep = model->MakeField<int>("to_keep");
reader = ROOT::RNTupleReader::Open(std::move(model), TUPLENAME, FILEPATH);
for (auto i : *reader) {
reader->LoadEntry(i);
}
This reports reading only 48B which makes me think it is effectively ignoring "to_ignore" while reading.
view
For what its worth, I can also have the reader only read 48B by using GetView.
auto view = reader->GetView<int>("to_keep");
for (auto i : reader->GetEntryRange()) {
view(i);
}
I’m reluctant to use GetView in the framework since I forsee integrating it to be difficult. I would probably drop this “ignore” feature instead of trying to integrate GetView to be honest.
skimmed model
Now the actual issue. I would like to be able to read "to_keep" and only "to_keep" without needing to specify the type of "to_keep". My first attempt to do this was just to try to create a model after opening the file and then re-opening the RNTupleReader with the updated model. This attempt fails with the error message fixed column representative only valid when connecting to a page sink.
auto reader = ROOT::RNTupleReader::Open(TUPLENAME, FILEPATH);
auto model = ROOT::RNTupleModel::Create();
for (auto& value : reader->GetModel().GetDefaultEntry()) {
if (value.GetField().GetFieldName().find("ignore") != std::string::npos) {
continue;
}
const auto& name = value.GetField().GetFieldName();
model->AddField(value.GetField().Clone(name));
model->GetDefaultEntry().BindValue<void>(name, value.GetPtr<void>());
}
reader = ROOT::RNTupleReader::Open(std::move(model), TUPLENAME, FILEPATH);
auto keep = reader->GetModel().GetDefaultEntry().GetPtr<int>("to_keep");
reader->EnableMetrics();
for (auto i: *reader) {
reader->LoadEntry(i);
}
Is there a way to construct this “subset” RNTupleModel from the “full on-disk” model without knowing the types? Or alternatively, can I LoadEntry on only certain fields of the RNTuple like the view does?