Branches of vectors of vectors


Please read tips for efficient and successful posting and posting code

_ROOT Version:6.18.04
_Platform:Linux
_Compiler:g++


Hi ROOT community.
In a simple code I’m trying to simulate events and store them inside branches. The branches which refer to vectors of vectors/TLorentzVectors are not working (not even appearing in the ROOT file).

My source code:

#include <iostream>
#include <sstream>

#include "Pythia8/Pythia.h"

#include "TH1.h"

// ROOT, for interactive graphics.
#include "TVirtualPad.h"
//#include "TApplication.h"

// ROOT, for saving file.
#include "TFile.h"
#include "TTree.h"
#include "TLorentzVector.h"
#include "TROOT.h"

using namespace Pythia8;

TFile* file;
TTree* tree;
vector<TLorentzVector> p4;
vector<int>* 		id;
vector<vector<int> >* 	parents;
vector<vector<int> >*	children;
float			Q;
float			Q2;
float			aS;
float			sHat;
float			tHat;
float			uHat;
float			mHat;

//Everything inside main for now
//============================================================================
int main(int argc, char* argv[], TString name) {

//File setting
	file = new TFile("ContactInteraction.root", "RECREATE");
//Tree setting
	tree = new TTree("qqbar->qqbar","qqbar->qqbar");
	p4 = new vector<TLorentzVector>;
	id = new vector<int>;
	parents = new vector<vector<int> >;
	children = new vector<vector<int> >;
	//Branch setting
	tree->Branch("p4", &p4);
	tree->Branch("id", &id);
	tree->Branch("parents", &parents);
	tree->Branch("children", &children);
	tree->Branch("Q", &Q);
	tree->Branch("Q2", &Q2);
	tree->Branch("aS", &aS);
	tree->Branch("sHat", &sHat);
	tree->Branch("tHat", &tHat);
	tree->Branch("uHat", &uHat);
	tree->Branch("mHat", &mHat);

// Pythia stuff
  	Pythia pythia;
	pythia.readString("ContactInteractions:QCqq2qq = on");
	pythia.readString("ContactInteractions:Lambda = 2000.");
	pythia.readString("ContactInteractions:etaLL = -1");
	pythia.readString("ContactInteractions:etaRR = 0");
	pythia.readString("ContactInteractions:etaLR = 0");
	pythia.readString("PhaseSpace:pTHatMin = 20.");
  	pythia.readString("Beams:eCM = 14000.");
  	pythia.init();

  // Begin event loop. Generate event; skip if generation aborted.
  for (int iEvent = 0; iEvent < 100; ++iEvent) {
    if (!pythia.next()) continue;
    //Tree clearing
    p4.clear();
    id->clear();
    for(int i=0 ; i<parents->size() ; ++i) parents->at(i).clear();
    for(int i=0 ; i<children->size() ; ++i) children->at(i).clear();
    parents->clear();
    children->clear();
    Q  = -1;
    Q2 = -1;
    aS = -1;
    sHat = -1;
    tHat = -1;
    uHat = -1;
    mHat = -1;

	pythia.process.list();
	Q  	= pythia.info.QRen();
	Q2 	= pythia.info.Q2Ren();
	aS	= pythia.info.alphaS();
	sHat 	= pythia.info.sHat();
	tHat	= pythia.info.tHat();
	uHat	= pythia.info.uHat();
	mHat	= pythia.info.mHat();

	vector<int> vtmp;

	for (int i = 0; i < pythia.process.size(); ++i)
	{
	TLorentzVector p;
	p->SetPxPyPzE(pythia.process[i].px(),pythia.process[i].py(),pythia.process[i].pz(),pythia.process[i].e());
	p4->push_back(p);
	id->push_back(pythia.process[i].id());
	int m1 = pythia.process[i].mother1();
	int m2 = pythia.process[i].mother2();
	int d1 = pythia.process[i].daughter1();
	int d2 = pythia.process[i].daughter2();
	parents->push_back(vtmp);
	children->push_back(vtmp);
	if(m1>=0) parents->at(i).push_back(pythia.process[m1].index());
	if(m2>=0) parents->at(i).push_back(pythia.process[m2].index());
	if(d1>=0) children->at(i).push_back(pythia.process[d1].index());
	if(d2>=0) children->at(i).push_back(pythia.process[d2].index());
	}
	//Tree filling
	file->cd();
	tree->Fill();
	}
	//Tree writing
	file->cd();
	tree->Write();
 	pythia.stat();

  return 0;
}

The code is built OK but upon running I get a segmentation violation and as mentioned above the branches named p4, parents and children do not even appear inside the TTree. All other branches seem fine. Help please!

First, I think it should be:

vector<TLorentzVector> *p4 = nullptr;
vector<int>* 		id = nullptr;
vector<vector<int> >* 	parents = nullptr;
vector<vector<int> >*	children = nullptr;

Then, this code is wrong:

	TLorentzVector p;
	p->SetPxPyPzE(pythia.process[i].px(),pythia.process[i].py(),pythia.process[i].pz(),pythia.process[i].e());
	p4->push_back(p);

It should be either something like this:

	TLorentzVector *p = new TLoretzVector(pythia.process[i].px(),pythia.process[i].py(),pythia.process[i].pz(),pythia.process[i].e());
	p4->push_back(p);

or something (most probably) like this:

	TLorentzVector p;
p.SetPxPyPzE(pythia.process[i].px(),pythia.process[i].py(),pythia.process[i].pz(),pythia.process[i].e());
	p4->push_back(p);

It is weird that your compiler doesn’t complain when compiling this code…

Thanks for the quick reply.
I’ve set the four vectors to nullptr and implemented

TLorentzVector p;
p.SetPxPyPzE(pythia.process[i].px(),pythia.process[i].py(),pythia.process[i].pz(),pythia.process[i].e());
p4->push_back(p);

Unfortunately, no change…
Just to clarify: the id vector of integers works fine and appears inside the TTree.

Can you post the traceback?

Sure:

 *-------  PYTHIA Error and Warning Messages Statistics  ----------------------------------------------------------* 
 |                                                                                                                 | 
 |  times   message                                                                                                | 
 |                                                                                                                 | 
 |      1   Warning in StringFragmentation::fragmentToJunction: bad convergence junction rest frame                | 
 |                                                                                                                 | 
 *-------  End PYTHIA Error and Warning Messages Statistics  ------------------------------------------------------* 

 *** Break *** segmentation violation



===========================================================
There was a crash.
This is the entire stack trace of all threads:
===========================================================
#0  0x00007f932e326dba in __GI___wait4 (pid=732433, stat_loc=stat_loc
entry=0x7fff02ed4b18, options=options
entry=0, usage=usage
entry=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:27
#1  0x00007f932e326d7b in __GI___waitpid (pid=<optimized out>, stat_loc=stat_loc
entry=0x7fff02ed4b18, options=options
entry=0) at waitpid.c:38
#2  0x00007f932e2960e7 in do_system (line=<optimized out>) at ../sysdeps/posix/system.c:172
#3  0x00007f932f682e63 in TUnixSystem::StackTrace() () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#4  0x00007f932f685854 in TUnixSystem::DispatchSignals(ESignals) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#5  <signal handler called>
#6  0x00007f932e2dbd01 in _int_malloc (av=av
entry=0x7f932e42cb80 <main_arena>, bytes=bytes
entry=72) at malloc.c:3671
#7  0x00007f932e2de2d4 in __GI___libc_malloc (bytes=72) at malloc.c:3058
#8  0x00007f932e649c29 in operator new(unsigned long) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#9  0x00007f932f585ae9 in TStorage::ObjectAlloc(unsigned long) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#10 0x00007f932f5dcbab in THashList::THashList(int, int) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#11 0x00007f932f645be8 in TListOfDataMembers::TListOfDataMembers(TClass*) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#12 0x00007f932f61c9bc in TClass::GetListOfDataMembers(bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#13 0x00007f932f62c0da in TClass::GetDataMember(char const*) const () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#14 0x00007f932f63020e in TBuildRealData::Inspect(TClass*, char const*, char const*, void const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#15 0x00007f9329e3864a in TCling::InspectMembers(TMemberInspector&, void const*, TClass const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libCling.so
#16 0x00007f932f61eb58 in TClass::CallShowMembers(void const*, TMemberInspector&, bool) const () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#17 0x00007f932f62e05d in TClass::BuildRealData(void*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#18 0x00007f932ee40e55 in TBufferFile::WriteClassBuffer(TClass const*, void*) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#19 0x00007f932f666396 in TStreamerSTL::Streamer(TBuffer&) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#20 0x00007f932ee400cc in TBufferFile::WriteObjectClass(void const*, TClass const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#21 0x00007f932ee47355 in TBufferIO::WriteObjectAny(void const*, TClass const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#22 0x00007f932f5ee86d in TObjArray::Streamer(TBuffer&) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#23 0x00007f932ee400cc in TBufferFile::WriteObjectClass(void const*, TClass const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#24 0x00007f932ee47243 in TBufferIO::WriteObjectAny(void const*, TClass const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#25 0x00007f932eef946a in TStreamerInfo::Streamer(TBuffer&) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#26 0x00007f932ee400cc in TBufferFile::WriteObjectClass(void const*, TClass const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#27 0x00007f932ee47355 in TBufferIO::WriteObjectAny(void const*, TClass const*, bool) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#28 0x00007f932f5e9b9f in TList::Streamer(TBuffer&) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#29 0x00007f932eed8309 in TKey::TKey(TObject const*, char const*, int, TDirectory*) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#30 0x00007f932eea18c8 in TFile::WriteStreamerInfo() () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#31 0x00007f932eea0b54 in TFile::Close(char const*) () from /home/rbrener/Programs/root_v6.18.04/lib/libRIO.so.6.18
#32 0x00007f932f5223a1 in (anonymous namespace)::R__ListSlowClose(TList*) () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#33 0x00007f932f52302c in TROOT::CloseFiles() () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#34 0x00007f932f523742 in TROOT::EndOfProcessCleanups() () from /home/rbrener/Programs/root_v6.18.04/lib/libCore.so.6.18
#35 0x00007f932e28aa27 in __run_exit_handlers (status=0, listp=0x7f932e42c718 <__exit_funcs>, run_list_atexit=run_list_atexit
entry=true, run_dtors=run_dtors
entry=true) at exit.c:108
#36 0x00007f932e28abe0 in __GI_exit (status=<optimized out>) at exit.c:139
#37 0x00007f932e2680ba in __libc_start_main (main=0x5563939e06a0 <main>, argc=1, argv=0x7fff02ed8768, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fff02ed8758) at ../csu/libc-start.c:342
#38 0x00005563939e19ae in _start ()
===========================================================

Another question: do you have any warning when you compile your code?

None…

OK so I don’t see anything obviously wrong in your code (beside the p4.clear() which is now probably p4->clear(), otherwise the compiler would complain), but maybe @pcanal or @eguiraud can take another look and see something I didn’t… Or build your code in debug mode and start to debug it

Thanks again. Of course I’ve adapted on a par with the p4 pointer etc. BTW things like std::cout << p4->at(i).Pz() << std::endl; produce expected outputs (looks fine)…

You’re welcome. So let’s see if @pcanal has another idea…

To add something that may be useful: even when removing all operations w.r.t. p4 and leaving only:

vector<TLorentzVector>* p4 = nullptr;
p4 = new vector<TLorentzVector>;
tree->Branch("p4", &p4);

the branch p4 isn’t created.

I know what’s going wrong. I’ll keep you in touch

When running your code, you should see those errors:

Error in <TTree::Branch>: The class requested (vector<TLorentzVector>) for the branch "p4" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<TLorentzVector>) to avoid to write corrupted data.
Error in <TTree::Branch>: The class requested (vector<vector<int> >) for the branch "parents" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<vector<int> >) to avoid to write corrupted data.
Error in <TTree::Branch>: The class requested (vector<vector<int> >) for the branch "children" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<vector<int> >) to avoid to write corrupted data.

Meaning that you have to generate a dictionary for your collections. For example, add a LinkDef.h file containing

#ifdef __CINT__

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

#pragma link C++ class std::vector<TLorentzVector>+;
#pragma link C++ class std::vector<std::vector<int>>+;
#pragma link C++ class std::vector<std::vector<int>>+;

#endif

And to prevent the crash, add

   file->Close();
   delete file;

at the end, before return 0;

BTW, here is the resulting root file: ContactInteraction.root (20.9 KB)

Hi! Thanks. I’ve added the file and correspondingly included i.e. #include "LinkDef.h". I’ve also made the changes you noted. The file you generated looks great! But unfortunately at my end there is no change. What may I be missing?

BTW I’ve also tried adding a line #pragma link C++ defined_in "LinkDef.h"; alas, without change.

Just to mention, you are right that I’m (still) seeing the error:

Error in <TTree::Branch>: The class requested (vector<TLorentzVector>) for the branch "p4" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<TLorentzVector>) to avoid to write corrupted data.
Error in <TTree::Branch>: The class requested (vector<vector<int> >) for the branch "parents" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<vector<int> >) to avoid to write corrupted data.
Error in <TTree::Branch>: The class requested (vector<vector<int> >) for the branch "children" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<vector<int> >) to avoid to write corrupted data.

So now the problem is perhaps linking my code to the LinkDef.h header? I thought #include "LinkDef.h" would be sufficient… I feel we’re nearly there — sorry if I’ve missed something obvious.

Well, sorry, I’ve not been clear enough. You have to generate a dictionary. To do so, you need to add two lines in your LinkDef.h file:

#include <vector>
#include "TLorentzVector.h"

#ifdef __CINT__

#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;

#pragma link C++ class std::vector<TLorentzVector>+;
#pragma link C++ class std::vector<std::vector<int>>+;
#pragma link C++ class std::vector<std::vector<int>>+;

#endif

And then, if you use CMake, add

ROOT_GENERATE_DICTIONARY(MyDict LinkDef.h)

and add MyDict.cxx in the list of source files in your CMakeLists.txt
Otherwise you can add this command in your makefile (or type it in the command line):

rootcling -f myDict.cxx LinkDef.h

and add myDict.cxx in the list of source files
You can take a look at rootcling the cling dictionary generator documentation

BTW, here is my CMakeLists.txt, if that can help:

# Check if cmake has the required version
CMAKE_MINIMUM_REQUIRED(VERSION 3.16.4 FATAL_ERROR)

set(PROJECT_NAME test_pythia8)
project(${PROJECT_NAME})

find_package(ROOT REQUIRED)

set(CMAKE_CXX_FLAGS "${ROOT_CXX_FLAGS}")

ROOT_GENERATE_DICTIONARY(${PROJECT_NAME}Dict LinkDef.h)

set(PYTHIA8 $ENV{PYTHIA8})
set(PYTHIA8_INCLUDE_DIR  "${PYTHIA8}/include")
set(PYTHIA8_LIB_DIR "${PYTHIA8}/lib")

include(${ROOT_USE_FILE})
include_directories(${ROOT_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${PYTHIA8_INCLUDE_DIR})
link_directories(${ROOT_LIBRARY_DIR} ${PYTHIA8_LIB_DIR})

add_executable(${PROJECT_NAME} ${PROJECT_NAME}.cxx ${PROJECT_NAME}Dict.cxx)
target_link_libraries(${PROJECT_NAME} ${ROOT_LIBRARIES} Pythia8.lib)

Thanks and sorry — I need to be completely unequivocal because there are many directories/files alike. To be clear:

  • I’ve added the two lines to LinkDef.h
  • CMake — I’m not sure whether I do use it. I can testify I’ve got a file ~/Programs/pythia8303/examples/Makefile which has Pythia-related definitions. The only location I can think of where I’ve found a CMakeLists.txt file is ~/Programs/root_v6.18.04/tutorials/CMakeLists.txt and I’m unsure whether that’s the one I should edit.
  • Source files — I’ve got a bunch of them here ~/Programs/pythia8303/src relating to Pythia — is this the location I should add myDict.cxx to?
    Thanks again.