diff --git a/CepGen/CMakeLists.txt b/CepGen/CMakeLists.txt
index a946120..072118f 100644
--- a/CepGen/CMakeLists.txt
+++ b/CepGen/CMakeLists.txt
@@ -1,110 +1,120 @@
 file(GLOB core_sources Core/*.cpp *.cpp)
 file(GLOB phys_sources Physics/*.cpp)
 file(GLOB sf_sources StructureFunctions/*.cpp)
 file(GLOB io_sources IO/GenericExportHandler.cpp IO/TextHandler.cpp)
 file(GLOB hadr_sources Hadronisers/GenericHadroniser.cpp)
 
 include_directories(${PROJECT_SOURCE_DIR})
 
 #----- check the external dependencies for SFs
 
 set(GRV_PATH ${PROJECT_SOURCE_DIR}/External)
 file(GLOB grv_sources ${GRV_PATH}/grv_*.f)
 if(grv_sources)
   message(STATUS "GRV PDFset found in ${grv_sources}!")
   add_definitions(-DGRVPDF)
   list(APPEND sf_sources ${grv_sources})
 else()
   message(STATUS "GRV PDFset not found. Will proceed without it")
 endif()
 
 #----- check the external dependencies for physics utilities
 
 if(alphas_sources)
   list(APPEND phys_sources ${alphas_sources})
 endif()
 
 set(addons_libraries "")
 set(strf_libraries ${GSL_LIB} ${GSL_CBLAS_LIB})
 
 #--- linking with LHAPDF
 
 if(LHAPDF)
   message(STATUS "LHAPDF found in ${LHAPDF}")
   list(APPEND strf_libraries ${LHAPDF})
   include_directories(${LHAPDF_INCLUDE})
 else()
   file(GLOB partonic_sf StructureFunctions/Partonic.cpp)
   list(REMOVE_ITEM sf_sources ${partonic_sf})
 endif()
 
 #--- linking with Pythia 6
 
 if(PYTHIA6)
   message(STATUS "Pythia 6 found in ${PYTHIA6}")
   list(APPEND hadr_sources "Hadronisers/Pythia6Hadroniser.cpp")
   list(APPEND addons_libraries ${PYTHIA6})
   if(PYTHIA6DUMMY)
     message(STATUS "Pythia 6 addons found in ${PYTHIA6DUMMY}")
     list(APPEND addons_libraries ${PYTHIA6DUMMY})
   endif()
 elseif(EXISTS $ENV{PYTHIA6_SRC})
   file(GLOB pythia6_src $ENV{PYTHIA6_SRC})
   message(STATUS "Pythia 6 source found in ${pythia6_src}")
   set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wno-tabs -Wno-maybe-uninitialized -Wno-integer-division -Wno-unused-variable -Wno-unused-dummy-argument")
   add_library(pythia6 SHARED ${pythia6_src})
   list(APPEND hadr_sources "Hadronisers/Pythia6Hadroniser.cpp")
   list(APPEND addons_libraries pythia6)
 endif()
 
 #--- linking with Pythia 8
 
 if(PYTHIA8)
   message(STATUS "Pythia 8 found in ${PYTHIA8}")
   message(STATUS "Pythia 8 will be used for LHEF output")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-misleading-indentation")
   include_directories(${PYTHIA8_INCLUDE})
   add_definitions(-DPYTHIA8)
   list(APPEND hadr_sources "Hadronisers/Pythia8Hadroniser.cpp")
   list(APPEND io_sources "IO/PythiaEventInterface.cpp")
   list(APPEND io_sources "IO/LHEFPythiaHandler.cpp")
   list(APPEND addons_libraries ${PYTHIA8} dl)
 endif()
 
 #--- linking with HepMC
 
 if(HEPMC_LIB)
   message(STATUS "HepMC found in ${HEPMC_LIB}")
   if(HEPMC_LIB MATCHES ".*HepMC3.?.so")
     message(STATUS "HepMC version 3 found")
     if(HEPMC_ROOT_LIB)
       message(STATUS "HepMC ROOT I/O library found")
       add_definitions(-DHEPMC3_ROOTIO)
       list(APPEND addons_libraries ${HEPMC_ROOT_LIB})
     endif()
     add_definitions(-DHEPMC3)
   endif()
   list(APPEND io_sources "IO/HepMCHandler.cpp")
   if(NOT PYTHIA8)
     message(STATUS "HepMC will be used for LHEF output")
     list(APPEND io_sources "IO/LHEFHepMCHandler.cpp")
   endif()
   list(APPEND addons_libraries ${HEPMC_LIB})
   include_directories(${HEPMC_INCLUDE})
 endif()
 
+#--- linking with ROOT
+
+if(ROOT_FOUND)
+  message(STATUS "ROOT found in ${ROOT_LIBRARY_DIR}")
+  list(APPEND addons_libraries ${ROOT_LIBRARIES})
+  list(APPEND io_sources "IO/ROOTTreeHandler.cpp")
+  include_directories(${ROOT_INCLUDE_DIRS})
+  link_directories(${ROOT_LIBRARY_DIR})
+endif()
+
 #----- build the objects
 
 add_library(CepGenCore SHARED ${core_sources} ${phys_sources} ${sf_sources})
 target_link_libraries(CepGenCore ${CEPGEN_EXTERNAL_CORE_REQS})
 target_link_libraries(CepGenCore ${strf_libraries})
 
 add_library(CepGenAddOns SHARED ${io_sources} ${hadr_sources})
 target_link_libraries(CepGenAddOns ${addons_libraries})
 target_link_libraries(CepGenAddOns CepGenEvent)
 
 #----- installation rules
 
 install(TARGETS CepGenCore DESTINATION lib)
 install(TARGETS CepGenAddOns DESTINATION lib)
 
diff --git a/CepGen/IO/ROOTTreeHandler.cpp b/CepGen/IO/ROOTTreeHandler.cpp
new file mode 100644
index 0000000..2b4d51f
--- /dev/null
+++ b/CepGen/IO/ROOTTreeHandler.cpp
@@ -0,0 +1,103 @@
+#include "CepGen/IO/ExportHandler.h"
+#include "CepGen/IO/ROOTTreeInfo.h"
+
+#include "CepGen/Core/Exception.h"
+#include "CepGen/Core/ParametersList.h"
+
+#include "CepGen/Event/Event.h"
+#include "CepGen/Parameters.h"
+
+// ROOT includes
+#include "TFile.h"
+
+#include <sstream>
+
+namespace cepgen
+{
+  namespace io
+  {
+    /**
+     * Handler for the storage of events in a ROOT format
+     * \author Laurent Forthomme <laurent.forthomme@cern.ch>
+     * \date 27 Jan 2014
+     */
+    class ROOTTreeHandler : public GenericExportHandler
+    {
+      public:
+        /// Class constructor
+        explicit ROOTTreeHandler( const ParametersList& );
+        ~ROOTTreeHandler();
+
+        void initialise( const Parameters& ) override;
+        /// Writer operator
+        void operator<<( const Event& ) override;
+        void setCrossSection( double, double ) override;
+
+      private:
+        std::unique_ptr<TFile> file_;
+        std::unique_ptr<ROOT::CepGenRun> run_tree_;
+        std::unique_ptr<ROOT::CepGenEvent> evt_tree_;
+    };
+
+    ROOTTreeHandler::ROOTTreeHandler( const ParametersList& params ) :
+      GenericExportHandler( "root" ),
+      file_( TFile::Open( params.get<std::string>( "filename", "output.root" ).c_str(), "recreate" ) ),
+      run_tree_( new ROOT::CepGenRun ), evt_tree_( new ROOT::CepGenEvent )
+    {
+      if ( !file_->IsOpen() )
+        throw CG_FATAL( "ROOTTreeHandler" ) << "Failed to create the output file!";
+      run_tree_->create();
+      evt_tree_->create();
+    }
+
+    ROOTTreeHandler::~ROOTTreeHandler()
+    {
+      run_tree_->fill();
+      file_->Write();
+    }
+
+    void
+    ROOTTreeHandler::initialise( const Parameters& params )
+    {
+      run_tree_->litigious_events = 0;
+      run_tree_->sqrt_s = params.kinematics.sqrtS();
+    }
+
+    void
+    ROOTTreeHandler::operator<<( const Event& ev )
+    {
+      evt_tree_->gen_time = ev.time_generation;
+      evt_tree_->tot_time = ev.time_total;
+      evt_tree_->np = 0;
+      for ( const auto& p : ev.particles() ) {
+        const cepgen::Particle::Momentum m = p.momentum();
+        evt_tree_->rapidity[evt_tree_->np] = m.rapidity();
+        evt_tree_->pt[evt_tree_->np] = m.pt();
+        evt_tree_->eta[evt_tree_->np] = m.eta();
+        evt_tree_->phi[evt_tree_->np] = m.phi();
+        evt_tree_->E[evt_tree_->np] = p.energy();
+        evt_tree_->m[evt_tree_->np] = p.mass();
+        evt_tree_->pdg_id[evt_tree_->np] = p.integerPdgId();
+        evt_tree_->parent1[evt_tree_->np] = ( p.mothers().size() > 0 ) ? *p.mothers().begin() : -1;
+        evt_tree_->parent2[evt_tree_->np] = ( p.mothers().size() > 1 ) ? *p.mothers().rbegin() : -1;
+        evt_tree_->status[evt_tree_->np] = (int)p.status();
+        evt_tree_->stable[evt_tree_->np] = ( (short)p.status() > 0 );
+        evt_tree_->charge[evt_tree_->np] = p.charge();
+        evt_tree_->role[evt_tree_->np] = p.role();
+
+        evt_tree_->np++;
+      }
+      run_tree_->num_events += 1;
+      evt_tree_->fill();
+    }
+
+    void
+    ROOTTreeHandler::setCrossSection( double xsect, double xsect_err )
+    {
+      run_tree_->xsect = xsect;
+      run_tree_->errxsect = xsect_err;
+    }
+  }
+}
+
+REGISTER_IO_MODULE( root, ROOTTreeHandler )
diff --git a/test/TreeInfo.h b/CepGen/IO/ROOTTreeInfo.h
similarity index 98%
rename from test/TreeInfo.h
rename to CepGen/IO/ROOTTreeInfo.h
index 7d95027..b7082c7 100644
--- a/test/TreeInfo.h
+++ b/CepGen/IO/ROOTTreeInfo.h
@@ -1,201 +1,200 @@
-#ifndef Test_TreeInfo_h
-#define Test_TreeInfo_h
+#ifndef CepGen_IO_ROOTTreeInfo_h
+#define CepGen_IO_ROOTTreeInfo_h
 
 #include "TFile.h"
 #include "TTree.h"
-#include "Math/Vector3D.h"
-#include "Math/Vector4D.h"
 
 #include <exception>
 #include <string>
+#include <iostream>
 
 namespace ROOT
 {
   /// All useful information about a generation run
   class CepGenRun
   {
     public:
       static constexpr const char* TREE_NAME = "run"; ///< Output tree name
       double sqrt_s; ///< Centre of mass energy for beam particles
       double xsect; ///< Process cross section, in pb
       double errxsect; ///< Uncertainty on process cross section, in pb
       unsigned int num_events; ///< Number of events generated in run
       unsigned int litigious_events; ///< Number of litigious events in run
 
       CepGenRun() {
         clear();
       }
       /// Reinitialise the run tree
       void clear() {
         sqrt_s = -1.;
         xsect = errxsect = -1.;
         num_events = litigious_events = 0;
       }
       /// Populate the run tree
       void create() {
         tree_ = std::make_shared<TTree>( TREE_NAME, "a tree containing information on the previous run" );
         if ( !tree_ )
           throw std::runtime_error( "Failed to create the run TTree!" );
         tree_->Branch( "xsect", &xsect, "xsect/D" );
         tree_->Branch( "errxsect", &errxsect, "errxsect/D" );
         tree_->Branch( "num_events", &num_events, "num_events/i" );
         tree_->Branch( "litigious_events", &litigious_events, "litigious_events/i" );
         tree_->Branch( "sqrt_s", &sqrt_s, "sqrt_s/D" );
       }
       /// Retrieve the ROOT tree
       TTree* tree() {
         return tree_.get();
       }
       /// Fill the run tree
       void fill() {
         tree_->Fill();
       }
       /// Attach the run tree reader to a given file
       void attach( const char* filename, const char* run_tree = TREE_NAME ) {
         attach( TFile::Open( filename ), run_tree );
       }
       /// Attach the run tree reader to a given tree
       void attach( TFile* file, const char* run_tree = TREE_NAME ) {
         //--- special constructor to avoid the memory to be cleared at destruction time
         tree_ = std::shared_ptr<TTree>( dynamic_cast<TTree*>( file->Get( run_tree ) ), [=]( TTree* ){} );
         if ( !tree_ )
           throw std::runtime_error( "Failed to attach to the run TTree!" );
         tree_->SetBranchAddress( "xsect", &xsect );
         tree_->SetBranchAddress( "errxsect", &errxsect );
         tree_->SetBranchAddress( "num_events", &num_events );
         tree_->SetBranchAddress( "litigious_events", &litigious_events );
         tree_->SetBranchAddress( "sqrt_s", &sqrt_s );
         if ( tree_->GetEntriesFast() > 1 )
           std::cerr << "The run tree has more than one entry." << std::endl;
         tree_->GetEntry( 0 );
       }
 
     private:
       /// ROOT tree used for storage/retrieval of this run information
       std::shared_ptr<TTree> tree_;
   };
 
   /// All useful information about a generated event
   class CepGenEvent
   {
     public:
       // book a sufficienly large number to allow the large multiplicity
       // of excited proton fragmentation products
       static constexpr unsigned short maxpart = 5000; ///< Maximal number of particles in event
       static constexpr const char* TREE_NAME = "events"; ///< Output tree name
 
       float gen_time; ///< Event generation time
       float tot_time; ///< Total event generation time
       int nremn_ch[2], nremn_nt[2];
       int np; ///< Number of particles in the event
       double pt[maxpart]; ///< Particles transverse momentum
       double eta[maxpart]; ///< Particles pseudo-rapidity
       double phi[maxpart]; ///< Particles azimutal angle
       double rapidity[maxpart]; ///< Particles rapidity
       double E[maxpart]; ///< Particles energy, in GeV
       double m[maxpart]; ///< Particles mass, in GeV/c\f${}^2\f$
       double charge[maxpart]; ///< Particles charges, in e
       int pdg_id[maxpart]; ///< Integer particles PDG id
       int parent1[maxpart]; ///< First particles mother
       int parent2[maxpart]; ///< Last particles mother
       int stable[maxpart]; ///< Whether the particle must decay or not
       int role[maxpart]; ///< Particles role in the event
       int status[maxpart]; ///< Integer status code
 
       CepGenEvent() {
         clear();
       }
       /// Reinitialise the event content
       void clear() {
         gen_time = tot_time = 0.;
         for ( unsigned short i = 0; i < 2; ++i )
           nremn_ch[i] = nremn_nt[i] = 0;
         np = 0;
         for ( unsigned short i = 0; i < maxpart; ++i ) {
           pt[i] = eta[i] = phi[i] = rapidity[i] = E[i] = m[i] = charge[i] = 0.;
           pdg_id[i] = parent1[i] = parent2[i] = stable[i] = role[i] = status[i] = 0;
         }
       }
       /// Retrieve the ROOT tree
       TTree* tree() {
         return tree_.get();
       }
       /// Fill the tree with a new event
       void fill() {
         if ( !tree_ )
           throw std::runtime_error( "CepGenEvent: Trying to fill a non-existent tree!" );
 
         tree_->Fill();
         clear();
       }
       /// Populate the tree and all associated branches
       void create() {
         tree_ = std::make_shared<TTree>( TREE_NAME, "a tree containing information on events generated in previous run" );
         if ( !tree_ )
           throw std::runtime_error( "Failed to create the events TTree!" );
         tree_->Branch( "npart", &np, "npart/I" );
         tree_->Branch( "nremn_charged", nremn_ch, "nremn_charged[2]/I" );
         tree_->Branch( "nremn_neutral", nremn_nt, "nremn_neutral[2]/I" );
         tree_->Branch( "role", role, "role[npart]/I" );
         tree_->Branch( "pt", pt, "pt[npart]/D" );
         tree_->Branch( "eta", eta, "eta[npart]/D" );
         tree_->Branch( "phi", phi, "phi[npart]/D" );
         tree_->Branch( "rapidity", rapidity, "rapidity[npart]/D" );
         tree_->Branch( "E", E, "E[npart]/D" );
         tree_->Branch( "m", m, "m[npart]/D" );
         tree_->Branch( "charge", charge, "charge[npart]/D" );
         tree_->Branch( "pdg_id", pdg_id, "pdg_id[npart]/I" );
         tree_->Branch( "parent1", parent1, "parent1[npart]/I" );
         tree_->Branch( "parent2", parent2, "parent2[npart]/I" );
         tree_->Branch( "stable", stable, "stable[npart]/I" );
         tree_->Branch( "status", status, "status[npart]/I" );
         tree_->Branch( "generation_time", &gen_time, "generation_time/F" );
         tree_->Branch( "total_time", &tot_time, "total_time/F" );
       }
       /// Attach the event tree reader to a given file
       void attach( const char* filename, const char* events_tree = TREE_NAME ) {
         file_.reset( TFile::Open( filename ) );
         attach( file_.get(), events_tree );
       }
       /// Attach the event tree reader to a given ROOT file
       void attach( TFile* f, const char* events_tree = TREE_NAME ) {
         //--- special constructor to avoid the memory to be cleared at destruction time
         tree_ = std::shared_ptr<TTree>( dynamic_cast<TTree*>( f->Get( events_tree ) ), [=]( TTree* ){} );
         attach();
       }
       /// Attach the event tree reader to a given tree
       void attach() {
         if ( !tree_ )
           throw std::runtime_error( "Failed to attach to the events TTree!" );
         tree_->SetBranchAddress( "npart", &np );
         tree_->SetBranchAddress( "nremn_charged", nremn_ch );
         tree_->SetBranchAddress( "nremn_neutral", nremn_ch );
         tree_->SetBranchAddress( "role", role );
         tree_->SetBranchAddress( "pt", pt );
         tree_->SetBranchAddress( "eta", eta );
         tree_->SetBranchAddress( "phi", phi );
         tree_->SetBranchAddress( "rapidity", rapidity );
         tree_->SetBranchAddress( "E", E );
         tree_->SetBranchAddress( "m", m );
         tree_->SetBranchAddress( "charge", charge );
         tree_->SetBranchAddress( "pdg_id", pdg_id );
         tree_->SetBranchAddress( "parent1", parent1 );
         tree_->SetBranchAddress( "parent2", parent2 );
         tree_->SetBranchAddress( "stable", stable );
         tree_->SetBranchAddress( "status", status );
         tree_->SetBranchAddress( "generation_time", &gen_time );
         tree_->SetBranchAddress( "total_time", &tot_time );
       }
 
     private:
       /// Tree for which the event is booked
       std::shared_ptr<TTree> tree_;
       std::unique_ptr<TFile> file_;
   };
 }
 
 constexpr const char* ROOT::CepGenRun::TREE_NAME;
 constexpr const char* ROOT::CepGenEvent::TREE_NAME;
 
 #endif
 
diff --git a/cmake/UseEnvironment.cmake b/cmake/UseEnvironment.cmake
index 6114b63..8705392 100644
--- a/cmake/UseEnvironment.cmake
+++ b/cmake/UseEnvironment.cmake
@@ -1,84 +1,86 @@
 if(NOT CMAKE_VERSION VERSION_LESS 3.1)
   set(CMAKE_CXX_STANDARD 14)
 else()
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
 endif()
 set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -Wall -cpp")
 #--- check if we are at CERN
 if($ENV{HOSTNAME} MATCHES "^lxplus[0-9]+.cern.ch")
   set(IS_LXPLUS "yes")
 endif()
 #--- ensure a proper version of the compiler is found
 if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 6.1)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic-errors -g")
 else()
   message(STATUS "clang or gcc above 6.1 is required")
   if(IS_LXPLUS)
     set(LXPLUS_SRC_ENV "source ${CMAKE_SOURCE_DIR}/source-lxplus.sh")
     message(STATUS "Compiling on LXPLUS. Did you properly source the environment variables? E.g.\n\n\t${LXPLUS_SRC_ENV}\n")
   endif()
   message(FATAL_ERROR "Please clean up this build environment, i.e.\n\trm -rf CMake*\nand try again...")
 endif()
 #--- set the default paths for external dependencies
 if(IS_LXPLUS)
   set(BASE_DIR "/cvmfs/sft.cern.ch/lcg")
   list(APPEND CMAKE_PREFIX_PATH "${BASE_DIR}/external/CMake/2.8.9/Linux-i386/share/cmake-2.8/Modules")
   set(GSL_DIR "${BASE_DIR}/releases/GSL/2.5-32fc5/x86_64-centos7-gcc62-opt")
   set(HEPMC_DIR "${BASE_DIR}/releases/HepMC/2.06.09-0a23a/x86_64-centos7-gcc62-opt")
   set(LHAPDF_DIR "${BASE_DIR}/releases/MCGenerators/lhapdf/6.2.2-8a3e6/x86_64-centos7-gcc62-opt")
   set(PYTHIA6_DIR "${BASE_DIR}/releases/MCGenerators/pythia6/429.2-c4089/x86_64-centos7-gcc62-opt")
   set(PYTHIA8_DIR "${BASE_DIR}/releases/MCGenerators/pythia8/240p1-ecd34/x86_64-centos7-gcc62-opt")
   set(PYTHON_DIR "${BASE_DIR}/releases/Python/2.7.15-075d4/x86_64-centos7-gcc62-opt")
   set(PYTHON_LIBRARY "${PYTHON_DIR}/lib/libpython2.7.so")
   set(PYTHON_EXECUTABLE "${PYTHON_DIR}/bin/python")
   set(PYTHON_INCLUDE_DIR "${PYTHON_DIR}/include/python2.7")
 
   message(STATUS "Compiling on LXPLUS. Do not forget to source the environment variables!")
   message(STATUS "e.g. `${LXPLUS_SRC_ENV}`")
 endif()
 #--- searching for GSL
 find_library(GSL_LIB gsl HINTS ${GSL_DIR} PATH_SUFFIXES lib REQUIRED)
 find_library(GSL_CBLAS_LIB gslcblas HINTS ${GSL_DIR} PATH_SUFFIXES lib)
 find_path(GSL_INCLUDE gsl HINTS ${GSL_DIR} PATH_SUFFIXES include)
 include_directories(${GSL_INCLUDE})
 #--- searching for LHAPDF
 find_library(LHAPDF LHAPDF HINTS ${LHAPDF_DIR} PATH_SUFFIXES lib)
 find_path(LHAPDF_INCLUDE LHAPDF HINTS ${LHAPDF_DIR} PATH_SUFFIXES include)
 #--- searching for HepMC
 find_library(HEPMC_LIB NAMES HepMC3 HepMC HINTS ${HEPMC_DIR} PATH_SUFFIXES lib)
 find_library(HEPMC_ROOT_LIB NAMES HepMC3rootIO PATH_SUFFIXES root)
 find_path(HEPMC_INCLUDE NAMES HepMC3 HepMC HINTS ${HEPMC_DIR} PATH_SUFFIXES include)
 #--- searching for Pythia 6
 set(PYTHIA6_DIRS $ENV{PYTHIA6_DIR} ${PYTHIA6_DIR} /usr /usr/local /opt/pythia6)
 find_library(PYTHIA6 pythia6 HINTS ${PYTHIA6_DIRS} PATH_SUFFIXES lib)
 find_library(PYTHIA6DUMMY pythia6_dummy HINTS ${PYTHIA6_DIRS} PATH_SUFFIXES lib)
 #--- searching for Pythia 8
 set(PYTHIA8_DIRS $ENV{PYTHIA8_DIR} ${PYTHIA8_DIR} /usr /usr/local /opt/pythia8)
 find_library(PYTHIA8 pythia8 HINTS ${PYTHIA8_DIRS} PATH_SUFFIXES lib)
 find_path(PYTHIA8_INCLUDE Pythia8 HINTS ${PYTHIA8_DIRS} PATH_SUFFIXES include include/Pythia8 include/pythia8)
+#--- searching for ROOT
+find_package(ROOT QUIET)
 
 message(STATUS "GSL found in ${GSL_LIB}")
 list(APPEND CEPGEN_EXTERNAL_CORE_REQS ${GSL_LIB} ${GSL_CBLAS_LIB})
 
 find_package(PythonLibs 2.7)
 find_library(MUPARSER muparser)
 if(MUPARSER)
   message(STATUS "muParser found in ${MUPARSER}")
   list(APPEND CEPGEN_EXTERNAL_CORE_REQS ${MUPARSER})
   add_definitions(-DMUPARSER)
 else()
   find_path(EXPRTK exprtk.hpp PATH_SUFFIXES include)
   if(EXPRTK)
     message(STATUS "exprtk found in ${EXPRTK}")
     add_definitions(-DEXPRTK)
     include_directories(${EXPRTK})
   endif()
 endif()
 #--- semi-external dependencies
 set(ALPHAS_PATH ${PROJECT_SOURCE_DIR}/External)
 file(GLOB alphas_sources ${ALPHAS_PATH}/alphaS.f)
 if(alphas_sources)
   message(STATUS "alphaS evolution found in ${alphas_sources}")
   add_definitions(-DALPHA_S)
 endif()
 
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 867ae34..16b6510 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,53 +1,52 @@
 #----- list all test executables
 
 file(GLOB executables_noroot RELATIVE ${PROJECT_SOURCE_DIR}/test *.cpp)
 file(GLOB executables_root RELATIVE ${PROJECT_SOURCE_DIR}/test *.cxx)
 file(GLOB executables_fortran RELATIVE ${PROJECT_SOURCE_DIR}/test *.f)
 
 #----- include the utilitaries
 
 set(tests "")
 
 #----- build all tests and link them to the core library
 
 foreach(exec_src ${executables_noroot})
   string(REPLACE ".cpp" "" exec_bin ${exec_src})
   add_executable(${exec_bin} ${exec_src})
   set_target_properties(${exec_bin} PROPERTIES EXCLUDE_FROM_ALL true)
   target_link_libraries(${exec_bin} ${CEPGEN_LIBRARIES})
   list(APPEND tests ${exec_bin})
 endforeach()
 
 foreach(exec_src ${executables_fortran})
   string(REPLACE ".f" "" exec_bin ${exec_src})
   add_executable(${exec_bin} ${exec_src})
   set_target_properties(${exec_bin} PROPERTIES EXCLUDE_FROM_ALL true)
   target_link_libraries(${exec_bin} ${CEPGEN_LIBRARIES})
   list(APPEND tests ${exec_bin})
 endforeach()
 
 #----- specify the tests requiring ROOT
 
-find_package(ROOT QUIET)
 if(ROOT_FOUND)
   include_directories(${ROOT_INCLUDE_DIRS})
   link_directories(${ROOT_LIBRARY_DIR})
 
   foreach(exec_src ${executables_root})
     string(REPLACE ".cxx" "" exec_bin ${exec_src})
     add_executable(${exec_bin} ${exec_src})
     set_target_properties(${exec_bin} PROPERTIES EXCLUDE_FROM_ALL true)
     target_link_libraries(${exec_bin} ${CEPGEN_LIBRARIES} ${ROOT_LIBRARIES})
     list(APPEND tests ${exec_bin})
   endforeach()
 else()
   message(STATUS "ROOT not found! skipping these tests!")
 endif()
 
 message(STATUS "The following tests/executables are available:\n${tests}")
 
 file(GLOB_RECURSE test_input_cards RELATIVE ${PROJECT_SOURCE_DIR}/test test_processes/* __init__.py)
 foreach(_files ${test_input_cards})
   configure_file(${_files} ${_files} COPYONLY)
 endforeach()
 configure_file(${PROJECT_SOURCE_DIR}/test/test_processes.cfg test_processes.cfg COPYONLY)
diff --git a/test/cepgen-root.cxx b/test/cepgen-root.cxx
deleted file mode 100644
index d40ced3..0000000
--- a/test/cepgen-root.cxx
+++ /dev/null
@@ -1,116 +0,0 @@
-#include "CepGen/Cards/Handler.h"
-#include "CepGen/Generator.h"
-#include "CepGen/Event/Event.h"
-
-#include <iomanip>
-#include <iostream>
-
-#include "TreeInfo.h"
-#include "AbortHandler.h"
-
-// ROOT includes
-#include "TFile.h"
-#include "TTree.h"
-#include "TLorentzVector.h"
-
-using namespace std;
-
-std::unique_ptr<ROOT::CepGenRun> run;
-std::unique_ptr<ROOT::CepGenEvent> ev;
-
-void fill_event_tree( const cepgen::Event& event, unsigned long ev_id )
-{
-  //if ( ev_id % 10 == 0 )
-  //  cout << ">> event " << ev_id << " generated" << endl;
-
-  if ( !ev || !run )
-    return;
-
-  ev->gen_time = event.time_generation;
-  ev->tot_time = event.time_total;
-  ev->np = 0;
-  //cout << event.particles().size() << endl;
-  for ( const auto& p : event.particles() ) {
-    const cepgen::Particle::Momentum m = p.momentum();
-    ev->rapidity[ev->np] = m.rapidity();
-    ev->pt[ev->np] = m.pt();
-    ev->eta[ev->np] = m.eta();
-    ev->phi[ev->np] = m.phi();
-    ev->E[ev->np] = p.energy();
-    ev->m[ev->np] = p.mass();
-    ev->pdg_id[ev->np] = p.integerPdgId();
-    ev->parent1[ev->np] = ( p.mothers().size() > 0 ) ? *p.mothers().begin() : -1;
-    ev->parent2[ev->np] = ( p.mothers().size() > 1 ) ? *p.mothers().rbegin() : -1;
-    ev->status[ev->np] = (int)p.status();
-    ev->stable[ev->np] = ( (short)p.status() > 0 );
-    ev->charge[ev->np] = p.charge();
-    ev->role[ev->np] = p.role();
-
-    ev->np++;
-  }
-  run->num_events += 1;
-  ev->fill();
-}
-
-/**
- * Generation of events and storage in a ROOT format
- * \author Laurent Forthomme <laurent.forthomme@cern.ch>
- * \date 27 jan 2014
- * \defgroup Executables List of executables
- * \addtogroup Executables
- */
-int main( int argc, char* argv[] )
-{
-  cepgen::utils::AbortHandler ctrl_c;
-
-  cepgen::Generator mg;
-
-  if ( argc < 2 )
-    throw CG_FATAL( "main" ) << "Usage: " << argv[0] << " input-card [filename=events.root]";
-
-  mg.setParameters( cepgen::card::Handler::parse( argv[1] ) );
-  CG_INFO( "main" ) << mg.parametersPtr();
-
-  //----- open the output root file
-
-  const char* filename = ( argc > 2 ) ? argv[2] : "events.root";
-  TFile file( filename, "recreate" );
-  if ( !file.IsOpen() )
-    throw CG_FATAL( "main" ) << "Failed to create the output file!";
-
-  //----- then generate the events and the container tree structure
-
-  run.reset( new ROOT::CepGenRun );
-  run->create();
-  ev.reset( new ROOT::CepGenEvent );
-  ev->create();
-
-  try {
-    //----- start by computing the cross section for the list of parameters applied
-    double xsec, err;
-    mg.computeXsection( xsec, err );
-
-    //----- populate the run tree
-
-    run->xsect = xsec;
-    run->errxsect = err;
-    run->litigious_events = 0;
-    run->sqrt_s = mg.parameters().kinematics.sqrtS();
-
-    //----- launch the events generation
-    mg.generate( fill_event_tree );
-    run->fill();
-  } catch ( const cepgen::utils::RunAbortedException& e ) {
-    e.dump();
-  } catch ( const cepgen::Exception& e ) {
-    e.dump();
-  }
-
-  file.Write();
-  CG_INFO( "main" )
-    << run->num_events << " event" << cepgen::utils::s( run->num_events )
-    << " written in \"" << filename << "\".";
-
-  return 0;
-}
-