/**
* @file BaseConfig.C
* @author Christian Holm Christensen <cholm@nbi.dk>
* @date Wed Oct 15 12:52:58 2014
*
* @brief Base classes for configurations shared amoung steps.
*
*
*/
//====================================================================
/**
* Base class for detector configuration. By default, everything is on
* except ACORDE.
*/
struct VirtualDetCfg
{
virtual Bool_t UseABSO() const { return true; }
virtual Bool_t UseACORDE() const { return false; }
virtual Bool_t UseDIPO() const { return true; }
virtual Bool_t UseEMCAL() const { return true; }
virtual Bool_t UseFMD() const { return true; }
virtual Bool_t UseFRAME() const { return true; }
virtual Bool_t UseHALL() const { return true; }
virtual Bool_t UseITS() const { return true; }
virtual Bool_t UseMAG() const { return true; }
virtual Bool_t UseMUON() const { return true; }
virtual Bool_t UsePHOS() const { return true; }
virtual Bool_t UsePIPE() const { return true; }
virtual Bool_t UsePMD() const { return true; }
virtual Bool_t UseHMPID() const { return true; }
virtual Bool_t UseSHIL() const { return true; }
virtual Bool_t UseT0() const { return true; }
virtual Bool_t UseTOF() const { return true; }
virtual Bool_t UseTPC() const { return true; }
virtual Bool_t UseTRD() const { return true; }
virtual Bool_t UseVZERO() const { return true; }
virtual Bool_t UseZDC() const { return true; }
virtual void Print()
{
Printf("ABSO: %3s", UseABSO() ? "yes" : "no");
Printf("ACORDE: %3s", UseACORDE() ? "yes" : "no");
Printf("DIPO: %3s", UseDIPO() ? "yes" : "no");
Printf("EMCAL: %3s", UseEMCAL() ? "yes" : "no");
Printf("FMD: %3s", UseFMD() ? "yes" : "no");
Printf("FRAME: %3s", UseFRAME() ? "yes" : "no");
Printf("HALL: %3s", UseHALL() ? "yes" : "no");
Printf("ITS: %3s", UseITS() ? "yes" : "no");
Printf("MAG: %3s", UseMAG() ? "yes" : "no");
Printf("MUON: %3s", UseMUON() ? "yes" : "no");
Printf("PHOS: %3s", UsePHOS() ? "yes" : "no");
Printf("PIPE: %3s", UsePIPE() ? "yes" : "no");
Printf("PMD: %3s", UsePMD() ? "yes" : "no");
Printf("HMPID: %3s", UseHMPID() ? "yes" : "no");
Printf("SHIL: %3s", UseSHIL() ? "yes" : "no");
Printf("T0: %3s", UseT0() ? "yes" : "no");
Printf("TOF: %3s", UseTOF() ? "yes" : "no");
Printf("TPC: %3s", UseTPC() ? "yes" : "no");
Printf("TRD: %3s", UseTRD() ? "yes" : "no");
Printf("VZERO: %3s", UseVZERO() ? "yes" : "no");
Printf("ZDC: %3s", UseZDC() ? "yes" : "no");
}
/**
* Get the string of enabled detectors for local reconstruction.
*
* @param enable On return, contains string of enable detectors
*/
void GetRecoString(TString& enable) const
{
if (UseITS()) Append2Str(enable, "ITS");
if (UseTPC()) Append2Str(enable, "TPC");
if (UseTRD()) Append2Str(enable, "TRD");
if (UseTOF()) Append2Str(enable, "TOF");
if (UsePHOS()) Append2Str(enable, "PHOS");
if (UseHMPID()) Append2Str(enable, "HMPID");
if (UseEMCAL()) Append2Str(enable, "EMCAL");
if (UseMUON()) Append2Str(enable, "MUON");
if (UseFMD()) Append2Str(enable, "FMD");
if (UseZDC()) Append2Str(enable, "ZDC");
if (UsePMD()) Append2Str(enable, "PMD");
if (UseT0()) Append2Str(enable, "T0");
if (UseVZERO()) Append2Str(enable, "VZERO");
}
/**
* Get the string of detectors for which we should make Summable
* Digits
*
* @param sDigits On returm contains the string of enable detectors
*/
void GetSDigitString(TString& sDigits) const
{
if (UseTRD()) Append2Str(sDigits, "TRD");
if (UseTOF()) Append2Str(sDigits, "TOF");
if (UsePHOS()) Append2Str(sDigits, "PHOS");
if (UseHMPID()) Append2Str(sDigits, "HMPID");
if (UseEMCAL()) Append2Str(sDigits, "EMCAL");
if (UseMUON()) Append2Str(sDigits, "MUON");
if (UseFMD()) Append2Str(sDigits, "FMD");
if (UseZDC()) Append2Str(sDigits, "ZDC");
if (UsePMD()) Append2Str(sDigits, "PMD");
if (UseT0()) Append2Str(sDigits, "T0");
if (UseVZERO()) Append2Str(sDigits, "VZERO");
}
/**
* Get the sting of detectors for which we should do the hit to
* digit conversion directly.
*
* @param fromHits On returm contains the string of enable detectors
*/
void GetHits2DigitsString(TString& fromHits) const
{
if (UseITS()) Append2Str(fromHits, "ITS");
if (UseTPC()) Append2Str(fromHits, "TPC");
}
/**
* Append a C style string to a string, possibly adding a space before
*
* @param str Where to append
* @param append What to append
*/
static void Append2Str(TString& str, const char* append)
{
if (!str.IsNull()) str.Append(" ");
str.Append(append);
}
};
/** Global variable */
VirtualDetCfg* detCfg = 0;
//====================================================================
/**
* Base class for the OCDG configration
*/
struct VirtualOCDBCfg
{
/**
* This member function must return the default prefix.
*
* @return Prefix of OCDB specific storages
*/
virtual const char* Prefix() const { return ""; }
/**
* This member function should define the real setup.
*
* @param forSim Whether we're setting up for simulations or not
*/
virtual void Init(Bool_t forSim)
{
::Fatal("VirtualOCDBConfig", "Dummy init called - redefine!");
}
/**
* Set the specific storage for a given key (possibly wild-carded).
*
* @param key Key
* @param ideal Whether it is residual or ideal
*/
void AddStore(const char* key,
Bool_t ideal)
{
AliCDBManager* cdb = AliCDBManager::Instance();
const char* prefix = Prefix();
TString path = Form("alien://Folder=/alice/simulation/%s/%s",
prefix, !ideal ? "Residual" : "Ideal");
::Info("AddStore", "%s -> %s", key, path.Data());
cdb->SetSpecificStorage(key, path);
}
};
/** Global variable */
VirtualOCDBCfg* ocdbCfg = 0;
//====================================================================
/**
* Event generator configuration
*
*/
struct VirtualEGCfg
{
TString runType;
VirtualEGCfg() : runType("") {}
virtual ~VirtualEGCfg() {}
virtual Bool_t IsLego() const { return false; }
/**
* Set the default generator based on the beam type
*
* - p-p PYTHIA
* - p-A or A-p DPMJet
* - A-A Hijing
*/
static const char* DeduceRunType()
{
if (grp->IsPP()) return "pythia";
else if (grp->IsPA() || grp->IsAP()) return "dpmjet";
else if (grp->IsAA()) return "hijing";
return "hijing";
}
static void LoadLibrary(const TString& name,
const TString& cls="")
{
// If we're looking for a specific class, check that first, and
// if available, do nothing;
if (!cls.IsNull() && gROOT->GetClass(cls)) return;
// Now check the list of loaded and linekd libraries
TString libs(gSystem->GetLibraries("", "SD"));
// IF already in the list, do nothing
if (libs.Contains(name)) return;
// Otherwise load the library
gSystem->Load(name);
}
/**
* Load the general libraries needed
*
*/
static void LoadGen(const TString& runType) {
LoadLibrary("liblhapdf","AliStructFuncType"); // Parton density functions
LoadLibrary("libEGPythia6","TPythia6"); // TGenerator interface
if (!runType.EqualTo("hydjet", TString::kIgnoreCase))
LoadPythia(false);
}
/**
* Load the pythia libraries
*
* @param vers Optional version post-fix
*/
static void LoadPythia(Bool_t gen=true, const char* vers="6.4.21")
{
if (gen) LoadGen("");
char m = vers[0];
if (gROOT->GetClass(Form("AliPythia6%c", m))) return;
LoadLibrary("libmicrocern");
LoadLibrary(Form("libpythia%s",vers));
LoadLibrary(Form("libAliPythia%c", m));
}
/**
* Load HIJING libraries
*/
static void LoadHijing()
{
LoadPythia();
if (gROOT->GetClass("THijing")) return;
LoadLibrary("libhijing");
LoadLibrary("libTHijing");
AliPDG::AddParticlesToPdgDataBase();
}
/**
* Load HydJet libraries
*/
static void LoadHydjet()
{
LoadLibrary("libTUHKMgen","TUHKMgen");
}
/**
* Load DPMJet libraries
*/
static void LoadDpmjet()
{
LoadPythia();
if (gROOT->GetClass("TDPMjet")) return;
LoadLibrary("libdpmjet");
LoadLibrary("libTDPMjet");
}
/**
* Load AMPT libraries
*/
static void LoadAmpt()
{
LoadPythia();
if (gROOT->GetClass("TAmpt")) return;
LoadLibrary("libampt");
LoadLibrary("libTAmpt");
}
/**
* Make the generator
*
* @param rt Event generator identifier
* @param b1 Least impact parameter
* @param b2 Largest impact parameter
* @param smear If true, smear interaction per event
*
* @return Point to newly allocated generator or null
*
*/
AliGenerator* MakeGenerator(const TString& rt,
Float_t b1,
Float_t b2,
Bool_t smear=true)
{
if (rt.IsNull()) {
::Fatal("MakeGenerator", "No EG spec given");
return 0;
}
TString runType = rt;
runType.ToLower();
AliGenerator* g = CreateGenerator(runType,b1,b2);
if (g && smear) g->SetVertexSmear(AliGenerator::kPerEvent);
return g;
}
/**
* Make our decayer
*
* @param rt The EG to use
*
* @return Newly allocated decayer or null
*/
TVirtualMCDecayer* MakeDecayer(const TString& rt)
{
if (rt.IsNull()) {
::Fatal("MakeGenerator", "No EG spec given");
return 0;
}
TString runType = rt;
rt.ToLower();
TVirtualMCDecayer* decayer = CreateDecayer(runType);
if (decayer) decayer->Init();
return decayer;
}
protected:
/**
* Create the generator. This function must be defined in a derived class.
*
* @param runType The generator ID (all lower case)
* @param b1 Least impact parameter
* @param b2 Largest impact parameter
*
* @return Must return a pointer to a new AliGenerator or null
*/
virtual AliGenerator* CreateGenerator(const TString& runType,
Float_t b1,
Float_t b2) = 0;
/**
* Create the decayer. This function must be defined in a derived class.
*
* @param runType The generator ID (all lower case)
*
* @return Must return a pointer to a new TVirtualMCDecayer or null
*/
virtual TVirtualMCDecayer* CreateDecayer(const TString& runType) = 0;
};
/** Global variable */
VirtualEGCfg* egCfg = 0;
//====================================================================
/**
* Base class for trains
*
*/
struct VirtualTrain
{
/**
* Run this train
*
* @param run
* @param xmlFile
* @param stage
* @param cdb
*
* @return
*/
Bool_t Run(UInt_t run,
const char* xmlFile = "wn.xml",
Int_t stage = 0,
const char* cdb = "raw://")
{
// --- Load configuration script ---------------------------------
LoadConfig();
// --- Set-up for CDB access through Grid ------------------------
TString cdbString(cdb);
if (cdbString.Contains("raw://")) {
TGrid::Connect("alien://");
if (!gGrid || !gGrid->IsConnected()) {
::Error("Run", "No grid connection");
return false;
}
}
// --- Some environment variables --------------------------------
// Temp dir is here, and compilation is here too
gSystem->Setenv("TMPDIR", gSystem->pwd());
gSystem->SetBuildDir(gSystem->pwd(), kTRUE);
// --- Now load common libraries ---------------------------------
LoadBaseLibraries();
// --- Now create and configure manager --------------------------
AliAnalysisManager *mgr = new AliAnalysisManager(GetName(),
"Production train");
mgr->SetRunFromPath(grp->run);
// --- Create ESD input handler ------------------------------------
AliESDInputHandlerRP *esdHandler = new AliESDInputHandlerRP();
mgr->SetInputEventHandler(esdHandler);
if (UseFriends()) {
esdHandler->SetReadFriends(kTRUE);
esdHandler->SetActiveBranches("ESDfriend");
}
// --- Monte Carlo handler -----------------------------------------
if (UseMC()) {
AliMCEventHandler* mcHandler = new AliMCEventHandler();
mgr->SetMCtruthEventHandler(mcHandler);
mcHandler->SetPreReadMode(1);
mcHandler->SetReadTR(true);
}
// --- AOD output handler ----------------------------------------
if (MakeAOD()) {
AliAODHandler* aodHandler = new AliAODHandler();
aodHandler->SetOutputFileName("AliAOD.root");
mgr->SetOutputEventHandler(aodHandler);
}
// --- Call user routine for adding tasks ------------------------
if (!AddTasks()) return false;
// --- Check if we are to merge ----------------------------------
if (stage > 0)
return Merge(xmlfile, stage);
// --- Otherwise run the train -----------------------------------
TChain* chain = CreateChain();
if (!chain) return false;
TStopwatch timer;
timer.Start();
if (!mgr->InitAnalysis()) {
::Error("Run", "Failed to initialize the train");
return false;
}
mgr->PrintStatus();
mgr->SetSkipTerminate(kTRUE);
mgr->StartAnalysis("local", chain);
timer.Print();
}
/**
* Merge requested files
*
* @param dir Output directory
* @param stage Stage
*
* @return true on success
*/
Bool_t Merge(const char* dir, Int_t stage)
{
TStopwatch timer;
timer.Start();
TString outputDir = dir;
Bool_t final = outputDir.Contains("Stage");
TCollection* outputFiles = GetFilesToMerge(stage, final);
if (!outputFiles) {
::Warning("Merge", "Nothing to merge");
return true;
}
TIter iter(outputFiles);
TObjString* str = 0;
Bool_t merged = kTRUE;
while((str = static_cast<TObjString*>(iter()))) {
TString& outputFile = str->GetString();
// Skip already merged outputs
if (!gSystem->AccessPathName(outputFile)) {
::Warning("Merge","Output file <%s> found. Not merging again.",
outputFile.Data());
continue;
}
merged = AliAnalysisAlien::MergeOutput(outputFile,
outputDir,
10,
stage);
if (merged) continue;
::Error("Merge", "Cannot merge %s\n", outputFile.Data());
}
// --- possible merge file information files ---------------------
if (MergeFileInfo()) {
TString infolog = "fileinfo.log";
AliAnalysisAlien::MergeInfo(infolog, dir);
}
// --- If not final stage, get out here --------------------------
if (!final) {
ValidateOutput();
timer.Print();
return true;
}
// --- set up and run termiante ----------------------------------
AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
mgr->SetSkipTerminate(kFALSE);
if (!mgr->InitAnalysis()) {
::Error("Merge", "Failed to initialize the train");
return false;
}
mgr->PrintStatus();
mgr->StartAnalysis("gridterminate", (TTree*)0);
ValidateOutput();
timer.Print();
return true;
}
/**
* Load a library/module
*
* @param module Library/module name
*
* @return true on success
*/
Bool_t LoadLibrary(const char *module)
{
// Load a module library in a given mode. Reports success.
Int_t result = 0;
TString mod(module);
::Info("LoadLibrary", "Loading %s", module);
gROOT->IncreaseDirLevel();
if (mod.IsNull()) {
::Error("LoadLibrary", "Empty module name");
gROOT->DecreaseDirLevel();
return kFALSE;
}
// If a library is specified, just load it
if (mod.EndsWith(".so")) {
mod.Remove(mod.Index(".so"));
::Info("LoadLibrary", "Loading .so: %s", mod.Data());
result = gSystem->Load(mod);
if (result < 0) {
::Error("oadLibrary", "Could not load library %s", module);
}
gROOT->DecreaseDirLevel();
return (result >= 0);
}
// Check if the library is already loaded
if (strlen(gSystem->GetLibraries(Form("%s.so", module), "", kFALSE)) > 0) {
::Info("LoadLibrary", "Module %s.so already loaded", module);
gROOT->DecreaseDirLevel();
return kTRUE;
}
::Info("LoadLibrary", "Trying to load lib%s.so", module);
result = gSystem->Load(Form("lib%s.so", module));
if (result < 0)
::Error("LoadLibrary", "Could not load module %s", module);
::Info("LoadLibrary", "Module %s, successfully loaded", module);
gROOT->DecreaseDirLevel();
return (result >= 0);
}
/**
* Load common libraries
*
* @return true on sucess
*/
virtual Bool_t LoadBaseLibraries()
{
// Load common analysis libraries.
if (!gSystem->Getenv("ALICE_ROOT")) {
::Error("LoadBaseLibraries",
"Analysis trains requires that analysis libraries are "
"compiled with a local AliRoot");
return false;
}
Bool_t success = true;
// Load framework classes. Par option ignored here.
success &= LoadLibrary("libSTEERBase.so");
success &= LoadLibrary("libESD.so");
success &= LoadLibrary("libAOD.so");
success &= LoadLibrary("libANALYSIS.so");
success &= LoadLibrary("libOADB.so");
success &= LoadLibrary("libANALYSISalice.so");
success &= LoadLibrary("libESDfilter.so");
success &= LoadLibrary("libCORRFW.so");
success &= LoadLibrary("libPWGPP.so");
gROOT->ProcessLine(".include $ALICE_ROOT/include");
if (success) {
::Info("LoadBaseLibraries",
"Load common libraries: SUCCESS");
::Info("LoadBaseLibraries",
"Include path for Aclic compilation:\n%s",
gSystem->GetIncludePath());
} else {
::Info("LoadBaseLibraries",
"Load common libraries: FAILED");
}
return success;
}
/**
* Create the input chain
*
* @return Pointer to newly allocated train
*/
TChain* CreateChain()
{
if (gSystem->AccessPathName("AliESDs.root")) {
::Error("CreateChain",
"File: AliESDs.root not in ./data dir");
return 0;
}
// Create the input chain
TChain* chain = new TChain("esdTree");
chain->Add("AliESDs.root");
if (!chain->GetNtrees()) {
delete chain;
chain = 0;
}
return chain;
}
/**
* Helper function to make @c outputs_valid file
*
*/
void ValidateOutput()
{
std::ofstream out;
out.open("outputs_valid", ios::out);
out.close();
}
/**
* @{
* @name Functions to overload
*/
/**
* Load the configuration script. Override to load specific script.
*/
virtual void LoadConfig() {};
/**
* Override to set a name of the analysis manager
*
* @return Name of analysis manager
*/
virtual const char* GetName() const { return "dummy"; }
/**
* Override to return true if friends are needed.
*
* @return false
*/
virtual Bool_t UseFriends() const { return false; }
/**
* Override to return true if MC info is needed
*
* @return false
*/
virtual Bool_t UseMC() const { return false; }
/**
* Override to return true if AODs should be made
*
* @return false
*/
virtual Bool_t MakeAOD() const { return false; }
/**
* User rountine for adding tasks. Override to add tasks to the
* train.
*
* @return true
*/
virtual Bool_t AddTasks() const { return true; }
/**
* Override to return true to merge file information files.
*
* @return false
*/
virtual Bool_t MergeFileInfo() const { return false; }
/**
* Return the list of ouput files (TObjString objects)
*
* @param stage Merge stage
* @param final Final merging (also terminate)
*
* @return Pointer to TCollection.
*/
virtual TCollection* GetFilesToMerge(Int_t stage, Bool_t final) const
{
return 0;
}
};
//====================================================================
/**
* A function so that we can do TROOT::Macro. Does nothing but print a message.
*
*/
void BaseConfig()
{
Info("", "Defined base classes for configuration");
}
//
// EOF
//