Pb with two dimensional arrays in TBranch

Hello Rooters,

We are trying to implement two dimensional arrays and we are encountering unexpected behaviours.
Within a same tree we declare several TBranches with two dimensional arrays.

While looking at the spectra, one realised that the first TBranch contains elements from the next TBranch.
I t
Please find in the following text more details:

Here are the declaration of the arrays:
In EventAction.hh

...
	Double_t**	    Cl_Cr_KU_En;
	Double_t**	    Cl_Cr_KU_EnAb;
	Double_t**		Cl_Cr_KU_X;	
	Double_t**		Cl_Cr_KU_Y;	
	Double_t**		Cl_Cr_KU_Z;	
	Double_t**		Cl_Cr_KU_Rho;	
	Double_t**		Cl_Cr_KU_Theta;	
	Double_t**		Cl_Cr_KU_Phi;	
	Double_t**		Cl_Cr_KU_XAb;	
	Double_t**		Cl_Cr_KU_YAb;	
	Double_t**		Cl_Cr_KU_ZAb;	
	Double_t**		Cl_Cr_KU_RhoAb;	
	Double_t**		Cl_Cr_KU_ThetaAb;	
	Double_t**		Cl_Cr_KU_PhiAb;	
...

In EventAction.cc:

...
Cl_Cr_KU_En         = new Double_t*[nb_ClKU];
Cl_Cr_KU_EnAb       = new Double_t*[nb_ClKU];

Cl_Cr_KU_X			= new Double_t*[nb_ClKU];
Cl_Cr_KU_Y			= new Double_t*[nb_ClKU];
Cl_Cr_KU_Z			= new Double_t*[nb_ClKU];
Cl_Cr_KU_XAb		= new Double_t*[nb_ClKU];
Cl_Cr_KU_YAb		= new Double_t*[nb_ClKU];
Cl_Cr_KU_ZAb		= new Double_t*[nb_ClKU];

Cl_Cr_KU_Rho		= new Double_t*[nb_ClKU];
Cl_Cr_KU_Theta		= new Double_t*[nb_ClKU];
Cl_Cr_KU_Phi		= new Double_t*[nb_ClKU];
Cl_Cr_KU_RhoAb		= new Double_t*[nb_ClKU];
Cl_Cr_KU_ThetaAb	= new Double_t*[nb_ClKU];
Cl_Cr_KU_PhiAb		= new Double_t*[nb_ClKU];
...

...
    for(int yup=0; yup<nb_ClKU;yup++){
      Cl_Cr_KU_En[yup]		= new Double_t[4];
      Cl_Cr_KU_EnAb[yup]	= new Double_t[4];

      Cl_Cr_KU_X[yup]		= new Double_t[4];
      Cl_Cr_KU_Y[yup]		= new Double_t[4];
      Cl_Cr_KU_Z[yup]		= new Double_t[4];
      Cl_Cr_KU_XAb[yup]		= new Double_t[4];
      Cl_Cr_KU_YAb[yup]		= new Double_t[4];
      Cl_Cr_KU_ZAb[yup]		= new Double_t[4];

      Cl_Cr_KU_Rho[yup]		= new Double_t[4];
      Cl_Cr_KU_Theta[yup]	= new Double_t[4];
      Cl_Cr_KU_Phi[yup]		= new Double_t[4];
      Cl_Cr_KU_RhoAb[yup]	= new Double_t[4];
      Cl_Cr_KU_ThetaAb[yup]	= new Double_t[4];
      Cl_Cr_KU_PhiAb[yup]	= new Double_t[4];
    }
...
...
                fTree2 -> Branch ("Cl_Cr_KU_En",	&Cl_Cr_KU_En[0][0],	Form("Cl_Cr_KU_En[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_EnAb",	&Cl_Cr_KU_EnAb[0][0],	Form("Cl_Cr_KU_EnAb[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_X",		&Cl_Cr_KU_X[0][0],	Form("Cl_Cr_KU_X[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_Y",		&Cl_Cr_KU_Y[0][0],	Form("Cl_Cr_KU_Y[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_Z",		&Cl_Cr_KU_Z[0][0],	Form("Cl_Cr_KU_Z[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_Rho",	&Cl_Cr_KU_Rho[0][0],	Form("Cl_Cr_KU_Rho[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_Theta",	&Cl_Cr_KU_Theta[0][0],	Form("Cl_Cr_KU_Theta[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_Phi",	&Cl_Cr_KU_Phi[0][0],	Form("Cl_Cr_KU_Phi[%i][4]/D",	nb_ClKU));

                fTree2 -> Branch ("Cl_Cr_KU_XAb",	&Cl_Cr_KU_XAb[0][0],		Form("Cl_Cr_KU_XAb[%i][4]/D",		nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_YAb",	&Cl_Cr_KU_YAb[0][0],		Form("Cl_Cr_KU_YAb[%i][4]/D",		nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_ZAb",	&Cl_Cr_KU_ZAb[0][0],		Form("Cl_Cr_KU_ZAb[%i][4]/D",		nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_RhoAb",	&Cl_Cr_KU_RhoAb[0][0],		Form("Cl_Cr_KU_RhoAb[%i][4]/D",		nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_ThetaAb",	&Cl_Cr_KU_ThetaAb[0][0],	Form("Cl_Cr_KU_ThetaAb[%i][4]/D",	nb_ClKU));
                fTree2 -> Branch ("Cl_Cr_KU_PhiAb",	&Cl_Cr_KU_PhiAb[0][0],		Form("Cl_Cr_KU_PhiAb[%i][4]/D",		nb_ClKU));
...

So to be more precise, in the spectra of Cl_Cr_KU_En[3][1], one can observe the content not of an energy but a spectrum corresponding to a position X Y or Z. In the beginning of the array, one observe energy spectra.

In order to remedy to this problem, we changed all the double as Double_t but it did not change the situation.
We thought that the problem might come from the values we were filling in the tree, but by filling each element of the arrays in a separate TBranch we observe the expected values.

If you have any idea how to solve this issue, please help :slight_smile:.

Thank you in advance,

Christophe

_ROOT Version: ROOT Version: 6.16/00
Built for macosx64 on Sep 26 2019
_Platform: Mac Osx Mojave 10.14.6
_Compiler: g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.16)
Target: x86_64-apple-darwin18.7.0


Double_t**		Cl_Cr_KU_X;	
...
Cl_Cr_KU_X			= new Double_t*[nb_ClKU];

We do not really support this kind of construct (too hard to pass the ‘size’ information to the I/O part.
Notably when using:

fTree2 -> Branch ("Cl_Cr_KU_X",		&Cl_Cr_KU_X[0][0],	Form("Cl_Cr_KU_X[%i][4]/D",	nb_ClKU));

The TTree expect a nb_ClKU*4 contiguous double starting at the address &Cl_Cr_KU_X[0][0] (So in your case, the first 4 should be always okay and depending on the memory allocator the other ‘might’ also happen to be in the right place but it is unlikely).

You need to use either

Double_t* Cl_Cr_KU_X;	
...
Cl_Cr_KU_X = new Double_t[nb_ClKU][4];

or a std::vector<std::vector<double>>

Cheers,
Philippe.

Thank a lot for the prompt reply, it worked!

However, the problem persisted with std::vector<std::vector>, so I guessed it might come from the TBranch declaration.

I tried several declarations:
- 1st attempt with:

fTree2 -> Branch ("vCl_Cr_KU_En",	&vCl_Cr_KU_En[0][0],	Form("vCl_Cr_KU_En[%i][4]/D",	nb_ClKU));

The spectra were still mixed.
- 2nd attempt with:

fTree2 -> Branch ("vCl_Cr_KU_En",	&vCl_Cr_KU_En, "vCl_Cr_KU_En/D");

The spectra are empty in this case, most likely it does not find what to fill.
- 3rd attempt with:

fTree2 -> Branch ("vCl_Cr_KU_En",	&vCl_Cr_KU_En);

It is working like charm (but not 4th time).

However, is it correct that there is no need to generate dictionaries?
I tried with and without the following line in my EventAction.cc constructor (from post Vector in Branch):

gROOT->ProcessLine("#include <vector>");

And there was no difference.
Is it because it is a std::vector? and not a user defined type or class?

Thank you again!!!

The 1st and 2nd attempt are ‘wrong’ for std::vector of std::vector, as they tell the TBranch to use an incorrect memory layout.

However , is it correct that there is no need to generate dictionaries?

It does ‘work’ without dictionary because it is std::vector (or std::vector of vector) of numerical type.

However, if it is not to much of burden, you are still better off generating the dictionaries.

Thanks again for the reply.

So I have been trying a long time to produce dictionaries but for some reason, nothing is created, and I don’t find any solution from the documentation/forum ([1], [2], [3]).

Would it be possible to explain me where is the mistake?

Here is the present situation for the code:
CMakeList.txt:

#----------------------------------------------------------------------------
# Setup the project
#
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
project(g4ids)

#NO WARNING FLAGS (C.S.)
set  (CMAKE_CXX_FLAGS "-w")
#----------------------------------------------------------------------------
# Find Geant4 package, activating all available UI and Vis drivers by default
# You can set WITH_GEANT4_UIVIS to OFF via the command line or ccmake/cmake-gui
# to build a batch mode only executable
#
option(WITH_GEANT4_UIVIS "Build example with Geant4 UI and Vis drivers" ON)
if(WITH_GEANT4_UIVIS)
  find_package(Geant4 REQUIRED ui_all vis_all)
else()
  find_package(Geant4 REQUIRED)
endif()

#----------------------------------------------------------------------------
# Find ROOT package
#
list(APPEND CMAKE_PREFIX_PATH $ENV{ROOTSYS})

# Locate the ROOT package and defines a number of variables (e.g. ROOT_INCLUDE_DIRS)
find_package(ROOT CONFIG REQUIRED COMPONENTS MathCore RIO Hist Tree Net)

# Define useful ROOT functions and macros (e.g. ROOT_GENERATE_DICTIONARY)
include(${ROOT_USE_FILE})
include_directories(${CMAKE_SOURCE_DIR} ${ROOT_INCLUDE_DIR})
add_definitions(${ROOT_CXX_FLAGS})

#----------------------------------------------------------------------------
# Setup Geant4 include directories and compile definitions
# Setup include directory for this project
#
include(${Geant4_USE_FILE})
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(/Users/csotty/CADMESH/CADMesh-1.1/include)
#----------------------------------------------------------------------------
# Locate sources and headers for this project + link ROOT .h
# NB: headers are included so they will show up in IDEs
#
file(GLOB sources ${PROJECT_SOURCE_DIR}/src/*.cc)
file(GLOB headers ${PROJECT_SOURCE_DIR}/include/*.hh)
#ROOT_GENERATE_DICTIONARY(include/G4IDSEventActionDict include/G4IDSEventAction.hh LINKDEF include/LinkDef.h)
#ROOT_GENERATE_DICTIONARY(G4IDSEventActionDict G4IDSEventAction.hh LINKDEF LinkDef.h)
ROOT_GENERATE_DICTIONARY(G4IDSEventActionDict include/G4IDSEventAction.hh LINKDEF include/LinkDef.h)

#---Create a shared library with geneated dictionary
#add_library(src/G4IDSEADict SHARED src/G4IDSEventAction.cc src/G4IDSEventActionDict.cc)
#add_library(G4IDSEADict SHARED G4IDSEventAction.cc G4IDSEventActionDict.cc)
add_library(G4IDSEADict SHARED src/G4IDSEventAction.cc src/G4IDSEventActionDict.cc)
#----------------------------------------------------------------------------
# Add the executable, and link it to the Geant4 libraries
#
add_executable(g4ids g4ids.cc ${sources} ${headers})
target_link_libraries(g4ids ${Geant4_LIBRARIES})
target_link_libraries(g4ids ${ROOT_LIBRARIES})
target_link_libraries(g4ids /Users/csotty/CADMESH/CADMesh-1.1-build/libcadmesh.dylib)

target_compile_options(g4ids PRIVATE -Wno-shadow)
target_compile_options(g4ids PRIVATE -Wno-address-of-packed-member)
target_compile_options(g4ids PRIVATE -Wno-vla-extension)

#----------------------------------------------------------------------------
# Copy all scripts to the build directory, i.e. the directory in which we
# build B4a. This is so that we can run the executable directly because it
# relies on these scripts being in the current working directory.
#
set(g4ids_SCRIPTS
  vrml.mac
  vis.mac
  gui.mac
  noGUI.mac
  icons.mac
  init.mac
  init_vis.mac
  root2ascii.C
  root2ascii.h
  )

foreach(_script ${g4ids_SCRIPTS})
  configure_file(
    ${PROJECT_SOURCE_DIR}/macros/${_script}
    ${PROJECT_BINARY_DIR}/${_script}
    COPYONLY
    )
endforeach()
#----------------------------------------------------------------------------
# Install the executable to 'bin' directory under CMAKE_INSTALL_PREFIX
#
install(TARGETS g4ids DESTINATION bin)

LinkDef.h:

#ifdef __CINT__

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

#pragma link C++ class vector<double>+;
#pragma link C++ class vector<vector<double>>+;
#pragma link C++ class G4IDSEventAction+;
#pragma link C++ defined_in "G4IDSEventAction.hh";

#endif

Include File:

//Include-files for Event Action
#ifndef G4IDSEventAction_h
#define G4IDSEventAction_h 1

#include "global.hh"
#include "G4UserEventAction.hh"
#include "G4Run.hh"
#include "G4Event.hh"
#include "G4Track.hh"
#include "G4TrajectoryContainer.hh"
#include "G4SteppingManager.hh"
#include "G4SteppingVerbose.hh"
#include "tndge_SteppingVerbose.hh"
#include "G4IDSPrimaryGeneratorAction.hh"
#include "G4IDSDetectorConstruction.hh"
//#include "G4IDSSteppingAction.hh"
#include "G4SDManager.hh"
#include "G4THitsCollection.hh"
#include "G4HCofThisEvent.hh"
#include "G4Timer.hh"
#include "G4UnitsTable.hh"
#include "G4ios.hh"

#include "TTimeStamp.h"
#include "TFile.h"
#include "TTree.h"
#include "TString.h"
#include "TKey.h"
#include "TArrayD.h"
#include "TArrayI.h"
#include "TH1F.h"
#include "TRandom2.h"
#include "Rtypes.h"

#include "CloverSingleHit.hh"
#include "CloverSingleSD.hh"
#include "CloverSingleTrackingAction.hh"
#include "CloverSingleBuchHit.hh"
#include "CloverSingleBuchSD.hh"
#include "CloverSingleBuchTrackingAction.hh"


#include <vector>

#include "TObject.h"
#include "TClonesArray.h"
#include "TRefArray.h"
#include "TRef.h"
#include "TH1.h"
#include "TBits.h"
#include "TMath.h"

using namespace std;

class G4Event;


// Event Action Class
class G4IDSEventAction : public G4UserEventAction
{
    // Constructor, Destructor and Manipulators
    public:
	G4IDSEventAction(G4IDSDetectorConstruction* p_G4IDS_DC, G4String p_fFileName);
	~G4IDSEventAction();

	void BeginOfEventAction(const G4Event*);
	void EndOfEventAction(const G4Event*);

    //private:
	G4IDSDetectorConstruction*	G4IDS_DC;


	// ROOT data saving stuff
	static TFile	*fRootFile;
	static TTree	*fTree;
	TString		fFileName;


	// TTree
	G4ThreeVector**.             Cl_Cr_KU_Pos;
	double**                     Cl_Cr_KU_En;
	double**	    	         Cl_Cr_KU_X;
	double**	     	         Cl_Cr_KU_Y;
	double**	    	         Cl_Cr_KU_Z;
	double**	   	             Cl_Cr_KU_Rho;
	double**	   	             Cl_Cr_KU_Theta;
	double**	     	         Cl_Cr_KU_Phi;
	vector<vector<double>>       vCl_Cr_KU_En;
	vector<vector<double>>	     vCl_Cr_KU_X;
	vector<vector<double>>	     vCl_Cr_KU_Y;
	vector<vector<double>>	     vCl_Cr_KU_Z;
	vector<vector<double>>       vCl_Cr_KU_Rho;
	vector<vector<double>>       vCl_Cr_KU_Theta;
	vector<vector<double>>       vCl_Cr_KU_Phi;
	int		fNPoints_KU;

    private:
    G4int nb_ClKU;
	
    //ClassDef(G4IDSEventAction,1)
};

#endif

Error returned by CMake:

CMake Error at CMakeLists.txt:92 (add_library):
  Cannot find source file:

    src/G4IDSEventActionDict.cc

  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
  .hpp .hxx .in .txx


CMake Error at CMakeLists.txt:92 (add_library):
  No SOURCES given to target: G4IDSEADict


CMake Generate step failed.  Build files cannot be regenerated correctly.
-- Configuring done
CMake Error at CMakeLists.txt:92 (add_library):
  Cannot find source file:

    src/G4IDSEventActionDict.cc

  Tried extensions .c .C .c++ .cc .cpp .cxx .cu .m .M .mm .h .hh .h++ .hm
  .hpp .hxx .in .txx


CMake Error at CMakeLists.txt:92 (add_library):
  No SOURCES given to target: G4IDSEADict


CMake Generate step failed.  Build files cannot be regenerated correctly.
make: *** [cmake_check_build_system] Error 1
Christophes-MacBook-Pro:build sotty$ [A
-bash: [A: command not found

So basically, the dictionary is not generated and thus it does not find it.
I changed the path in many ways, even in absolute but nothing works.

Thank you in advance

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