Dear ROOTers,
I have a class XDataTreeInfo:
class XDataTreeInfo: public XTreeInfo {
protected:
Int_t fNQuantiles; //number of quantiles
Double_t *fQuantiles; //[fNQuantiles] Array of quantile values
Double_t *fIntenQuant; //[fNQuantiles] Array of intensity quantiles
public :
XDataTreeInfo();
XDataTreeInfo(const char *name, const char *title);
virtual ~XDataTreeInfo();
virtual void AddUserInfo(Int_t nquant, Double_t *q, Double_t *quant);
ClassDef(XDataTreeInfo,2)
};
As you see this class contains two dynamic arrays.
I am adding this class to my trees using:
void XGeneChipHyb::AddDataTreeInfo(TTree *tree, const char *name, Int_t nquant, Double_t *q, Double_t *quant)
{
XDataTreeInfo *info = new XDataTreeInfo(name, "");
info->AddUserInfo(nquant, q, quant);
tree->GetUserInfo()->Add(info);
}//AddDataTreeInfo
Then I am writing the trees to a root file in method ReadData().
It is also possible to export the user info using method ExportDataTreeInfo().
The relevant code is shown here:
class XDataTreeInfo: public XTreeInfo {
protected:
Int_t fNQuantiles; //number of quantiles
Double_t *fQuantiles; //[fNQuantiles] Array of quantile values
Double_t *fIntenQuant; //[fNQuantiles] Array of intensity quantiles
public :
XDataTreeInfo();
XDataTreeInfo(const char *name, const char *title);
virtual ~XDataTreeInfo();
virtual void AddUserInfo(Int_t nquant, Double_t *q, Double_t *quant);
ClassDef(XDataTreeInfo,2) //DataTreeInfo
};
//______________________________________________________________________________
XDataTreeInfo::XDataTreeInfo()
:XTreeInfo()
{
fNQuantiles = 0;
fQuantiles = 0;
fIntenQuant = 0;
//?? fQuantiles = new Double_t[fNQuantiles]; //since default constructor called for permanent obj??
//?? fIntenQuant = new Double_t[fNQuantiles]; //since default constructor called for permanent obj??
}//Constructor
//______________________________________________________________________________
XDataTreeInfo::XDataTreeInfo(const char *name, const char *title)
:XTreeInfo(name, title)
{
fNQuantiles = 7;
fQuantiles = new Double_t[fNQuantiles];
fIntenQuant = new Double_t[fNQuantiles];
}//Constructor
//______________________________________________________________________________
XDataTreeInfo::~XDataTreeInfo()
{
if (fIntenQuant) {delete [] fIntenQuant; fIntenQuant = 0;}
if (fQuantiles) {delete [] fQuantiles; fQuantiles = 0;}
}//Destructor
//______________________________________________________________________________
void XDataTreeInfo::AddUserInfo(Int_t nquant, Double_t *q, Double_t *quant)
{
if (nquant > fNQuantiles) {
if (fIntenQuant) {delete [] fIntenQuant; fIntenQuant = 0;}
if (fQuantiles) {delete [] fQuantiles; fQuantiles = 0;}
fQuantiles = new Double_t[nquant];
fIntenQuant = new Double_t[nquant];
}//if
fNQuantiles = nquant;
memcpy(fQuantiles, q, nquant*sizeof(Double_t));
memcpy(fIntenQuant, quant, nquant*sizeof(Double_t));
}//AddUserInfo
//______________________________________________________________________________
//______________________________________________________________________________
void XGeneChipHyb::AddDataTreeInfo(TTree *tree, const char *name,
Int_t nquant, Double_t *q, Double_t *quant)
{
XDataTreeInfo *info = new XDataTreeInfo(name, "");
info->AddUserInfo(nquant, q, quant);
tree->GetUserInfo()->Add(info);
}//AddDataTreeInfo
//______________________________________________________________________________
Int_t XGeneChipHyb::ReadData(ifstream &input, Option_t *option, const char * /*sep*/,
char delim, Int_t split)
{
char nextline[kBufSize];
Int_t i, x, y;
Double_t inten, stdev;
Int_t nquant = 7;
Double_t q[] = {0.0, 0.1, 0.25, 0.5, 0.75, 0.9, 1.0};
Double_t *quantI = 0;
if (!(quantI = new (nothrow) Double_t[nquant])) return errInitMemory;
// Create data tree
TString exten = Path2Name(option, ".", "");
fDataTreeName = fTreeName + "." + exten;
TTree *datatree = new TTree(fDataTreeName, fSchemeName);
if (datatree == 0) return errCreateTree;
XGCCell *cell = new XGCCell();
Int_t bufsize = XManager::GetBufSize();
datatree->Branch("DataBranch", "XGCCell", &cell, bufsize, split);
// Read header line containing column names
input.getline(nextline, kBufSize, delim);
if (strncmp("CellHeader=", nextline, 11) != 0) return errMissingLine;
// Read data and store in data tree
for (i=0; i<fNCells; i++) {
input.getline(nextline, kBufSize, delim);
if (!input.good()) {err = errPrematureEOF; break;}
sscanf(nextline,"%i %i %lf %lf %hi", &x, &y, &inten, &stdev);
// fill data tree
cell->SetX(x);
cell->SetY(y);
cell->SetIntensity(inten);
cell->SetStdev(stdev);
datatree->Fill();
}//for_i
// Write data tree to file
AddDataTreeInfo(datatree, datatree->GetName(), nquant, q, quantI);
WriteTree(datatree, TObject::kOverwrite);
// Delete data tree from RAM
datatree->Delete("");
datatree = 0;
delete cell;
if (quantI) {delete [] quantI; quantI = 0;}
return errNoErr;
}//ReadData
//______________________________________________________________________________
Int_t XGeneChipHyb::ExportDataTreeInfo(Int_t n, TString *names,
ofstream &output, const char *sep)
{
// Get trees
TTree **tree = new TTree*[n];
XDataTreeInfo **info = new XDataTreeInfo*[n];
if (fTrees->GetSize() == 0) {
// Get trees from names
for (Int_t k=0; k<n; k++) {
tree[k] = (TTree*)gDirectory->Get((names[k]).Data());
if (!tree[k]) return errGetTree;
info[k] = (XDataTreeInfo*)tree[k]->GetUserInfo()->At(0);
}//for_k
}//if
// Output header
output << "Parameter";
for (Int_t k=0; k<n; k++) output << sep << names[k].Data();
output << endl;
// Output parameters
output << "NQuantiles";
for (Int_t k=0; k<n; k++) output << sep << (Int_t)(info[k]->GetValue("fNQuantiles"));
output << endl;
Double_t **quant = new Double_t*[n];
Double_t **inten = new Double_t*[n];
for (Int_t k=0; k<n; k++) {
quant[k] = info[k]->GetQuantiles();
inten[k] = info[k]->GetIntenQuantiles();
}//for_k
Int_t nq = (Int_t)(info[0]->GetValue("fNQuantiles"));
for (Int_t i=0; i<nq; i++) {
TString str; str.Form("Intensity_Q%4.2f", quant[0][i]);
output << str.Data();
for (Int_t k=0; k<n; k++) output << sep << inten[k][i];
output << endl;
}//for_i
delete [] inten;
delete [] quant;
for (Int_t k=0; k<n; k++) {
//no! SafeDelete(info[k]);
SafeDelete(tree[k]);
}//for_k
delete [] info;
delete [] tree;
return errNoErr;
}//ExportDataTreeInfo
Although I have run my program using valgrind and did not find any problem, I want to make sure
that everything is ok, thus I have the following questions:
1, Is it ok that I define the default constructor as follows:
XDataTreeInfo::XDataTreeInfo():XTreeInfo()
{
fNQuantiles = 0;
fQuantiles = 0;
fIntenQuant = 0;
}
or do I need to init the arrays as in the constructor:
XDataTreeInfo::XDataTreeInfo(const char *name, const char *title):XTreeInfo(name, title)
{
fNQuantiles = 7;
fQuantiles = new Double_t[fNQuantiles];
fIntenQuant = new Double_t[fNQuantiles];
}
The reason I am asking is that when I export the user info from the trees stored in the root
file, then the default contructor is called.
2, In method AddDataTreeInfo() I am creating:
XDataTreeInfo *info = new XDataTreeInfo(name, "");
but do not delete it. I am not sure if this is ok although the help for TTree:GetUserInfo() says:
“By default the TTree destructor will delete all objects added to this list.”
I would appreciate if you could tell me whether my code is correct or if there are some hidden problems.
Thank you in advance
Best regards
Christian