Commits

Anonymous committed 77e21a6

Tagging AthenaServices-01-56-00. add src/AtDSFMTGenSvc.cxx, src/AtDSFMTGenSvc.h - new service which uses a Mersenne Twister random number generator. (By Michael and Paolo.) Requires External/AtlasDSFMT and Simulation/Tools/AtlasCLHEP_RandomGenerators packages to be in the release. src/components/AthenaServices_entries.cxx - add entries for AtDSFMTGenSvc. cmt/requirements - add use statement for AtlasCLHEP_RandomGenerators package.

  • Participants
  • Parent commits e9d200d

Comments (0)

Files changed (5)

+2012-02-21  John Chapman  <John.Chapman@cern.ch>
+
+	* tagging AthenaServices-01-56-00 
+	* add src/AtDSFMTGenSvc.cxx, src/AtDSFMTGenSvc.h - new service
+	which uses a Mersenne Twister random number generator. (By Michael
+	and Paolo.) Requires External/AtlasDSFMT and
+	Simulation/Tools/AtlasCLHEP_RandomGenerators packages to be in the
+	release.
+	* src/components/AthenaServices_entries.cxx - add entries for
+	AtDSFMTGenSvc.
+	* cmt/requirements - add use statement for
+	AtlasCLHEP_RandomGenerators package.
+
 2012-02-01  Paolo Calafiura  <calaf@localhost6.localdomain6>
 
 	* tagging AthenaServices-01-55-05
 use AtlasPolicy      AtlasPolicy-*
 
 private
-use GaudiInterface   GaudiInterface-*  	  External
-use StoreGate        StoreGate-*       	  Control
-use Navigation       Navigation-*         Control
+use AtlasCLHEP_RandomGenerators    AtlasCLHEP_RandomGenerators-*    Simulation/Tools
+use GaudiInterface                 GaudiInterface-*  	            External
+use StoreGate                      StoreGate-*       	            Control
+use Navigation                     Navigation-*                     Control
 
 library AthenaServices *.cxx -s=components *.cxx
 apply_pattern component_library

src/AtDSFMTGenSvc.cxx

+#include "GaudiKernel/ISvcLocator.h"
+#include "GaudiKernel/IIncidentSvc.h"
+#include "GaudiKernel/Incident.h"
+#include "GaudiKernel/ServiceHandle.h"
+
+#include "EventInfo/EventIncident.h"
+#include "EventInfo/EventInfo.h"
+#include "EventInfo/EventID.h"
+
+#include "interpretSeeds.h"
+#include "AtDSFMTGenSvc.h"
+#include "crc_combine.h"
+
+#include "AtlasCLHEP_RandomGenerators/dSFMTEngine.h"
+
+#include <cassert>
+#include <iostream>
+
+/*FIXME temporarily needed for old seeding scheme*/
+#include "StoreGate/tools/hash_functions.h" 
+
+using namespace std;
+
+/// Standard Constructor
+AtDSFMTGenSvc::AtDSFMTGenSvc(const std::string& name,ISvcLocator* svc)
+  : AthService(name,svc), 
+    m_read_from_file(false),
+    m_file_to_read(name + ".out"),    
+    m_save_to_file(true),
+    m_file_to_write(name + ".out"),
+    m_eventReseed(true),
+    m_reseedStreamNames(),
+    m_reseedingOffsets(),
+    m_engines(), m_engines_copy()
+{
+    // Get user's input
+    declareProperty("Seeds", m_streams_seeds,
+                    "seeds for the engines, this is a vector of strings of the form ['SequenceName [OFFSET num] Seed1 Seed2', ...] where OFFSET is an optional integer that allows to change the sequence of randoms for a given run/event no and SequenceName combination. Notice that Seed1/Seed2 are dummy when EventReseeding is used");
+    declareProperty("ReadFromFile", m_read_from_file,
+                    "set/restore the status of the engine from file");
+    declareProperty("FileToRead",   m_file_to_read,
+                    "name of a ASCII file, usually produced by AtDSFMTGenSvc itself at the end of a job, containing the information to fully set/restore the status");
+    declareProperty("SaveToFile", m_save_to_file,
+                    "save the status of the engine to file");
+    declareProperty("FileToWrite",   m_file_to_write,
+                    "name of an ASCII file which will be produced on finalize, containing the information to fully set/restore the status");
+    declareProperty("EventReseeding", m_eventReseed, "reseed every event using a hash of run and event numbers");
+    declareProperty("ReseedStreamNames", m_reseedStreamNames, "the streams we are going to set the seeds of (default: all streams)");
+
+    // Set Default values
+    m_default_seed1               =        3591;
+    m_default_seed2               =        2309736;
+    m_PYTHIA_default_seed1        =        93453591;
+    m_PYTHIA_default_seed2        =        73436;
+    m_HERWIG_default_seed1        =        355391;
+    m_HERWIG_default_seed2        =        97336;
+}
+
+
+/// Standard Destructor
+AtDSFMTGenSvc::~AtDSFMTGenSvc()  
+{
+  engineIter i(m_engines.begin()), e(m_engines.end());
+  while (i != e) delete (i++)->second;
+}
+
+// Query the interfaces.
+//   Input: riid, Requested interface ID
+//          ppvInterface, Pointer to requested interface
+//   Return: StatusCode indicating SUCCESS or FAILURE.
+// N.B. Don't forget to release the interface after use!!!
+StatusCode AtDSFMTGenSvc::queryInterface(const InterfaceID& riid, void** ppvInterface) 
+{
+    if ( IAtRndmGenSvc::interfaceID().versionMatch(riid) )    {
+        *ppvInterface = (IAtRndmGenSvc*)this;
+    }
+    else  {
+        // Interface is not directly available: try out a base class
+        return AthService::queryInterface(riid, ppvInterface);
+    }
+    addRef();
+    return StatusCode::SUCCESS;
+}
+
+StatusCode AtDSFMTGenSvc::initialize()
+{
+  ATH_MSG_INFO
+    ("Initializing " << name()
+     << " - package version " << PACKAGE_VERSION 
+     << "\n INITIALISING RANDOM NUMBER STREAMS. ");
+
+  /// Incident Service
+  ServiceHandle<IIncidentSvc> pIncSvc("IncidentSvc", name());
+
+  // set up the incident service:
+  if (!(pIncSvc.retrieve()).isSuccess()) {
+    ATH_MSG_ERROR ("Could not locate IncidentSvc ");
+    return StatusCode::FAILURE;
+  }
+  
+  //start listening to "EndEvent"
+  static const int PRIORITY = 100;
+  pIncSvc->addListener(this, "EndEvent", PRIORITY);
+
+  //and to BeginEvent if we are reseeding
+  if (m_eventReseed) {
+      ATH_MSG_INFO ("will be reseeded for every event");
+      pIncSvc->addListener(this, "BeginEvent", PRIORITY);
+  }
+  pIncSvc.release().ignore();
+
+  if (m_read_from_file) {
+    // Read from a file
+    ifstream infile( m_file_to_read.c_str() );
+    if ( !infile ) {
+      ATH_MSG_ERROR (" Unable to open: " << m_file_to_read);
+      return StatusCode::FAILURE;
+    } else {
+      std::string buffer;
+      while (std::getline(infile, buffer)) {
+        string stream; 
+        std::vector<uint32_t> seeds;
+        //split the space-separated string in 3 words:
+        if (interpretSeeds(buffer, stream, seeds)) {
+          msg (MSG::DEBUG) 
+            << " INITIALISING " << stream << " stream with seeds ";
+          for (std::vector<uint32_t>::const_iterator i = seeds.begin(); i != seeds.end(); ++i){
+            // The state returned is a set of 32-bit numbers.
+            // On 64-bit platforms, though, the vector holds 64-bit ints.
+            // For the first word, one gets garbage in the high 32 bits.
+            // (This is because the crc32 routine used in clhep
+            // to hash the engine names doesn't mask down to 32 bits.)
+            // So mask off the garbage so that we get consistent results
+            // across platforms.
+            msg() << ((*i) & 0xffffffffu) << " ";
+          }
+          msg() << " read from file " << m_file_to_read << endreq;
+          if (CreateStream(seeds, stream)) {
+            msg(MSG::DEBUG)
+              << stream << " stream initialized succesfully" <<endreq;
+          } else {
+            msg(MSG::ERROR)
+              << stream << " stream FAILED to initialize" <<endreq;
+            return StatusCode::FAILURE;
+          }
+        } else {                
+          msg(MSG::ERROR)
+            << "bad line\n" << buffer 
+            << "\n in input file " << m_file_to_read << endreq;
+          return StatusCode::FAILURE;
+        }                
+      }
+      
+    }
+  }
+  // Create the various streams according to user's request
+  for (VStrings::const_iterator i = m_streams_seeds.begin(); i != m_streams_seeds.end(); ++i) {
+    string stream; 
+    uint32_t seed1, seed2, offset(0);
+    //parse the stream property string
+    short ll(0); // temp copy so we don't overwrite default
+    if (interpretSeeds(*i, stream, seed1, seed2, ll, offset)) {
+      ATH_MSG_VERBOSE("Seeds property: stream " << stream 
+                      << " seeds " << seed1 << ' ' << seed2 
+                      << ", luxury level " << ll
+                      << ", reseeding offset " << offset);
+    } else {
+      ATH_MSG_ERROR("bad Seeds property\n" << (*i));
+      return StatusCode::FAILURE;
+    }                
+            
+    // Check if stream already generated (e.g. from reading a file)
+    bool not_found(true);
+    if ( number_of_streams() != 0 ) {
+      engineConstIter sf(begin());
+      while (sf != end() && (not_found=((*sf).first != stream))) ++sf;
+    }
+        
+    if (not_found) {
+      ATH_MSG_DEBUG
+        (" INITIALISING " << stream << " stream with seeds "
+         << seed1 << "  " << seed2);
+      CreateStream(seed1, seed2, stream);
+      if (m_eventReseed) {
+        m_reseedingOffsets.insert(std::make_pair(stream, offset));
+        // apply the offset we just inserted
+        ATH_MSG_DEBUG("Applying reseeding  offset " << offset << 
+                      " to stream " << stream);
+        this->setOnDefinedSeeds(seed1, seed2, stream);
+      }
+    }
+    
+  }
+  return StatusCode::SUCCESS;
+}
+
+void AtDSFMTGenSvc::handle(const Incident &inc) {
+  ATH_MSG_DEBUG (" Handle EndEvent ");
+
+  if ( inc.type() == "EndEvent") 
+  {
+    m_engines_copy.clear();
+    engineConstIter iE(begin()), eE(end());
+    while(iE != eE) {
+      HepRandomEngine* engine = GetEngine(iE->first);
+      std::vector<unsigned long> v = engine->put();
+      std::vector<uint32_t> tseeds(v.size());
+      for (size_t i=0; i<v.size(); ++i) {
+        // The state returned is a set of 32-bit numbers.
+        // On 64-bit platforms, though, the vector holds 64-bit ints.
+        // For the first word, one gets garbage in the high 32 bits.
+        // (This is because the crc32 routine used in clhep
+        // to hash the engine names doesn't mask down to 32 bits.)
+        // Mask off the garbage to get consistent results
+        // across platforms.
+        tseeds[i] = (v[i] & 0xffffffffu);
+      }
+      m_engines_copy.insert(std::make_pair(iE->first, tseeds));
+      ++iE;
+    }
+    
+    print();    
+  } else if (inc.type() == "BeginEvent") {
+    ATH_MSG_DEBUG (" Handle BeginEvent ");
+    EventID* pei((dynamic_cast<const EventIncident&>(inc)).eventInfo().event_ID());
+    //loop over generator streams, combining the stream name to the hash
+    vector<string>::const_iterator i(m_reseedStreamNames.begin());
+    vector<string>::const_iterator e(m_reseedStreamNames.end());
+    //by default (when no streams are specified in streamNames, seed all
+    //streams
+    if (i == e) {
+      if (!(this->setAllOnDefinedSeeds(pei->event_number(), 
+                                       pei->run_number())))
+        throw GaudiException("can not reseed all streams ", name(), StatusCode::FAILURE);
+    } else {
+      while (i != e) {
+        const string& strName(*i++);
+        if (0 == this->setOnDefinedSeeds(pei->event_number(), 
+                                         pei->run_number(),
+                                         strName)) { 
+          throw GaudiException(string("can not reseed stream ") + strName,  
+                               name(), StatusCode::FAILURE);
+        } else {
+          msg() << MSG::VERBOSE << "Reseeded stream " << strName 
+                << " for random service " << endmsg;
+        }
+      }
+    }
+  }
+}
+
+StatusCode AtDSFMTGenSvc::finalize()
+{
+  ATH_MSG_INFO (" FINALISING ");
+
+  if (m_save_to_file) {
+    // Write the status of the Service to file
+    std::ofstream outfile( m_file_to_write.c_str() );
+    if ( !outfile ) {
+      ATH_MSG_ERROR ("error: unable to open: " << m_file_to_write);
+    } else {
+      for (std::map<std::string, std::vector<uint32_t> >::const_iterator i = m_engines_copy.begin();
+           i != m_engines_copy.end();
+           ++i) {
+        outfile << (*i).first << " ";
+        for (std::vector<uint32_t>::const_iterator j = (*i).second.begin(); j !=(*i).second.end(); ++j){
+          outfile << (*j) << " ";
+        }
+        outfile << endl;
+      }
+      ATH_MSG_DEBUG (" wrote seeds to " << m_file_to_write );
+    }
+  }
+  return AthService::finalize();
+}
+
+HepRandomEngine* AtDSFMTGenSvc::GetEngine        ( const std::string& streamName )
+{
+    engineConstIter citer = m_engines.find(streamName);
+    if ( citer == m_engines.end() )
+    {
+        m_engines.insert( engineValType( streamName, new CLHEP::dSFMTEngine() ) );
+        SetStreamSeeds( streamName );
+    }
+    
+    engineIter iter = m_engines.find(streamName);
+    return (HepRandomEngine*)(*iter).second;
+}
+
+void AtDSFMTGenSvc::CreateStream(uint32_t seed1, uint32_t seed2, const std::string& streamName )
+{
+    long seeds[3] = { seed1, seed2, 0 };
+    const long* s = seeds;
+    engineConstIter citer = m_engines.find(streamName);
+    if ( citer == m_engines.end() ) 
+      m_engines.insert(engineValType(streamName, new CLHEP::dSFMTEngine(s)));
+    engineIter iter = m_engines.find(streamName);
+    ((*iter).second)->setSeeds(s, 0);
+}
+
+bool AtDSFMTGenSvc::CreateStream(const std::vector<uint32_t>& seeds, const std::string& streamName)
+{
+    engineConstIter citer = m_engines.find(streamName);
+    if ( citer == m_engines.end() ) m_engines.insert(engineValType(streamName, new CLHEP::dSFMTEngine() ) );
+    engineIter iter = m_engines.find(streamName);
+    std::vector<unsigned long> longSeeds(seeds.size());
+    for (size_t i=0; i<seeds.size(); ++i) longSeeds[i]=seeds[i];
+    return (((*iter).second)->getState( longSeeds ));
+}
+
+void AtDSFMTGenSvc::SetStreamSeeds( const std::string& StreamName )
+{
+    uint32_t seed1;
+    uint32_t seed2;
+    if (StreamName == "PYTHIA")
+    {
+        seed1 = m_PYTHIA_default_seed1;
+        seed2 = m_PYTHIA_default_seed2;
+    }
+    else if (StreamName == "HERWIG")
+    {
+        seed1 = m_HERWIG_default_seed1;
+        seed2 = m_HERWIG_default_seed2;
+    }
+    else
+    {
+        seed1 = m_default_seed1;
+        seed2 = m_default_seed2;
+    }
+    ATH_MSG_WARNING
+      (" INITIALISING " << StreamName << " stream with DEFAULT seeds "
+       << seed1 << "  " << seed2);
+    
+    long seeds[3] = { seed1, seed2, 0 };
+    const long* s = seeds;
+    engineIter iter = m_engines.find(StreamName);
+    ((*iter).second)->setSeeds(s,0);
+}
+
+void AtDSFMTGenSvc::print(const std::string& StreamName )
+{
+    engineConstIter citer = m_engines.find(StreamName);
+    if ( citer == m_engines.end() ) {
+      ATH_MSG_WARNING (" Stream =  " << StreamName << " NOT FOUND");
+    } else {
+      std::vector<unsigned long> v = ((*citer).second)->put();
+      msg(MSG::INFO) << " Stream =  " << StreamName << " ";
+      for (std::vector<unsigned long>::const_iterator i = v.begin(); i != v.end(); ++i){
+        // The state returned is a set of 32-bit numbers.
+        // On 64-bit platforms, though, the vector holds 64-bit ints.
+        // For the first word, one gets garbage in the high 32 bits.
+        // (This is because the crc32 routine used in clhep
+        // to hash the engine names doesn't mask down to 32 bits.)
+        // So mask off the garbage so that we get consistent results
+        // across platforms.
+        msg() << ((*i) & 0xffffffffu) << " ";
+      }
+      msg() << endreq;
+    }
+}
+
+void AtDSFMTGenSvc::print        ( void )
+{
+    for (engineConstIter i = m_engines.begin(); i != m_engines.end(); ++i)
+        print( (*i).first );
+}
+
+HepRandomEngine* AtDSFMTGenSvc::setOnDefinedSeeds(uint32_t eventNumber, uint32_t runNumber,
+                                                  const std::string& streamName)
+{
+  uint32_t theHash(eventNumber);
+  map<string, uint32_t>::const_iterator citer(m_reseedingOffsets.find(streamName));
+  bool hasOffset(citer != m_reseedingOffsets.end() && 0 != citer->second);
+  if (hasOffset) theHash=crc_combine(theHash, citer->second);
+
+  theHash=crc_combine(theHash, runNumber);
+  ATH_MSG_VERBOSE( "Reseeding stream " << streamName 
+                   << " with eventNumber " << eventNumber 
+                   << " runNumber " << runNumber);
+  if (hasOffset) ATH_MSG_VERBOSE("Applied offset " <<  citer->second);
+  return this->setOnDefinedSeeds(theHash, streamName);
+}
+
+HepRandomEngine* AtDSFMTGenSvc::setOnDefinedSeeds(uint32_t theSeed, 
+                                                  const std::string& streamName){
+  engineConstIter citer = m_engines.find(streamName);
+  ///create engine if not found. FIXME this may not be a good idea
+  if ( citer == m_engines.end() ) 
+    m_engines.insert(engineValType(streamName, new CLHEP::dSFMTEngine() ) );
+
+  engineIter iter = m_engines.find(streamName);
+  theSeed=crc_combine(theSeed, streamName);
+  ATH_MSG_DEBUG("Reseeding stream " << streamName << " with " << theSeed);
+  HepRandomEngine* eng = (*iter).second;
+  eng->setSeed( theSeed, 0 );
+  return (HepRandomEngine*)eng;
+}
+
+bool
+AtDSFMTGenSvc::setAllOnDefinedSeeds(uint32_t eventNumber, uint32_t runNumber)
+{
+  bool allOK(true);
+  engineIter i(m_engines.begin()), e(m_engines.end());
+  while (i!=e && (allOK=(0 != this->setOnDefinedSeeds(eventNumber,
+                                                      runNumber,
+                                                      (*i++).first))));
+  return allOK;
+}
+
+bool
+AtDSFMTGenSvc::setAllOnDefinedSeeds(uint32_t theSeed){
+  bool allOK(true);
+  engineIter i(m_engines.begin()), e(m_engines.end());
+  while (i!=e && (allOK=(0 != this->setOnDefinedSeeds(theSeed, (*i++).first))));
+  return allOK;
+}

src/AtDSFMTGenSvc.h

+#ifndef ATDSFMTGENSVC_H
+#define ATDSFMTGENSVC_H
+/** @file AtDSFMTGenSvc.h
+ *  @brief A random number engine manager, based on dSFMT. 
+ *  http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/
+ *  author (of wrapper) Michael Duehrssen
+ *  
+ *  $Id$
+ */
+
+#include <map>
+
+//base classes
+#include "AthenaKernel/IAtRndmGenSvc.h"
+#include "GaudiKernel/IIncidentListener.h"
+#include "AthenaBaseComps/AthService.h"
+
+#include "CLHEP/Random/RandomEngine.h"
+
+class IAlgorithm; 
+class ISvcLocator;
+class IIncident;
+
+
+/** @class AtDSFMTGenSvc
+ *  @brief A random number engine manager, based on dSFMT. 
+ *
+ *  @details this service mantains a number of named, independent random
+ *  number sequences. Each sequence is initialized by an entry of the form
+ *  "SequenceName Seed1 Seed2" in the Seeds property. For example
+ *  @code
+ *   Seeds = [ "PYTHIA 4789899 989240512", "PYTHIA_INIT 820021 2347532",
+ *             "JIMMY 390020611 821000366", "JIMMY_INIT 820021 2347532",
+ *             "HERWIG 390020611 821000366", "HERWIG_INIT 820021 2347532" ]
+ *
+ *  @endcode
+ *  At the end of the job  in AtDSFMTGenSvc::finalize(), the status of the
+ *  engine is dumped as an array of unsigned long to the ASCII file
+ *  "AtDSFMTGenSvc.out".  This file can be used to restore the status of the
+ *  engine in another job by setting the properties
+ *  @code
+ *   ReadFromFile = true
+ *   FileToRead = path_to_ascii_file
+ *  @endcode
+ */
+class AtDSFMTGenSvc : virtual public IAtRndmGenSvc,
+		     virtual public IIncidentListener,
+		     public AthService
+{
+public:
+    /// @name Interface to the CLHEP engine
+    //@{
+    HepRandomEngine*	GetEngine	( const std::string& streamName );
+    void		CreateStream	( uint32_t seed1, uint32_t seed2, const std::string& streamName );
+    bool  CreateStream (const std::vector<uint32_t>& seeds, const std::string& streamName);
+    //@}
+
+    /// CLHEP engines typedefs:
+    typedef	std::map<std::string, HepRandomEngine*>	engineMap;
+    typedef	engineMap::iterator 			engineIter;
+    typedef	engineMap::const_iterator		engineConstIter;  
+    typedef	engineMap::value_type			engineValType;
+
+    /// @name Stream access
+    //@{
+    engineConstIter	begin			(void)	const;
+    engineConstIter	end			(void)	const;
+    unsigned int	number_of_streams	(void)	const;    
+    void		print		( const std::string& streamName );
+    void		print		( void );
+    //@}
+
+    virtual HepRandomEngine* setOnDefinedSeeds (uint32_t theSeed,const std::string& streamName);
+    virtual HepRandomEngine* setOnDefinedSeeds (uint32_t eventNumber, uint32_t runNumber, const std::string& streamName);
+    ///seed all streams we manage, combining theSeed and the stream names
+    virtual bool setAllOnDefinedSeeds (uint32_t theSeed); 
+    ///seed all streams, combining eventNumber, runNumber and the stream names
+    virtual bool setAllOnDefinedSeeds (uint32_t eventNumber, uint32_t runNumber);  
+    /// @name Gaudi Service Implementation
+    //@{
+    StatusCode initialize();
+    StatusCode finalize();
+    virtual StatusCode queryInterface( const InterfaceID& riid, void** ppvInterface );
+    //@}
+
+    /// IIncidentListener implementation. Handles EndEvent incident
+    void handle(const Incident&);
+
+private:
+    typedef	std::vector< std::string >	VStrings;
+    /// @name Properties
+    //@{
+    /// seeds for the engines, this is a vector of strings of the form "EnginName Seed1 Seed2"
+    VStrings m_streams_seeds;   
+    bool     m_read_from_file;  ///< read engine status from file
+    std::string	m_file_to_read; ///< name of the file to read the engine status from
+    bool m_save_to_file; ///< should current engine status be saved to file ?
+    std::string m_file_to_write; ///< name of the file to save the engine status to.
+
+    bool m_eventReseed; ///< reseed for every event
+    VStrings m_reseedStreamNames; ///< streams to be reseeded for every event   
+    //@}
+
+    /// optional offsets to combine to run/evt no when reseeding.
+    /// Set using OFFSET keyword of the Seeds property
+    std::map<std::string, uint32_t> m_reseedingOffsets;
+
+    engineMap	m_engines;
+    /// Random engine copy (for output to a file)
+    std::map<std::string, std::vector<uint32_t> >	m_engines_copy;
+
+
+    /// @name Default seed values
+    //@{
+    long m_default_seed1;
+    long m_default_seed2;
+    long m_PYTHIA_default_seed1;
+    long m_PYTHIA_default_seed2;
+    long m_HERWIG_default_seed1;
+    long m_HERWIG_default_seed2;
+    //@}
+
+    void SetStreamSeeds( const std::string& StreamName );
+    
+public:
+    
+    // Standard Constructor
+    AtDSFMTGenSvc(const std::string& name, ISvcLocator* svc);
+        
+    // Standard Destructor
+    virtual ~AtDSFMTGenSvc();
+
+};
+ 
+inline	AtDSFMTGenSvc::engineConstIter
+AtDSFMTGenSvc::begin			(void)	const
+{ return m_engines.begin(); }
+
+inline	AtDSFMTGenSvc::engineConstIter
+AtDSFMTGenSvc::end			(void)	const
+{ return m_engines.end(); }
+
+inline	unsigned int
+AtDSFMTGenSvc::number_of_streams		(void)	const
+{ return m_engines.size(); }
+
+#endif // ATDSFMTGENSVC_H
+
+

src/components/AthenaServices_entries.cxx

 #include "../AthenaConditionStream.h"
 #include "../AtRndmGenSvc.h"
 #include "../AtRanluxGenSvc.h"
+#include "../AtDSFMTGenSvc.h"
 #include "../MultipleEventLoopMgr.h"
 #include "../SimplePOSIXTimeKeeperSvc.h"
 #include "../MixingEventSelector.h"
     DECLARE_ALGORITHM( TestRandomSeqAlg )
     DECLARE_SERVICE( AtRndmGenSvc )
     DECLARE_SERVICE( AtRanluxGenSvc )
+    DECLARE_SERVICE( AtDSFMTGenSvc )
     DECLARE_SERVICE( AthenaEventLoopMgr )
     DECLARE_SERVICE( MultipleEventLoopMgr )
     DECLARE_SERVICE( PyAthenaEventLoopMgr )
 DECLARE_ALGORITHM_FACTORY( TestRandomSeqAlg )
 DECLARE_SERVICE_FACTORY( AtRndmGenSvc )
 DECLARE_SERVICE_FACTORY( AtRanluxGenSvc )
+DECLARE_SERVICE_FACTORY( AtDSFMTGenSvc )
 DECLARE_SERVICE_FACTORY( AthenaEventLoopMgr )
 DECLARE_SERVICE_FACTORY( MultipleEventLoopMgr )
 DECLARE_SERVICE_FACTORY( PyAthenaEventLoopMgr )