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)
70 fOptions.Add("help", "Show help", false);
71 fOptions.Add("date", "YYYY-MM-DD HH:MM", "Set date", "now");
72 fOptions.Add("bare-ps", "Use bare physics selection w/o task", false);
73 fOptions.Add("verbose", "LEVEL", "Set verbosity level", 0);
74 fOptions.Add("url", "URL", "Job location & input URL", "");
75 fOptions.Add("overwrite", "Allow overwrite", false);
76 fOptions.Add("events", "N", "Number of events to analyse", -1);
77 fOptions.Add("type", "ESD|AOD|USER", "Input data stype", "");
78 fOptions.Add("setup", "Only do the setup", false);
79 fOptions.Add("branches", "Load only requested branches", false);
80 fEscapedName = EscapeName(fName, "");
85 * @param o Object to copy from
87 TrainSetup(const TrainSetup& o)
89 fEscapedName(o.fEscapedName),
96 * @param o Object to assign from
98 * @return Reference to this object
100 TrainSetup& operator=(const TrainSetup& o)
102 if (&o == this) return *this;
104 fEscapedName = o.fEscapedName;
105 fOptions = o.fOptions;
113 virtual ~TrainSetup() {}
115 //__________________________________________________________________
123 * @return true on success
127 // --- Create the helper -----------------------------------------
128 TString url = fOptions.Get("url");
129 Int_t verbose = fOptions.AsInt("verbose");
131 fHelper = Helper::Create(url.Data(), verbose);
133 Error("Init", "Failed to make the worker for URL %s", url.Data());
137 // --- Check the type, if possible -------------------------------
138 UShort_t type = fHelper->InputType();
139 Bool_t mc = fHelper->IsMC();
140 if (fOptions.Has("type")) {
141 const TString& it = fOptions.Get("type");
142 if (it.EqualTo("ESD",TString::kIgnoreCase)) type = Helper::kESD;
143 else if (it.EqualTo("AOD",TString::kIgnoreCase)) type = Helper::kAOD;
144 else if (it.EqualTo("user",TString::kIgnoreCase))
145 type = Helper::kUser;
148 // --- Rewrite the escpaed name ----------------------------------
149 if (fOptions.Has("date")) {
150 TString date = fOptions.Get("date");
151 fEscapedName = EscapeName(fName, date);
154 // --- Get current directory and set-up sub-directory ------------
155 TString cwd = gSystem->WorkingDirectory();
156 if (!SetupWorkingDirectory()) return false;
158 // --- Do initial helper setup -----------------------------------
159 if (!fHelper->PreSetup()) return false;
161 // --- Load ROOT libraries ---------------------------------------
162 if (!fHelper->LoadROOT()) return false;
164 // --- Load AliROOT libraries ------------------------------------
165 if (!fHelper->LoadAliROOT()) return false;
167 // --- Create analysis manager -----------------------------------
168 AliAnalysisManager *mgr = CreateAnalysisManager(fEscapedName);
170 // In test mode, collect system information on every event
171 // if (oper == kTest) mgr->SetNSysInfo(1);
172 if (verbose > 0) mgr->SetDebugLevel(verbose);
173 mgr->SetAutoBranchLoading(!fOptions.Has("branches"));
174 if (fHelper->Mode() == Helper::kLocal)
175 mgr->SetUseProgressBar(kTRUE, 100);
177 // --- ESD input handler ------------------------------------------
178 AliVEventHandler* inputHandler = CreateInputHandler(type);
179 if (inputHandler) mgr->SetInputEventHandler(inputHandler);
181 // --- Monte-Carlo ------------------------------------------------
182 AliVEventHandler* mcHandler = CreateMCHandler(type,mc);
183 if (mcHandler) mgr->SetMCtruthEventHandler(mcHandler);
185 // --- AOD output handler -----------------------------------------
186 AliVEventHandler* outputHandler = CreateOutputHandler(type);
187 if (outputHandler) mgr->SetOutputEventHandler(outputHandler);
189 // --- Include analysis macro path in search path ----------------
190 gROOT->SetMacroPath(Form("%s:%s:$ALICE_ROOT/ANALYSIS/macros",
191 cwd.Data(), gROOT->GetMacroPath()));
193 // --- Physics selction - only for ESD ---------------------------
194 if (type == Helper::kESD) CreatePhysicsSelection(mc, mgr);
196 // --- Create centrality task ------------------------------------
197 CreateCentralitySelection(mc, mgr);
199 // --- Create tasks ----------------------------------------------
202 // --- Post set-up initialization of helper ----------------------
203 if (!fHelper->PostSetup()) return false;
205 // --- Set debug level on defined tasks --------------------------
207 TIter next(mgr->GetTasks());
208 AliAnalysisTask* sub = 0;
209 while ((sub = static_cast<AliAnalysisTask*>(next()))) {
210 AliAnalysisTaskSE* se = dynamic_cast<AliAnalysisTaskSE*>(sub);
212 se->SetDebugLevel(verbose);
216 // --- Print this setup ------------------------------------------
219 // --- Initialise the train --------------------------------------
220 if (!mgr->InitAnalysis()) {
221 gSystem->ChangeDirectory(cwd.Data());
222 Error("Init","Failed to initialise train");
226 // --- Enable progress bar ---------------------------------------
227 if (fHelper->Mode() != Helper::kGrid)
228 mgr->SetUseProgressBar(true, 100);
230 // --- Save setup to disk ----------------------------------------
233 // --- Some information ------------------------------------------
235 if (fHelper->Mode() != Helper::kLocal) {
236 TIter next(mgr->GetTasks());
237 AliAnalysisTask* sub = 0;
238 while ((sub = static_cast<AliAnalysisTask*>(next()))) {
245 * Print timer information
247 * @param timer The timer
248 * @param where Where this was called from
250 void PrintTimer(TStopwatch& timer, const char* where)
253 Double_t t = timer.RealTime();
254 Int_t h = Int_t(t / 3600); t -= h * 3600;
255 Int_t m = Int_t(t / 60); t -= m * 60;
257 Info(where, "took %4d:%02d:%06.3f", h, m, t);
262 * @return true on success
266 TString cwd = gSystem->WorkingDirectory();
267 Bool_t status = false;
271 if (!Init()) throw TString("Failed to intialize the train");
272 PrintTimer(timer, "Initialization");
275 // Check if we're asked to only do the setup
276 if (fOptions.Has("setup")) {
278 throw TString("Only did setup, no running");
281 // if (r) SaveSetup(*r, nEvents, asShell);
283 Long64_t nEvents = fOptions.AsLong("events", -1);
284 Long64_t ret = fHelper->Run(nEvents);
285 PrintTimer(timer, "Processing");
288 // Make sure we go back
289 gSystem->ChangeDirectory(cwd.Data());
292 if (ret < 0) throw TString("Analysis failed");
297 if (status) Warning("Run", "%s", e.Data());
298 else Error("Run", "%s", e.Data());
300 if (fOptions.Has("date")) {
301 TString escaped = EscapeName(fName, "");
302 gSystem->Exec(Form("rm -f last_%s", escaped.Data()));
303 gSystem->Exec(Form("ln -sf %s last_%s",
304 fEscapedName.Data(), escaped.Data()));
306 PrintTimer(timer, "Finish");
314 * @return Reference ot the options
316 OptionList& Options() { return fOptions; }
318 * Print information to standard output
321 void Print(Option_t* ="") const
323 std::cout << "Train: " << fName << " (" << fEscapedName << ")"
325 fOptions.Show(std::cout);
326 if (fHelper) fHelper->Print();
331 * @param o Output stream
332 * @param asProg If true, output as program options
336 Bool_t Help(std::ostream& o=std::cout, bool asProg=false)
338 if (!fOptions.Has("help")) return true;
341 o << "Usage: RunTrain(NAME, CLASS, OPTIONS)";
343 o << "\n\nTrain Options:\n";
344 fOptions.Help(o, asProg ? " --" : " ");
347 if (!fHelper && fOptions.Has("url")) {
348 TString url = fOptions.Get("url");
349 fHelper = Helper::Create(url.Data());
352 o << fHelper->Desc() << " URL form:\n\n"
353 << " " << fHelper->UrlHelp() << "\n\n"
355 fHelper->Options().Help(o, " ");
359 o << "Possible URL forms:\n\n";
360 Helper::ShowUrlHelp("LocalHelper");
361 Helper::ShowUrlHelp("ProofHelper");
362 Helper::ShowUrlHelp("LiteHelper");
363 Helper::ShowUrlHelp("AAFHelper");
364 Helper::ShowUrlHelp("AAFPluginHelper");
365 Helper::ShowUrlHelp("GridHelper");
371 * Run train. This will AcLic compile the setup script, create
372 * an object of that type with the given name, and then pass the
373 * options to it. Then, it will run the setup.
375 * @param name Train name
376 * @param cls Class name
377 * @param opts Comma seperated list of options
378 * @param asProg Run as program
379 * @param spawn Spawn ROOT shell after execution
381 * @return true on success
383 static Bool_t Main(const TString& name, const TString& cls,
384 const TCollection* opts,
391 throw TString("No class name specified");
393 throw TString("No train name specified");
395 gROOT->ProcessLine("gSystem->RedirectOutput(\"build.log\",\"w\");");
397 Int_t r1 = gROOT->LoadMacro(Form("%s.C+g", cls.Data()), &error);
398 gROOT->ProcessLine("gSystem->RedirectOutput(0);");
400 throw TString::Format("Failed to load setup %s: %d - see build.log",
403 // Make our object using the interpreter
404 TString create = TString::Format("new %s(\"%s\")",
405 cls.Data(), name.Data());
406 gROOT->ProcessLine("gSystem->RedirectOutput(\"build.log\",\"a\");");
407 Long_t retP = gROOT->ProcessLine(create, &error);
408 gROOT->ProcessLine("gSystem->RedirectOutput(0);");
410 throw TString::Format("Failed to make object of class %s "
411 "(see build.log): 0x%08lx/%d\n\t%s",
412 cls.Data(), retP, error, create.Data());
414 TrainSetup* train = reinterpret_cast<TrainSetup*>(retP);
416 // Now parse the options
417 if (!train->Options().Parse(opts))
418 throw TString("Failed to parse options");
420 // Info("", "URL=%s", train->Options().Get("url").Data());
422 // Check if we got a help request
423 if (train->Options().Has("help")) {
424 train->Help(std::cout, asProg);
429 // return train->Init();
433 if (!e.IsNull()) Error("Main", "%s", e.Data());
435 // Info("Main", "End of main loop (app=%p, asProg=%s, spawn=%s)",
436 // gApplication, asProg ? "true" : "false", spawn ? "true" : "false");
437 if (gApplication && asProg) {
440 gApplication->Terminate(ret ? 0 : 1);
446 //__________________________________________________________________
449 * @name Overloadable behaviour
451 //------------------------------------------------------------------
453 * Create the analysis manager
455 * @param name Name of the analysis
457 * @return Created analysis manager
459 virtual AliAnalysisManager* CreateAnalysisManager(const char* name)
461 return new AliAnalysisManager(name,"Analysis Train");
463 //------------------------------------------------------------------
465 * Create input handler
471 virtual AliVEventHandler* CreateInputHandler(UShort_t type)
474 case Helper::kESD: return new AliESDInputHandler();
475 case Helper::kAOD: return new AliAODInputHandler();
476 case Helper::kUser: return 0;
480 //------------------------------------------------------------------
482 * Create MC input handler
484 * @param mc Assume monte-carlo input
488 virtual AliVEventHandler* CreateMCHandler(UShort_t /*type*/, bool mc)
491 AliMCEventHandler* mcHandler = new AliMCEventHandler();
492 mcHandler->SetReadTR(true);
495 //------------------------------------------------------------------
497 * Create output event handler
503 virtual AliVEventHandler* CreateOutputHandler(UShort_t type)
505 AliAODHandler* ret = new AliAODHandler();
508 ret->SetOutputFileName("AliAOD.root");
511 ret->SetOutputFileName("AliAOD.pass2.root");
519 //------------------------------------------------------------------
521 * Create physics selection, and add to manager
523 * @param mc Whether this is for MC
526 virtual void CreatePhysicsSelection(Bool_t mc, AliAnalysisManager* mgr)
528 if (fOptions.Has("bare-ps")) {
529 AliInputEventHandler* input =
530 dynamic_cast<AliInputEventHandler*> (mgr->GetInputEventHandler());
533 AliPhysicsSelection* ps = new AliPhysicsSelection();
534 if (mc) ps->SetAnalyzeMC();
536 input->SetEventSelection(ps);
540 gROOT->Macro(Form("AddTaskPhysicsSelection.C(%d)", mc));
541 mgr->RegisterExtraFile("event_stat.root");
542 mgr->AddStatisticsTask(AliVEvent::kAny);
544 //------------------------------------------------------------------
546 * Create centrality selection, and add to manager
548 * @param mc Whether this is for MC
551 virtual void CreateCentralitySelection(Bool_t mc, AliAnalysisManager* mgr)
553 gROOT->Macro("AddTaskCentrality.C(true)");
554 const char* name = "CentralitySelection";
555 AliCentralitySelectionTask* ctask =
556 dynamic_cast<AliCentralitySelectionTask*>(mgr->GetTask(name));
558 if (mc) ctask->SetMCInput();
560 //------------------------------------------------------------------
562 * Create analysis tasks. Must be overloaded by sub-class
566 virtual void CreateTasks(AliAnalysisManager* mgr)=0;
568 * Add a task using a script and possibly some arguments
570 * @param macro Script to execute
571 * @param args Optional arguments to the script
573 * @return Created task or null
575 virtual AliAnalysisTask* AddTask(const TString& macro,
578 TString p = gSystem->Which(gROOT->GetMacroPath(), macro.Data());
580 Error("AddTask", "Macro %s not found", macro.Data());
585 cmd.Append(TString::Format("(%s)", args.Data()));
588 Long_t ret = gROOT->Macro(cmd.Data(), &err, false);
590 Error("AddTask", "Failed to execute %s", cmd.Data());
593 return reinterpret_cast<AliAnalysisTask*>(ret);
596 * Add a task to the train with no arguments passed to the script
598 * @param macro The <b>AddTask</b> macro.
600 * @return The added task, if any
602 virtual AliAnalysisTask* AddTask(const TString& macro)
605 return AddTask(macro, args);
608 * Add a single event analysis task to the train, passing the
609 * specified arguments to the macro.
611 * @param macro The <b>AddTask</b> macro
612 * @param args Arguments to pass the macro
614 * @return The added task, if any
616 virtual AliAnalysisTaskSE* AddSETask(const TString& macro,
619 return dynamic_cast<AliAnalysisTaskSE*>(AddTask(macro, args));
622 * Add a single event task to the train with no arguments passed to
625 * @param macro The <b>AddTask</b> macro.
627 * @return The added task, if any
629 virtual AliAnalysisTaskSE* AddSETask(const TString& macro)
632 return AddSETask(macro, args);
636 * Set the name of the train - should be name of the class. Must be
639 * @return Class name as a constant C string
641 virtual const Char_t* ClassName() const = 0;
643 //__________________________________________________________________
646 * @name Utility functions
649 * Escape bad elements of the name
651 * @param name Name to escape
652 * @param datimeStr Date and Time string
654 * @return escaped name
656 static TString EscapeName(const char* name, const TString& datimeStr)
658 TString escaped = name;
659 char c[] = { ' ', '/', '@', 0 };
662 char tmp[] = { *p, '\0' };
663 escaped.ReplaceAll(tmp, "_");
666 if (!datimeStr.IsNull()) {
668 if (datimeStr.EqualTo("now", TString::kIgnoreCase))
671 // Try various formats
673 const char* formats[] = { "%Ec", // Locale
677 "%Y%m%d_%H%M", // YYYYMMDD_HHMM
678 "%F %R", // ISO standard, no seconds
680 const char** f = formats;
681 Bool_t found = false;
682 while (*f && !found) {
683 // Reset needed fields
689 // Stop processing on first match
690 if (strptime(datimeStr.Data(), *f, &t) != 0) found = true;
694 t.tm_mon += 1; // Return 0-based month
695 datime.Set(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, 0);
698 if (datime.GetYear() <= 1995 ||
699 datime.GetMonth() == 0 ||
700 datime.GetDay() == 0) return escaped;
701 escaped.Append(Form("_%04d%02d%02d_%02d%02d",
706 datime.GetMinute()));
711 * Make our working directory if so requested
713 * @return true on success
715 Bool_t SetupWorkingDirectory()
717 // Get the name of the target directory
718 TString& nam = fEscapedName;
720 // Check if the directory exists already
721 Bool_t exists = gSystem->AccessPathName(nam.Data()) == 0;
722 if (fHelper->Operation() == Helper::kTerminate && !exists) {
723 Error("SetupWorkingDirectory", "File/directory %s does not exists",
728 Bool_t overwrite = fOptions.Has("overwrite");
729 // If we're not allowed to overwrite, then complain
730 if (!overwrite && exists) {
731 Error("SetupWorkingDirectory", "File/directory %s already exists",
736 // Make the target directory if it doesn't exists
738 if (gSystem->MakeDirectory(nam.Data())) {
739 Error("SetupWorkingDirectory", "Failed to make directory '%s'",
745 // Change directory to target directory
746 if (!gSystem->ChangeDirectory(nam.Data())) {
747 Error("SetupWorkingDirectory", "Failed to change directory to %s",
751 // Info("SetupWorkingDirectory", "Made subdirectory %s, and cd'ed there",
756 * Save the setup as a ROOT script and possibly also a shell script
758 * @param asShellScript If true, also save as shell script
760 virtual void SaveSetup(Bool_t asShellScript)
762 OptionList tmp(fOptions);
763 const OptionList* uopts = (fHelper ? &fHelper->Options() : 0);
764 if (tmp.Find("overwrite")) tmp.Set("overwrite");
765 if (tmp.Find("date") && fEscapedName.Length() > fName.Length()+1) {
766 Int_t n = fName.Length()+1;
767 tmp.Set("date", fEscapedName(n, fEscapedName.Length()-n));
770 SaveSetupShell("rerun", ClassName(), fName, tmp, uopts);
771 SaveSetupROOT("ReRun", ClassName(), fName, tmp, uopts);
772 if (fHelper) fHelper->AuxSave(fEscapedName, asShellScript);
775 * Save a setup as a shell script
777 * @param out Output name of shell script
778 * @param cls Class of the train
779 * @param name Name of the train
780 * @param opts Option list
781 * @param uopts Url options
783 static void SaveSetupShell(const TString& out, const TString& cls,
784 const TString& name, const OptionList& opts,
785 const OptionList* uopts)
787 std::ofstream o(Form("%s.sh", out.Data()));
788 o << "#!/bin/bash\n\n"
789 << "class=\"" << cls << "\"\n"
790 << "name=\"" << name << "\"\n\n"
791 << "# Available options\n"
793 opts.Help(o, "# --");
796 << "# Available URI options\n"
798 uopts->Help(o, "# ");
801 << "opts=(--class=$class \\\n"
803 opts.Store(o, " \\\n --", "", true);
805 << "echo \"Running runTrain ${opts[@]} $@\"\n"
806 << "runTrain \"${opts[@]}\" $@\n\n"
807 << "# EOF" << std::endl;
809 gSystem->Exec(Form("chmod a+x %s.sh", out.Data()));
812 * Save a setup as a ROOT script
814 * @param out Output name of shell script
815 * @param cls Class of the train
816 * @param name Name of the train
817 * @param opts Option list
818 * @param uopts Url options
820 static void SaveSetupROOT(const TString& out, const TString& cls,
821 const TString& name, const OptionList& opts,
822 const OptionList* uopts)
824 OptionList tmp(opts);
827 std::ofstream o(Form("%s.C", out.Data()));
828 o << "// Available options:\n"
833 << "// Available URI options\n";
834 uopts->Help(o, "// ");
837 << "Bool_t " << out << "()\n"
839 << " TString name(\"" << name << "\");\n"
840 << " TString cls(\"" << cls << "\");\n"
841 << " TUrl uri(\"" << opts.Get("url") << "\");\n"
844 tmp.Store(o, "\"", ",\"\n ", false);
847 TString path(gROOT->GetMacroPath());
848 TObjArray* elements = path.Tokenize(":");
849 TObjString* element = 0;
850 TIter next(elements);
851 while ((element = static_cast<TObjString*>(next()))) {
852 if (element->String().IsNull()) continue;
853 o << "\n \"" << element->GetName() << ":\"";
857 << " path.Append(\"$ALICE_ROOT/PWGLF/FORWARD/trains\");\n"
858 << " gROOT->SetMacroPath(path);\n\n"
859 << " gROOT->LoadMacro(\"RunTrain.C\");\n\n"
860 << " return RunTrain(name, cls, uri, opts);\n"
864 << "//" << std::endl;
869 TString fEscapedName;