Example 3 Getting ROOT Output With Fluka -------------------------------------------------------- UPDATED===10.10.2008.09.13.19 TITLE===Getting ROOT Output With Fluka TYPE===database -------------------------------------------------------- --------------------------------------------------------
Riccardo Brunetti (INFN, Italy); 9 May 2003
Vasilis Vlachoudis (CERN, Geneve); 6 March 2008
R. Brunetti
Last Updated by Vasilis Vlachoudis
In this document we describe a possible approach to the problem of obtaining the output of a FLUKA simulation in the form of a ROOT file, like a ROOT tree.
The FLUKA program comes to the users as a huge library of routines entirely written in FORTRAN and is originally designed to provide an output in its own format, that can be manipulated with special tools provided with the code.
Recently, however, a number of users changed their frameworks to the C/C++ environment and started to use ROOT as the main analysis tool, hence a simple method to merge the two packages could be useful.
On the other hand the FLUKA package, as it is now, is the result of many years of development and to rewrite it in some OO language, in order to completely integrate it in the ROOT framework, (even it is possible in principle) could be very dangerous.
The procedure we will describe reduces as much as possible the changes in the FLUKA fortran routines, simply adding calls to external library functions where needed inside the original FLUKA users routines.
The standard scoring mechanisms of FLUKA are strongly recommended for most of the cases, sometimes a custom scoring is needed. While it can be convinient to create customised histograms and n-tuples in ROOT one has to pay special attention on how to interpret the information he is scorring.
The use of an External C/C++ Library ::::::::::::Instead of rewriting the FLUKA users routine in some language other than FORTRAN, the simplest approach is the one of calling from inside them user C/C++ functions from a custom external library.
In doing this, the main problem is the one of passing the needed variables to the external function. Some of them are locally available inside the FORTRAN user subroutine or entry point, while others are placed inside global COMMON BLOCKS.
In the first case, it's very simple to pass the variables to the C/C++ function; this operation can be performed through the function's arguments, provided to follow some simple rule.
In the second case one has to include some header files in the C/C++ code, that make the FORTRAN COMMON BLOCKS available through C/C++ globally defined structures.
Once the problem of the variables has been solved, the C/C++ library and the FLUKA FORTRAN user routines can be compiled separately, to obtain the required object files to be linked into the FLUKA executable.
It is important to remember that, in order to avoid problems of undefined symbols when linking (the symbol's names follow different rules for C++ and fortran compilers), all the external C/C++ functions must be declared inside external "C" blocks.
Compiling and Linking ::::::::::::The FORTRAN and C/C++ code can be compiled separately. For the modified FLUKA user routines the script fff can be simply used without any modifications, while for the C/C++ library a Makefile can be prepared.
The Makefile should produce an object file containing the library part of the code and a ROOT shared object that can be loaded dynamically inside the ROOT CINT environment, containing the information about the custom classes used in the program.
To finally link everything to the FLUKA executable, the lfluka is used, including the required ROOT libraries and the custom shared object previously created.
A Simple Example ::::::::::::We give here a simple example of an external C++ library which allows to obtain the output of the a simple example root.inp input file in the form of a ROOT tree, that can be saved on file and then opened and analyzed. The main steps are the following:
#ifndef ROOT_Results #define ROOT_Results #include "TObject.h" class Results : public TObject { private: Int_t ij; Double_t econtr, xa, ya, za, txx, tyy, tzz; public: Results() : ij(0), econtr(0), xa(0), ya(0), za(0), txx(0), tyy(0), tzz(0) {} Results(Int_t ijj, Double_t econtrr, Double_t xaa, Double_t yaa, Double_t zaa, Double_t txxx, Double_t tyyy, Double_t tzzz); virtual ~Results(); ClassDef(Results,1); }; #endif
#ifndef __CFORTRAN_LOADED #include "cfortran.h" #endif #include#include #include "Results.h" #include #include #ifndef WIN32 #define myusrini myusrini_ #else #define myusrini MYUSRINI #endif static TFile *RootFile = 0; static TTree *RootTree = 0; static Results *TheResults = 0; extern "C" { void myusrini (Double_t &pluto) { printf("Executing MYUSRINI\n"); RootFile = new TFile("Out.root","recreate"); RootTree = new TTree("ResultsTree","Protons"); RootTree->Branch("Results", "Results", &TheResults, 64000, 1); printf("%f\n", pluto); } } #ifndef WIN32 #define treefill treefill_ #else #define treefill TREEFILL #endif extern "C" { void treefill(Int_t &ij, Double_t &econtr, Double_t , Double_t &ya, Double_t &za, Double_t &txx, Double_t &tyy, Double_t &tzz) { if (TheResults) { delete TheResults; TheResults = 0; } TheResults = new Results(ij, econtr, xa, ya, za, txx, tyy, tzz); RootTree->Fill(); } } #ifndef WIN32 #define fileclose fileclose_ #else #define fileclose FILECLOSE #endif extern "C" { void fileclose() { if (TheResults) { delete TheResults; TheResults = 0; } RootTree->Write(); RootFile->Close(); } }
... LUSRIN = .TRUE. * *** Write from here on *** * PIPPO = 2.5D0 CALL myusrini(PIPPO); ...
... CALL FILECLOSE ...
... * *======================================================================* * * * Boundary-(X)crossing DRAWing: * * * * Icode = 1x: call from Kaskad * * 19: boundary crossing * * Icode = 2x: call from Emfsco * * 29: boundary crossing * * Icode = 3x: call from Kasneu * * 39: boundary crossing * * Icode = 4x: call from Kashea * * 49: boundary crossing * * Icode = 5x: call from Kasoph * * 59: boundary crossing * * * *======================================================================* * * ENTRY BXDRAW ( ICODE, MREG, NEWREG, XSCO, YSCO, ZSCO ) IF(MREG.EQ.3.AND.NEWREG.EQ.2) THEN IF( JTRACK.EQ.1) THEN IF(ETRACK.GT.AM(JTRACK)) THEN XTUP(1) = JTRACK XTUP(2) = ETRACK-AM(JTRACK) XTUP(3) = XSCO XTUP(4) = YSCO XTUP(5) = ZSCO XTUP(6) = CXTRCK XTUP(7) = CYTRCK XTUP(8) = CZTRCK CALL treefill(JTRACK, + (ETRACK-AM(JTRACK)),XSCO,YSCO,ZSCO, + CXTRCK,CYTRCK,CZTRCK) ENDIF ENDIF ENDIF RETURN ...
![]() |
Figure 1: ROOT tree browser showing the variables retrieved from FLUKA run |
![]() |
Figure 2: Example of a distribution of an output variable |
Using an external library it is possible to merge piece of codes written in C/C++ with the FLUKA package. This allows to build custom functions which act as interfaces with the ROOT framework, in order, for example, to obtain the output of the simulation in the form of ROOT files.
The changes in the original fortran code are minimal, and simply consist in adding some external function calls where needed, without touching the core of the FLUKA program.
This approach can thus be considered as an alternative to the h2root method and can give more flexibility for those people who want to write custom pieces of code in C or C++ and to use ROOT for the following data analysis.