Problem in saving vector< vector <float> > into a TTree

Dear Rooters,

I have got a problem in saving (generated) detector signals into a TTree. The signals are copied to 2d-vectors of type std::vector< vector> (each channel == one 1d vector), but should be saved as 1d vectors of type std::vector.
The signal generator works fine, the signals are passed properly to the method, which will fill the vectors into the TTree, but their content is not saved. Saving std::vector directly into the Tree works fine (see the pGlTime vector of the attached code).
I attached a minimal (not) working example. Don’t be confused by creating the signals as local pointers and passing them to global variables. The code was extracted from a more complex QtRoot application.

Thanks in advance for your suggestions.

[code]//macro to save vector in TTree
//std. c includes
#include <stdlib.h>
#include <stdio.h>
#include

//root includes
#include “TTree.h”
#include “TFile.h”
#include “TBranch.h”
#include “TSystem.h”

//global Variable definition
std::vector *pGlTime;
std::vector <vector > *pGlSignalVector;

TTree *pGlSignalTree;
TFile *pGlFile;

using namespace std;

//______________________________________________________________________________
void FillTTreeAcq()
{ //main method
//define signal characteristics
unsigned int NumEvents = 10000,
NumChannels = 1,
NumSamples = 1000,
BaseLine = 100,
Width = 300;
double Offset[] = {0.4,0.3,0.2,0.1};

//init global signal vectors
pGlTime         = new vector<float>();
pGlSignalVector = new vector <vector <float> >();
    pGlSignalVector->resize(4);

//define and init local signal vector
vector <float>              *pTime = new vector <float>();
vector <float>              *pSignal = new vector <float>();
vector <vector <float> >    *pSignalVector = new vector <vector <float> >();

//initializise the TFile and the TTree
init_TTree(NumChannels, NumSamples);
    
//fill the time vector
for (unsigned int i_sa=0; i_sa<NumSamples; i_sa++)
   pTime->push_back(i_sa);

//define loop variables
unsigned int Event, i_ch;
//event loop  
for (Event=0; Event<NumEvents; Event++)
{   //loop over channels
    for (i_ch=0; i_ch<NumChannels; i_ch++)
    {   //generate signal and fill it to pSignal
        GenerateSignal( pSignal, NumSamples, BaseLine, Width, Offset[i_ch]);
        pSignalVector->push_back(*pSignal);
    }
    
    //record the signals
    RecordSignals(*pTime, *pSignalVector);

    gSystem->ProcessEvents();
    //clear the signal vector
    pSignalVector->clear();
}

//write the TTree to TFile, close the TFile
pGlSignalTree->Write();
pGlFile->Close();

}

//______________________________________________________________________________
double init_TTree(unsigned int NumChannels, unsigned int NumSamples)
{ //method to init the TTree
char tree_name[100] = “”;
char tree_description[100] = “”;
char branch_name[100] = “”;

//(re-)create  TFile
pGlFile = new TFile("Data.root", "RECREATE");

//set name and description of the TTree
sprintf(tree_name, "Signals");
sprintf(tree_description, "Tree containing signals from a generator");

//create the TTree
pGlSignalTree = new TTree(tree_name, tree_description);
    pGlSignalTree->Branch("time", &pGlTime, NumSamples, 0);
    for (int i_ch=0; i_ch<NumChannels; i_ch++)
    {   sprintf(branch_name, "channel%i",i_ch+1);
        pGlSignalTree->Branch(branch_name, &pGlSignalVector->at(i_ch), 
                              NumSamples,0);
    }

return 0;

}

//______________________________________________________________________________
void RecordSignals(vector pTime, vector< vector > pSignalVector)
{ //method to copy the produced signals into global variables and filling of
//the tree with them

//copy local to global vectors
pGlTime         = &pTime;
pGlSignalVector = &pSignalVector;

//ouput

// for (int i_ch=0; i_ch<1; i_ch++)
// for (int i_sa=0; i_saat(i_ch).size(); i_sa++)
// cout << "Channel: " << i_ch << “\t”
// << pGlSignalVector->at(i_ch).at(i_sa) << endl;

//Fill the TTree
pGlSignalTree->Fill();

//clear the global vectors
pGlTime->clear();
pGlSignalVector->clear();

}

//______________________________________________________________________________
void GenerateSignal(vector *pSignal, int Length, int BaseLine,
int Width, double Offset)
{ // method to create a logic signal with noise
////////////////////////////////////////////////////////////////////////////////

// <------------------------Length--------------------------------->
// <—BaseLine---->
// Offset ________________ _____________________________________
// H | |
// e | |
// i | |
// g | |
// h | |
// t -------------
// <–Width–>

////////////////////////////////////////////////////////////////////////////////
// double Height = gRandom->Uniform(0,-0.8);
double Height = gRandom->Gaus(-0.4, 0.1);
double noise;

//clear vector
pSignal->clear();

for (int sample=0; sample<Length; sample++)
{   //Baseline
    if (sample<BaseLine)
    {   noise = gRandom->Gaus(Offset, fabs(0.01*Height));
        pSignal->push_back(noise);
    }
    //signal
    else if (sample<BaseLine+Width)
    {   noise = gRandom->Gaus(Offset+Height, fabs(0.01*Height));
        pSignal->push_back(noise);
    }
    //rest
    else
    {   noise = gRandom->Gaus(Offset, fabs(0.01*Height));
        pSignal->push_back(noise);
    }
}

return;

}[/code]
FillTTreeAcq.cpp (5.89 KB)

In “RecordSignals” you overwrite “pGlSignalVector”.

This is true, but the intention is to copy the content of “pSignalVector” into the global counterpart “pGlSignalVector”. The current content of this global vector should be filled into the branches. So how this code can be modified to do this?

Do not use “pSignalVector” at all (BTW. assigning pointers is not copying the contents of objects they are pointing to).
Fill “*pGlSignalVector” and make sure that you do not reallocate it (you use “&pGlSignalVector->at(i_ch)” as branch addresses so these addresses must not change).