Project

General

Profile

Converting a Module from FMWK

It is very straight forward to convert a module from the FMWK framework into the CD developed framework.

There are only a few easy steps to doing the conversion, as illustrated using the GENIEGen module.

The .h file must be changed so that the module inherits from the proper type of art module and the Update method must be removed.

In the .cxx file the line calling the macro to declare a module is removed and of course the proper header files must be included. The Update method must be removed and the parameters are set using the art::ParameterSet passed into the constructor. The last major change is how objects from previous modules are gotten out of the art::Event, as might be expected.

NB Objects are stored in the art::Event as collections of references, not pointers. You need to get them out of the event as collections of references, not pointers. Additionally, if you are getting an object out of an art::Event, you must declare the local variable in your code to be an art::Ptr<T>, not a standard C pointer. See the examples below for details

A new file, the _module.cc file is needed to call the macro declaring the module to the framework.

All of these steps are shown below. In the steps to change the .h and .cxx files the FMWK code is shown first, followed by the code in the new framework.

Changing the .h file

First the code in the FMWK framework:

////////////////////////////////////////////////////////////////////////
/// \file GENIEGen.h
//
/// \version $Id: GENIEGen.h,v 1.3 2010/02/12 22:27:32 rbpatter Exp $
/// \author  messier@indiana.edu
////////////////////////////////////////////////////////////////////////
#ifndef EVGEN_GENIEGEN_H
#define EVGEN_GENIEGEN_H
#include "JobControl/Module.h" 
#include "EventGeneratorBase/GENIEHelper.h" 

#include "TStopwatch.h" 

namespace edm { class EventHandle; }
namespace cfg { class Config;      }

namespace evgen {
  /// A module to check the results from the Monte Carlo generator
  class GENIEGen : public jobc::Module {
  public:
    GENIEGen(const char* version);
    ~GENIEGen();                        
    void Update(const cfg::Config& c);

    jobc::Result Reco(edm::EventHandle& evt);  

  private:

    evgb::GENIEHelper  *fGENIEHelp;      ///< GENIEHelper object
    std::string         fGeoVersion;     ///< version of geometry to use
    std::string         fGENIEVersion;   ///< version of genie xml file to use    
    int                 fPassEmptySpills;///< whether or not to kill events withno interactions         
    TStopwatch          fStopwatch;      ///keep track of how long it takes to rn the job  
 };
}#endif // EVGEN_GENIEGEN_H
////////////////////////////////////////////////////////////////////////

Now in the new framework with extra comments about the changes called out as

  ////////////////////////////////////////////////////////////
  // some comment here
  ////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// \file GENIEGen.h
//
/// \version $Id: GENIEGen.h,v 1.2 2010/09/28 18:00:17 p-novaart Exp $
/// \author  messier@indiana.edu
////////////////////////////////////////////////////////////////////////
#ifndef EVGEN_GENIEGEN_H
#define EVGEN_GENIEGEN_H

#include "art/Framework/Core/EDProducer.h" //include the proper bit of the framework
#include "EventGeneratorBase/GENIEHelper.h" 

#include "TStopwatch.h" 

namespace evgen {

  ////////////////////////////////////////////////////////////
  //notice the module inherits from the module type, in this case a edm::EDProducer
  //////////////////////////////////////////////////////////// 

  /// A module to check the results from the Monte Carlo generator
  class GENIEGen : public art::EDProducer {

  public:

    explicit GENIEGen(fhicl::ParameterSet const &pset);// the explicit tag tells the compiler that GENIEGen is not an edm::ParameterSet
    virtual ~GENIEGen();                        
                                    ////////////////////////////////////////////////////////
    void produce(edm::Event& evt);  // produce is what makes the MCTruth objects  
    void beginJob();                // beginJob is there to make histograms at the beginning of the job
                                    // A edm::EDProducer does not have the ability to also be a edm::Analyzer
                                    ////////////////////////////////////////////////////////

  private:

    evgb::GENIEHelper  *fGENIEHelp;      ///< GENIEHelper object
    int                 fPassEmptySpills;///< whether or not to kill events with no interactions
    TStopwatch          fStopwatch;      ///keep track of how long it takes to run the job
  };
}

#endif // EVGEN_GENIEGEN_H
////////////////////////////////////////////////////////////////////////

Basically the only changes are to include the proper bits of the framework, remove the Update method and change Reco to produce and BeginJob to beginJob.

Changing the .cxx file

Again the FMWK version is shown first.

////////////////////////////////////////////////////////////////////////
// $Id: GENIEGen.cxx,v 1.7 2010/04/06 15:42:03 rhatcher Exp $
//
// gGENIE neutrino event generator
//
// brebel@fnal.gov
//
////////////////////////////////////////////////////////////////////////
#include <cassert>
#include <cstdlib>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <unistd.h>

#include "XMLInterface/xmli.h" 
#include "EventDataModel/edm.h" 
#include "IoModules/ReadWriteModule.h" 
#include "Config/Config.h" 
#include "JobControl/jobc.h" 
#include "SimulationBase/MCTruth.h" 
#include "SimulationBase/MCNeutrino.h" 
#include "SimulationBase/MCFlux.h" 
#include "EventGenerator/GENIEGen.h" 
#include "Header/Header.h" 
#include "Geometry/geo.h" 
#include "Utilities/RandomHandler.h" 

using namespace evgen;

MODULE_DECL(evgen::GENIEGen);

//____________________________________________________________________________
GENIEGen::GENIEGen(const char* version) :
  jobc::Module("evgen::GENIEGen"),
  fGENIEHelp(0)
{  
  fStopwatch.Start();
  this->SetWatch("generation", version);
}

//____________________________________________________________________________
GENIEGen::~GENIEGen()
{  
  fStopwatch.Stop();
  std::cout << "real time to produce file: " << fStopwatch.RealTime() << std::endl;
}

//____________________________________________________________________________
void GENIEGen::Update(const cfg::Config& c)
{
  std::string fluxtype;
  c("GeometryVersion").Get(fGeoVersion);  
  c("FluxType")       .Get(fluxtype);
  c("PassEmptySpills").Get(fPassEmptySpills);

  std::string geoshort = "ipnd";
  if(fGeoVersion.find("neardet")     != std::string::npos) geoshort = "nd";
  else if(fGeoVersion.find("ndos")   != std::string::npos) geoshort = "ndos";
  else if(fGeoVersion.find("fardet") != std::string::npos) geoshort = "fd";

  ///for ntuple fluxes, there is no change to geoshort
  if(fluxtype.compare("histogram") == 0) geoshort += "hist";
  else if(fluxtype.compare("mono") == 0) geoshort  = "default";
  else if(fluxtype.compare("simple_flux") == 0) geoshort  += "simple";

  std::cout << "using " << fGeoVersion.c_str() << " geometry" << std::endl;
  std::cout << "getting GENIEHelper with " << geoshort.c_str() << " configuration" << std::endl;

  fGENIEHelp = new evgb::GENIEHelper("GENIE", geoshort);
  fGENIEVersion = geoshort;
  fGENIEHelp->Initialize( geo::Geometry::Instance(0, fGeoVersion.c_str()) );

}

//____________________________________________________________________________
jobc::Result GENIEGen::Reco(edm::EventHandle& evt)
{
  TString gseed = getenv("GSEED");

  ///setup the Header
  hdr::Header header;
  header.SetVersion      ("MonteCarlo",       "GENIE");
  header.SetRandomSeed   ("GENIE",            gseed.Atoll());
  header.SetConfiguration("GENIE",            fGENIEVersion);
  header.SetConfiguration("DetectorLocation", fGENIEHelp->DetectorLocation());
  header.SetConfiguration("Geometry",         fGeoVersion);
  header.SetConfiguration("GENIEJob",         jobc::XMLConfiguration());

  ///check if we are going to make events for this spill - could be 
  ///that we are using flux histograms and the poisson number for 
  ///how many interactions to make is 0
  if(fGENIEHelp->Stop()&&!fPassEmptySpills){
    //std::cerr << "no events made for this spill" << std::endl;
    return jobc::kFailed;
  }

  evt.DAQ().Put(header, ".");

  while(!fGENIEHelp->Stop()){

    simb::MCTruth truth;
    simb::MCFlux  flux;

    ///GENIEHelper returns a false in the sample method if 
    ///either no neutrino was generated, or the interaction
    ///occurred beyond the detector's z extent - ie something we
    ///would never see anyway.
    if(fGENIEHelp->Sample(truth, flux)){

      evt.MC().Put(truth, ".");
      evt.MC().Put(flux, ".");
    }///end if genie was able to make an event

  }///end event generation loop

  return jobc::kPassed;
}

Now in the new framework with comments called out as

  ////////////////////////////////////////////////////////////
  // some comment here
  ////////////////////////////////////////////////////////////
// Framework includes
//////////////////////////////////////////////////////
// Of course these are all different
//////////////////////////////////////////////////////

#include <cassert>
#include <cstdlib>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <unistd.h>
#include <iostream>
#include <ctime>

// ART includes
#include "art/Framework/Core/Event.h" 
#include "fhiclcpp/ParameterSet.h" 
#include "art/Persistency/Common/Handle.h" 
#include "art/Framework/Core/ModuleMacros.h" 
#include "art/Framework/Services/Registry/ServiceHandle.h" 
#include "art/Framework/Services/Optional/TFileService.h" 
#include "art/Framework/Core/TFileDirectory.h" 
#include "messagefacility/MessageLogger/MessageLogger.h" 

// NOvA includes
#include "SimulationBase/simbase.h" 
#include "EventGenerator/GENIEGen.h" 
#include "Utilities/RandomHandler.h" 
#include "Geometry/inc/geo.h" 

#include "TH1.h" 
#include "TMath.h" 
#include "TRandom3.h" 

namespace evgen {

  //-----------------------------------------------------
  //////////////////////////////////////////////////////  
  // Notice the difference with the Update method in FMWK 
  // - the constructor is passed the parameter set of key value
  // pairs to set the parameters
  //////////////////////////////////////////////////////
  GENIEGen::GENIEGen(edm::ParameterSet const& pset) :
    fGENIEHelp(new evgb::GENIEHelper(pset))
    , fPassEmptySpills(pset.get< bool >("PassEmptySpills"))
  {  
    fStopwatch.Start();

    //////////////////////////////////////////////////////
    // This next line tells the framework that this module will
    // make a std::vector<sim::Electrons> > to store in the event
    // There must be one produces line for every collection to be 
    // stored in the event.  See LArG4/src/LArG4.cxx for example 
    // of a module storing multiple objects to the event.
    //////////////////////////////////////////////////////
    produces< std::vector<simb::MCTruth> >();
    produces< std::vector<simb::MCFlux>  >();

  }

   //____________________________________________________________________________
  GENIEGen::~GENIEGen()
  {  
    fStopwatch.Stop();

    ////////////////////////////////////////////////////
    // Use the message facility to set the output
    ////////////////////////////////////////////////////

    mf::LogInfo("GENIERunTime") << "real time to produce file: " << fStopwatch.RealTime();
  }

  //____________________________________________________________________________
  //////////////////////////////////////////////////////
  // The beginJob is a method where you can make histograms using TFileService
  // The TFileService is what hooks up histograms, graphs and trees
  // made in a module to the appropriate output location in 
  // the output histogram file.  It also handles the memory management
  // for these objects
  //////////////////////////////////////////////////////
  void GENIEGen::beginJob()
  {
    fGENIEHelp->Initialize();
  }

  //____________________________________________________________________________
  void GENIEGen::produce(edm::Event& evt)
  {
    // check if we are going to make events for this spill - could be 
    // that we are using flux histograms and the poisson number for 
    // how many interactions to make is 0
    if(fGENIEHelp->Stop()&&!fPassEmptySpills){
      throw cms::Exception("NoNuInteraction") << "no neutrino interaction made for this spill";
      return;
    }

    //////////////////////////////////////////////////////
    // Make a std::auto_ptr<> for the thing you want to put into the event
    // because that handles the memory management for you
    //////////////////////////////////////////////////////
    std::auto_ptr< std::vector<simb::MCTruth> > truthcol(new std::vector<simb::MCTruth>);
    std::auto_ptr< std::vector<simb::MCFlux>  > fluxcol (new std::vector<simb::MCFlux >);

    while(!fGENIEHelp->Stop()){

      simb::MCTruth truth;
      simb::MCFlux  flux;

      // GENIEHelper returns a false in the sample method if 
      // either no neutrino was generated, or the interaction
      // occurred beyond the detector's z extent - ie something we
      // would never see anyway.
      if(fGENIEHelp->Sample(truth, flux)){

        truthcol->push_back(truth);
        fluxcol->push_back(flux);

      }// end if genie was able to make an event

    }// end event generation loop

    //////////////////////////////////////////////////////
    // here is how to put the collection into the edm::Event
    //////////////////////////////////////////////////////
    evt.put(truthcol);
    evt.put(fluxcol);

    return;
  }
}// namespace

Making a _module.cc file

Below is the GENIEGen_module.cc file

// Framework includes
#include "art/Framework/Core/ModuleMacros.h" 

#include "EventGenerator/GENIEGen.h" 

namespace evgen{

  DEFINE_ART_MODULE(GENIEGen);

}