Problem with ROOT working with Geant4... dictionary problem?

Dear all,

I am trying to save my some results of a Geant4 simulation in a ROOT ntuple, with data storage through a class inheriting from TObject. Methods of the class need Geant4 types as input. For example, I use my class to take a G4Track and store its associated momentum in the ntuple.

I create my own class: here’s the header file

[code]
#if !defined Targ01Storage_H
#define Targ01Storage_H

// Root components
#include <Rtypes.h>
#include <TString.h>
#include <TObject.h>
#include <TList.h>

// G4
#include “G4Track.hh”
#include “G4TrackStatus.hh”
#include “G4ParticleDefinition.hh”
#include “G4ParticleTypes.hh”

class Targ01Storage : public TObject
{
private:

public:

// Special member functions
Targ01Storage();
~Targ01Storage();

// Variables with stored information
Int_t partNo;
Int_t partId;
TString partName;
Double_t part4Momentum[4];
Double_t partKinEn;
//Double_t partMass;

//Targ01Storage specific methods
void PartNo(Int_t no);
void PartId(const G4Track* aTrack);
void Part4Momentum(const G4Track* aTrack);

// Cint preprocessor token
ClassDef(Targ01Storage, 1)

};

#endif[/code]

and the source is here:

[code]
#include “Targ01Storage.hh”
#include “G4Track.hh”
#include “TString.h”

// CINT Preprocessor class import definition
ClassImp(Targ01Storage)

//______________________________________________________________________________
Targ01Storage::Targ01Storage()
{
// Sets up the default event

partNo = -9999;
partId = -9999;
partName = “”;
for (Int_t jj = 0; jj<4; jj++) part4Momentum[jj] = -9999;
partKinEn = -9999;
}
//______________________________________________________________________________
Targ01Storage::~Targ01Storage()
{
// Default destructor.
std::cout<<“Targ01Storage::Targ01Storage: default destructor\n”;

// Deletes the root object
}
//______________________________________________________________________________
void Targ01Storage::PartNo(Int_t no)
{
// Sets the particle number through a counter
partNo = no;
}
//______________________________________________________________________________
void Targ01Storage::PartId(const G4Track* aTrack)
{
// Sets the particle PDG encoding
partId = aTrack->GetDefinition()->GetPDGEncoding();
partName = TString(aTrack->GetDefinition()->GetParticleName());
}
//______________________________________________________________________________
void Targ01Storage::Part4Momentum(const G4Track* aTrack)
{
// Sets the particle kinematics
partKinEn = aTrack->GetKineticEnergy();
part4Momentum[0] = aTrack->GetTotalEnergy();
part4Momentum[1] = (aTrack->GetMomentum()).x();
part4Momentum[1] = (aTrack->GetMomentum()).y();
part4Momentum[1] = (aTrack->GetMomentum()).z();
}[/code]

Then, I provide a linkdef file to link my own class

[code]
#ifdef CINT

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

#pragma link C++ class Targ01Storage+;

#endif[/code]

I use the Geant4 makefile (the one provided with G4 example/novice/N01) with recursive calls to other .gmk files. I put in it the dictionary generation instructions

[code]
name := targ01
G4TARGET := $(name)
G4EXLIB := true

ifndef G4INSTALL
G4INSTALL = /home/pozzobon/geant4/9.2
endif

.PHONY: all
all: custom lib bin

custom:
@echo “Generating dictionary …”
@rootcint -f Targ01Dictionary.cc -c -Iinclude Targ01Storage.hh Targ01LinkDef.hh

include $(G4INSTALL)/config/architecture.gmk

CPPFLAGS = -Iinclude $(shell root-config --cflags)
LDFLAGS = $(shell root-config --glibs --libs) -L$(G4INSTALL)/lib/Linux-g++ Targ01Dictionary.cc

include $(G4INSTALL)/config/binmake.gmk[/code]

but when I compile, I get

[quote]Generating dictionary …
Error: cannot open file “G4Track.hh” include/Targ01Storage.hh:13:
Error: cannot open file “G4TrackStatus.hh” include/Targ01Storage.hh:14:
Error: cannot open file “G4ParticleDefinition.hh” include/Targ01Storage.hh:15:
Error: cannot open file “G4ParticleTypes.hh” include/Targ01Storage.hh:16:
Warning: Error occurred during reading source files
Warning: Error occurred during dictionary source generation
!!!Removing Targ01Dictionary.cc Targ01Dictionary.h !!!
Error: rootcint: error loading headers…
make: *** [custom] Error 1[/quote]

so that I put all the G4 includes listed in the called binmake.gmk file

ifndef G4INSTALL
G4INSTALL = /home/pozzobon/geant4/9.2
endif

[code]
… (omissis)

DICTFLAGS :=
-I/home/pozzobon/geant4/9.2/source/global/management/include
… (omissis)
-I/home/pozzobon/geant4/9.2/source/intercoms/include

… (omissis)

custom:
@echo “Generating dictionary …”
@rootcint -f Targ01Dictionary.cc -c -Iinclude $(DICTFLAGS) Targ01Storage.hh Targ01LinkDef.hh[/code]

This way, my compilation still fails because of an error loading headers:

[quote]Error: Symbol ostreamG4cout is not defined in current scope /home/pozzobon/geant4/9.2/source/global/management/include/G4ios.hh:48:
Error: Symbol ostreamG4cerr is not defined in current scope /home/pozzobon/geant4/9.2/source/global/management/include/G4ios.hh:49:
Error: cannot open file “CLHEP/Units/PhysicalConstants.h” /home/pozzobon/geant4/9.2/source/global/management/include/G4PhysicalConstants.hh:28:
Error: cannot open file “CLHEP/Units/SystemOfUnits.h” /home/pozzobon/geant4/9.2/source/global/management/include/G4SystemOfUnits.hh:28:
Error: cannot open file “CLHEP/Vector/ThreeVector.h” /home/pozzobon/geant4/9.2/source/global/management/include/G4ThreeVector.hh:42:
Error: class,struct,union or type CLHEP not defined /home/pozzobon/geant4/9.2/source/global/management/include/G4ThreeVector.hh:43:
Error: class,struct,union or type CLHEP not defined /home/pozzobon/geant4/9.2/source/global/management/include/G4ThreeVector.hh:43:
Error: cannot open file “CLHEP/Vector/Rotation.h” /home/pozzobon/geant4/9.2/source/global/management/include/G4RotationMatrix.hh:43:
Error: class,struct,union or type CLHEP not defined /home/pozzobon/geant4/9.2/source/global/management/include/G4RotationMatrix.hh:44:
Error: class,struct,union or type CLHEP not defined /home/pozzobon/geant4/9.2/source/global/management/include/G4RotationMatrix.hh:44:
Error: cannot open file “CLHEP/Vector/LorentzVector.h” /home/pozzobon/geant4/9.2/source/global/HEPGeometry/include/G4LorentzVector.hh:35:
Error: class,struct,union or type CLHEP not defined /home/pozzobon/geant4/9.2/source/global/HEPGeometry/include/G4LorentzVector.hh:36:
Error: class,struct,union or type CLHEP not defined /home/pozzobon/geant4/9.2/source/global/HEPGeometry/include/G4LorentzVector.hh:36:
Error: Symbol G4DLLIMPORTG4Allocator is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4ElectronOccupancy.hh:107:
Error: Symbol G4ElectronOccupancy is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4ElectronOccupancy.hh:107:
Error: Symbol aElectronOccupancyAllocator is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4ElectronOccupancy.hh:107:
Error: Symbol G4DLLIMPORTG4Allocator is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4PrimaryParticle.hh:213:
Error: Symbol G4PrimaryParticle is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4PrimaryParticle.hh:213:
Error: Symbol aPrimaryParticleAllocator is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4PrimaryParticle.hh:213:
Error: Symbol G4DLLIMPORTG4Allocator is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4DynamicParticle.icc:41:
Error: Symbol G4DynamicParticle is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4DynamicParticle.icc:41:
Error: Symbol aDynamicParticleAllocator is not defined in current scope /home/pozzobon/geant4/9.2/source/particles/management/include/G4DynamicParticle.icc:41:
Error: G4CountedObject::aCountedObjectAllocator already declared as different type /home/pozzobon/geant4/9.2/source/global/management/include/G4ReferenceCountedHandle.hh:316:
Error: G4CountedObject::aCountedObjectAllocator not allocated(2), maybe duplicate declaration /home/pozzobon/geant4/9.2/source/global/management/include/G4ReferenceCountedHandle.hh:316:
Error: G4ReferenceCountedHandle::aRCHAllocator already declared as different type /home/pozzobon/geant4/9.2/source/global/management/include/G4ReferenceCountedHandle.hh:320:
Error: G4ReferenceCountedHandle::aRCHAllocator not allocated(2), maybe duplicate declaration /home/pozzobon/geant4/9.2/source/global/management/include/G4ReferenceCountedHandle.hh:320:
Error: Symbol STP_Temperature is not defined in current scope /home/pozzobon/geant4/9.2/source/materials/include/G4Material.hh:115:
Error: Symbol STP_Pressure is not defined in current scope /home/pozzobon/geant4/9.2/source/materials/include/G4Material.hh:116:
Error: Symbol STP_Temperature is not defined in current scope /home/pozzobon/geant4/9.2/source/materials/include/G4Material.hh:126:
Error: Symbol STP_Pressure is not defined in current scope /home/pozzobon/geant4/9.2/source/materials/include/G4Material.hh:127:
Error: Symbol G4DLLIMPORTG4Allocator is not defined in current scope /home/pozzobon/geant4/9.2/source/track/include/G4Track.icc:38:
Error: Symbol G4Track is not defined in current scope /home/pozzobon/geant4/9.2/source/track/include/G4Track.icc:38:
Error: Symbol aTrackAllocator is not defined in current scope /home/pozzobon/geant4/9.2/source/track/include/G4Track.icc:38:
Warning: Error occurred during reading source files
Warning: Error occurred during dictionary source generation
!!!Removing Targ01Dictionary.cc Targ01Dictionary.h !!!
Error: rootcint: error loading headers…
make: *** [custom] Error 1[/quote]

I found other people had similar problems http://root.cern.ch/phpBB2/viewtopic.php?t=3493 but I couldn’t find any solution in this topic (and in many other topics in this RootTalk)

I already spent all my ideas about how to fix this, without any success… Did anyone ever manage to make ROOT and Geant4 talk to each other? Does anyone know the solution?

Thank you very much!
Nicola

My solution to this problem is to completely separate the Root bits from the Geant bits. Specifically, the Root bits should not reference any Geant types. Then, you write a function that converts from the Geant side of the house to the Root side of the house.

More concretely, I usually have a bunch of different Geant HitCollections that need to end up in Root Trees. In the Geant sim, for instance, I will have a class trackerHit, derived from G4VHit, that is stored by the sensitive detectors into a G4THitsCollection. In order to keep the Geant headers out of the Dictionary generation process, I have a class trackerRecord that is composed only of built in types and classes Root knows about, and I store them in a std::vector inside a TTree in the Root file. At this point, the trackerRecord doesn’t know anything about the trackerHit, and vice versa. To solve that problem, I have a global function that can convert a trackerHit to a trackerRecord:

trackerRecord convert(trackerHit const*);

and in EventAction::EndOfEventAction, I call this function in a loop over the G4THitsCollection to fill the std::vector that is on the TTree branch, just before I TTree::Fill

Hope that helps. Let me know if you need some more detailed example code.

Try the -p option of rootcint (request external preprocessor)rootcint -f Targ01Dictionary.cc -c -p -Iinclude $(DICTFLAGS) Targ01Storage.hh Targ01LinkDef.hh

Cheers,
Philippe.

Thanks both to krlynch and Philippe.

Before asking krlynch some more example code, I’m first trying with the second option, which seems more conservative.

When I compile with the ‘-p’ option in the rootcint line, I get a syntax error

[quote]Generating Dictionary …
sh: -c: line 0: syntax error near unexpected token newline' sh: -c: line 0:g++ -E -C “-DG__LINUX=1” “-DG__GNUC=4” “-DG__GNUC_MINOR=1” “-DG__GNUC_VER=4001” “-DG__GLIBC=2” “-DG__GLIBC_MINOR=5” “-DG__i386=1” “-DG__ROOT=1” “-DG__NATIVELONGLONG=1” “-DTRUE=1” “-DFALSE=0” “-Dexternalref=extern” “-DSYSV” “-D__MAKECINT__” “-DG__CINTVERSION=50160029” -I. -Iinclude -I/home/pozzobon/geant4/9.2/source/global/management/include


(very long list of all G4 includes…)


-I/home/pozzobon/geant4/9.2/source/intercoms/include -I/usr/local/include/root -D__CINT__ -I/usr/local/lib/root/cint/cint/include -I/usr/local/lib/root/cint/cint/stl -I/usr/local/lib/root/cint/cint/lib /po > '
make: *** [custom] Segmentation fault [/quote]

It seems that there is another piece pf some file path (/po) at the end of the line, so I tried changing the option order in the rootcint line to see what happens… the only change I have in my error message is what is comprised between [quote]-I/usr/local/lib/root/cint/cint/lib[/quote] and [quote] > '[/quote] , so exactly that “/po” which takes other names (always meaningless but always pieces of known paths)

This makes me guess that the resulting command line interpreted by CINT is too long and is uncorrectly split… I tried keeping only the G4 includes I need in my class, but since G4 headers are recursively invoked in all G4 classes, I need all of them… Is my guess about the line length correct? Is there any way to bypass this feature?

Thanks again!
Nicola

Hi,

This might be either a CINT or a shell command line length limitation.
Either way, you can dramactically reduce the command line size by storing all the -I in a file (let’s say myincludes) and replace them by @myincludes

Cheers,
Philippe.

umh… it doesn’t work… at least, I tried

and CINT thinks that “@myincludes” should be the name of a header file to be processed…

I tried with

but I have the same problem… I guess this is a CINT issue, since looking carefully at the “segmentation fault” warning, one can see that the g++ command line produced by CINT has some repeated words, such as CINT were trying to overwrite something somewhere…

[quote]sh: -c: line 0: syntax error near unexpected token )' sh: -c: line 0:g++ -E -C “-DG__LINUX=1” “-DG__GNUC=4” “-DG__GNUC_MINOR=1” “-DG__GNUC_VER=4001” “-DG__GLIBC=2” “-DG__GLIBC_MINOR=5” “-DG__i386=1” “-DG__ROOT=1” “-DG__NATIVELONGLONG=1” “-DTRUE=1” “-DFALSE=0” “-Dexternalref=extern” “-DSYSV” “-D__MAKECINT__” “-DG__CINTVERSION=50160029” -I. -I./include -I$(G4INSTALL)/source/global/management/include -I$(G4INSTALL)/source/global/HEPRandom/include -I$(G4INSTALL)/source/global/HEPGeometry/include -I$(G4INSTALL)/source/global/HEPNumerics/include -I$(G4INSTALL)/source

***

-I/usr/local/include/root -D__CINT__ -I/usr/local/lib/root/cint/cint/include -I/usr/local/lib/root/cint/cint/stl -I/usr/local/lib/root/cint/cint/lib L)/source/geometry/divisions/include -I$(G4INSTALL)/source/geometry/volumes/include

*************** > /tmp/GWX6kc_cint’
make: *** [custom] Segmentation fault[/quote]

you see? there is a L)/ in the line between asterisks, coming from a $(G4INSTALL)…
any other suggestions?

thanks again!

Hi,

The only solution I can see is to increase the CINT buffer size by making sure that G__LONGBUF is defined during the compilation of ROOT (the easiest way is to go an modify cint/cint/inc/G__ci.h and add #define G__LONGBUF somewhere at the top).

Cheers,
Philippe

Hi,

do you really need these tons of -I? Can’t you remove some? GEANT4 installations seem to allow you to simply use -I${G4INSTALL}/share/include, instead of enumerating all the source subdirectories. Why doesn’t that work for you?

Cheers, Axel.

Hi,

Also, you could ‘simply’ copy all the Geant4 headers in a single directory … (if it is not already done in ${G4INSTALL}/share/include).

Cheers,
Philippe.

Let me thank all of you once again for your patience…

I reinstalled G4 with the option “all the headers in one directory” and included only that one with the -I. It looks like there is some redundancy (I had the same problem when I simply tried copying all the headers in one directory without reinstalling G4)

[quote]Generating Dictionary …
Error: G4CountedObject::aCountedObjectAllocator already declared as different type /home/pozzobon/geant4.9.2/include/G4ReferenceCountedHandle.hh:316:
Error: G4CountedObject::aCountedObjectAllocator not allocated(2), maybe duplicate declaration /home/pozzobon/geant4.9.2/include/G4ReferenceCountedHandle.hh:316:
Error: G4ReferenceCountedHandle::aRCHAllocator already declared as different type /home/pozzobon/geant4.9.2/include/G4ReferenceCountedHandle.hh:320:
Error: G4ReferenceCountedHandle::aRCHAllocator not allocated(2), maybe duplicate declaration /home/pozzobon/geant4.9.2/include/G4ReferenceCountedHandle.hh:320:
Warning: Error occurred during reading source files
Warning: Error occurred during dictionary source generation
!!!Removing Targ01Dictionary.cc Targ01Dictionary.h !!!
Error: rootcint: error loading headers…
make: *** [custom] Error 1[/quote]

is it a CINT problem?

Hi,

It is hard to tell (from these messages alone) whether the re-definition is really in the Geant4 headers or a bug in the parsing. Can you reduce the issue to the minimal set of files and then me those?

Thanks,
Philippe.

umh… now I think that the problem is my null experience with template classes

in attachment there should be the file with the problem… and another one that may be useful…

Thanks a lot once again…
G4Allocator.h (7.36 KB)
G4ReferenceCountedHandle.h (8.89 KB)

Hi,

I can not reproduce the problem (and/or guess what the problem is) with just this file. I would really need a full set (including the command that leads to the error).

Cheers,
Philippe.

Dear Philippe… I fear that a complete set of files to reproduce the problem would need a Geant4 installation… do you have one?

However, I tried the brutal way: I commented the lines with the “double definition” in the header file G4ReferenceCountedHandle… I made the change only in the one in $G4INSTALL/include, which is the directory with all the headers. The corresponding file in the specific directory $G4INSTALL/source/global/management/include is still like the original one.

I hope this solution is fine even if unelegant (and maybe dangerous…) I know it is only an “overcoming” and not a deep understanding of the problem but, you see, the dictionary is generated… compilation is fine, linking gives some warnings about forbidden casting but they are warnings, not errors

Anyway, after long suffering, I am able to write my simple output in the Root TTree way I wanted…

Thanks again to everyone

Hi,
I think I have ran into the same problem before. I have my own ROOT based event class to store the information from GEANT4. I am not exactly sure why but rootcint seems to like absolute paths. Here is a makefile that works for me:

##3333333333333333333333333333333333333333333333333#####
name := crystal
G4TARGET := $(name)
G4EXLIB := true

INCLUDES+=$PWD/src

ifndef G4INSTALL
G4INSTALL = …/…/…
endif

.PHONY: all
all: rootcint lib bin

include $(G4INSTALL)/config/architecture.gmk

G4NOHIST := true
CPPFLAGS += $(shell root-config --cflags)
LDFLAGS += $(shell root-config --glibs)
LDFLAGS += -lXMLIO

rootcint:
@echo “----- Making Dictionaries -----”
@rootcint -f $(PWD)/src/EventDict.cc -c $(PWD)/include/Event.hh $(PWD)/include/EventLinkDef.h

include $(G4INSTALL)/config/binmake.gmk

####3333333333333333333333333333333333333333333333####

obviously my Event.cc lives in the src directory of my GEANT4 application and Event.hh/EventLinkDef.h live in the include directory.

and as a side note if you use I do not think it is needed to use GEANT4 Hit/HitsCollection classes and then convert them to root tree (you will be doing the same work twise, your app will run slower).

Needed? Certainly not. Undesirable? Hardly. Run slower? Not at all.

While you certainly don’t need to separate out the Geant definitions from your Root dictionaries, (among other practical issues) it gives a significant benefit that downstream users of your data don’t need a Geant installation, nor do they need any knowledge or understanding of Geant types, to use the results of your work.

This is a specific example of a very general software engineering principle: minimal coupling. Each piece of your design should know as little about the rest of your design as possible. This improves compile time, reduces bugs, and decreases the barrier to understanding and using a piece of code. Geant itself is a very good example of a system with minimal coupling between subsystems.

As for running slower: in principle that could happen. In my experience, when you actually profile a running Geant application, the additional overhead is not measurable in comparison to the huge amount of code necessary to take a single simulation step. Add in the ability to apply generic filtering and formatting before storage, and I’ve always found this type of design to be a big win.