Writing a user-defined class to a TTree

Hi all. I’m new to root, and as part of my introduction to it, I’ve been trying to write a user-defined class (my class is named ‘Measurement’) to a TTree. My class is very simple and only contains a vector called ‘measurements’, a double called ‘average’, and an int called ‘counter’. I’ve written a for loop that on each iteration, sets each element of the vector (the size of the vector is randomized each on iteration) to a random value based on a gaussian distribution centered at 511.0. On each iteration of the for loop, I write the class to a tree. However, when I run this program, root crashes and I am left with the following error message:

“Fatal in TBranchElement::InitializeOffsets: Could not find the real data member ‘measurements’ when constructing the branch ‘data1’ [Likely an internal error, please report to the developers].”

The version of root I’m running is 5.34/.34 and my operating system is Ubuntu 14.04. If anyone has any idea on how to fix this, please let me know. Thank you very much.

Here is my code:

#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>

// Root Header Files
#include "TFile.h"
#include "TTree.h"
#include "TCanvas.h"
#include "TFrame.h"
#include "TRandom.h"
#include "TSystem.h"
#include "TBrowser.h"
#include "TBenchmark.h"
#include "TObject.h"
#include "TH1.h"

#ifdef __MAKECINT__
#pragma link C++ class vector<double>+;
#endif

class Measurement : public TObject {

private:
  vector<Double_t> measurements;
  Double_t average;
  Int_t counter;

public:
  Measurement() {average = 0.0; counter = 0.0;}
  void Measurement::Fill_Vec(Double_t arra[], Int_t length) {
    for (Int_t h = 0; h < length; h++) {
      measurements.push_back(arra[h]);}
  }
  void Measurement::Set_Average() {
    Double_t sum = 0.0;
    for (Int_t y = 0; y < measurements.size(); y++) {
      sum += measurements[y];
    }
    average = sum/(measurements.size());
  }	

  void Measurement::Set_Counter() { counter = measurements.size(); }
  void Measurement::Clear_Vec() { measurements.clear(); }
  void Measurement::Display_Size() { cout << measurements.size() << endl; }
  void Measurement::Display_Content() {
    for (Int_t w = 0; w < measurements.size(); w++) {
      std::cout << measurements[w] << std::endl;}
  }
  void Set_Average(Double_t x) {average = x;}
  void Set_counter(Double_t y) {counter = y;}

ClassDef(Measurement,1);

};

ClassImp(Measurement);


void tree_with_class_write() {
	
  Measurement *data1 = new Measurement();

  srand( time(NULL) );
  
  TCanvas *c = new TCanvas("c","Example Histogram",200,10,700,500);
  c->SetFillColor(42);
  c->GetFrame()->SetFillColor(21);
  c->GetFrame()->SetBorderSize(6);
  c->GetFrame()->SetBorderMode(-1);
  
  TH1F* h1 = new TH1F("h1","Gaussian Distribution (mean = 511; deviation = 15)",100,450,575);
  h1->SetFillColor(75);
  
  TFile *f = new TFile("class_tree.root","recreate");
  TTree *ct = new TTree("class_tree","An example tree using a basic c++ class");
  ct->Branch("data1",&data1);
	
  for (Int_t b = 0; b < 25000; b++) {	
    Int_t n = gRandom->Integer(10);
    Double_t ran[n];

    for (Int_t j = 0; j < n; j++) {
      ran[j] = gRandom->Gaus(511.0,15.0);
      h1->Fill(ran[j]);
    }
	
    data1->Clear_Vec();
    data1->Fill_Vec(ran,n)
    data1->Set_Average();
    data1->Set_Counter();
		
    ct->Fill();
	    
  }
	
  h1->Draw();
  f->Write();
	
  delete f;
  delete c;
  new TBrowser();
  ct->StartViewer();
  
}

void tree_with_class_read() {
	
}


void tree_with_class() {
  gBenchmark->Start("tree_with_class");
	
  tree_with_class_write();
  tree_with_class_read();
	
  gBenchmark->Show("tree_with_class");
}

Hi,

please find attached* reviewed version of your code, to be run with the command “root tree_with_class_C+”.
The important points:
o You were missing the dictionary for Measurement: this was added with the “#pragma link C++ class Measurement+” line.
o The “+” at the end of the macro tells root to compile it with Aclic and actually create the dictionary for Measurement
o The line “ct->StartViewer();” was commented. If you want to start browsing the tree you should take care of its ownership (you delete the file f immediately above).

If not, well done!

Cheers,
Danilo

#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>

// Root Header Files
#include "TFile.h"
#include "TTree.h"
#include "TCanvas.h"
#include "TFrame.h"
#include "TRandom.h"
#include "TSystem.h"
#include "TBrowser.h"
#include "TBenchmark.h"
#include "TObject.h"
#include "TH1.h"

#ifdef __MAKECINT__
#pragma link C++ class Measurement+;
#endif

class Measurement : public TObject {

private:
  vector<Double_t> measurements;
  Double_t average;
  Int_t counter;

public:
  Measurement() {average = 0.0; counter = 0.0;}
  void Fill_Vec(Double_t arra[], Int_t length) {
    for (Int_t h = 0; h < length; h++) {
      measurements.push_back(arra[h]);}
  }
  void Set_Average() {
    Double_t sum = 0.0;
    for (UInt_t y = 0; y < measurements.size(); y++) {
      sum += measurements[y];
    }
    average = sum/(measurements.size());
  }

  void Set_Counter() { counter = measurements.size(); }
  void Clear_Vec() { measurements.clear(); }
  void Display_Size() { cout << measurements.size() << endl; }
  void Display_Content() {
    for (UInt_t w = 0; w < measurements.size(); w++) {
      std::cout << measurements[w] << std::endl;}
  }
  void Set_Average(Double_t x) {average = x;}
  void Set_counter(Double_t y) {counter = y;}

ClassDef(Measurement,1);

};

ClassImp(Measurement);


void tree_with_class_write() {

  Measurement *data1 = new Measurement();

  srand( time(NULL) );

  TCanvas *c = new TCanvas("c","Example Histogram",200,10,700,500);
  c->SetFillColor(42);
  c->GetFrame()->SetFillColor(21);
  c->GetFrame()->SetBorderSize(6);
  c->GetFrame()->SetBorderMode(-1);

  TH1F* h1 = new TH1F("h1","Gaussian Distribution (mean = 511; deviation = 15)",100,450,575);
  h1->SetFillColor(75);

  TFile *f = new TFile("class_tree.root","recreate");
  TTree *ct = new TTree("class_tree","An example tree using a basic c++ class");
  ct->Branch("data1",&data1);

  for (Int_t b = 0; b < 25000; b++) {
    Int_t n = gRandom->Integer(10);
    Double_t ran[n];

    for (Int_t j = 0; j < n; j++) {
      ran[j] = gRandom->Gaus(511.0,15.0);
      h1->Fill(ran[j]);
    }

    data1->Clear_Vec();
    data1->Fill_Vec(ran,n);
    data1->Set_Average();
    data1->Set_Counter();

    ct->Fill();

  }

  h1->Draw();
  f->Write();

  delete f;
  delete c;
//  new TBrowser();
//  ct->StartViewer();

}

void tree_with_class_read() {

}


void tree_with_class() {
  gBenchmark->Start("tree_with_class");

  tree_with_class_write();
  tree_with_class_read();

  gBenchmark->Show("tree_with_class");
}

Thank you very much, that fixed the problem!