Wrong return value of AnalysisReader::SetNtupleXColumn()?

Hi all

Probably a question for @ivana

I would like to read ntuple data from a previously created (also with Geant4) ROOT ntuple:

...
auto analysisReader = G4RootAnalysisReader::Instance();
analysisReader->SetFileName(fFileName);
G4int id = analysisReader->GetNtuple(fNtupleName);
fHasTime = analysisReader->SetNtupleFColumn("time", fTime);
...

Surprisingly fHasTime is true even if the branch “time” doesn’t exist in the ntuple. Also, the following error is issued when calling G4RootAnalysisReader::GetNtupleRow():

tools::rroot::ntuple::initialize : error : for column binding with name “time”, no ntuple column found.

IMHO the SetNtupleXColumn() methods should return false when the column doesn’t exist and in this case no binding should be made so later no error will be produced.

Alternatively, one could introduce an easy top-level method to check the existence of a column in an ntuple.

Many thanks
Dominik

Geant4 Version: geant4-11-04-patch-01
Operating System: RHEL 9
Compiler/Version: gcc (GCC) 11.5.0 20240719 (Red Hat 11.5.0-14)
CMake Version: 3.31.8


Hello Dominik,

Indeed, the SetNtupleXColumn functions are defined with the G4bool return type; however as at this phase the analysis reader cannot evaluate success or failure of this operation, it always returns true and it is useless for the users to get and test this value.

The success/failure of reading is returned only by the GetNtupleRow when the reading really happens.

We can better change the G4bool return type to void in the next version, to avoid this confusion.

Best regards,

Hi Ivana

Thanks for your reply. I agree that changing the return type to voidwould make things clearer although a correct Boolean after the required check would of course be preferable. The following code basically does the job for flat ntuples in the top directory of a ROOT file:

#include "tools/rroot/file"
#include "tools/rroot/fac"
#include "toolx/zlib"

auto rfile = new tools::rroot::file(G4cout, fileName);
rfile->add_unziper('Z', toolx::decompress_buffer);
if (!rfile->is_open())
{
  // error handling and clean-up
}

auto key = rfile->dir().find_key(ntupleName);
if (!key)
{
  // error handling and clean-up
}

unsigned int size;
char* charBuffer = key->get_object_buffer(*rfile, size);
if (!charBuffer)
{
  // error handling and clean-up
}
G4bool verbose = false;
auto buffer = new tools::rroot::buffer(G4cout, rfile->byte_swap(), size, charBuffer, key->key_length(), verbose);
buffer->set_map_objs(true);
auto fac = new tools::rroot::fac(G4cout);
auto tree = new tools::rroot::tree(*rfile, *fac);
if (!tree->stream(*buffer))
{
  // error handling and clean-up
}

if (tree->find_branch(branchName))
{
  // branch/column is present
}

It would be great it this could somehow be integrated in the official codebase.

Cheers
Dominik