2 * @defgroup pwglf_forward_trains Trains
9 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
10 * @date Tue Oct 16 17:56:57 2012
12 * @brief Base classs for train specifications
14 * @ingroup pwglf_forward_trains
24 # include <TApplication.h>
25 # include <TStopwatch.h>
26 # include <AliAnalysisManager.h>
27 # include <AliVEventHandler.h>
28 # include <AliPhysicsSelection.h>
29 # include <AliPhysicsSelectionTask.h>
30 # include <AliCentralitySelectionTask.h>
31 # include <AliESDInputHandler.h>
32 # include <AliAODInputHandler.h>
33 # include <AliAODHandler.h>
34 # include <AliMCEventHandler.h>
43 class AliVEventHandler;
44 class AliAnalysisManager;
45 class AliInputEventHandler;
48 //====================================================================
50 * Generic set-up of an analysis train
52 * See also @ref train_setup_doc
54 * @ingroup pwglf_forward_trains
62 * @param name Name of the train
64 TrainSetup(const TString& name)
71 fOptions.Add("help", "Show help", false);
72 fOptions.Add("date", "YYYY-MM-DD HH:MM", "Set date", "now");
73 fOptions.Add("bare-ps", "Use bare physics selection w/o task", false);
74 fOptions.Add("verbose", "LEVEL", "Set verbosity level", 0);
75 fOptions.Add("url", "URL", "Job location & input URL", "");
76 fOptions.Add("overwrite", "Allow overwrite", false);
77 fOptions.Add("events", "N", "Number of events to analyse", -1);
78 fOptions.Add("type", "ESD|AOD|USER", "Input data stype", "");
79 fOptions.Add("setup", "Only do the setup", false);
80 fOptions.Add("branches", "Load only requested branches", false);
82 fEscapedName = EscapeName(fName, fDatimeString);
87 * @param o Object to copy from
89 TrainSetup(const TrainSetup& o)
91 fEscapedName(o.fEscapedName),
92 fDatimeString(o.fDatimeString),
99 * @param o Object to assign from
101 * @return Reference to this object
103 TrainSetup& operator=(const TrainSetup& o)
105 if (&o == this) return *this;
107 fEscapedName = o.fEscapedName;
108 fDatimeString = o.fDatimeString;
109 fOptions = o.fOptions;
117 virtual ~TrainSetup() {}
119 //__________________________________________________________________
127 * @return true on success
131 // --- Create the helper -----------------------------------------
132 TString url = fOptions.Get("url");
133 Int_t verbose = fOptions.AsInt("verbose");
135 fHelper = Helper::Create(url.Data(), verbose);
137 Error("Init", "Failed to make the worker for URL %s", url.Data());
141 // --- Check the type, if possible -------------------------------
142 UShort_t type = fHelper->InputType();
143 Bool_t mc = fHelper->IsMC();
144 if (fOptions.Has("type")) {
145 const TString& it = fOptions.Get("type");
146 if (it.EqualTo("ESD",TString::kIgnoreCase)) type = Helper::kESD;
147 else if (it.EqualTo("AOD",TString::kIgnoreCase)) type = Helper::kAOD;
148 else if (it.EqualTo("user",TString::kIgnoreCase))
149 type = Helper::kUser;
152 // --- Rewrite the escpaed name ----------------------------------
153 if (fOptions.Has("date")) {
154 fDatimeString = fOptions.Get("date");
155 fEscapedName = EscapeName(fName, fDatimeString);
158 // --- Get current directory and set-up sub-directory ------------
159 TString cwd = gSystem->WorkingDirectory();
160 if (!SetupWorkingDirectory()) return false;
162 // --- Do initial helper setup -----------------------------------
163 if (!fHelper->PreSetup()) return false;
165 // --- Load ROOT libraries ---------------------------------------
166 if (!fHelper->LoadROOT()) return false;
168 // --- Load AliROOT libraries ------------------------------------
169 if (!fHelper->LoadAliROOT()) return false;
171 // --- Create analysis manager -----------------------------------
172 AliAnalysisManager *mgr = CreateAnalysisManager(fEscapedName);
174 // In test mode, collect system information on every event
175 // if (oper == kTest) mgr->SetNSysInfo(1);
176 if (verbose > 0) mgr->SetDebugLevel(verbose);
177 mgr->SetAutoBranchLoading(!fOptions.Has("branches"));
178 if (fHelper->Mode() == Helper::kLocal)
179 mgr->SetUseProgressBar(kTRUE, 100);
181 // --- ESD input handler ------------------------------------------
182 AliVEventHandler* inputHandler = CreateInputHandler(type);
183 if (inputHandler) mgr->SetInputEventHandler(inputHandler);
185 // --- Monte-Carlo ------------------------------------------------
186 AliVEventHandler* mcHandler = CreateMCHandler(type,mc);
187 if (mcHandler) mgr->SetMCtruthEventHandler(mcHandler);
189 // --- AOD output handler -----------------------------------------
190 AliVEventHandler* outputHandler = CreateOutputHandler(type);
191 if (outputHandler) mgr->SetOutputEventHandler(outputHandler);
193 // --- Include analysis macro path in search path ----------------
194 gROOT->SetMacroPath(Form("%s:%s:$ALICE_ROOT/ANALYSIS/macros",
195 cwd.Data(), gROOT->GetMacroPath()));
197 // --- Physics selction - only for ESD ---------------------------
198 if (type == Helper::kESD) CreatePhysicsSelection(mc, mgr);
200 // --- Create centrality task ------------------------------------
201 CreateCentralitySelection(mc, mgr);
203 // --- Create tasks ----------------------------------------------
206 // --- Post set-up initialization of helper ----------------------
207 if (!fHelper->PostSetup()) return false;
209 // --- Set debug level on defined tasks --------------------------
211 TIter next(mgr->GetTasks());
212 AliAnalysisTask* sub = 0;
213 while ((sub = static_cast<AliAnalysisTask*>(next()))) {
214 AliAnalysisTaskSE* se = dynamic_cast<AliAnalysisTaskSE*>(sub);
216 se->SetDebugLevel(verbose);
220 // --- Print this setup ------------------------------------------
223 // --- Initialise the train --------------------------------------
224 if (!mgr->InitAnalysis()) {
225 gSystem->ChangeDirectory(cwd.Data());
226 Error("Init","Failed to initialise train");
230 // --- Enable progress bar ---------------------------------------
231 if (fHelper->Mode() != Helper::kGrid)
232 mgr->SetUseProgressBar(true, 100);
234 // --- Save setup to disk ----------------------------------------
237 // --- Some information ------------------------------------------
239 if (fHelper->Mode() != Helper::kLocal) {
240 TIter next(mgr->GetTasks());
241 AliAnalysisTask* sub = 0;
242 while ((sub = static_cast<AliAnalysisTask*>(next()))) {
249 * Print timer information
251 * @param timer The timer
252 * @param where Where this was called from
254 void PrintTimer(TStopwatch& timer, const char* where)
257 Double_t t = timer.RealTime();
258 Int_t h = Int_t(t / 3600); t -= h * 3600;
259 Int_t m = Int_t(t / 60); t -= m * 60;
261 Info(where, "took %4d:%02d:%06.3f", h, m, t);
266 * @return true on success
270 TString cwd = gSystem->WorkingDirectory();
271 Bool_t status = false;
275 if (!Init()) throw TString("Failed to intialize the train");
276 PrintTimer(timer, "Initialization");
279 // Check if we're asked to only do the setup
280 if (fOptions.Has("setup")) {
282 throw TString("Only did setup, no running");
285 // if (r) SaveSetup(*r, nEvents, asShell);
287 Long64_t nEvents = fOptions.AsLong("events", -1);
288 Long64_t ret = fHelper->Run(nEvents);
289 PrintTimer(timer, "Processing");
292 // Make sure we go back
293 gSystem->ChangeDirectory(cwd.Data());
296 if (ret < 0) throw TString("Analysis failed");
301 if (status) Warning("Run", "%s", e.Data());
302 else Error("Run", "%s", e.Data());
304 if (fOptions.Has("date")) {
306 TString escaped = EscapeName(fName, tmp);
307 gSystem->Exec(Form("rm -f last_%s", escaped.Data()));
308 gSystem->Exec(Form("ln -sf %s last_%s",
309 fEscapedName.Data(), escaped.Data()));
311 PrintTimer(timer, "Finish");
319 * @return Reference ot the options
321 OptionList& Options() { return fOptions; }
323 * Print information to standard output
326 void Print(Option_t* ="") const
328 std::cout << "Train: " << fName << " (" << fEscapedName << ")"
330 fOptions.Show(std::cout);
331 if (fHelper) fHelper->Print();
336 * @param o Output stream
337 * @param asProg If true, output as program options
341 Bool_t Help(std::ostream& o=std::cout, bool asProg=false)
343 if (!fOptions.Has("help")) return true;
346 o << "Usage: RunTrain(NAME, CLASS, OPTIONS)";
348 o << "\n\nTrain Options:\n";
349 fOptions.Help(o, asProg ? " --" : " ");
352 if (!fHelper && fOptions.Has("url")) {
353 TString url = fOptions.Get("url");
354 fHelper = Helper::Create(url.Data());
357 o << fHelper->Desc() << " URL form:\n\n"
358 << " " << fHelper->UrlHelp() << "\n\n"
360 fHelper->Options().Help(o, " ");
364 o << "Possible URL forms:\n\n";
365 Helper::ShowUrlHelp("LocalHelper");
366 Helper::ShowUrlHelp("ProofHelper");
367 Helper::ShowUrlHelp("LiteHelper");
368 Helper::ShowUrlHelp("AAFHelper");
369 Helper::ShowUrlHelp("AAFPluginHelper");
370 Helper::ShowUrlHelp("GridHelper");
376 * Run train. This will AcLic compile the setup script, create
377 * an object of that type with the given name, and then pass the
378 * options to it. Then, it will run the setup.
380 * @param name Train name
381 * @param cls Class name
382 * @param opts Comma seperated list of options
383 * @param asProg Run as program
384 * @param spawn Spawn ROOT shell after execution
386 * @return true on success
388 static Bool_t Main(const TString& name, const TString& cls,
389 const TCollection* opts,
396 throw TString("No class name specified");
398 throw TString("No train name specified");
400 gROOT->ProcessLine("gSystem->RedirectOutput(\"build.log\",\"w\");");
402 Int_t r1 = gROOT->LoadMacro(Form("%s.C+g", cls.Data()), &error);
403 gROOT->ProcessLine("gSystem->RedirectOutput(0);");
405 throw TString::Format("Failed to load setup %s: %d - see build.log",
408 // Make our object using the interpreter
409 TString create = TString::Format("new %s(\"%s\")",
410 cls.Data(), name.Data());
411 gROOT->ProcessLine("gSystem->RedirectOutput(\"build.log\",\"a\");");
412 Long_t retP = gROOT->ProcessLine(create, &error);
413 gROOT->ProcessLine("gSystem->RedirectOutput(0);");
415 throw TString::Format("Failed to make object of class %s "
416 "(see build.log): 0x%08lx/%d\n\t%s",
417 cls.Data(), retP, error, create.Data());
419 TrainSetup* train = reinterpret_cast<TrainSetup*>(retP);
421 // Now parse the options
422 if (!train->Options().Parse(opts))
423 throw TString("Failed to parse options");
425 // Info("", "URL=%s", train->Options().Get("url").Data());
427 // Check if we got a help request
428 if (train->Options().Has("help")) {
429 train->Help(std::cout, asProg);
434 // return train->Init();
438 if (!e.IsNull()) Error("Main", "%s", e.Data());
440 // Info("Main", "End of main loop (app=%p, asProg=%s, spawn=%s)",
441 // gApplication, asProg ? "true" : "false", spawn ? "true" : "false");
442 if (gApplication && asProg) {
445 gApplication->Terminate(ret ? 0 : 1);
451 //__________________________________________________________________
454 * @name Overloadable behaviour
456 //------------------------------------------------------------------
458 * Create the analysis manager
460 * @param name Name of the analysis
462 * @return Created analysis manager
464 virtual AliAnalysisManager* CreateAnalysisManager(const char* name)
466 return new AliAnalysisManager(name,"Analysis Train");
468 //------------------------------------------------------------------
470 * Create input handler
476 virtual AliVEventHandler* CreateInputHandler(UShort_t type)
479 case Helper::kESD: return new AliESDInputHandler();
480 case Helper::kAOD: return new AliAODInputHandler();
481 case Helper::kUser: return 0;
485 //------------------------------------------------------------------
487 * Create MC input handler
489 * @param mc Assume monte-carlo input
493 virtual AliVEventHandler* CreateMCHandler(UShort_t /*type*/, bool mc)
496 AliMCEventHandler* mcHandler = new AliMCEventHandler();
497 mcHandler->SetReadTR(true);
500 //------------------------------------------------------------------
502 * Create output event handler
508 virtual AliVEventHandler* CreateOutputHandler(UShort_t type)
510 AliAODHandler* ret = new AliAODHandler();
513 ret->SetOutputFileName("AliAOD.root");
516 ret->SetOutputFileName("AliAOD.pass2.root");
524 //------------------------------------------------------------------
526 * Create physics selection, and add to manager
528 * @param mc Whether this is for MC
531 virtual void CreatePhysicsSelection(Bool_t mc, AliAnalysisManager* mgr)
533 if (fOptions.Has("bare-ps")) {
534 AliInputEventHandler* input =
535 dynamic_cast<AliInputEventHandler*> (mgr->GetInputEventHandler());
538 AliPhysicsSelection* ps = new AliPhysicsSelection();
539 if (mc) ps->SetAnalyzeMC();
541 input->SetEventSelection(ps);
545 gROOT->Macro(Form("AddTaskPhysicsSelection.C(%d)", mc));
546 mgr->RegisterExtraFile("event_stat.root");
547 mgr->AddStatisticsTask(AliVEvent::kAny);
549 //------------------------------------------------------------------
551 * Create centrality selection, and add to manager
553 * @param mc Whether this is for MC
556 virtual void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
558 gROOT->Macro("AddTaskCentrality.C(true)");
559 const char* name = "CentralitySelection";
560 AliCentralitySelectionTask* ctask =
561 dynamic_cast<AliCentralitySelectionTask*>(mgr->GetTask(name));
563 if (mc) ctask->SetMCInput();
565 //------------------------------------------------------------------
567 * Create analysis tasks. Must be overloaded by sub-class
571 virtual void CreateTasks(AliAnalysisManager* mgr)=0;
573 * Add a task using a script and possibly some arguments
575 * @param macro Script to execute
576 * @param args Optional arguments to the script
578 * @return Created task or null
580 virtual AliAnalysisTask* AddTask(const TString& macro,
583 TString p = gSystem->Which(gROOT->GetMacroPath(), macro.Data());
585 Error("AddTask", "Macro %s not found", macro.Data());
590 cmd.Append(TString::Format("(%s)", args.Data()));
593 Long_t ret = gROOT->Macro(cmd.Data(), &err, false);
595 Error("AddTask", "Failed to execute %s", cmd.Data());
598 return reinterpret_cast<AliAnalysisTask*>(ret);
601 * Add a task to the train with no arguments passed to the script
603 * @param macro The <b>AddTask</b> macro.
605 * @return The added task, if any
607 virtual AliAnalysisTask* AddTask(const TString& macro)
610 return AddTask(macro, args);
613 * Add a single event analysis task to the train, passing the
614 * specified arguments to the macro.
616 * @param macro The <b>AddTask</b> macro
617 * @param args Arguments to pass the macro
619 * @return The added task, if any
621 virtual AliAnalysisTaskSE* AddSETask(const TString& macro,
624 return dynamic_cast<AliAnalysisTaskSE*>(AddTask(macro, args));
627 * Add a single event task to the train with no arguments passed to
630 * @param macro The <b>AddTask</b> macro.
632 * @return The added task, if any
634 virtual AliAnalysisTaskSE* AddSETask(const TString& macro)
637 return AddSETask(macro, args);
641 * Set the name of the train - should be name of the class. Must be
644 * @return Class name as a constant C string
646 virtual const Char_t* ClassName() const = 0;
648 //__________________________________________________________________
651 * @name Utility functions
654 * Escape bad elements of the name
656 * @param name Name to escape
657 * @param datimeStr Date and Time string
659 * @return escaped name
661 static TString EscapeName(const char* name, TString& datimeStr)
663 TString escaped = name;
664 char c[] = { ' ', '/', '@', 0 };
667 char tmp[] = { *p, '\0' };
668 escaped.ReplaceAll(tmp, "_");
671 if (!datimeStr.IsNull()) {
673 if (datimeStr.EqualTo("now", TString::kIgnoreCase))
676 // Try various formats
678 const char* formats[] = { "%Ec", // Locale
682 "%Y%m%d_%H%M", // YYYYMMDD_HHMM
683 "%F %R", // ISO standard, no seconds
685 const char** f = formats;
686 Bool_t found = false;
687 while (*f && !found) {
688 // Reset needed fields
694 // Stop processing on first match
695 if (strptime(datimeStr.Data(), *f, &t) != 0) found = true;
699 t.tm_mon += 1; // Return 0-based month
700 datime.Set(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, 0);
703 if (datime.GetYear() <= 1995 ||
704 datime.GetMonth() == 0 ||
705 datime.GetDay() == 0) return escaped;
706 datimeStr = Form("%04d%02d%02d_%02d%02d",
712 escaped.Append(Form("_%s", datimeStr.Data()));
717 * Make our working directory if so requested
719 * @return true on success
721 Bool_t SetupWorkingDirectory()
723 // Get the name of the target directory
724 TString& nam = fEscapedName;
726 // Check if the directory exists already
727 Bool_t exists = gSystem->AccessPathName(nam.Data()) == 0;
728 if (fHelper->Operation() == Helper::kTerminate && !exists) {
729 Error("SetupWorkingDirectory", "File/directory %s does not exists",
734 Bool_t overwrite = fOptions.Has("overwrite");
735 // If we're not allowed to overwrite, then complain
736 if (!overwrite && exists) {
737 Error("SetupWorkingDirectory", "File/directory %s already exists",
742 // Make the target directory if it doesn't exists
744 if (gSystem->MakeDirectory(nam.Data())) {
745 Error("SetupWorkingDirectory", "Failed to make directory '%s'",
751 // Change directory to target directory
752 if (!gSystem->ChangeDirectory(nam.Data())) {
753 Error("SetupWorkingDirectory", "Failed to change directory to %s",
757 // Info("SetupWorkingDirectory", "Made subdirectory %s, and cd'ed there",
762 * Save the setup as a ROOT script and possibly also a shell script
764 * @param asShellScript If true, also save as shell script
766 virtual void SaveSetup(Bool_t asShellScript)
768 OptionList tmp(fOptions);
769 const OptionList* uopts = (fHelper ? &fHelper->Options() : 0);
770 if (tmp.Find("overwrite")) tmp.Set("overwrite");
771 if (tmp.Find("date") && fEscapedName.Length() > fName.Length()+1) {
772 Int_t n = fName.Length()+1;
773 tmp.Set("date", fEscapedName(n, fEscapedName.Length()-n));
776 SaveSetupShell("rerun", ClassName(), fName, tmp, uopts);
777 SaveSetupROOT("ReRun", ClassName(), fName, tmp, uopts);
778 if (fHelper) fHelper->AuxSave(fEscapedName, asShellScript);
781 * Save a setup as a shell script
783 * @param out Output name of shell script
784 * @param cls Class of the train
785 * @param name Name of the train
786 * @param opts Option list
787 * @param uopts Url options
789 static void SaveSetupShell(const TString& out, const TString& cls,
790 const TString& name, const OptionList& opts,
791 const OptionList* uopts)
793 std::ofstream o(Form("%s.sh", out.Data()));
794 o << "#!/bin/bash\n\n"
795 << "class=\"" << cls << "\"\n"
796 << "name=\"" << name << "\"\n\n"
797 << "# Available options\n"
799 opts.Help(o, "# --");
802 << "# Available URI options\n"
804 uopts->Help(o, "# ");
807 << "opts=(--class=$class \\\n"
809 opts.Store(o, " \\\n --", "", true);
811 << "echo \"Running runTrain ${opts[@]} $@\"\n"
812 << "runTrain \"${opts[@]}\" $@\n\n"
813 << "# EOF" << std::endl;
815 gSystem->Exec(Form("chmod a+x %s.sh", out.Data()));
818 * Save a setup as a ROOT script
820 * @param out Output name of shell script
821 * @param cls Class of the train
822 * @param name Name of the train
823 * @param opts Option list
824 * @param uopts Url options
826 static void SaveSetupROOT(const TString& out, const TString& cls,
827 const TString& name, const OptionList& opts,
828 const OptionList* uopts)
830 OptionList tmp(opts);
833 std::ofstream o(Form("%s.C", out.Data()));
834 o << "// Available options:\n"
839 << "// Available URI options\n";
840 uopts->Help(o, "// ");
843 << "Bool_t " << out << "()\n"
845 << " TString name(\"" << name << "\");\n"
846 << " TString cls(\"" << cls << "\");\n"
847 << " TUrl uri(\"" << opts.Get("url") << "\");\n"
850 tmp.Store(o, "\"", ",\"\n ", false);
853 TString path(gROOT->GetMacroPath());
854 TObjArray* elements = path.Tokenize(":");
855 TObjString* element = 0;
856 TIter next(elements);
857 while ((element = static_cast<TObjString*>(next()))) {
858 if (element->String().IsNull()) continue;
859 o << "\n \"" << element->GetName() << ":\"";
863 << " path.Append(\"$ALICE_ROOT/PWGLF/FORWARD/trains\");\n"
864 << " gROOT->SetMacroPath(path);\n\n"
865 << " gROOT->LoadMacro(\"RunTrain.C\");\n\n"
866 << " return RunTrain(name, cls, uri, opts);\n"
870 << "//" << std::endl;
875 TString fEscapedName;
876 TString fDatimeString;