How to fill a tree of vector containing structure from ascii file?

Here is sample of how my ascii file looks like (ascii.dat):

comment line
1 2 3
4 5
1 2 3
4 5

Here is my code to read this ascii (macro_ascii.C):

void macro_ascii(Char_t const *InputFile){
  char rootfile[2000];
  int a, b, c, d, e;
  struct fullevent {
    int a; int b; int c;
    int d; int e;
  };

  TFile *froot[150];
  TTree *tree = new TTree("tree","detector data ascii file");
  
  tree->Branch("a",&a,"a/I");
  tree->Branch("b",&b,"b/I");
  tree->Branch("c",&c,"c/I");
  tree->Branch("d",&d,"d/I");
  tree->Branch("e",&e,"e/I");
    
  sprintf(rootfile,"./ascii.root");
  froot[1] = new TFile(rootfile,"RECREATE");
  tree->Reset();
  ifstream aFile(InputFile);
  vector<fullevent> event;
  string txt;

  getline(aFile, txt);//ignore comment line
  
  while (aFile){
    fullevent line;
    aFile >> line.a;
    aFile >> line.b;
    aFile >> line.c;
    aFile >> line.d;
    aFile >> line.e;
    if (aFile){
      event.push_back(line);
      tree->Fill();
    }
  }
  tree->Write();
  froot[1]->Write();
  froot[1]->Close();  
}

When I run in root as following way:
root [0] .x macro_ascii.C("./ascii.dat")
it worked without error and produces the ascii.root file. But when I look at the content of the root file using TBrowser it shows garbage filled in my tree variables (I mean it is not the same values as I have in my ascii.dat file). See the root file attached I uploaded:
ascii.root (5.5 KB)

Please help, thank you !

PS: I found following post which seem to be similar problem as I have but I am not good enough programmer to understand it.

Hi,
there are a few weird things in this macro (why do you call TTree::Reset? why do you use a char[] and sprintf instead of std::string? why do you declare a c-style array of 150 TFiles and then only use the second (the one at index 1)?) but the origin of your problem is simple:

you are linking your TTree tree to variables a,b, etc but you never set the values of those variables!
In your while loop you need to set a,b etc. to the new values and then call TTree::Fill. You never created a branch that reads values from your event vector.

You can also take a look at ROOT’s TTree tutorials and see how things are done there.
Hopes this helps,
Enrico

thanks @eguiraud, you saved me a lot of time. With your suggestions, I made changes and it works as I want. See below the new macro and if you have still better suggestions/commend to improve, much appreciated:

 void macro_ascii(Char_t const *InputFile){
  char rootfile[2000];
  vector<int> a, b, c, d, e;
  struct fullevent {
    int aa; int bb; int cc;
    int dd; int ee;
  };

  TFile *froot;
  TTree *tree = new TTree("tree","detector data ascii file");
  
  tree->Branch("a",&a);
  tree->Branch("b",&b);
  tree->Branch("c",&c);
  tree->Branch("d",&d);
  tree->Branch("e",&e);
    
  sprintf(rootfile,"./ascii.root");
  froot = new TFile(rootfile,"RECREATE");
  ifstream aFile(InputFile);
  vector<fullevent> event;
  string txt;

  getline(aFile, txt);//ignore comment line
  
  while (aFile){
    fullevent line;
    aFile >> line.aa;
    aFile >> line.bb;
    aFile >> line.cc;
    aFile >> line.dd;
    aFile >> line.ee;
    if (aFile){
      event.push_back(line);
      a.push_back(line.aa);
      b.push_back(line.bb);
      c.push_back(line.cc);
      d.push_back(line.dd);
      e.push_back(line.ee);
    }
  }      tree->Fill();
  
  tree->Write();
  froot->Write();
  froot->Close();  
}

Hi Gunn,
your code cannot work as intended.
You have to be aware of what the lines you write do.

If you think of your data as being laid out in a table, you can think of a TTree entry as a table row and of each TTree branch as a column of that table. In your latest snippet, each of your branches/columns (a, b, etc.) are now vectors. This means that each cell of the table, for a given row and a given column, will contain a vector.

Your macro makes these vectors longer and longer with push_back and each time you add an element you save their current status in an row/entry of your tree. You end up with a TTree in which each entry contains longer and longer vectors, the subsequent ones adding one new element to the ones before.

Here’s a snippet that fills each entry of the TTree with five integers (one per branch, I have not tested the code):

 void ascii_to_ttree(std::string input_filename){
  // create output file and output tree
  TFile froot("out.root","RECREATE");
  TTree tree("tree","detector data ascii file");

  // create five `int` branches "linked" to the five `int` variables
  int a, b, c, d, e;
  tree->Branch("a",&a);
  tree->Branch("b",&b);
  tree->Branch("c",&c);
  tree->Branch("d",&d);
  tree->Branch("e",&e);
  
  // loop over ascii file, save each row as a TTree entry
  std::ifstream infile(input_filename);
  while (infile){
    infile >> a >> b >> c >> d >> e;
    tree->Fill();
  }

  // write to disk
  tree->Write();
  froot->Close();  
}
1 Like

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