Save std::vector<std::string> Ntuple to file

Hello everyone,

I am currently trying to implement an Ntuple column with the vector for each event of the energy deposition for each hit. This work smoothly when I want to save, for example, the energy deposition itself:

analysisManager -> CreateNtupleDColumn("E_dep", fEventAction->GetEdep());

for which I obtain the expected Ntuple column and when visualize it, I see a distribution of the deposited energy in each hits, for a total of 2068 hits over 10 events.

The issue is when I try to save a vector, as it should be allowed since GEANT4 v11 (I am using v11.0.3). I create a column in RunAction::BeginOfRunAction() like the following:

analysisManager -> CreateNtupleSColumn("depProc", fEventAction->GetDepositionProcess());

where analysisManager is an instance of G4RootAnalysisManager. The function called is:

vector<string>& GetDepositionProcess() {return fvec_depProcess;}

When I check the output, I would expect to have a string for each hit, but what I see is that I have a unique long string joining all the output for each hit, like the following:

You can see that instead of having 2068 entries as before, I have 10 entries and each one is just a long string of all the individual processes in an event (“msc”,“eIon”,…). Is this normal and I simply need to take care of it in a second stage, or am I doing something wrong?

I have never used this feature, but according to the manual vectors of strings are not supported, only for integers floats and doubles.

I have seen that, but in the release notes of version 11 it says that now vectors of strings are implemented (see section 4, analysis). Maybe they are not implemented for G4ROOTAnalysisManager and it is simply casting the vector<string> to a string?


Vectors of strings are supported with Root output, but they need to be read in ROOT in a special way. You can find a complete test in g4tools test.

Below I give an example of code that reads an ntuple including columns of doubles, vector of doubles, strings and vector of strings using Root:

// open Root file
TFile f("myFile.root");

// get ntuple as TTree
TTree* tree = (TTree*)f.Get("myTree");

// column of double
double eabs;

// column of vector of double
std::vector<double>* edepVector = new std::vector<double>();

// column of strings
char* label;
TLeafC* leafLabel = (TLeafC*)tree->GetLeaf("Label");

// column of vector of strings
char* labelVector;
TLeafC* leafLabelVector = (TLeafC*)tree->GetLeaf("LabelVector");

// Get number of entries (events)
int num = tree->GetEntries();
std::cout << "number of events = " << num << std::endl;

// Read events in a loop
for(int i=0;i<num;i++) {


   std::cout << i << "th entry: " << std::endl;

   // print Eabs, EdepVector
   std::cout << "EAbs: " << eabs << std::endl;
   for (auto edep : *edepVector) {
      std::cout << "EdepVector element: " << edep << std::endl;

    // print label
    if(leafLabel) {
      char* labelChar = leafLabel->GetValueString();
      std::cout << "label: " << std::string(labelChar) << std::endl;

   // print labelVector
   if(leafLabelVector) {
      char* labelVectorChar = leafLabelVector->GetValueString();
      std::vector<std::string> labelVectorString;
      tools::get_lines(labelVectorChar, labelVectorString);
           // this converts the vector of chars into vector of strings
      for (auto label : labelVectorString) {
         std::cout << "LabelVector element: " << label << std::endl;

There is used `get_lines` function from tools, that you can get from Geant4 source (geant4/source/externals/g4tools/include/tools) and copy in your working directory together with `cstr` and include this file in your Root macro.

Best regards,
1 Like

So this is more an “issue” at ROOT level and how they are to be read from a TTree.

Thank you very much for the example and your help!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.