Creating an array of TVectorD objects?

I am trying to collect a set of TVectorDs, which will (in a separate function) be written out to a text file. I have a function which pulls a histogram out of a file and extracts the bin contents into a TVectorD. So in my collector, I have code:

TVectorD traces[4][2];
for (Int_t i=0; i<4; i++) {
  traces[i][0] = GetTrace(file, channel[i]);
  traces[i][1] = GetTrace(file, xtalk[i]);
}

where channel and xtalk are lists of histogram names. This does not work as written. When it runs, I get a series of errors:

Error in <TVectorT<double>::operator=(const TVectorT<Element> &)>: vectors not compatible

So I modified the loop to instead use

  traces[i][0].Use(GetTrace(file, channel[i]));

But this also fails. I seem to end up with corrupted memory in the various traces in my array.

Does TVectorT<>::Use() copy the contents of the RHS, or does it shallowly copy the pointer to the contents? Is there something else I’m doing wrong, here? Is there maybe a better way within ROOT to do what I want to do (extract lists of values from file histograms, collect the lists into an array, and pass them around)?


Please read tips for efficient and successful posting and posting code

ROOT Version: 6.12.06
Compiler: N/A (Interpreted)


Ugh. It definitely appears that TVectorT does shallow copies, or rather, that Use picks up a non-owned pointer back to the previous data, which can go out of scope without warning.

I had to modify my nice, intuitive code above into something even more cumbersome than STL usually is:

for (Int_t i=0; i<4; i++) {
  TVectorD ti0(GetTrace(file, zipdir+"/"+channel[i]));
  traces[i][0].ResizeTo(ti0).SetElements(ti0.GetMatrixArray());

  TVectorD ti1(GetTrace(file, zipdir+"/"+xtalk[i]));
  traces[i][1].ResizeTo(ti1).SetElements(ti1.GetMatrixArray());
}

Am I missing something in the .h files? Is there a proper deep copy function?

Hi @Michael_Kelsey,

I had a look at documentation and code here, and found out:

  • Vectors have their own storage, but they can adopt.
  • Storage sizes must be compatible to be able to use the assignment operator (i.e., you need to resize as you did or you create them directly with the desired size).
  • When you Use, storage space from another vector is used and not owned. You indeed have to keep the original alive, and changing something in the using vector will also change things in the original.

You can try this code. If I didn’t overlook something, you save one copy:

const auto& ti0 = GetTrace(file, zipdir+"/"+channel[i]);
traces[i][0].ResizeTo(ti0) = ti0;

Hi,

TVectorD is designed to be used in linear algebra operations, e.g. matrix vector multiplication. For example you want to be sure to have compatible dimensions when doing vector-vector or matric-vector operations.
If you want to use them as simple vector containers, they are not designed for this.
I would suggest for this use case to use something as std::vector TVectorD is not the ROOT equivalent of std::vector !

Lorenzo

@moneta Thanks for the advice! I started using TVectorD in this manner because ROOT provided a nice interface to create TGraphs using them (where passing Double_t* pointers is just wrong :confused: ). If there was a better interface to TGraph (using std::vector, for instance), I’d use it.

@StephanH Thank you! That’s nicer; I had seen that ResizeTo() returns a ref, but it somehow it didn’t click that I could use it as an lvalue.

For TGraph, I used something like

TGraph graph(xvec.size(), xvec.data(), yvec.data());

As long as x and y have the same dimensions, it’s safe and a one-liner. Now you have two alternatives to choose from. Hope that one is usable. :slight_smile:

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