TTree Generated with surplus sub branches

Hello,

I am writing a C++ program that reads in an ASCII file containing the output of a micro black hole simulation run under the program BlackMax (projects.hepforge.org/blackmax/) and stores it as a TTree within a root TFile.

A simplified version ot the tree would be as follows:

Tree Name: BlackMaxData
-Branch: Event_
–Leaf: fEvent_Number (Integer) – Identifies black hole to which a particle belongs.
–Leaf: fNumber_Particles (Integer) – Identifies the number of particles produced by each event/black hole.
–Leaf: fPbhMass (Float) – Mass of the black hole determined from the black holes momentum.
–Sub-branch: fParticle – Contains information on the individual particles emitted per event/black hole.
—Leaf: fType (String) – Type of particle (Parent: Particle that produces bh; —Leaf: fPDGid (Integer) – Particle type using the Particle Data Group Naming system
—Leaf: fColor_Charge[3] (Integer Array) – Colour charge of the particle.
—Leaf: fEnergy_Momentum (Pointer toFloat Array) – Energy-Momentum vector of the particle.
—Leaf: fEPArraySize (Integer) – Magnitude of the fEnergy_Momentum array consisting of at least 4 components (1 Energy + 3 Momentum: Px, Py, Pz) Plus optional additional dimentions.

The details of the above listed structure are not relevant, but merely provided to give context to my problem and code.

My code succeeds in transferring the data from the ASCII format input file to the above described TTree, but creates surplice entries within the fParticle branch. I suspect this is due to my inability to correctly use/write the class destructor that corresponds to the Particle class I have written to describe the structure of this sub-branch. I have tried to synthesize the program as much as possible whilst having it remain fully operational so as to post it here.

I have provides an example of the input file the program reads, it is counter intuitively named “output.txt” as that is how the files are named when generate by BlackMax. The sample file contains 5 events and 61 particles. My code however creates a tree with 5 entries within “Event_”, but 68 entries within “fParticle”.

Any help would be appreciated as there is nobody at my university department with sufficient knowledge of root to help me resolve this issue.

Thank you in advance,

Aitzol Casado

//Event.h////////////////////////////////////////////////////////////
#ifndef Event_H
#define Event_H
#include <fstream>
#include <cstring>
#include <TObject.h>
#include <TTree.h>
#include <TClonesArray.h>
using namespace std;

//Particle
class Particle : public TObject{
 private :
  string        fType;
  Int_t         fPDGid;
  Int_t         fColor_Charge[3];
  Int_t         fEPArraySize;
  Double_t     *fEnergy_Momentum; // [fEPArraySize]
  
 public:
  Particle();
  Particle(Int_t, ifstream &, string, Double_t &);
  virtual ~Particle();
  void          ParentBuild(ifstream &);
  void          PbhBuild(Int_t, ifstream &, Double_t &);
  void          PemBuild(Int_t, ifstream &);
  void          ElastBuild(ifstream &);

 ClassDef(Particle,1)
};

//Event
class Event : public TObject{
 private :
  Int_t         fEvent_Number;
  Int_t         fNumber_Particles;
  Double_t      fPbhMass;
  TClonesArray *fParticle;
  static        TClonesArray *fgParticles;
  
 public:
  Event();
  virtual      ~Event();
  void          Build(Int_t, TTree *, ifstream &);

 ClassDef(Event,1)
};
#endif

//Event.cc///////////////////////////////////////////////////////////
#include <TObject.h>
#include <TTree.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include "Event.h"

ClassImp(Particle)
ClassImp(Event)

TClonesArray *Event::fgParticles = 0;

using namespace std;

// Particle
Particle::Particle()
{
  fType  = "";
  fPDGid = 0;
  for(int i=0; i<3; i++){
    fColor_Charge[i]  = 0;
  }
  fEnergy_Momentum = NULL; 
}

Particle::Particle(Int_t EPArraySize, ifstream &in, string inType, Double_t &fPbhMass) : TObject()
{
  if(inType == "Pbh"){
    PbhBuild(EPArraySize, in, fPbhMass);
  }else if(inType == "Parent"){
    ParentBuild(in);
  }else if(inType == "Pem"){
    PemBuild(EPArraySize, in);
  }else if(inType == "Elast"){
    ElastBuild(in);
  }
}

Particle::~Particle(){
  delete [] fEnergy_Momentum; 
  fEnergy_Momentum=0;   
  printf(" Particle REPORT: Class Destructor Called\n");
}

void Particle::ParentBuild(ifstream & in)
{
  fEPArraySize = 4;
  fEnergy_Momentum = new Double_t[fEPArraySize];
  fType = "Parent";
  in >> fPDGid;
  for(int i=0; i<3; i++){
    in >> fColor_Charge[i];
  }
  for(int i=0; i<fEPArraySize; i++){
    in >> fEnergy_Momentum[i];
  }
}

void Particle::PbhBuild(Int_t EPArraySize, ifstream & in, Double_t & fPbhMass)
{
  fEPArraySize = EPArraySize+1;
  fEnergy_Momentum = new Double_t[fEPArraySize];
  fType = "Pbh";
  in >> fPDGid;
  for(int i=0; i<3; i++){
    in >> fColor_Charge[i];
  }
  for(int i=0; i<fEPArraySize; i++){
    in >> fEnergy_Momentum[i];
    if(i==0){
      fPbhMass = fEnergy_Momentum[i]*fEnergy_Momentum[i];
    }else{
      fPbhMass-= fEnergy_Momentum[i]*fEnergy_Momentum[i];
    }
  }
  cout << "    Particle REPORT: Event Black Hole Mass^2:" << fPbhMass << endl;
  fPbhMass = sqrt(fPbhMass);
  cout << "    Particle REPORT: Event Black Hole Mass  :" << fPbhMass << endl;
}

void Particle::PemBuild(Int_t EPArraySize, ifstream & in)
{
  fEPArraySize = EPArraySize;
  fEnergy_Momentum = new Double_t[fEPArraySize];
  fType = "Pem";
  in >> fPDGid;
  for(int i=0; i<3; i++){
    in >> fColor_Charge[i];
  }
  cout << "    Particle REPORT: Pem,   fEnergy_Momentum =";
  for(int i=0; i<fEPArraySize; i++){
    in >> fEnergy_Momentum[i];
    cout << " " << fEnergy_Momentum[i];
  }
  cout << endl;
}

void Particle::ElastBuild(ifstream & in)
{
  fEPArraySize = 4;
  fEnergy_Momentum = new Double_t[fEPArraySize];
  fType = "Elast";
  in >> fPDGid;
  for(int i=0; i<3; i++){
    in >> fColor_Charge[i];
  }
  cout << "    Particle REPORT: Elast, fEnergy_Momentum =";
  for(int i=0; i<fEPArraySize; i++){
    in >> fEnergy_Momentum[i];
    cout << " " << fEnergy_Momentum[i];
  }
  cout << endl;
}

// Event
Event::Event()
{
  fEvent_Number  = 0;
  fNumber_Particles = 0;

  if (!fgParticles) fgParticles = new TClonesArray("Particle", 1000);
  fParticle = fgParticles;
}

Event::~Event(){
  printf(" Event REPORT: Class Destructor Called\n");
}

void Event::Build(Int_t EPArraySize, TTree *tree, ifstream & in)
{
  cout << "   \n******************************************************************************\n";
  cout << "   Event REPORT: Event.Build(Int_t EPArraySize, TTree *tree, ifstream & in) Initiated, Event #";

  string inType;     in >> inType;
  Int_t  inEvntNmbr; in >> inEvntNmbr;
  Int_t  oldEvntNmbr = inEvntNmbr;
  Particle *particle = 0;

  cout << inEvntNmbr << endl;

  while(oldEvntNmbr==inEvntNmbr && in.good()){

    TClonesArray &particles = *fParticle; // &particles is the list of all particles in "THIS" event
    particle = new(particles[fNumber_Particles++]) Particle(EPArraySize, in, inType, fPbhMass);

    in >> inType;
    in >> inEvntNmbr;   
  }

  fEvent_Number = oldEvntNmbr;
  for(int i=0; i<14; i++){in.unget();}

  cout << "   Event REPORT: Event contains the folowing number of particles:" << fNumber_Particles << endl;
  cout << "   Event REPORT: Event.Build(Int_t EPArraySize, TTree *tree, ifstream & in) Finished" << endl;
}

//treeGen.cc/////////////////////////////////////////////////////////

#include <iostream>
#include <fstream>
#include <cstring>
#include <TFile.h>
#include <TTree.h>
#include "Event.h"
#include "treeGenFunctions.h"

using namespace std;

int main(){

 printBanner();

 char fileName[]="bmData.root", treeName[]="BlackMaxData", branchName[]="Event_", dataName[]="output.txt";

  //Generating File
  TFile * file = TFile::Open(fileName, "RECREATE", "A BlackMax simulation File"); //chopo look at TFile Open
  cout << " fileGen REPORT: File \"" << fileName << "\" created" << endl;

  TTree * tree= new TTree(treeName,"A BlackMax simulation TTree");
  cout << " fileGen REPORT: Tree \"" << treeName << "\" created" << endl;

  Event * event=0;
  Int_t bsize = 64000;

  tree->Branch(branchName, "Event", &event, bsize, 2);
  cout << " fileGen REPORT: Branch \"" << branchName << "\" created" << endl;

  //This data is includes and estracted from "output.txt" in the full version
  Int_t numberSimulations = 5;
  Int_t EPArraySize  = 5;       // 1 Energy + 3 Momentum (Px, Py, Pz) + 1 Extra dimention 
  
  //Accesing BM Data
  cout << " fileGen REPORT: Accessing \"" << dataName << "\" data" << endl;
  ifstream bmInput;
  bmInput.open(dataName);

    for(Int_t i=0; i<numberSimulations && bmInput.good(); i++){ 

      event = new Event();
      event->Build(EPArraySize, tree, bmInput);
      tree->Fill();
    }

    cout << "\n******************************************************************************\n";
    cout << " fileGen REPORT: Finished populating \"" << branchName << "\" branch" << endl;
    cout << " fileGen REPORT: Finished populating \"" << treeName    << "\" tree" << endl;
    
  bmInput.close();

  cout << "\n******************************************************************************\n\n";
  file->Write();
  cout << " fileGen REPORT: Finished writing to \"" << fileName << "\" file" << endl;
  file->Close();
  cout << " fileGen REPORT: \"" << fileName << "\" Closed" << endl;
  cout << " fileGen REPORT: job Done!\n" << endl;
  return 0;
}

output.txt (5.58 KB)
treeGen.c (1.96 KB)
Event.c (3.89 KB)
Event.h (1.07 KB)

Hi,

The issue is that you use a static TClonesArray but never clear it, hence you accumulate the particle for each events. The simplest solution is to move th e ‘event = new Event();’ outside of the loop and to add at the beginning of Event::Build a line like fgParticles.Clear();

Cheers,
Philippe.

[quote=“pcanal”]Hi,

The issue is that you use a static TClonesArray but never clear it, hence you accumulate the particle for each events. The simplest solution is to move th e ‘event = new Event();’ outside of the loop and to add at the beginning of Event::Build a line like fgParticles.Clear();

Cheers,
Philippe.[/quote]

Hi, pcanal

Thanks so much, I tried adding and removing “delete Particle” and “delete Event” all over my code with no effect (hence the lack of even destructors that I will immediately add), but never though the cultrate could be the TClonesArray. I have however amended the code slightly differently than how you recommended as I (bizarrely) found a huge performance hit when I removed the Event() constructor from the loop it’s in. Instead I have reinstated a “delete Event” command after the fill function (not present in the code I posted) at the end of the loop and added modified the Event destructor to delete fgParticles when called.

I’ll post my new code tomorrow after I clean it up.

Thanks Again, pcanal

Aitzol