RandomProcessor.cpp

Go to the documentation of this file.
00001 /* Documentation is in header file. */
00002 
00003 #include <stdexcept>
00004 
00005 #include "cafe/Config.hpp"
00006 #include "cafe/RandomProcessor.hpp"
00007 #include "TFile.h"
00008 
00009 #include <iomanip>
00010 
00011 using std::endl;
00012 
00013 namespace cafe {
00014 
00015   // avoid ROOT v4 bug in TRandom3 (thanks to Henrik for testing performances)
00016   void patchedSetSeed (TRandom3& rnd, const UInt_t seed, 
00017                        const bool treatZeroAsSpecial, const int method, const int debug)
00018   {
00019     // Low numbers are bad, make it hard to get them. But don't spoil/fake the special value 0.
00020     // This logic will only use the nonreproducible 0 seed (time stamp) if it's explicitely asked for!
00021     int anInt  = 20060925;
00022     bool usedTimeStamp = false;
00023     if (seed == anInt) {
00024       rnd.SetSeed (seed);
00025     } else {
00026       if (treatZeroAsSpecial && seed == 0) {
00027         rnd.SetSeed (0);
00028         usedTimeStamp = true;
00029       } else {
00030         rnd.SetSeed (seed ^ anInt);
00031       }
00032     }
00033     if (debug) std::cout<<"DBG patchedSetSeed Input: "<<seed
00034                         <<" --> timestamp? "<<usedTimeStamp<<", seed: "<<rnd.GetSeed()<<endl;
00035 
00036     if (usedTimeStamp) {
00037       // Now avoid the ROOT v4 bug (if needed)
00038       if (method == 1) { // first number happens to be OK
00039         //             aaBBccDD                  aaBBccDD - 4 bytes each. UInt_t hardwired to be 4 bytes.
00040         UInt_t myRandomSeed = rnd.Integer (0xFFffFFff);
00041         time_t now;
00042         time(&now);
00043         UInt_t myRandomSeedWithTime = myRandomSeed + (UInt_t) now; // add the time
00044         if (myRandomSeedWithTime < 10000) myRandomSeedWithTime ^= 20050823; // protect against small numbers (in particular, 0)
00045         if (debug) std::cout<<"DBG patchedSetSeed avoiding v4 bug. myRandomSeed: "<<myRandomSeed<<" ^ I(time): "<<UInt_t (now)
00046                             <<" --> myRandomSeedWithTime: "<<myRandomSeedWithTime<<endl;
00047         rnd.SetSeed (myRandomSeedWithTime);
00048         
00049       } else if (method == 2) { // after 624 numbers, the rest are OK
00050         for (int it=0; it<700; ++it) rnd.Uniform();
00051         if (debug) std::cout<<"DBG patchedSetSeed, after discarding some numbers RandomSeed: "<<rnd.GetSeed()<<endl;
00052       }
00053     }
00054   }
00055 
00056   
00057   // Fake constructor (see header)
00058   RandomProcessor::RandomProcessor () : 
00059     Processor()
00060   {
00061     // this should never happen, but to have sensible values, these force only one timestamp seeding
00062     _eventKey = false;
00063     _rnd.SetSeed (0);
00064   }
00065 
00066   // Normal Constructor 
00067   RandomProcessor::RandomProcessor(const char *name) : 
00068     Processor(name)
00069   {
00070     // Read the config
00071     // ===============
00072     Config config(name);
00073     _eventKey            = config.get("EventKey", true);
00074     _seed                = config.get("Seed", 0);
00075     _mTable              = config.get("TableSize", 10000);
00076     _ROOT4patch          = config.get("ROOT4patch", 1);
00077     int debug            = config.get("DebugConstructor", 0);
00078     _ignoreDirectory     = config.get("IgnoreDirectory", false);
00079     _nFirstCharsToIgnore = config.get("NFirstCharsToIgnore", 0);
00080     _nLastCharsToIgnore  = config.get("NLastCharsToIgnore", 0);
00081     _addPrefix           = config.get("AddPrefix", "");
00082 
00083     if (_eventKey && _mTable <= 100) throw std::runtime_error("RandomProcessor: table size too small");
00084 
00085     // Initialize the seed
00086     // ===================
00087     if (_seed == 0 && _eventKey) {// need reproducible results with eventKey --> use processor name as seed
00088       patchedSetSeed (_rnd, hashString (name), false, 1, debug); // if it comes out 0, it's just a number
00089       out()<<" RandomProcessor["<<name<<"]: Seed==0, so took it from processor name ("
00090            <<name<<" --> "<<_rnd.GetSeed()<<")"<<endl;
00091     } else {
00092       patchedSetSeed (_rnd, _seed, true, 1, debug); // if _seed is 0, _eventKey must be false and the user really means it 
00093     }
00094 
00095     // Print the parameters
00096     if (_eventKey) {
00097       out()<<" RandomProcessor["<<name<<"]: Will reseed random generator per event, based on filename and event #"<<endl;
00098       if (_ignoreDirectory || _nFirstCharsToIgnore || _nLastCharsToIgnore || _addPrefix.Length()) {
00099         out()<<" Each file's path will be processes as follows:"<<endl;
00100         if (_ignoreDirectory) out()<<"  Ignoring directories"<<endl;
00101         if (_nFirstCharsToIgnore) out()<<"  Ignoring the first "<<_nFirstCharsToIgnore<<" characters"<<endl;
00102         if (_nLastCharsToIgnore) out()<<"  Ignoring the last "<<_nFirstCharsToIgnore<<" characters"<<endl;
00103         if (_addPrefix.Length()) out()<<"  Adding the prefix: "<<_addPrefix<<endl;
00104       }
00105     } else {
00106       out()<<" RandomProcessor["<<name<<"]: Seed is "<<_rnd.GetSeed()<<" (from input "<<_seed<<"), it will not be reinitialized."<<endl; 
00107     }
00108 
00109     // initialize table
00110     if (_eventKey) {
00111       if (debug) out()<<"Debugging constructor. Pre-table we have seed: "<<_rnd.GetSeed()<<" (from input "<<_seed<<"), and"
00112                       <<" _mTable: "<<_mTable<<endl;
00113       for (int i=0; i<_mTable; ++i) {
00114         _seeds.push_back (_rnd.Integer (0xffFFffFFu)); // UInt_t is guaranteed to be 4 bytes.
00115         if (debug > 9) out()<<"i: "<<i<<", l: "<<_seeds.size()<<", s: "<<_seeds[i]<<endl;
00116       }
00117     }
00118   }
00119 
00120   void RandomProcessor::inputFileOpened(TFile* file)
00121   {
00122     if (_eventKey) {
00123       TString filename = file->GetName();
00124 
00125       if (debug() > 40) out()<<"RandomProcessor::inputFileOpened name from ROOT: "<<filename<<endl;
00126 
00127       if (_ignoreDirectory) {
00128         filename = gSystem->BaseName(filename);
00129       }
00130       if (_nFirstCharsToIgnore) {
00131         filename.Remove (0, _nFirstCharsToIgnore);
00132       }
00133       if (_nLastCharsToIgnore) {
00134         if (!filename.EndsWith (".root")) throw std::runtime_error ("RandomProcessor::inputFileOpened ["+name()
00135                                                                     +"] when using the NLastCharsToIgnore option, all "
00136                                                                     +"input file names must end with \".root\".");
00137         filename.Remove (TMath::Max(0, filename.Length() - 5 - _nLastCharsToIgnore), _nLastCharsToIgnore);
00138       }
00139       filename.Prepend (_addPrefix);
00140 
00141       _fileHash = hashString (filename);
00142       if (debug() > 5) out()<<"_fileHash: "<<_fileHash<<" <--- "<<filename<<endl;
00143     }
00144   }
00145 
00146   bool RandomProcessor::processEvent(cafe::Event& event)
00147   {
00148     if (_eventKey) {
00149       // get the event's number in the tree
00150       TTree* ptree = event.getTree();
00151       if (ptree == 0) throw std::runtime_error ("event's tree pointer is NULL!");
00152       Long64_t iEvent = ptree->GetReadEntry();
00153 
00154       UInt_t rawindex = (UInt_t (iEvent) ^ _fileHash);
00155       if (debug() > 99) out()<<"iEvent: "<<iEvent<<", rawindex: "<<rawindex<<" -> ["<<(rawindex % _mTable)<<"]"<<endl;
00156       UInt_t newseed = _seeds [rawindex % _mTable];
00157       patchedSetSeed (_rnd, newseed, false, 1, debug()); // if it comes out 0, it's just a number
00158       if (debug() > 29) out()<<"iEvent: "<<iEvent<<", newseed: "<<newseed<<" -> "<<_rnd.GetSeed()<<endl;
00159     }
00160     // else we simply don't reseed
00161     return true;
00162   }
00163 }
00164 
00165 ClassImp(cafe::RandomProcessor)
00166 
00167 

Generated on Thu Apr 3 04:14:23 2008 for CAF by doxygen 1.3.4