]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
add few ebe dihadron and jet correlation to be compared to normal dihadron correlatio...
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisAlien.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 // Author: Mihaela Gheata, 01/09/2008
17
18 //==============================================================================
19 //   AliAnalysisAlien - AliEn utility class. Provides interface for creating
20 // a personalized JDL, finding and creating a dataset.
21 //==============================================================================
22
23 #include "AliAnalysisAlien.h"
24
25 #include "Riostream.h"
26 #include "TEnv.h"
27 #include "TKey.h"
28 #include "TBits.h"
29 #include "TError.h"
30 #include "TROOT.h"
31 #include "TSystem.h"
32 #include "TInterpreter.h"
33 #include "TFile.h"
34 #include "TFileCollection.h"
35 #include "TChain.h"
36 #include "TObjString.h"
37 #include "TObjArray.h"
38 #include "TMacro.h"
39 #include "TGrid.h"
40 #include "TGridResult.h"
41 #include "TGridCollection.h"
42 #include "TGridJDL.h"
43 #include "TGridJobStatusList.h"
44 #include "TGridJobStatus.h"
45 #include "TFileMerger.h"
46 #include "AliAnalysisManager.h"
47 #include "AliAnalysisTaskCfg.h"
48 #include "AliVEventHandler.h"
49 #include "AliAnalysisDataContainer.h"
50 #include "AliMultiInputEventHandler.h"
51
52 using std::ofstream;
53 using std::ifstream;
54 using std::ios;
55 using std::endl;
56 ClassImp(AliAnalysisAlien)
57 #if 0
58 ;
59 #endif  
60
61 namespace {
62   Bool_t copyLocal2Alien(const char* where, const char* loc, const char* rem)
63   {
64     TString sl(Form("file:%s", loc));
65     TString sr(Form("alien://%s", rem));
66     Bool_t ret = TFile::Cp(sl, sr);
67     if (!ret) { 
68       Warning(where, "Failed to copy %s to %s", sl.Data(), sr.Data());
69     }
70     return ret;
71   }
72 }
73     
74 //______________________________________________________________________________
75 AliAnalysisAlien::AliAnalysisAlien()
76                  :AliAnalysisGrid(),
77                   fGridJDL(NULL),
78                   fMergingJDL(NULL),
79                   fPrice(0),
80                   fTTL(0),
81                   fSplitMaxInputFileNumber(0),
82                   fMaxInitFailed(0),
83                   fMasterResubmitThreshold(0),
84                   fNtestFiles(0),
85                   fNrunsPerMaster(0),
86                   fMaxMergeFiles(0),
87                   fMaxMergeStages(0),
88                   fNsubmitted(0),
89                   fProductionMode(0),
90                   fOutputToRunNo(0),
91                   fMergeViaJDL(0),
92                   fFastReadOption(0),
93                   fOverwriteMode(1),
94                   fNreplicas(2),
95                   fNproofWorkers(0),
96                   fNproofWorkersPerSlave(0),
97                   fProofReset(0),
98                   fNMCevents(0),
99                   fNMCjobs(0),
100                   fRunNumbers(),
101                   fExecutable(),
102                   fExecutableCommand(),
103                   fArguments(),
104                   fExecutableArgs(),
105                   fAnalysisMacro(),
106                   fAnalysisSource(),
107                   fValidationScript(),
108                   fAdditionalRootLibs(),
109                   fAdditionalLibs(),
110                   fGeneratorLibs(),
111                   fSplitMode(),
112                   fAPIVersion(),
113                   fROOTVersion(),
114                   fAliROOTVersion(),
115                   fExternalPackages(),
116                   fUser(),
117                   fGridWorkingDir(),
118                   fGridDataDir(),
119                   fDataPattern(),
120                   fGridOutputDir(),
121                   fOutputArchive(),
122                   fOutputFiles(),
123                   fInputFormat(),
124                   fDatasetName(),
125                   fJDLName(),
126                   fTerminateFiles(),
127                             fMergeExcludes(),
128                   fRegisterExcludes(),
129                   fIncludePath(),
130                   fCloseSE(),
131                   fFriendChainName(),
132                   fJobTag(),
133                   fOutputSingle(),
134                   fRunPrefix(),
135                   fProofCluster(),
136                   fProofDataSet(),
137                   fFileForTestMode(),
138                   fAliRootMode(),
139                   fProofProcessOpt(),
140                   fMergeDirName(),
141                   fInputFiles(0),
142                   fPackages(0),
143                   fModules(0),
144                   fProofParam(),
145                   fDropToShell(true),
146                   fMCLoop(false),
147                   fGridJobIDs(""),
148                   fGridStages(""),
149                   fFriendLibs(""),
150                   fTreeName()
151 {
152 // Dummy ctor.
153    SetDefaults();
154 }
155
156 //______________________________________________________________________________
157 AliAnalysisAlien::AliAnalysisAlien(const char *name)
158                  :AliAnalysisGrid(name),
159                   fGridJDL(NULL),
160                   fMergingJDL(NULL),
161                   fPrice(0),
162                   fTTL(0),
163                   fSplitMaxInputFileNumber(0),
164                   fMaxInitFailed(0),
165                   fMasterResubmitThreshold(0),
166                   fNtestFiles(0),
167                   fNrunsPerMaster(0),
168                   fMaxMergeFiles(0),
169                   fMaxMergeStages(0),
170                   fNsubmitted(0),
171                   fProductionMode(0),
172                   fOutputToRunNo(0),
173                   fMergeViaJDL(0),
174                   fFastReadOption(0),
175                   fOverwriteMode(1),
176                   fNreplicas(2),
177                   fNproofWorkers(0),
178                   fNproofWorkersPerSlave(0),
179                   fProofReset(0),
180                   fNMCevents(0),
181                   fNMCjobs(0),
182                   fRunNumbers(),
183                   fExecutable(),
184                   fExecutableCommand(),
185                   fArguments(),
186                   fExecutableArgs(),
187                   fAnalysisMacro(),
188                   fAnalysisSource(),
189                   fValidationScript(),
190                   fAdditionalRootLibs(),
191                   fAdditionalLibs(),
192                   fGeneratorLibs(),
193                   fSplitMode(),
194                   fAPIVersion(),
195                   fROOTVersion(),
196                   fAliROOTVersion(),
197                   fExternalPackages(),
198                   fUser(),
199                   fGridWorkingDir(),
200                   fGridDataDir(),
201                   fDataPattern(),
202                   fGridOutputDir(),
203                   fOutputArchive(),
204                   fOutputFiles(),
205                   fInputFormat(),
206                   fDatasetName(),
207                   fJDLName(),
208                   fTerminateFiles(),
209                   fMergeExcludes(),
210                   fRegisterExcludes(),
211                   fIncludePath(),
212                   fCloseSE(),
213                   fFriendChainName(),
214                   fJobTag(),
215                   fOutputSingle(),
216                   fRunPrefix(),
217                   fProofCluster(),
218                   fProofDataSet(),
219                   fFileForTestMode(),
220                   fAliRootMode(),
221                   fProofProcessOpt(),
222                   fMergeDirName(),
223                   fInputFiles(0),
224                   fPackages(0),
225                   fModules(0),
226                   fProofParam(),
227                   fDropToShell(true),
228                   fMCLoop(false),
229                   fGridJobIDs(""),
230                   fGridStages(""),
231                   fFriendLibs(""),
232                   fTreeName()
233 {
234 // Default ctor.
235    SetDefaults();
236 }
237
238 //______________________________________________________________________________
239 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
240                  :AliAnalysisGrid(other),
241                   fGridJDL(NULL),
242                   fMergingJDL(NULL),
243                   fPrice(other.fPrice),
244                   fTTL(other.fTTL),
245                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
246                   fMaxInitFailed(other.fMaxInitFailed),
247                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
248                   fNtestFiles(other.fNtestFiles),
249                   fNrunsPerMaster(other.fNrunsPerMaster),
250                   fMaxMergeFiles(other.fMaxMergeFiles),
251                   fMaxMergeStages(other.fMaxMergeStages),
252                   fNsubmitted(other.fNsubmitted),
253                   fProductionMode(other.fProductionMode),
254                   fOutputToRunNo(other.fOutputToRunNo),
255                   fMergeViaJDL(other.fMergeViaJDL),
256                   fFastReadOption(other.fFastReadOption),
257                   fOverwriteMode(other.fOverwriteMode),
258                   fNreplicas(other.fNreplicas),
259                   fNproofWorkers(other.fNproofWorkers),
260                   fNproofWorkersPerSlave(other.fNproofWorkersPerSlave),
261                   fProofReset(other.fProofReset),
262                   fNMCevents(other.fNMCevents),
263                   fNMCjobs(other.fNMCjobs),
264                   fRunNumbers(other.fRunNumbers),
265                   fExecutable(other.fExecutable),
266                   fExecutableCommand(other.fExecutableCommand),
267                   fArguments(other.fArguments),
268                   fExecutableArgs(other.fExecutableArgs),
269                   fAnalysisMacro(other.fAnalysisMacro),
270                   fAnalysisSource(other.fAnalysisSource),
271                   fValidationScript(other.fValidationScript),
272                   fAdditionalRootLibs(other.fAdditionalRootLibs),
273                   fAdditionalLibs(other.fAdditionalLibs),
274                   fGeneratorLibs(other.fGeneratorLibs),
275                   fSplitMode(other.fSplitMode),
276                   fAPIVersion(other.fAPIVersion),
277                   fROOTVersion(other.fROOTVersion),
278                   fAliROOTVersion(other.fAliROOTVersion),
279                   fExternalPackages(other.fExternalPackages),
280                   fUser(other.fUser),
281                   fGridWorkingDir(other.fGridWorkingDir),
282                   fGridDataDir(other.fGridDataDir),
283                   fDataPattern(other.fDataPattern),
284                   fGridOutputDir(other.fGridOutputDir),
285                   fOutputArchive(other.fOutputArchive),
286                   fOutputFiles(other.fOutputFiles),
287                   fInputFormat(other.fInputFormat),
288                   fDatasetName(other.fDatasetName),
289                   fJDLName(other.fJDLName),
290                   fTerminateFiles(other.fTerminateFiles),
291                   fMergeExcludes(other.fMergeExcludes),
292                   fRegisterExcludes(other.fRegisterExcludes),
293                   fIncludePath(other.fIncludePath),
294                   fCloseSE(other.fCloseSE),
295                   fFriendChainName(other.fFriendChainName),
296                   fJobTag(other.fJobTag),
297                   fOutputSingle(other.fOutputSingle),
298                   fRunPrefix(other.fRunPrefix),
299                   fProofCluster(other.fProofCluster),
300                   fProofDataSet(other.fProofDataSet),
301                   fFileForTestMode(other.fFileForTestMode),
302                   fAliRootMode(other.fAliRootMode),
303                   fProofProcessOpt(other.fProofProcessOpt),
304                   fMergeDirName(other.fMergeDirName),
305                   fInputFiles(0),
306                   fPackages(0),
307                   fModules(0),
308                   fProofParam(),
309                   fDropToShell(other.fDropToShell),
310                   fMCLoop(other.fMCLoop),
311                   fGridJobIDs(other.fGridJobIDs),
312                   fGridStages(other.fGridStages),
313                   fFriendLibs(other.fFriendLibs),
314                   fTreeName(other.fTreeName)
315 {
316 // Copy ctor.
317    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
318    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
319    fRunRange[0] = other.fRunRange[0];
320    fRunRange[1] = other.fRunRange[1];
321    if (other.fInputFiles) {
322       fInputFiles = new TObjArray();
323       TIter next(other.fInputFiles);
324       TObject *obj;
325       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
326       fInputFiles->SetOwner();
327    }   
328    if (other.fPackages) {
329       fPackages = new TObjArray();
330       TIter next(other.fPackages);
331       TObject *obj;
332       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
333       fPackages->SetOwner();
334    }   
335    if (other.fModules) {
336       fModules = new TObjArray();
337       fModules->SetOwner();
338       TIter next(other.fModules);
339       AliAnalysisTaskCfg *mod, *crt;
340       while ((crt=(AliAnalysisTaskCfg*)next())) {
341          mod = new AliAnalysisTaskCfg(*crt);
342          fModules->Add(mod);
343       }
344    }   
345 }
346
347 //______________________________________________________________________________
348 AliAnalysisAlien::~AliAnalysisAlien()
349 {
350 // Destructor.
351    delete fGridJDL;
352    delete fMergingJDL;
353    delete fInputFiles;
354    delete fPackages;
355    delete fModules;
356    fProofParam.DeleteAll();
357 }   
358
359 //______________________________________________________________________________
360 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
361 {
362 // Assignment.
363    if (this != &other) {
364       AliAnalysisGrid::operator=(other);
365       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
366       fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
367       fPrice                   = other.fPrice;
368       fTTL                     = other.fTTL;
369       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
370       fMaxInitFailed           = other.fMaxInitFailed;
371       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
372       fNtestFiles              = other.fNtestFiles;
373       fNrunsPerMaster          = other.fNrunsPerMaster;
374       fMaxMergeFiles           = other.fMaxMergeFiles;
375       fMaxMergeStages          = other.fMaxMergeStages;
376       fNsubmitted              = other.fNsubmitted;
377       fProductionMode          = other.fProductionMode;
378       fOutputToRunNo           = other.fOutputToRunNo;
379       fMergeViaJDL             = other.fMergeViaJDL;
380       fFastReadOption          = other.fFastReadOption;
381       fOverwriteMode           = other.fOverwriteMode;
382       fNreplicas               = other.fNreplicas;
383       fNproofWorkers           = other.fNproofWorkers;
384       fNproofWorkersPerSlave   = other.fNproofWorkersPerSlave;
385       fProofReset              = other.fProofReset;
386       fNMCevents               = other.fNMCevents;
387       fNMCjobs                 = other.fNMCjobs;
388       fRunNumbers              = other.fRunNumbers;
389       fExecutable              = other.fExecutable;
390       fExecutableCommand       = other.fExecutableCommand;
391       fArguments               = other.fArguments;
392       fExecutableArgs          = other.fExecutableArgs;
393       fAnalysisMacro           = other.fAnalysisMacro;
394       fAnalysisSource          = other.fAnalysisSource;
395       fValidationScript        = other.fValidationScript;
396       fAdditionalRootLibs      = other.fAdditionalRootLibs;
397       fAdditionalLibs          = other.fAdditionalLibs;
398       fGeneratorLibs           = other.fGeneratorLibs;
399       fSplitMode               = other.fSplitMode;
400       fAPIVersion              = other.fAPIVersion;
401       fROOTVersion             = other.fROOTVersion;
402       fAliROOTVersion          = other.fAliROOTVersion;
403       fExternalPackages        = other.fExternalPackages;
404       fUser                    = other.fUser;
405       fGridWorkingDir          = other.fGridWorkingDir;
406       fGridDataDir             = other.fGridDataDir;
407       fDataPattern             = other.fDataPattern;
408       fGridOutputDir           = other.fGridOutputDir;
409       fOutputArchive           = other.fOutputArchive;
410       fOutputFiles             = other.fOutputFiles;
411       fInputFormat             = other.fInputFormat;
412       fDatasetName             = other.fDatasetName;
413       fJDLName                 = other.fJDLName;
414       fTerminateFiles          = other.fTerminateFiles;
415       fMergeExcludes           = other.fMergeExcludes;
416       fRegisterExcludes        = other.fRegisterExcludes;
417       fIncludePath             = other.fIncludePath;
418       fCloseSE                 = other.fCloseSE;
419       fFriendChainName         = other.fFriendChainName;
420       fJobTag                  = other.fJobTag;
421       fOutputSingle            = other.fOutputSingle;
422       fRunPrefix               = other.fRunPrefix;
423       fProofCluster            = other.fProofCluster;
424       fProofDataSet            = other.fProofDataSet;
425       fFileForTestMode         = other.fFileForTestMode;
426       fAliRootMode             = other.fAliRootMode;
427       fProofProcessOpt         = other.fProofProcessOpt;
428       fMergeDirName            = other.fMergeDirName;
429       fDropToShell             = other.fDropToShell;
430       fMCLoop                  = other.fMCLoop;
431       fGridJobIDs              = other.fGridJobIDs;
432       fGridStages              = other.fGridStages;
433       fFriendLibs              = other.fFriendLibs;
434       fTreeName                = other.fTreeName;
435       if (other.fInputFiles) {
436          fInputFiles = new TObjArray();
437          TIter next(other.fInputFiles);
438          TObject *obj;
439          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
440          fInputFiles->SetOwner();
441       }   
442       if (other.fPackages) {
443          fPackages = new TObjArray();
444          TIter next(other.fPackages);
445          TObject *obj;
446          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
447          fPackages->SetOwner();
448       }   
449       if (other.fModules) {
450          fModules = new TObjArray();
451          fModules->SetOwner();
452          TIter next(other.fModules);
453          AliAnalysisTaskCfg *mod, *crt;
454          while ((crt=(AliAnalysisTaskCfg*)next())) {
455             mod = new AliAnalysisTaskCfg(*crt);
456             fModules->Add(mod);
457          }
458       }   
459    }
460    return *this;
461 }
462
463 //______________________________________________________________________________
464 void AliAnalysisAlien::AddAdditionalLibrary(const char *name)
465 {
466 // Add a single additional library to be loaded. Extension must be present.
467    TString lib(name);
468    if (!lib.Contains(".")) {
469       Error("AddAdditionalLibrary", "Extension not defined for %s", name);
470       return;
471    }
472    if (fAdditionalLibs.Contains(name)) {
473       Warning("AddAdditionalLibrary", "Library %s already added.", name);
474       return;
475    }
476    if (!fAdditionalLibs.IsNull()) fAdditionalLibs += " ";
477    fAdditionalLibs += lib;
478 }   
479
480 //______________________________________________________________________________
481 void AliAnalysisAlien::AddModule(AliAnalysisTaskCfg *module)
482 {
483 // Adding a module. Checks if already existing. Becomes owned by this.
484    if (!module) return;
485    if (GetModule(module->GetName())) {
486       Error("AddModule", "A module having the same name %s already added", module->GetName());
487       return;
488    }
489    if (!fModules) {
490       fModules = new TObjArray();
491       fModules->SetOwner();
492    }
493    fModules->Add(module);
494 }
495
496 //______________________________________________________________________________
497 void AliAnalysisAlien::AddModules(TObjArray *list)
498 {
499 // Adding a list of modules. Checks if already existing. Becomes owned by this.
500    TIter next(list);
501    AliAnalysisTaskCfg *module;
502    while ((module = (AliAnalysisTaskCfg*)next())) AddModule(module);
503 }   
504
505 //______________________________________________________________________________
506 Bool_t AliAnalysisAlien::CheckDependencies()
507 {
508 // Check if all dependencies are satisfied. Reorder modules if needed.
509    Int_t nmodules = GetNmodules();
510    if (!nmodules) {
511       Warning("CheckDependencies", "No modules added yet to check their dependencies");
512       return kTRUE;
513    }   
514    AliAnalysisTaskCfg *mod = 0;
515    AliAnalysisTaskCfg *dep = 0;
516    TString depname;
517    Int_t i, j, k;
518    for (i=0; i<nmodules; i++) {
519       mod = (AliAnalysisTaskCfg*) fModules->At(i);
520       Int_t ndeps = mod->GetNdeps();
521       Int_t istart = i;
522       for (j=0; j<ndeps; j++) {
523          depname = mod->GetDependency(j);
524          dep = GetModule(depname);
525          if (!dep) {
526             Error("CheckDependencies","Dependency %s not added for module %s",
527                    depname.Data(), mod->GetName());
528             return kFALSE;
529          }
530          if (dep->NeedsDependency(mod->GetName())) {
531             Error("CheckDependencies","Modules %s and %s circularly depend on each other",
532                    mod->GetName(), dep->GetName());
533             return kFALSE;
534          }                  
535          Int_t idep = fModules->IndexOf(dep);
536          // The dependency task must come first
537          if (idep>i) {
538             // Remove at idep and move all objects below up one slot
539             // down to index i included.
540             fModules->RemoveAt(idep);
541             for (k=idep-1; k>=i; k--) fModules->AddAt(fModules->RemoveAt(k),k+1);
542             fModules->AddAt(dep, i++);
543          }
544          //Redo from istart if dependencies were inserted
545          if (i>istart) i=istart-1;
546       }
547    }
548    return kTRUE;
549 }      
550
551 //______________________________________________________________________________
552 AliAnalysisManager *AliAnalysisAlien::CreateAnalysisManager(const char *name, const char *filename)
553 {
554 // Create the analysis manager and optionally execute the macro in filename.
555    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
556    if (mgr) {
557       mgr->SetMCLoop(fMCLoop);
558       return mgr;
559    }   
560    mgr = new AliAnalysisManager(name);
561    mgr->SetGridHandler((AliAnalysisGrid*)this);
562    mgr->SetMCLoop(fMCLoop);
563    if (strlen(filename)) {
564       TString line = gSystem->ExpandPathName(filename);
565       line.Prepend(".x ");
566       gROOT->ProcessLine(line.Data());
567    }
568    return mgr;
569 }      
570       
571 //______________________________________________________________________________
572 Int_t AliAnalysisAlien::GetNmodules() const
573 {
574 // Get number of modules.
575    if (!fModules) return 0;
576    return fModules->GetEntries();
577 }
578
579 //______________________________________________________________________________
580 AliAnalysisTaskCfg *AliAnalysisAlien::GetModule(const char *name)
581 {
582 // Get a module by name.
583    if (!fModules) return 0;
584    return (AliAnalysisTaskCfg*)fModules->FindObject(name);
585 }
586    
587 //______________________________________________________________________________
588 Bool_t AliAnalysisAlien::LoadModule(AliAnalysisTaskCfg *mod)
589 {
590 // Load a given module.
591    if (mod->IsLoaded()) return kTRUE;
592    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
593    if (!mgr) {
594       Error("LoadModule", "No analysis manager created yet. Use CreateAnalysisManager first.");
595       return kFALSE;
596    }   
597    Int_t ndeps = mod->GetNdeps();
598    TString depname;
599    for (Int_t j=0; j<ndeps; j++) {
600       depname = mod->GetDependency(j);
601       AliAnalysisTaskCfg *dep = GetModule(depname);
602       if (!dep) {
603          Error("LoadModule","Dependency %s not existing for module %s",
604                 depname.Data(), mod->GetName());
605          return kFALSE;
606       }
607       if (!LoadModule(dep)) {
608          Error("LoadModule","Dependency %s for module %s could not be loaded",
609                 depname.Data(), mod->GetName());
610          return kFALSE;
611       }
612    }
613    // Load libraries for the module
614    if (!mod->CheckLoadLibraries()) {
615       Error("LoadModule", "Cannot load all libraries for module %s", mod->GetName());
616       return kFALSE;
617    }
618    // Check if a custom file name was requested
619    if (strlen(mod->GetOutputFileName())) mgr->SetCommonFileName(mod->GetOutputFileName());
620
621    // Check if a custom terminate file name was requested
622    if (strlen(mod->GetTerminateFileName())) {
623       if (!fTerminateFiles.IsNull()) fTerminateFiles += ",";
624       fTerminateFiles += mod->GetTerminateFileName();
625    }   
626
627    // Execute the macro
628    if (mod->ExecuteMacro()<0) {
629       Error("LoadModule", "Executing the macro %s with arguments: %s for module %s returned a negative value",
630              mod->GetMacroName(), mod->GetMacroArgs(), mod->GetName());
631       return kFALSE;
632    }
633    // Configure dependencies
634    if (mod->GetConfigMacro() && mod->ExecuteConfigMacro()<0) {
635       Error("LoadModule", "There was an error executing the deps config macro %s for module %s",
636             mod->GetConfigMacro()->GetTitle(), mod->GetName());
637       return kFALSE;
638    }
639    // Adjust extra libraries
640    Int_t nlibs = mod->GetNlibs();
641    TString lib;
642    for (Int_t i=0; i<nlibs; i++) {
643       lib = mod->GetLibrary(i);
644       lib = Form("lib%s.so", lib.Data());
645       if (fAdditionalLibs.Contains(lib)) continue;
646       if (!fAdditionalLibs.IsNull()) fAdditionalLibs += " ";
647       fAdditionalLibs += lib;
648    }
649    return kTRUE;
650 }
651
652 //______________________________________________________________________________
653 Bool_t AliAnalysisAlien::GenerateTrain(const char *name)
654 {
655 // Generate the full train.
656    fAdditionalLibs = "";
657    if (!LoadModules()) return kFALSE;
658    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
659    if (!mgr->InitAnalysis()) return kFALSE;
660    mgr->RunLocalInit();
661    mgr->PrintStatus();
662    Int_t productionMode = fProductionMode;
663    SetProductionMode();
664    TString macro = fAnalysisMacro;
665    TString executable = fExecutable;
666    TString validation = fValidationScript;
667    TString execCommand = fExecutableCommand;
668    SetAnalysisMacro(Form("%s.C", name));
669    SetExecutable(Form("%s.sh", name));
670 //   SetExecutableCommand("aliroot -b -q ");
671    SetValidationScript(Form("%s_validation.sh", name));
672    StartAnalysis();
673    SetProductionMode(productionMode);
674    fAnalysisMacro = macro;
675    fExecutable = executable;
676    fExecutableCommand = execCommand;
677    fValidationScript = validation;
678    return kTRUE;   
679 }   
680
681 //______________________________________________________________________________
682 Bool_t AliAnalysisAlien::GenerateTest(const char *name, const char *modname)
683 {
684 // Generate test macros for a single module or for the full train.
685    fAdditionalLibs = "";
686    if (strlen(modname)) {
687       if (!CheckDependencies()) return kFALSE;
688       AliAnalysisTaskCfg *mod = GetModule(modname);
689       if (!mod) {
690          Error("GenerateTest", "cannot generate test for inexistent module %s", modname);
691          return kFALSE;
692       }
693       if (!LoadModule(mod)) return kFALSE;
694       if (!LoadFriendLibs()) return kFALSE;
695    } else if (!LoadModules()) return kFALSE;
696    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
697    if (!mgr->InitAnalysis()) return kFALSE;
698    mgr->RunLocalInit();
699    mgr->PrintStatus();
700    SetLocalTest(kTRUE);
701    Int_t productionMode = fProductionMode;
702    SetProductionMode();
703    TString macro = fAnalysisMacro;
704    TString executable = fExecutable;
705    TString validation = fValidationScript;
706    TString execCommand = fExecutableCommand;
707    SetAnalysisMacro(Form("%s.C", name));
708    SetExecutable(Form("%s.sh", name));
709       fOutputFiles = GetListOfFiles("outaod");
710       // Add extra files registered to the analysis manager
711       TString extra = GetListOfFiles("ext");
712       if (!extra.IsNull()) {
713          extra.ReplaceAll(".root", "*.root");
714          if (!fOutputFiles.IsNull()) fOutputFiles += ",";
715          fOutputFiles += extra;
716       }
717 //   SetExecutableCommand("aliroot -b -q ");
718    SetValidationScript(Form("%s_validation.sh", name));
719    WriteAnalysisFile();   
720    WriteAnalysisMacro();
721    WriteExecutable();
722    WriteValidationScript();   
723    WriteMergingMacro();
724    WriteMergeExecutable();
725    WriteValidationScript(kTRUE);
726    SetLocalTest(kFALSE);
727    SetProductionMode(productionMode);
728    fAnalysisMacro = macro;
729    fExecutable = executable;
730    fExecutableCommand = execCommand;
731    fValidationScript = validation;
732    return kTRUE;   
733 }
734
735 //______________________________________________________________________________
736 Bool_t AliAnalysisAlien::LoadModules()
737 {
738 // Load all modules by executing the AddTask macros. Checks first the dependencies.
739    fAdditionalLibs = "";
740    Int_t nmodules = GetNmodules();
741    if (!nmodules) {
742       Warning("LoadModules", "No module to be loaded");
743       return kTRUE;
744    }   
745    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
746    if (!mgr) {
747       Error("LoadModules", "No analysis manager created yet. Use CreateAnalysisManager first.");
748       return kFALSE;
749    }   
750    if (!CheckDependencies()) return kFALSE;
751    nmodules = GetNmodules();
752    AliAnalysisTaskCfg *mod;
753    for (Int_t imod=0; imod<nmodules; imod++) {
754       mod = (AliAnalysisTaskCfg*)fModules->At(imod);
755       if (!LoadModule(mod)) return kFALSE;
756    }
757    // Load additional friend libraries
758    return LoadFriendLibs();
759 }      
760
761 //______________________________________________________________________________
762 Bool_t AliAnalysisAlien::LoadFriendLibs() const
763 {
764 // Load libraries required for reading friends.
765    if (fFriendLibs.Length()) {
766       TObjArray *list = 0;
767       TString lib;
768       if (fFriendLibs.Contains(",")) list  = fFriendLibs.Tokenize(",");
769       else                           list  = fFriendLibs.Tokenize(" ");
770       for (Int_t ilib=0; ilib<list->GetEntriesFast(); ilib++) {
771          lib = list->At(ilib)->GetName();
772          lib.ReplaceAll(".so","");
773          lib.ReplaceAll(".dylib","");
774          lib.ReplaceAll(" ","");
775          if (lib.BeginsWith("lib")) lib.Remove(0, 3);
776          lib.Prepend("lib");
777          Int_t loaded = strlen(gSystem->GetLibraries(lib,"",kFALSE));
778          if (!loaded) loaded = gSystem->Load(lib);
779          if (loaded < 0) {
780             Error("LoadModules", "Cannot load library for friends %s", lib.Data());
781             return kFALSE;
782          }
783       }
784       delete list;
785    }
786    return kTRUE;
787 }   
788
789 //______________________________________________________________________________
790 void AliAnalysisAlien::SetRunPrefix(const char *prefix)
791 {
792 // Set the run number format. Can be a prefix or a format like "%09d"
793    fRunPrefix = prefix;
794    if (!fRunPrefix.Contains("%")) fRunPrefix += "%d";
795 }   
796
797 //______________________________________________________________________________
798 void AliAnalysisAlien::AddIncludePath(const char *path)
799 {
800 // Add include path in the remote analysis macro.
801    TString p(path);
802    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
803    else                  fIncludePath += Form("-I%s ", path);
804 }
805
806 //______________________________________________________________________________
807 void AliAnalysisAlien::AddRunNumber(Int_t run)
808 {
809 // Add a run number to the list of runs to be processed.
810    if (fRunNumbers.Length()) fRunNumbers += " ";
811    fRunNumbers += Form(fRunPrefix.Data(), run);
812 }   
813
814 //______________________________________________________________________________
815 void AliAnalysisAlien::AddRunList(const char* runList)
816 {
817 // Add several runs into the list of runs; they are expected to be separated by a blank character.  
818   TString    sList = runList;
819   TObjArray *list  = sList.Tokenize(" ");
820   Int_t n = list->GetEntries();
821   for (Int_t i = 0; i < n; i++) {
822     TObjString *os = (TObjString*)list->At(i);
823     AddRunNumber(os->GetString().Atoi());
824   }
825   delete list;
826 }
827
828 //______________________________________________________________________________
829 void AliAnalysisAlien::AddRunNumber(const char* run)
830 {
831 // Add a run number to the list of runs to be processed.
832    TString runs = run;
833    TObjString *os;
834    TObjArray *arr = runs.Tokenize(" ");
835    TIter next(arr);
836    TString prefix; 
837    prefix.Append(fRunPrefix, fRunPrefix.Index("%d"));
838    while ((os=(TObjString*)next())){
839        if (fRunNumbers.Length()) fRunNumbers += " ";
840        fRunNumbers += Form("%s%s", prefix.Data(), os->GetString().Data());
841    }
842    delete arr;
843 }   
844
845 //______________________________________________________________________________
846 void AliAnalysisAlien::AddDataFile(const char *lfn)
847 {
848 // Adds a data file to the input to be analysed. The file should be a valid LFN
849 // or point to an existing file in the alien workdir.
850    if (!fInputFiles) fInputFiles = new TObjArray();
851    fInputFiles->Add(new TObjString(lfn));
852 }
853
854 //______________________________________________________________________________
855 void AliAnalysisAlien::AddExternalPackage(const char *package)
856 {
857 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
858    if (fExternalPackages) fExternalPackages += " ";
859    fExternalPackages += package;
860 }   
861       
862 //______________________________________________________________________________
863 Bool_t AliAnalysisAlien::Connect()
864 {
865 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
866    if (gGrid && gGrid->IsConnected()) return kTRUE;
867    if (fProductionMode) return kTRUE;
868    if (!gGrid) {
869       Info("Connect", "Trying to connect to AliEn ...");
870       TGrid::Connect("alien://");
871    }
872    if (!gGrid || !gGrid->IsConnected()) {
873       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
874       return kFALSE;
875    }  
876    fUser = gGrid->GetUser();
877    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
878    return kTRUE;
879 }
880
881 //______________________________________________________________________________
882 void AliAnalysisAlien::CdWork()
883 {
884 // Check validity of alien workspace. Create directory if possible.
885    if (!Connect()) {
886       Error("CdWork", "Alien connection required");
887       return;
888    } 
889    TString homedir = gGrid->GetHomeDirectory();
890    TString workdir = homedir + fGridWorkingDir;
891    if (DirectoryExists(workdir)) {
892       gGrid->Cd(workdir);
893       return;
894    }   
895    // Work directory not existing - create it
896    gGrid->Cd(homedir);
897    if (gGrid->Mkdir(workdir, "-p")) {
898       gGrid->Cd(fGridWorkingDir);
899       Info("CdWork", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
900    } else {
901       Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
902               workdir.Data(), homedir.Data());
903       fGridWorkingDir = "";
904    }          
905 }
906
907 //______________________________________________________________________________
908 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
909 {
910 // Check if file copying is possible.
911    if (fProductionMode) return kTRUE;
912    TString salienpath(alienpath);
913    if (salienpath.Contains(" ")) {
914       Error("CheckFileCopy", "path: <%s> contains blancs - FIX IT !",alienpath);
915       return kFALSE;
916    }   
917    if (!Connect()) {
918       Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
919       return kFALSE;
920    }
921    Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
922         \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
923    // Check if alien_CLOSE_SE is defined
924    TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
925    if (!closeSE.IsNull()) {
926       Info("CheckFileCopy", "Your current close storage is pointing to: \
927            \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
928    } else {
929       Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
930    }        
931    // Check if grid directory exists.
932    if (!DirectoryExists(alienpath)) {
933       Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
934       return kFALSE;
935    }
936    TString stest = "plugin_test_copy";
937    TFile f(stest, "RECREATE");
938    // User may not have write permissions to current directory 
939    if (f.IsZombie()) {
940       Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
941             gSystem->WorkingDirectory());
942       return kFALSE;
943    }
944    f.Close();
945    if (FileExists(Form("alien://%s/%s",alienpath, stest.Data()))) gGrid->Rm(Form("alien://%s/%s",alienpath, stest.Data()));
946    if (!TFile::Cp(stest.Data(), Form("alien://%s/%s",alienpath, stest.Data()))) {
947       Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
948            \n# 1. Make sure you have write permissions there. If this is the case: \
949            \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
950            \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
951            \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
952            \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
953       gSystem->Unlink(stest.Data());
954       return kFALSE;
955    }   
956    gSystem->Unlink(stest.Data());
957    gGrid->Rm(Form("%s/%s",alienpath,stest.Data()));
958    Info("CheckFileCopy", "### ...SUCCESS ###");
959    return kTRUE;
960 }   
961
962 //______________________________________________________________________________
963 Bool_t AliAnalysisAlien::CheckInputData()
964 {
965 // Check validity of input data. If necessary, create xml files.
966    if (fProductionMode) return kTRUE;
967    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
968       if (!fGridDataDir.Length()) {
969          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
970          return kFALSE;
971       }
972       if (fMergeViaJDL) {
973          Error("CheckInputData", "Merging via jdl works only with run numbers, run range or provided xml");
974          return kFALSE;
975       }   
976       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
977       if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
978          TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode) 
979       return kTRUE;
980    }
981    // Process declared files
982    Bool_t isCollection = kFALSE;
983    Bool_t isXml = kFALSE;
984    Bool_t useTags = kFALSE;
985    Bool_t checked = kFALSE;
986    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
987    TString file;
988    TString workdir = gGrid->GetHomeDirectory();
989    workdir += fGridWorkingDir;
990    if (fInputFiles) {
991       TObjString *objstr;
992       TIter next(fInputFiles);
993       while ((objstr=(TObjString*)next())) {
994          file = workdir;
995          file += "/";
996          file += objstr->GetString();
997          // Store full lfn path
998          if (FileExists(file)) objstr->SetString(file);
999          else {
1000             file = objstr->GetName();
1001             if (!FileExists(objstr->GetName())) {
1002                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
1003                      objstr->GetName(), workdir.Data());
1004                return kFALSE;
1005             }         
1006          }
1007          Bool_t iscoll, isxml, usetags;
1008          CheckDataType(file, iscoll, isxml, usetags);
1009          if (!checked) {
1010             checked = kTRUE;
1011             isCollection = iscoll;
1012             isXml = isxml;
1013             useTags = usetags;
1014             TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
1015          } else {
1016             if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
1017                Error("CheckInputData", "Some conflict was found in the types of inputs");
1018                return kFALSE;
1019             } 
1020          }
1021       }
1022    }
1023    // Process requested run numbers
1024    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
1025    // Check validity of alien data directory
1026    if (!fGridDataDir.Length()) {
1027       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
1028       return kFALSE;
1029    }
1030    if (!DirectoryExists(fGridDataDir)) {
1031       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
1032       return kFALSE;
1033    }
1034    if (isCollection) {
1035       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
1036       return kFALSE;   
1037    }
1038    
1039    if (checked && !isXml) {
1040       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
1041       return kFALSE;   
1042    }
1043    // Check validity of run number(s)
1044    TObjArray *arr;
1045    TObjString *os;
1046    TString format;
1047    Int_t nruns = 0;
1048    TString schunk, schunk2;
1049    TString path;
1050    if (!checked) {
1051       checked = kTRUE;
1052       useTags = fDataPattern.Contains("tag");
1053       TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
1054    }   
1055    if (useTags != fDataPattern.Contains("tag")) {
1056       Error("CheckInputData", "Cannot mix input files using/not using tags");
1057       return kFALSE;
1058    }
1059    if (fRunNumbers.Length()) {
1060       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
1061       arr = fRunNumbers.Tokenize(" ");
1062       TIter next(arr);
1063       while ((os=(TObjString*)next())) {
1064          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
1065          if (!DirectoryExists(path)) {
1066             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
1067             continue;
1068          }
1069          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
1070          TString msg = "\n#####   file: ";
1071          msg += path;
1072          msg += " type: xml_collection;";
1073          if (useTags) msg += " using_tags: Yes";
1074          else          msg += " using_tags: No";
1075          Info("CheckDataType", "%s", msg.Data());
1076          if (fNrunsPerMaster<2) {
1077             AddDataFile(Form("%s.xml", os->GetString().Data()));
1078          } else {
1079             nruns++;
1080             if (((nruns-1)%fNrunsPerMaster) == 0) {
1081                schunk = os->GetString();
1082             }   
1083             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
1084             schunk += Form("_%s.xml", os->GetString().Data());
1085             AddDataFile(schunk);
1086          }   
1087       }
1088       delete arr;   
1089    } else {
1090       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
1091       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1092          format = Form("%%s/%s ", fRunPrefix.Data());
1093          path = Form(format.Data(), fGridDataDir.Data(), irun);
1094          if (!DirectoryExists(path)) {
1095             continue;
1096          }
1097          format = Form("%%s/%s.xml", fRunPrefix.Data());
1098          path = Form(format.Data(), workdir.Data(),irun);
1099          TString msg = "\n#####   file: ";
1100          msg += path;
1101          msg += " type: xml_collection;";
1102          if (useTags) msg += " using_tags: Yes";
1103          else          msg += " using_tags: No";
1104          Info("CheckDataType", "%s", msg.Data());
1105          if (fNrunsPerMaster<2) {
1106             format = Form("%s.xml", fRunPrefix.Data());
1107             AddDataFile(Form(format.Data(),irun));
1108          } else {
1109             nruns++;
1110             if (((nruns-1)%fNrunsPerMaster) == 0) {
1111                schunk = Form(fRunPrefix.Data(),irun);
1112             }
1113             format = Form("_%s.xml", fRunPrefix.Data());
1114             schunk2 = Form(format.Data(), irun);
1115             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
1116             schunk += schunk2;
1117             AddDataFile(schunk);
1118          }   
1119       }
1120       if (!fInputFiles) {
1121          schunk += schunk2;
1122          AddDataFile(schunk);
1123       }   
1124    }
1125    return kTRUE;      
1126 }   
1127
1128 //______________________________________________________________________________
1129 Int_t AliAnalysisAlien::CopyLocalDataset(const char *griddir, const char *pattern, Int_t nfiles, const char *output, const char *archivefile, const char *outputdir)
1130 {
1131 // Copy data from the given grid directory according a pattern and make a local
1132 // dataset.
1133 // archivefile (optional) results in that the archive containing the file <pattern> is copied. archivefile can contain a list of files (semicolon-separated) which are all copied
1134    if (!Connect()) {
1135       Error("CopyLocalDataset", "Cannot copy local dataset with no grid connection");
1136       return 0;
1137    }
1138    if (!DirectoryExists(griddir)) {
1139       Error("CopyLocalDataset", "Data directory %s not existing.", griddir);
1140       return 0;
1141    }
1142    TString command = Form("find -z -l %d %s %s", nfiles, griddir, pattern);
1143    printf("Running command: %s\n", command.Data());
1144    TGridResult *res = gGrid->Command(command);
1145    Int_t nfound = res->GetEntries();
1146    if (!nfound) {
1147       Error("CopyLocalDataset", "No file found in <%s> having pattern <%s>", griddir, pattern);
1148       return 0;
1149    }
1150    printf("... found %d files. Copying locally ...\n", nfound);
1151    
1152    // archives
1153    TObjArray* additionalArchives = 0;
1154    if (strlen(archivefile) > 0 && TString(archivefile).Contains(";")) {
1155       additionalArchives = TString(archivefile).Tokenize(";");
1156       archivefile = additionalArchives->At(0)->GetName();
1157       additionalArchives->RemoveAt(0);
1158       additionalArchives->Compress();
1159    }
1160    
1161    // Copy files locally
1162    ofstream out;
1163    out.open(output, ios::out);
1164    TMap *map;
1165    TString turl, dirname, filename, temp;
1166    TString cdir = gSystem->WorkingDirectory();
1167    gSystem->MakeDirectory(outputdir);
1168    gSystem->ChangeDirectory(outputdir);
1169    Int_t ncopied = 0;
1170    for (Int_t i=0; i<nfound; i++) {
1171       map = (TMap*)res->At(i);
1172       turl = map->GetValue("turl")->GetName();
1173       filename = gSystem->BaseName(turl.Data());
1174       dirname = gSystem->DirName(turl.Data());
1175       dirname = gSystem->BaseName(dirname.Data());
1176       gSystem->MakeDirectory(dirname);
1177       
1178       TString source(turl);
1179       TString targetFileName(filename);
1180       
1181       if (strlen(archivefile) > 0) {
1182 // TODO here the archive in which the file resides should be determined
1183 // however whereis returns only a guid, and guid2lfn does not work
1184 // Therefore we use the one provided as argument for now
1185          source = Form("%s/%s", gSystem->DirName(source.Data()), archivefile);
1186          targetFileName = archivefile;
1187       }
1188       if (TFile::Cp(source, Form("file:./%s/%s", dirname.Data(), targetFileName.Data()))) {
1189          Bool_t success = kTRUE;
1190          if (additionalArchives) {
1191             for (Int_t j=0; j<additionalArchives->GetEntriesFast(); j++) {
1192                TString target;
1193                target.Form("./%s/%s", dirname.Data(), additionalArchives->At(j)->GetName());
1194                gSystem->MakeDirectory(gSystem->DirName(target));
1195                success &= TFile::Cp(Form("%s/%s", gSystem->DirName(source.Data()), additionalArchives->At(j)->GetName()), Form("file:%s", target.Data()));
1196             }
1197          }
1198
1199          if (success) {
1200             if (strlen(archivefile) > 0) targetFileName = Form("%s#%s", targetFileName.Data(), gSystem->BaseName(turl.Data()));
1201             out << cdir << Form("/%s/%s/%s", outputdir, dirname.Data(), targetFileName.Data()) << endl;
1202             ncopied++;
1203          }
1204       }
1205    }
1206    gSystem->ChangeDirectory(cdir);
1207    delete res;
1208    delete additionalArchives;
1209    return ncopied;
1210 }   
1211
1212 //______________________________________________________________________________
1213 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
1214 {
1215 // Create dataset for the grid data directory + run number.
1216    const Int_t gMaxEntries = 15000;
1217    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
1218    if (!Connect()) {
1219       Error("CreateDataset", "Cannot create dataset with no grid connection");
1220       return kFALSE;
1221    }   
1222
1223    // Cd workspace
1224    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
1225    TString workdir = gGrid->GetHomeDirectory();
1226    workdir += fGridWorkingDir;
1227
1228    // Compose the 'find' command arguments
1229    TString format;
1230    TString command;
1231    TString delimiter = pattern;
1232    delimiter.Strip();
1233    if (delimiter.Contains(" ")) delimiter = "";
1234    else delimiter = " ";
1235    TString options = "-x collection ";
1236    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
1237    else options += Form("-l %d ", gMaxEntries);  // Protection for the find command
1238    TString conditions = "";
1239    Int_t nstart = 0;
1240    Int_t ncount = 0;
1241    Int_t stage = 0;
1242    TString file;
1243    TString path;
1244    Int_t nruns = 0;
1245    TString schunk, schunk2;
1246    TGridCollection *cbase=0, *cadd=0;
1247    if (!fRunNumbers.Length() && !fRunRange[0]) {
1248       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
1249       // Make a single data collection from data directory.
1250       path = fGridDataDir;
1251       if (!DirectoryExists(path)) {
1252          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
1253          return kFALSE;
1254       } 
1255 //      CdWork();
1256       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1257       else file = Form("%s.xml", gSystem->BaseName(path));
1258       // cholm - Identical loop - should be put in common function for code simplification
1259       while (1) {
1260          ncount = 0;
1261          stage++;
1262          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1263             command = "find ";
1264             command += Form("%s -o %d ",options.Data(), nstart);
1265             command += path;
1266             command += delimiter;
1267             command += pattern;
1268             command += conditions;
1269             printf("command: %s\n", command.Data());
1270             TGridResult *res = gGrid->Command(command);
1271             if (res) delete res;
1272             // Write standard output to file
1273             gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage, file.Data()));
1274             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1275             Bool_t nullFile = kFALSE;
1276             if (!hasGrep) {
1277                 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1278             } else {
1279                nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1280                if (nullFile) {
1281                   Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
1282                   gSystem->Exec("rm -f __tmp*");
1283                   return kFALSE;
1284                }
1285                TString line;
1286                ifstream in;
1287                in.open("__tmp__");
1288                in >> line;
1289                in.close();
1290                gSystem->Exec("rm -f __tmp__");
1291                ncount = line.Atoi();
1292             }         
1293          }
1294          if (ncount == gMaxEntries) {
1295             Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1296             cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1297             if (!cbase) cbase = cadd;
1298             else {
1299               // cholm - Avoid using very slow TAlienCollection 
1300               // cbase->Add(cadd);
1301               // cholm - Use AddFast (via interpreter)
1302               gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1303                delete cadd;
1304             }   
1305             nstart += ncount;
1306          } else {
1307             if (cbase) {
1308                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1309                printf("... please wait - TAlienCollection::Add() scales badly...\n");
1310               // cholm - Avoid using very slow TAlienCollection 
1311               // cbase->Add(cadd);
1312               // cholm - Use AddFast (via interpreter)
1313               gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1314                delete cadd;
1315                cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1316                delete cbase; cbase = 0;               
1317             } else {
1318                TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1319             }
1320             gSystem->Exec("rm -f __tmp*");   
1321             Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1322             break;
1323          }
1324       }
1325       Bool_t fileExists = FileExists(file);
1326       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
1327          // Copy xml file to alien space
1328          if (fileExists) gGrid->Rm(file);
1329          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1330          if (!FileExists(file)) {
1331             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1332             return kFALSE;
1333          }
1334          // Update list of files to be processed.
1335       }
1336       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
1337       return kTRUE;
1338    }   
1339    // Several runs
1340    Bool_t nullResult = kTRUE;
1341    if (fRunNumbers.Length()) {
1342       TObjArray *arr = fRunNumbers.Tokenize(" ");
1343       TObjString *os;
1344       TIter next(arr);
1345       while ((os=(TObjString*)next())) {
1346          nstart = 0;
1347          stage = 0;
1348          path = Form("%s/%s", fGridDataDir.Data(), os->GetString().Data());
1349          if (!DirectoryExists(path)) continue;
1350 //         CdWork();
1351          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1352          else file = Form("%s.xml", os->GetString().Data());
1353          // cholm - Identical loop - should be put in common function for code simplification
1354          // If local collection file does not exist, create it via 'find' command.
1355          while (1) {
1356             ncount = 0;
1357             stage++;
1358             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1359                command = "find ";
1360                command +=  Form("%s -o %d ",options.Data(), nstart);
1361                command += path;
1362                command += delimiter;
1363                command += pattern;
1364                command += conditions;
1365                TGridResult *res = gGrid->Command(command);
1366                if (res) delete res;
1367                // Write standard output to file
1368                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1369                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1370                Bool_t nullFile = kFALSE;
1371                if (!hasGrep) {
1372                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1373                } else {
1374                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1375                   if (nullFile) {
1376                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1377                      gSystem->Exec("rm -f __tmp*");
1378                      fRunNumbers.ReplaceAll(os->GetString().Data(), "");
1379                      break;
1380                   }   
1381                   TString line;
1382                   ifstream in;
1383                   in.open("__tmp__");
1384                   in >> line;
1385                   in.close();
1386                   gSystem->Exec("rm -f __tmp__");   
1387                   ncount = line.Atoi();
1388                }
1389                nullResult = kFALSE;         
1390             }
1391             if (ncount == gMaxEntries) {
1392                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1393                if (fNrunsPerMaster > 1) {
1394                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1395                           file.Data(),gMaxEntries);
1396                   return kFALSE;
1397                }           
1398                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1399                if (!cbase) cbase = cadd;
1400                else {
1401                   // cholm - Avoid using very slow TAlienCollection 
1402                   // cbase->Add(cadd);
1403                   // cholm - Use AddFast (via interpreter)
1404                   gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1405
1406                   delete cadd;
1407                }   
1408                nstart += ncount;
1409             } else {
1410                if (cbase && fNrunsPerMaster<2) {
1411                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1412                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1413                   // cholm - Avoid using very slow TAlienCollection 
1414                   // cbase->Add(cadd);
1415                   // cholm - Use AddFast (via interpreter)
1416                   gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1417                   delete cadd;
1418                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1419                   delete cbase; cbase = 0;               
1420                } else {
1421                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1422                }
1423                gSystem->Exec("rm -f __tmp*");   
1424                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1425                break;
1426             }
1427          }   
1428          if (TestBit(AliAnalysisGrid::kTest)) break;
1429          // Check if there is one run per master job.
1430          if (fNrunsPerMaster<2) {
1431             if (FileExists(file)) {
1432                if (fOverwriteMode) gGrid->Rm(file);
1433                else {
1434                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1435                   continue;
1436                }   
1437             }        
1438             // Copy xml file to alien space
1439             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1440             if (!FileExists(file)) {
1441                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1442                delete arr;
1443                return kFALSE;
1444             }
1445          } else {
1446             nruns++;
1447             if (((nruns-1)%fNrunsPerMaster) == 0) {
1448                schunk = os->GetString();
1449                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1450             } else {
1451                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1452                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
1453                // cholm - Avoid using very slow TAlienCollection 
1454                // cbase->Add(cadd);
1455                // cholm - Use AddFast (via interpreter)
1456                gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1457                delete cadd;
1458             }
1459             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
1460                continue;
1461             }   
1462             schunk += Form("_%s.xml", os->GetString().Data());
1463             if (FileExists(schunk)) {               
1464                if (fOverwriteMode) gGrid->Rm(file);
1465                else {
1466                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1467                   continue;
1468                }   
1469             }        
1470             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
1471             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1472             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1473             if (!FileExists(schunk)) {
1474                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1475                delete arr;
1476                return kFALSE;
1477             }
1478          }
1479       }   
1480       delete arr;
1481       if (nullResult) {
1482          Error("CreateDataset", "No valid dataset corresponding to the query!");
1483          return kFALSE;
1484       }
1485    } else {
1486       // Process a full run range.
1487       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1488          format = Form("%%s/%s", fRunPrefix.Data());
1489          nstart = 0;
1490          stage = 0;
1491          path = Form(format.Data(), fGridDataDir.Data(), irun);
1492          if (!DirectoryExists(path)) continue;
1493 //         CdWork();
1494          format = Form("%s.xml", fRunPrefix.Data());
1495          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1496          else file = Form(format.Data(), irun);
1497          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
1498             if (fOverwriteMode) gGrid->Rm(file);
1499             else {
1500                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1501                continue;
1502             }   
1503          }
1504          // cholm - Identical loop - should be put in common function for code simplification
1505          // If local collection file does not exist, create it via 'find' command.
1506          while (1) {
1507             ncount = 0;
1508             stage++;
1509             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1510                command = "find ";
1511                command +=  Form("%s -o %d ",options.Data(), nstart);
1512                command += path;
1513                command += delimiter;
1514                command += pattern;
1515                command += conditions;
1516                TGridResult *res = gGrid->Command(command);
1517                if (res) delete res;
1518                // Write standard output to file
1519                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1520                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1521                Bool_t nullFile = kFALSE;
1522                if (!hasGrep) {
1523                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1524                } else {
1525                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1526                   if (nullFile) {
1527                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1528                      gSystem->Exec("rm -f __tmp*");
1529                      break;
1530                   }   
1531                   TString line;
1532                   ifstream in;
1533                   in.open("__tmp__");
1534                   in >> line;
1535                   in.close();
1536                   gSystem->Exec("rm -f __tmp__");   
1537                   ncount = line.Atoi();
1538                }
1539                nullResult = kFALSE;         
1540             }   
1541             if (ncount == gMaxEntries) {
1542                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1543                if (fNrunsPerMaster > 1) {
1544                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1545                           file.Data(),gMaxEntries);
1546                   return kFALSE;
1547                }           
1548                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1549                if (!cbase) cbase = cadd;
1550                else {
1551                  // cholm - Avoid using very slow TAlienCollection 
1552                  // cbase->Add(cadd);
1553                  // cholm - Use AddFast (via interpreter)
1554                  gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1555                   delete cadd;
1556                }   
1557                nstart += ncount;
1558             } else {
1559                if (cbase && fNrunsPerMaster<2) {
1560                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1561                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1562                  // cholm - Avoid using very slow TAlienCollection 
1563                  // cbase->Add(cadd);
1564                  // cholm - Use AddFast (via interpreter)
1565                  gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1566                   delete cadd;
1567                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1568                   delete cbase; cbase = 0;               
1569                } else {
1570                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1571                }
1572                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1573                break;
1574             }
1575          }   
1576          if (TestBit(AliAnalysisGrid::kTest)) break;
1577          // Check if there is one run per master job.
1578          if (fNrunsPerMaster<2) {
1579             if (FileExists(file)) {
1580                if (fOverwriteMode) gGrid->Rm(file);
1581                else {
1582                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1583                   continue;
1584                }   
1585             }        
1586             // Copy xml file to alien space
1587             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1588             if (!FileExists(file)) {
1589                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1590                return kFALSE;
1591             }
1592          } else {
1593             nruns++;
1594             // Check if the collection for the chunk exist locally.
1595             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
1596             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
1597                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
1598                else continue;
1599             }   
1600             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
1601             if (((nruns-1)%fNrunsPerMaster) == 0) {
1602                schunk = Form(fRunPrefix.Data(), irun);
1603                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1604             } else {
1605                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1606                // cholm - Avoid using very slow TAlienCollection 
1607                // cbase->Add(cadd);
1608                // cholm - Use AddFast (via interpreter)
1609                gROOT->ProcessLine(Form("((TAlienCollection*)%p)->AddFast((TGridCollection*)%p)",cbase,cadd));
1610                delete cadd;
1611             }
1612             format = Form("%%s_%s.xml", fRunPrefix.Data());
1613             schunk2 = Form(format.Data(), schunk.Data(), irun);
1614             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
1615                continue;
1616             }   
1617             schunk = schunk2;
1618             if (FileExists(schunk)) {
1619                if (fOverwriteMode) gGrid->Rm(schunk);
1620                else {
1621                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1622                   continue;
1623                }   
1624             }        
1625             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
1626             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1627             if (FileExists(schunk)) {
1628                if (fOverwriteMode) gGrid->Rm(schunk);
1629                else {
1630                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
1631                   continue;
1632                }   
1633             }   
1634             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1635             if (!FileExists(schunk)) {
1636                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1637                return kFALSE;
1638             }
1639          }   
1640       }
1641       if (nullResult) {
1642          Error("CreateDataset", "No valid dataset corresponding to the query!");
1643          return kFALSE;
1644       }      
1645    }      
1646    return kTRUE;
1647 }
1648
1649 //______________________________________________________________________________
1650 Bool_t AliAnalysisAlien::CreateJDL()
1651 {
1652 // Generate a JDL file according to current settings. The name of the file is 
1653 // specified by fJDLName.
1654    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1655    Bool_t error = kFALSE;
1656    TObjArray *arr = 0;
1657    Bool_t copy = kTRUE;
1658    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1659    Bool_t generate = kTRUE;
1660    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
1661    if (!Connect()) {
1662       Error("CreateJDL", "Alien connection required");
1663       return kFALSE;
1664    }   
1665    // Check validity of alien workspace
1666    TString workdir;
1667    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1668    if (!fProductionMode &&  !TestBit(AliAnalysisGrid::kTest)) CdWork();
1669    workdir += fGridWorkingDir;
1670    if (generate) {
1671       TObjString *os;
1672       if (!fInputFiles && !fMCLoop) {
1673          Error("CreateJDL()", "Define some input files for your analysis.");
1674          error = kTRUE;
1675       }
1676       // Compose list of input files   
1677       // Check if output files were defined
1678       if (!fOutputFiles.Length()) {
1679          Error("CreateJDL", "You must define at least one output file");
1680          error = kTRUE;
1681       }   
1682       // Check if an output directory was defined and valid
1683       if (!fGridOutputDir.Length()) {
1684          Error("CreateJDL", "You must define AliEn output directory");
1685          error = kTRUE;
1686       } else {
1687          if (!fProductionMode) {
1688             if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1689             if (!DirectoryExists(fGridOutputDir)) {
1690                if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1691                   Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1692                } else {
1693                   Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1694                   // error = kTRUE;
1695                }
1696             } else {
1697                Warning("CreateJDL", "#### Output directory %s exists! If this contains old data, jobs will fail with ERROR_SV !!! ###", fGridOutputDir.Data());
1698             }   
1699             gGrid->Cd(workdir);
1700          }   
1701       }   
1702       // Exit if any error up to now
1703       if (error) return kFALSE;   
1704       // Set JDL fields
1705       if (!fUser.IsNull()) {
1706          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1707          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1708       }
1709       TString executable = fExecutable;
1710       if (!executable.BeginsWith("/")) 
1711          executable.Prepend(Form("%s/", workdir.Data()));
1712       fGridJDL->SetExecutable(executable, "This is the startup script");
1713       TString mergeExec = executable;
1714       mergeExec.ReplaceAll(".sh", "_merge.sh");
1715       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
1716       mergeExec.ReplaceAll(".sh", ".C");
1717       fMergingJDL->AddToInputSandbox(Form("LF:%s", mergeExec.Data()), "List of input files to be uploaded to workers");
1718       if (!fArguments.IsNull())
1719          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
1720       if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
1721       else {
1722          if (fProductionMode)  fMergingJDL->SetArguments("wn.xml $4");    // xml, stage
1723          else                  fMergingJDL->SetArguments("wn.xml $2");    // xml, stage
1724      }               
1725
1726       fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1727       fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1728       fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1729       fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1730         
1731       if (fMaxInitFailed > 0) {
1732          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1733          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1734       }   
1735       if (fSplitMaxInputFileNumber > 0 && !fMCLoop) {
1736          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1737          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1738       }
1739       if (!IsOneStageMerging()) {
1740          fMergingJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"",fMaxMergeFiles));
1741          fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1742       }   
1743       if (fSplitMode.Length()) {
1744          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1745          fGridJDL->SetDescription("Split", "We split per SE or file");
1746       }
1747       fMergingJDL->SetValue("Split", "\"se\""); 
1748       fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1749       if (!fAliROOTVersion.IsNull()) {
1750          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1751          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1752       }   
1753       if (!fROOTVersion.IsNull()) {
1754          fGridJDL->AddToPackages("ROOT", fROOTVersion);
1755          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1756       }   
1757       if (!fAPIVersion.IsNull()) {
1758          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1759          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1760       }   
1761       if (!fExternalPackages.IsNull()) {
1762          arr = fExternalPackages.Tokenize(" ");
1763          TIter next(arr);
1764          while ((os=(TObjString*)next())) {
1765             TString pkgname = os->GetString();
1766             Int_t index = pkgname.Index("::");
1767             TString pkgversion = pkgname(index+2, pkgname.Length());
1768             pkgname.Remove(index);
1769             fGridJDL->AddToPackages(pkgname, pkgversion);
1770             fMergingJDL->AddToPackages(pkgname, pkgversion);
1771          }   
1772          delete arr;   
1773       }   
1774       if (!fMCLoop) {
1775          fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1776          fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1777       }   
1778       fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1779       fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1780       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1781       TString analysisFile = fExecutable;
1782       analysisFile.ReplaceAll(".sh", ".root");
1783       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1784       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1785       if (fAdditionalLibs.Length()) {
1786          arr = fAdditionalLibs.Tokenize(" ");
1787          TIter next(arr);
1788          while ((os=(TObjString*)next())) {
1789             if (os->GetString().Contains(".so") ||
1790                 os->GetString().Contains(".dylib")) continue;
1791             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1792             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1793          }   
1794          delete arr;   
1795       }
1796       if (fPackages) {
1797          TIter next(fPackages);
1798          TObject *obj;
1799          while ((obj=next())) {
1800             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1801             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1802          }
1803       }
1804       const char *comment = "List of output files and archives";
1805       if (fOutputArchive.Length()) {
1806          TString outputArchive = fOutputArchive;
1807          if (!fRegisterExcludes.IsNull()) {
1808             arr = fRegisterExcludes.Tokenize(" ");
1809             TIter next1(arr);
1810             while ((os=(TObjString*)next1())) {
1811                outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1812                outputArchive.ReplaceAll(os->GetString(),"");
1813             } 
1814             delete arr;
1815          }     
1816          arr = outputArchive.Tokenize(" ");
1817          TIter next(arr);
1818          Bool_t first = kTRUE;
1819          while ((os=(TObjString*)next())) {
1820             if (!os->GetString().Contains("@") && fCloseSE.Length())
1821                fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
1822             else
1823                fGridJDL->AddToSet("Output", os->GetString());
1824             if (first) fGridJDL->AddToSetDescription("Output", comment);
1825             first = kFALSE;   
1826          }      
1827          delete arr;
1828          // Output archive for the merging jdl
1829          if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1830             outputArchive = "log_archive.zip:std*@disk=1 ";
1831             // Add normal output files, extra files + terminate files
1832             TString files;
1833             if (IsMergeAOD()) files = GetListOfFiles("outaodextter");
1834             else files = GetListOfFiles("outextter");
1835             // Do not register files in fRegisterExcludes
1836             if (!fRegisterExcludes.IsNull()) {
1837                arr = fRegisterExcludes.Tokenize(" ");
1838                TIter next1(arr);
1839                while ((os=(TObjString*)next1())) {
1840                   files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1841                   files.ReplaceAll(os->GetString(),"");
1842                }   
1843                delete arr;
1844             }
1845             files.ReplaceAll(".root", "*.root");
1846             
1847             if (mgr->IsCollectThroughput())
1848                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d %s@disk=%d",files.Data(),fNreplicas, mgr->GetFileInfoLog(),fNreplicas);
1849             else
1850                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",files.Data(),fNreplicas);
1851          } else {
1852             TString files = fOutputArchive;
1853             files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1854             outputArchive = files;
1855          }   
1856          arr = outputArchive.Tokenize(" ");
1857          TIter next2(arr);
1858          first = kTRUE;
1859          while ((os=(TObjString*)next2())) {
1860             TString currentfile = os->GetString();
1861             if (!currentfile.Contains("@") && fCloseSE.Length())
1862                fMergingJDL->AddToSet("Output", Form("%s@%s",currentfile.Data(), fCloseSE.Data()));
1863             else
1864                fMergingJDL->AddToSet("Output", currentfile);
1865             if (first) fMergingJDL->AddToSetDescription("Output", comment);
1866             first = kFALSE;   
1867          }      
1868          delete arr;         
1869       }      
1870       arr = fOutputFiles.Tokenize(",");
1871       TIter next(arr);
1872       Bool_t first = kTRUE;
1873       while ((os=(TObjString*)next())) {
1874          // Ignore ouputs in jdl that are also in outputarchive
1875          TString sout = os->GetString();
1876          sout.ReplaceAll("*", "");
1877          sout.ReplaceAll(".root", "");
1878          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1879          if (fOutputArchive.Contains(sout)) continue;
1880          // Ignore fRegisterExcludes
1881          if (fRegisterExcludes.Contains(sout)) continue;
1882          if (!first) comment = NULL;
1883          if (!os->GetString().Contains("@") && fCloseSE.Length())
1884             fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1885          else
1886             fGridJDL->AddToSet("Output", os->GetString());
1887          if (first) fGridJDL->AddToSetDescription("Output", comment); 
1888          if (fMergeExcludes.Contains(sout)) continue;   
1889          if (!os->GetString().Contains("@") && fCloseSE.Length())
1890             fMergingJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1891          else
1892             fMergingJDL->AddToSet("Output", os->GetString());
1893          if (first) fMergingJDL->AddToSetDescription("Output", comment);
1894          first = kFALSE;
1895       }   
1896       delete arr;
1897       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1898       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1899       TString validationScript = fValidationScript;
1900       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1901       validationScript.ReplaceAll(".sh", "_merge.sh");
1902       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1903       if (fMasterResubmitThreshold) {
1904          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1905          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1906       }   
1907       // Write a jdl with 2 input parameters: collection name and output dir name.
1908       WriteJDL(copy);
1909    }
1910    // Copy jdl to grid workspace   
1911    if (copy) {
1912       // Check if an output directory was defined and valid
1913       if (!fGridOutputDir.Length()) {
1914          Error("CreateJDL", "You must define AliEn output directory");
1915          return kFALSE;
1916       } else {
1917          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1918          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1919             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1920                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1921             } else {
1922                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1923                return kFALSE;
1924             }
1925          }
1926          gGrid->Cd(workdir);
1927       }   
1928       if (TestBit(AliAnalysisGrid::kSubmit)) {
1929          TString mergeJDLName = fExecutable;
1930          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1931          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1932          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1933          if (fProductionMode) {
1934             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1935             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1936          }   
1937          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1938          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1939          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1940          if (!copyLocal2Alien("CreateJDL", fJDLName, locjdl)) 
1941             Fatal("","Terminating");
1942 //         TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1943          if (fMergeViaJDL) {
1944             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1945 //            TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1946             if (!copyLocal2Alien("CreateJDL", mergeJDLName.Data(), locjdl1)) 
1947                Fatal("","Terminating");
1948          }   
1949       }
1950       if (fAdditionalLibs.Length()) {
1951          arr = fAdditionalLibs.Tokenize(" ");
1952          TObjString *os;
1953          TIter next(arr);
1954          while ((os=(TObjString*)next())) {
1955             if (os->GetString().Contains(".so") ||
1956                 os->GetString().Contains(".dylib")) continue;
1957             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1958             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1959 //            TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1960             if (!copyLocal2Alien("CreateJDL", os->GetString().Data(), 
1961                 Form("%s/%s", workdir.Data(), os->GetString().Data())))
1962               Fatal("","Terminating");
1963          }   
1964          delete arr;   
1965       }
1966       if (fPackages) {
1967          TIter next(fPackages);
1968          TObject *obj;
1969          while ((obj=next())) {
1970             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1971             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1972 //            TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1973             if (!copyLocal2Alien("CreateJDL",obj->GetName(), 
1974                 Form("%s/%s", workdir.Data(), obj->GetName()))) 
1975               Fatal("","Terminating"); 
1976          }   
1977       }      
1978    } 
1979    return kTRUE;
1980 }
1981
1982 //______________________________________________________________________________
1983 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1984 {
1985 // Writes one or more JDL's corresponding to findex. If findex is negative,
1986 // all run numbers are considered in one go (jdl). For non-negative indices
1987 // they correspond to the indices in the array fInputFiles.
1988    if (!fInputFiles && !fMCLoop) return kFALSE;
1989    TObject *os;
1990    TString workdir;
1991    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1992    workdir += fGridWorkingDir;
1993    TString stageName = "$2";
1994    if (fProductionMode) stageName = "$4";
1995    if (!fMergeDirName.IsNull()) {
1996      fMergingJDL->AddToInputDataCollection(Form("LF:$1/%s/Stage_%s.xml,nodownload",fMergeDirName.Data(),stageName.Data()), "Collection of files to be merged for current stage");
1997      fMergingJDL->SetOutputDirectory(Form("$1/%s/Stage_%s/#alien_counter_03i#",fMergeDirName.Data(),stageName.Data()), "Output directory");
1998    } else {
1999      fMergingJDL->AddToInputDataCollection(Form("LF:$1/Stage_%s.xml,nodownload",stageName.Data()), "Collection of files to be merged for current stage");
2000      fMergingJDL->SetOutputDirectory(Form("$1/Stage_%s/#alien_counter_03i#",stageName.Data()), "Output directory");
2001    }
2002    if (fProductionMode) {
2003       TIter next(fInputFiles);
2004       while ((os=next())) {
2005          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
2006       }
2007       if (!fOutputToRunNo)
2008          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
2009       else  
2010          fGridJDL->SetOutputDirectory(fGridOutputDir);
2011    } else {            
2012       if (!fRunNumbers.Length() && !fRunRange[0]) {
2013          // One jdl with no parameters in case input data is specified by name.
2014          TIter next(fInputFiles);
2015          while ((os=next()))
2016             fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
2017          if (!fOutputSingle.IsNull())
2018             fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
2019          else {
2020             fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
2021 //            fMergingJDL->SetOutputDirectory(fGridOutputDir);         
2022          }   
2023       } else {
2024          // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
2025          fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
2026          if (!fOutputSingle.IsNull()) {
2027             if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
2028             else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
2029          } else {   
2030             fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
2031          }   
2032       }
2033    }
2034       
2035    // Generate the JDL as a string
2036    TString sjdl = fGridJDL->Generate();
2037    TString sjdl1 = fMergingJDL->Generate();
2038    // Final merge jdl
2039    if (!fMergeDirName.IsNull()) {
2040      fMergingJDL->SetOutputDirectory(Form("$1/%s",fMergeDirName.Data()), "Output directory");
2041      fMergingJDL->AddToInputSandbox(Form("LF:$1/%s/Stage_%s.xml",fMergeDirName.Data(),stageName.Data()));
2042    } else {  
2043      fMergingJDL->SetOutputDirectory("$1", "Output directory");
2044      fMergingJDL->AddToInputSandbox(Form("LF:$1/Stage_%s.xml",stageName.Data()));
2045    }  
2046    TString sjdl2 = fMergingJDL->Generate();
2047    Int_t index, index1;
2048    sjdl.ReplaceAll("\",\"", "\",\n   \"");
2049    sjdl.ReplaceAll("(member", "\n   (member");
2050    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2051    sjdl.ReplaceAll("{", "{\n   ");
2052    sjdl.ReplaceAll("};", "\n};");
2053    sjdl.ReplaceAll("{\n   \n", "{\n");
2054    sjdl.ReplaceAll("\n\n", "\n");
2055    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
2056    sjdl1.ReplaceAll("\",\"", "\",\n   \"");
2057    sjdl1.ReplaceAll("(member", "\n   (member");
2058    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2059    sjdl1.ReplaceAll("{", "{\n   ");
2060    sjdl1.ReplaceAll("};", "\n};");
2061    sjdl1.ReplaceAll("{\n   \n", "{\n");
2062    sjdl1.ReplaceAll("\n\n", "\n");
2063    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
2064    sjdl2.ReplaceAll("\",\"", "\",\n   \"");
2065    sjdl2.ReplaceAll("(member", "\n   (member");
2066    sjdl2.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2067    sjdl2.ReplaceAll("{", "{\n   ");
2068    sjdl2.ReplaceAll("};", "\n};");
2069    sjdl2.ReplaceAll("{\n   \n", "{\n");
2070    sjdl2.ReplaceAll("\n\n", "\n");
2071    sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
2072    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2073    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
2074    index = sjdl.Index("JDLVariables");
2075    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
2076    sjdl += "Workdirectorysize = {\"5000MB\"};";
2077    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2078    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2079    index = fJobTag.Index(":");
2080    if (index < 0) index = fJobTag.Length();
2081    TString jobTag = fJobTag;
2082    if (fProductionMode) jobTag.Insert(index,"_Stage$4");
2083    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:%s_Merging\"\n};\n", jobTag.Data()));
2084    if (fProductionMode) {   
2085      sjdl1.Prepend("# Generated merging jdl (production mode) \
2086                     \n# $1 = full alien path to output directory to be merged \
2087                     \n# $2 = train number \
2088                     \n# $3 = production (like LHC10b) \
2089                     \n# $4 = merging stage \
2090                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2091      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2092      sjdl2.Prepend("# Generated merging jdl \
2093                     \n# $1 = full alien path to output directory to be merged \
2094                     \n# $2 = train number \
2095                     \n# $3 = production (like LHC10b) \
2096                     \n# $4 = merging stage \
2097                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2098    } else {
2099      sjdl1.Prepend("# Generated merging jdl \
2100                     \n# $1 = full alien path to output directory to be merged \
2101                     \n# $2 = merging stage \
2102                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2103      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2104      sjdl2.Prepend("# Generated merging jdl \
2105                     \n# $1 = full alien path to output directory to be merged \
2106                     \n# $2 = merging stage \
2107                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2108    }
2109    index = sjdl1.Index("JDLVariables");
2110    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
2111    index = sjdl2.Index("JDLVariables");
2112    if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
2113    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2114    sjdl2 += "Workdirectorysize = {\"5000MB\"};";
2115    index = sjdl2.Index("Split =");
2116    if (index>=0) {
2117       index1 = sjdl2.Index("\n", index);
2118       sjdl2.Remove(index, index1-index+1);
2119    }
2120    index = sjdl2.Index("SplitMaxInputFileNumber");
2121    if (index>=0) {
2122       index1 = sjdl2.Index("\n", index);
2123       sjdl2.Remove(index, index1-index+1);
2124    }
2125    index = sjdl2.Index("InputDataCollection");
2126    if (index>=0) {
2127       index1 = sjdl2.Index(";", index);
2128       sjdl2.Remove(index, index1-index+1);
2129    }
2130    index = sjdl2.Index("InputDataListFormat");
2131    if (index>=0) {
2132       index1 = sjdl2.Index("\n", index);
2133       sjdl2.Remove(index, index1-index+1);
2134    }
2135    index = sjdl2.Index("InputDataList");
2136    if (index>=0) {
2137       index1 = sjdl2.Index("\n", index);
2138       sjdl2.Remove(index, index1-index+1);
2139    }
2140    sjdl2.ReplaceAll("wn.xml", Form("Stage_%s.xml",stageName.Data()));
2141    // Write jdl to file
2142    ofstream out;
2143    out.open(fJDLName.Data(), ios::out);
2144    if (out.bad()) {
2145       Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
2146       return kFALSE;
2147    }
2148    out << sjdl << endl;
2149    out.close();
2150    TString mergeJDLName = fExecutable;
2151    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2152    if (fMergeViaJDL) {
2153       ofstream out1;
2154       out1.open(mergeJDLName.Data(), ios::out);
2155       if (out1.bad()) {
2156          Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
2157          return kFALSE;
2158       }
2159       out1 << sjdl1 << endl;
2160       out1.close();
2161       ofstream out2;
2162       TString finalJDL = mergeJDLName;
2163       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2164       out2.open(finalJDL.Data(), ios::out);
2165       if (out2.bad()) {
2166          Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
2167          return kFALSE;
2168       }
2169       out2 << sjdl2 << endl;
2170       out2.close();
2171    }   
2172
2173    // Copy jdl to grid workspace   
2174    if (!copy) {
2175       Info("WriteJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
2176    } else {
2177       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
2178       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
2179       TString finalJDL = mergeJDLName;
2180       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2181       TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
2182       if (fProductionMode) {
2183          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2184          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
2185          locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
2186       }   
2187       if (FileExists(locjdl)) gGrid->Rm(locjdl);
2188       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
2189       if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
2190       Info("WriteJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
2191 //      TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
2192       if (!copyLocal2Alien("WriteJDL",fJDLName.Data(),locjdl.Data())) 
2193          Fatal("","Terminating");
2194       if (fMergeViaJDL) {
2195          Info("WriteJDL", "\n#####   Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
2196 //         TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
2197 //         TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
2198          if (!copyLocal2Alien("WriteJDL",mergeJDLName.Data(),locjdl1.Data()))
2199             Fatal("","Terminating");
2200          if (!copyLocal2Alien("WriteJDL",finalJDL.Data(),locjdl2.Data()))
2201            Fatal("","Terminating");
2202       }   
2203    } 
2204    return kTRUE;
2205 }
2206
2207 //______________________________________________________________________________
2208 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
2209 {
2210 // Returns true if file exists.
2211    if (!gGrid) return kFALSE;
2212    TString slfn = lfn;
2213    slfn.ReplaceAll("alien://","");
2214    TGridResult *res = gGrid->Ls(slfn);
2215    if (!res) return kFALSE;
2216    TMap *map = dynamic_cast<TMap*>(res->At(0));
2217    if (!map) {
2218       delete res;
2219       return kFALSE;
2220    }   
2221    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
2222    if (!objs || !objs->GetString().Length()) {
2223       delete res;
2224       return kFALSE;
2225    }
2226    delete res;   
2227    return kTRUE;
2228 }
2229
2230 //______________________________________________________________________________
2231 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
2232 {
2233 // Returns true if directory exists. Can be also a path.
2234 // Since there is not API in TAlien, we use the Cd trick:
2235    if (!gGrid) return kFALSE;
2236    // Backup current path
2237    TString cpath = gGrid->Pwd();
2238    TString command = "cd ";
2239    TString sdir(dirname);
2240    sdir.ReplaceAll("alien://", "");
2241    command += sdir;
2242    TGridResult *res = gGrid->Command(command);
2243    if (!res) {
2244       gGrid->Cd(cpath);
2245       return kFALSE;
2246    }   
2247    TMap *map = (TMap*)res->At(0);
2248    if (!map) {
2249       gGrid->Cd(cpath);
2250       delete res;
2251       return kFALSE;
2252    }
2253    TString sval = map->GetValue("__result__")->GetName();
2254    Bool_t retval = (Bool_t)sval.Atoi();
2255    gGrid->Cd(cpath);
2256    delete res;
2257    return retval;
2258 }   
2259
2260 //______________________________________________________________________________
2261 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
2262 {
2263 // Check input data type.
2264    isCollection = kFALSE;
2265    isXml = kFALSE;
2266    useTags = kFALSE;
2267    if (!gGrid) {
2268       Error("CheckDataType", "No connection to grid");
2269       return;
2270    }
2271    isCollection = IsCollection(lfn);
2272    TString msg = "\n#####   file: ";
2273    msg += lfn;
2274    if (isCollection) {
2275       msg += " type: raw_collection;";
2276    // special treatment for collections
2277       isXml = kFALSE;
2278       // check for tag files in the collection
2279       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
2280       if (!res) {
2281          msg += " using_tags: No (unknown)";
2282          Info("CheckDataType", "%s", msg.Data());
2283          return;
2284       }   
2285       const char* typeStr = res->GetKey(0, "origLFN");
2286       if (!typeStr || !strlen(typeStr)) {
2287          msg += " using_tags: No (unknown)";
2288          Info("CheckDataType", "%s", msg.Data());
2289          return;
2290       }   
2291       TString file = typeStr;
2292       useTags = file.Contains(".tag");
2293       if (useTags) msg += " using_tags: Yes";
2294       else          msg += " using_tags: No";
2295       Info("CheckDataType", "%s", msg.Data());
2296       return;
2297    }
2298    TString slfn(lfn);
2299    slfn.ToLower();
2300    isXml = slfn.Contains(".xml");
2301    if (isXml) {
2302    // Open xml collection and check if there are tag files inside
2303       msg += " type: xml_collection;";
2304       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
2305       if (!coll) {
2306          msg += " using_tags: No (unknown)";
2307          Info("CheckDataType", "%s", msg.Data());
2308          return;
2309       }   
2310       TMap *map = coll->Next();
2311       if (!map) {
2312          msg += " using_tags: No (unknown)";
2313          Info("CheckDataType", "%s", msg.Data());
2314          return;
2315       }   
2316       map = (TMap*)map->GetValue("");
2317       TString file;
2318       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
2319       useTags = file.Contains(".tag");
2320       delete coll;
2321       if (useTags) msg += " using_tags: Yes";
2322       else          msg += " using_tags: No";
2323       Info("CheckDataType", "%s", msg.Data());
2324       return;
2325    }
2326    useTags = slfn.Contains(".tag");
2327    if (slfn.Contains(".root")) msg += " type: root file;";
2328    else                        msg += " type: unknown file;";
2329    if (useTags) msg += " using_tags: Yes";
2330    else          msg += " using_tags: No";
2331    Info("CheckDataType", "%s", msg.Data());
2332 }
2333
2334 //______________________________________________________________________________
2335 void AliAnalysisAlien::EnablePackage(const char *package)
2336 {
2337 // Enables a par file supposed to exist in the current directory.
2338    TString pkg(package);
2339    pkg.ReplaceAll(".par", "");
2340    pkg += ".par";
2341    if (gSystem->AccessPathName(pkg)) {
2342       Fatal("EnablePackage", "Package %s not found", pkg.Data());
2343       return;
2344    }
2345    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
2346       Info("EnablePackage", "AliEn plugin will use .par packages");
2347    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
2348    if (!fPackages) {
2349       fPackages = new TObjArray();
2350       fPackages->SetOwner();
2351    }
2352    fPackages->Add(new TObjString(pkg));
2353 }      
2354
2355 //______________________________________________________________________________
2356 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
2357 {
2358 // Make a tree from files having the location specified in fFileForTestMode. 
2359 // Inspired from JF's CreateESDChain.
2360    if (fFileForTestMode.IsNull()) {
2361       Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2362       return NULL;
2363    }
2364    if (gSystem->AccessPathName(fFileForTestMode)) {
2365       Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2366       return NULL;
2367    }   
2368    // Open the file
2369    ifstream in;
2370    in.open(fFileForTestMode);
2371    Int_t count = 0;
2372     // Read the input list of files and add them to the chain
2373    TString line;
2374    TString streeName(treeName);
2375    if (IsUseMCchain()) streeName = "TE";
2376    TChain *chain = new TChain(streeName);
2377    TList *friends = new TList();
2378    TChain *cfriend = 0;
2379    if (!fFriendChainName.IsNull()) {
2380       TObjArray *list = fFriendChainName.Tokenize(" ");
2381       TIter next(list);
2382       TObjString *str;
2383       while((str=(TObjString*)next())) {
2384          cfriend = new TChain(streeName, str->GetName());
2385          friends->Add(cfriend);
2386          chain->AddFriend(cfriend);
2387       }
2388       delete list;
2389    } 
2390    TString bpath;
2391    TIter nextfriend(friends);
2392    while (in.good())
2393    {
2394       in >> line;
2395       if (line.IsNull() || line.BeginsWith("#")) continue;
2396       if (count++ == fNtestFiles) break;
2397       TString esdFile(line);
2398       TFile *file = TFile::Open(esdFile);
2399       if (file && !file->IsZombie()) {
2400          chain->Add(esdFile);
2401          file->Close();
2402          if (!fFriendChainName.IsNull()) {
2403             if (esdFile.Index("#") > -1)
2404                esdFile.Remove(esdFile.Index("#"));
2405             bpath = gSystem->DirName(esdFile);
2406             bpath += "/";
2407             TString fileFriend;
2408             nextfriend.Reset();
2409             while ((cfriend=(TChain*)nextfriend())) {
2410                fileFriend = bpath;
2411                fileFriend += cfriend->GetTitle();
2412                file = TFile::Open(fileFriend);
2413                if (file && !file->IsZombie()) {
2414                   file->Close();
2415                   cfriend->Add(fileFriend);
2416                } else {
2417                   Fatal("GetChainForTestMode", "Cannot open friend file: %s", fileFriend.Data());
2418                   return 0;
2419                } 
2420             }     
2421          }
2422       } else {
2423          Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
2424       }   
2425    }
2426    in.close();
2427    if (!chain->GetListOfFiles()->GetEntries()) {
2428        Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
2429        delete chain;
2430        friends->Delete();
2431        delete friends;
2432        return NULL;
2433    }
2434    return chain;
2435 }    
2436
2437 //______________________________________________________________________________
2438 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
2439 {
2440 // Get job status for all jobs with jobid>jobidstart.
2441    static char mstatus[20];
2442    mstatus[0] = '\0';
2443    nrunning = 0;
2444    nwaiting = 0;
2445    nerror   = 0;
2446    ndone    = 0;
2447    TGridJobStatusList *list = gGrid->Ps("");
2448    if (!list) return mstatus;
2449    Int_t nentries = list->GetSize();
2450    TGridJobStatus *status;
2451    Int_t pid;
2452    for (Int_t ijob=0; ijob<nentries; ijob++) {
2453       status = (TGridJobStatus *)list->At(ijob);
2454       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)%p)->GetKey(\"queueId\"));", status));
2455       if (pid<jobidstart) continue;
2456       if (pid == lastid) {
2457          gROOT->ProcessLine(Form("sprintf((char*)%p,((TAlienJobStatus*)%p)->GetKey(\"status\"));",mstatus, status));
2458       }   
2459       switch (status->GetStatus()) {
2460          case TGridJobStatus::kWAITING:
2461             nwaiting++; break;
2462          case TGridJobStatus::kRUNNING:
2463             nrunning++; break;
2464          case TGridJobStatus::kABORTED:
2465          case TGridJobStatus::kFAIL:
2466          case TGridJobStatus::kUNKNOWN:
2467             nerror++; break;
2468          case TGridJobStatus::kDONE:
2469             ndone++;
2470       }
2471    }
2472    list->Delete();
2473    delete list;
2474    return mstatus;
2475 }
2476
2477 //______________________________________________________________________________
2478 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
2479 {
2480 // Returns true if file is a collection. Functionality duplicated from
2481 // TAlien::Type() because we don't want to directly depend on TAlien.
2482    if (!gGrid) {
2483       Error("IsCollection", "No connection to grid");
2484       return kFALSE;
2485    }
2486    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
2487    if (!res) return kFALSE;
2488    const char* typeStr = res->GetKey(0, "type");
2489    if (!typeStr || !strlen(typeStr)) return kFALSE;
2490    if (!strcmp(typeStr, "collection")) return kTRUE;
2491    delete res;
2492    return kFALSE;
2493 }   
2494
2495 //______________________________________________________________________________
2496 Bool_t AliAnalysisAlien::IsSingleOutput() const
2497 {
2498 // Check if single-ouput option is on.
2499    return (!fOutputSingle.IsNull());
2500 }
2501
2502 //______________________________________________________________________________
2503 Long64_t AliAnalysisAlien::RunMacroAndExtractLibs(const char* macro, const char *args, TString &libs)
2504 {
2505 // Tries to run the specified macro and return the libraries that it loads.
2506    TString expname;
2507    if (strlen(macro)) expname = gSystem->ExpandPathName(macro);
2508    if (expname.IsNull() || gSystem->AccessPathName(expname)) {
2509       ::Error("RunMacroAndExtractLibs","Cannot find macro %s in current directory", macro);
2510       return -1;
2511    }   
2512    TString oldlibs = gSystem->GetLibraries();
2513    TMacro m(expname);
2514    Int_t error = 0;
2515    Long64_t retval = m.Exec(args, &error);
2516    if (error != TInterpreter::kNoError)
2517    {
2518       ::Error("RunMacroAndExtractLibs", "Macro interpretation %s failed", macro);
2519       return -1;
2520    }
2521    libs = gSystem->GetLibraries();
2522    libs.ReplaceAll(oldlibs, "");
2523    libs.Strip(TString::kLeading);
2524    TObjArray *libTokens = libs.Tokenize(" ");
2525    libs = "";
2526    for (Int_t i=0; i<libTokens->GetEntries(); i++) {
2527      if (!libs.IsNull()) libs += " ";
2528      libs += gSystem->BaseName(libTokens->At(i)->GetName());
2529    }
2530    delete libTokens;
2531    return retval;
2532 }   
2533       
2534 //______________________________________________________________________________
2535 void AliAnalysisAlien::Print(Option_t *) const
2536 {
2537 // Print current plugin settings.
2538    printf("### AliEn analysis plugin current settings ###\n");
2539    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2540    if (mgr && mgr->IsProofMode()) {
2541       TString proofType = "=   PLUGIN IN PROOF MODE ON CLUSTER:_________________";
2542       if (TestBit(AliAnalysisGrid::kTest))
2543          proofType = "=   PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
2544       printf("%s %s\n", proofType.Data(), fProofCluster.Data());
2545       if (!fProofDataSet.IsNull())
2546       printf("=   Requested data set:___________________________ %s\n", fProofDataSet.Data());
2547       if (fProofReset==1)
2548       printf("=   Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2549       if (fProofReset>1)   
2550       printf("=   Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2551       if (!fROOTVersion.IsNull())
2552       printf("=   ROOT version requested________________________ %s\n", fROOTVersion.Data());
2553       else
2554       printf("=   ROOT version requested________________________ default\n");
2555       printf("=   AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
2556       if (!fAliRootMode.IsNull())
2557       printf("=   Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());  
2558       if (fNproofWorkers)
2559       printf("=   Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
2560       if  (fNproofWorkersPerSlave)
2561       printf("=   Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
2562       if (TestSpecialBit(kClearPackages))
2563       printf("=   ClearPackages requested...\n");
2564       if (fIncludePath.Data())
2565       printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2566       printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2567       if (fPackages && fPackages->GetEntries()) {
2568          TIter next(fPackages);
2569          TObject *obj;
2570          TString list;
2571          while ((obj=next())) list += obj->GetName();
2572          printf("=   Par files to be used: ________________________ %s\n", list.Data());
2573       } 
2574       if (TestSpecialBit(kProofConnectGrid))
2575       printf("=   Requested PROOF connection to grid\n");
2576       return;
2577    }
2578    printf("=   OverwriteMode:________________________________ %d\n", fOverwriteMode);
2579    if (fOverwriteMode) {
2580       printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
2581             \n*****       To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
2582    }
2583    printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
2584    printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO:Print");
2585    printf("=   Production mode:______________________________ %d\n", fProductionMode);
2586    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
2587    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
2588    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
2589    if (fUser.Length()) 
2590    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
2591    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
2592    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
2593    TString basedatadir = fGridDataDir;
2594    TString pattern = fDataPattern;
2595    pattern.Strip();
2596    Int_t ind = pattern.Index(" ");
2597    if (ind>=0) {
2598       basedatadir += "/%run%/";
2599       basedatadir += pattern(0, ind);
2600       pattern = pattern(ind+1, pattern.Length());
2601    }   
2602    printf("=   Data base directory path requested: __________ %s\n", basedatadir.Data());
2603    printf("=   Data search pattern: _________________________ %s\n", pattern.Data());
2604    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
2605    if (fRunNumbers.Length()) 
2606    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
2607    if (fRunRange[0])
2608    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
2609    if (!fRunRange[0] && !fRunNumbers.Length()) {
2610       TIter next(fInputFiles);
2611       TObject *obj;
2612       TString list;
2613       while ((obj=next())) list += obj->GetName();
2614       printf("=   Input files to be processed: _________________ %s\n", list.Data());
2615    }
2616    if (TestBit(AliAnalysisGrid::kTest))
2617    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
2618    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
2619    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
2620    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
2621    printf("=   List of outputs that should not be registered: %s\n", fRegisterExcludes.Data());
2622    printf("=   List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
2623    printf("=====================================================================\n");
2624    printf("=   Job price: ___________________________________ %d\n", fPrice);
2625    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
2626    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
2627    if (fMaxInitFailed>0) 
2628    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
2629    if (fMasterResubmitThreshold>0) 
2630    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
2631    printf("=   Number of replicas for the output files_______ %d\n", fNreplicas);
2632    if (fNrunsPerMaster>0)
2633    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
2634    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
2635    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
2636    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
2637    if (fArguments.Length()) 
2638    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
2639    if (fExecutableArgs.Length()) 
2640    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
2641    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
2642    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
2643    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2644    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
2645    if (fDatasetName)
2646    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
2647    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
2648    if (fIncludePath.Data())
2649    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2650    if (fCloseSE.Length())
2651    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
2652    if (fFriendChainName.Length())
2653    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
2654    if (fPackages && fPackages->GetEntries()) {
2655       TIter next(fPackages);
2656       TObject *obj;
2657       TString list;
2658       while ((obj=next())) list += obj->GetName();
2659       printf("=   Par files to be used: ________________________ %s\n", list.Data());
2660    }   
2661 }
2662
2663 //______________________________________________________________________________
2664 void AliAnalysisAlien::SetDefaults()
2665 {
2666 // Set default values for everything. What cannot be filled will be left empty.
2667    if (fGridJDL) delete fGridJDL;
2668    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2669    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2670    fPrice                      = 1;
2671    fTTL                        = 30000;
2672    fSplitMaxInputFileNumber    = 100;
2673    fMaxInitFailed              = 0;
2674    fMasterResubmitThreshold    = 0;
2675    fNtestFiles                 = 10;
2676    fNreplicas                  = 2;
2677    fRunRange[0]                = 0;
2678    fRunRange[1]                = 0;
2679    fRunPrefix                  = "%d";
2680    fNrunsPerMaster             = 1;
2681    fMaxMergeFiles              = 100;
2682    fRunNumbers                 = "";
2683    fExecutable                 = "analysis.sh";
2684    fExecutableCommand          = "root -b -q -x";
2685    fArguments                  = "";
2686    fExecutableArgs             = "";
2687    fAnalysisMacro              = "myAnalysis.C";
2688    fAnalysisSource             = "";
2689    fAdditionalLibs             = "";
2690    fSplitMode                  = "se";
2691    fAPIVersion                 = "";
2692    fROOTVersion                = "";
2693    fAliROOTVersion             = "";
2694    fUser                       = "";  // Your alien user name
2695    fGridWorkingDir             = "";
2696    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
2697    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
2698    fFriendChainName            = "";
2699    fGridOutputDir              = "output";
2700    fOutputArchive              = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
2701    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
2702    fInputFormat                = "xml-single";
2703    fJDLName                    = "analysis.jdl";
2704    fJobTag                     = "Automatically generated analysis JDL";
2705    fMergeExcludes              = "";
2706    fMergeViaJDL                = 0;
2707    SetUseCopy(kTRUE);
2708    SetCheckCopy(kTRUE);
2709    SetDefaultOutputs(kTRUE);
2710    fOverwriteMode              = 1;
2711 }   
2712
2713 //______________________________________________________________________________
2714 void AliAnalysisAlien::SetFriendChainName(const char *name, const char *libnames)
2715 {
2716    // Set file name for the chain of friends and optionally additional libs to be loaded.
2717    // Libs should be separated by blancs.
2718    fFriendChainName = name;
2719    fFriendChainName.ReplaceAll(",", " ");
2720    fFriendChainName.Strip();
2721    fFriendChainName.ReplaceAll("  ", " ");
2722    
2723    fFriendLibs = libnames;
2724    if (fFriendLibs.Length()) {
2725      if(!fFriendLibs.Contains(".so") && 
2726         !fFriendLibs.Contains(".dylib"))
2727        Fatal("SetFriendChainName()", "You should provide explicit library names (with extension)");
2728      fFriendLibs.ReplaceAll(",", " ");
2729      fFriendLibs.Strip();
2730      fFriendLibs.ReplaceAll("  ", " ");
2731    }
2732 }
2733
2734 //______________________________________________________________________________
2735 void AliAnalysisAlien::SetRootVersionForProof(const char *version)
2736 {
2737 // Obsolete method. Use SetROOTVersion instead
2738    Warning("SetRootVersionForProof", "Obsolete. Use SetROOTVersion instead");
2739    if (fROOTVersion.IsNull()) SetROOTVersion(version);
2740    else Error("SetRootVersionForProof", "ROOT version already set to %s", fROOTVersion.Data());
2741 }
2742    
2743 //______________________________________________________________________________
2744 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
2745 {
2746 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
2747    // First check if the result is already in the output directory.
2748    if (FileExists(Form("%s/%s",aliendir,filename))) {
2749       printf("Final merged results found. Not merging again.\n");
2750       return kFALSE;
2751    }
2752    // Now check the last stage done.
2753    Int_t stage = 0;
2754    while (1) {
2755       if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
2756       stage++;
2757    }
2758    // Next stage of merging
2759    stage++;
2760    TString pattern = "*root_archive.zip";
2761    if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
2762    TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
2763    if (res) delete res;
2764    // Write standard output to file
2765    gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
2766    // Count the number of files inside
2767    ifstream ifile;
2768    ifile.open(Form("Stage_%d.xml",stage));
2769    if (!ifile.good()) {
2770       ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
2771       return kFALSE;
2772    }   
2773    TString line;
2774    Int_t nfiles = 0;
2775    while (!ifile.eof()) {
2776       ifile >> line;
2777       if (line.Contains("/event")) nfiles++;
2778    }
2779    ifile.close();
2780    if (!nfiles) {
2781       ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
2782       return kFALSE;
2783    } else {
2784       printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
2785    }   
2786    // Copy the file in the output directory
2787    printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
2788 //   TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
2789    if (!copyLocal2Alien("CheckMergedFiles", Form("Stage_%d.xml",stage), 
2790         Form("%s/Stage_%d.xml",aliendir,stage))) Fatal("","Terminating");
2791    // Check if this is the last stage to be done.
2792    Bool_t laststage = (nfiles<nperchunk);
2793    if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
2794    Int_t jobId = 0;
2795    if (laststage) {
2796       printf("### Submiting final merging stage %d\n", stage);
2797       TString finalJDL = jdl;
2798       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2799       TString query = Form("submit %s %s %d", finalJDL.Data(), aliendir, stage);
2800       jobId = SubmitSingleJob(query);
2801    } else {
2802       printf("### Submiting merging stage %d\n", stage);
2803       TString query = Form("submit %s %s %d", jdl, aliendir, stage);
2804       jobId = SubmitSingleJob(query);
2805    }
2806    if (!jobId) return kFALSE;           
2807
2808    if (!fGridJobIDs.IsNull()) fGridJobIDs.Append(" ");
2809    fGridJobIDs.Append(Form("%d", jobId));
2810    if (!fGridStages.IsNull()) fGridStages.Append(" ");
2811    fGridStages.Append(Form("%s_merge_stage%d", 
2812                            laststage ? "final" : "partial", stage));
2813
2814    return kTRUE;   
2815 }        
2816
2817 //______________________________________________________________________________
2818 AliAnalysisManager *AliAnalysisAlien::LoadAnalysisManager(const char *fname)
2819 {
2820 // Loat the analysis manager from a file.
2821    TFile *file = TFile::Open(fname);
2822    if (!file) {
2823       ::Error("LoadAnalysisManager", "Cannot open file %s", fname);
2824       return 0;
2825    }   
2826    TIter nextkey(file->GetListOfKeys());
2827    AliAnalysisManager *mgr = 0;
2828    TKey *key;
2829    while ((key=(TKey*)nextkey())) {
2830       if (!strcmp(key->GetClassName(), "AliAnalysisManager"))
2831          mgr = (AliAnalysisManager*)file->Get(key->GetName());
2832    }
2833    if (!mgr) 
2834       ::Error("LoadAnalysisManager", "No analysis manager found in file %s", fname);
2835    return mgr;
2836 }      
2837
2838 //______________________________________________________________________________
2839 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
2840 {
2841 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
2842    if (!gGrid) return 0;
2843    printf("=> %s ------> ",query);
2844    TGridResult *res = gGrid->Command(query);
2845    if (!res) return 0;
2846    TString jobId = res->GetKey(0,"jobId");
2847    delete res;
2848    if (jobId.IsNull()) {
2849       printf("submission failed. Reason:\n");
2850       gGrid->Stdout();
2851       gGrid->Stderr();
2852       ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
2853       return 0;
2854    }
2855    Int_t ijobId = jobId.Atoi();
2856    printf(" Job id: '%s' (%d)\n", jobId.Data(), ijobId);
2857    return ijobId; 
2858 }  
2859
2860 //______________________________________________________________________________
2861 Bool_t AliAnalysisAlien::MergeInfo(const char *output, const char *collection)
2862 {
2863 // Merges a collection of output files using concatenation.
2864    TString scoll(collection);
2865    if (!scoll.Contains(".xml")) return kFALSE;
2866    TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", collection));
2867    if (!coll) {
2868       ::Error("MergeInfo", "Input XML %s collection empty.", collection);
2869       return kFALSE;
2870    }
2871    // Iterate grid collection
2872    TString outtmp;
2873    Bool_t merged = kFALSE;
2874    Int_t ifile = 0;
2875    while (coll->Next()) {
2876       TString fname = gSystem->DirName(coll->GetTURL());
2877       fname += "/";
2878       fname += output;
2879       outtmp = Form("%d_%s", ifile, output);
2880       if (!TFile::Cp(fname, outtmp)) {
2881          ::Error("MergeInfo", "Could not copy %s", fname.Data());
2882          continue;
2883       }
2884       ifile++;
2885       if (ifile<2) {
2886          gSystem->Exec(Form("cp %s lastmerged", outtmp.Data()));
2887          continue;
2888       }
2889       gSystem->Exec(Form("cat lastmerged %s > tempmerged", outtmp.Data()));
2890       gSystem->Exec("cp tempmerged lastmerged");
2891    }
2892    if (ifile) {
2893       gSystem->Exec(Form("cp lastmerged %s", output));
2894       gSystem->Exec(Form("rm tempmerged lastmerged *_%s", output));
2895       merged = kTRUE;
2896    }
2897    return merged;
2898 }   
2899
2900 //______________________________________________________________________________
2901 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
2902 {
2903 // Merge given output files from basedir. Basedir can be an alien output directory
2904 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
2905 // files in a group (ignored for xml input). Merging can be done in stages:
2906 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
2907 // stage=1 : works with an xml of all root_archive.zip in the output directory
2908 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
2909    TString outputFile = output;
2910    TString command;
2911    TString outputChunk;
2912    TString previousChunk = "";
2913    TObjArray *listoffiles = new TObjArray();
2914 //   listoffiles->SetOwner();
2915    Int_t countChunk = 0;
2916    Int_t countZero = nmaxmerge;
2917    Bool_t merged = kTRUE;
2918    Bool_t isGrid = kTRUE;
2919    Int_t index = outputFile.Index("@");
2920    if (index > 0) outputFile.Remove(index);
2921    TString inputFile = outputFile;
2922    TString sbasedir = basedir;
2923    if (sbasedir.Contains(".xml")) {
2924       // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
2925       nmaxmerge = 9999999;
2926       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
2927       if (!coll) {
2928          ::Error("MergeOutput", "Input XML collection empty.");
2929          return kFALSE;
2930       }
2931       // Iterate grid collection
2932       while (coll->Next()) {
2933          TString fname = gSystem->DirName(coll->GetTURL());
2934          fname += "/";
2935          fname += inputFile;      
2936          listoffiles->Add(new TNamed(fname.Data(),""));
2937       }   
2938    } else if (sbasedir.Contains(".txt")) {
2939       // The file having the .txt extension is expected to contain a list of
2940       // folders where the output files will be looked. For alien folders,
2941       // the full folder LFN is expected (starting with alien://)
2942       // Assume lfn's on each line
2943       TString line;
2944       ifstream in;
2945       in.open(sbasedir);
2946       if (in.fail()) {
2947          ::Error("MergeOutput", "File %s cannot be opened. Merging stopped." ,sbasedir.Data());
2948          return kTRUE;
2949       }           
2950       Int_t nfiles = 0;
2951       while (in.good()) {
2952          in >> line;
2953          if (line.IsNull() || line.BeginsWith("#")) continue;
2954          line.Strip();
2955          if (!line.Contains("alien:")) isGrid = kFALSE;
2956          line += "/";
2957          line += outputFile;
2958          nfiles++;
2959          listoffiles->Add(new TNamed(line.Data(),""));
2960       }
2961       in.close();
2962       if (!nfiles) {
2963          ::Error("MergeOutput","Input file %s contains no files to be merged\n", sbasedir.Data());
2964          delete listoffiles;
2965          return kFALSE;
2966       }
2967    } else {   
2968       command = Form("find %s/ *%s", basedir, inputFile.Data());
2969       printf("command: %s\n", command.Data());
2970       TGridResult *res = gGrid->Command(command);
2971       if (!res) {
2972          ::Error("MergeOutput","No result for the find command\n");
2973          delete listoffiles;
2974          return kFALSE;
2975       }     
2976       TIter nextmap(res);
2977       TMap *map = 0;
2978       while ((map=(TMap*)nextmap())) {
2979          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
2980          if (!objs || !objs->GetString().Length()) {
2981             // Nothing found - skip this output
2982             delete res;
2983             delete listoffiles;
2984             return kFALSE;
2985          }
2986          listoffiles->Add(new TNamed(objs->GetName(),""));
2987       }
2988       delete res;
2989    }
2990    if (!listoffiles->GetEntries()) {
2991       ::Error("MergeOutput","No result for the find command\n");
2992       delete listoffiles;
2993       return kFALSE;
2994    }     
2995
2996    TFileMerger *fm = 0;
2997    TIter next0(listoffiles);
2998    TObjArray *listoffilestmp = new TObjArray();
2999    listoffilestmp->SetOwner();
3000    TObject *nextfile;
3001    TString snextfile;
3002    // Keep only the files at upper level
3003    Int_t countChar = 0;
3004    while ((nextfile=next0())) {
3005       snextfile = nextfile->GetName();
3006       Int_t crtCount = snextfile.CountChar('/');
3007       if (nextfile == listoffiles->First()) countChar = crtCount;
3008       if (crtCount < countChar) countChar = crtCount;
3009    }
3010    next0.Reset();
3011    while ((nextfile=next0())) {
3012       snextfile = nextfile->GetName();
3013       Int_t crtCount = snextfile.CountChar('/');
3014       if (crtCount > countChar) {
3015          delete nextfile;
3016          continue;
3017       }   
3018       listoffilestmp->Add(nextfile);
3019    }
3020    delete listoffiles;
3021    listoffiles = listoffilestmp;  // Now contains 'good' files
3022    listoffiles->Print();
3023    TIter next(listoffiles);   
3024    // Check if there is a merge operation to resume. Works only for stage 0 or 1.
3025    outputChunk = outputFile;
3026    outputChunk.ReplaceAll(".root", "_*.root");
3027    // Check for existent temporary merge files
3028    // Check overwrite mode and remove previous partial results if needed
3029    // Preserve old merging functionality for stage 0.
3030    if (stage==0) {
3031       if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3032          while (1) {
3033             // Skip as many input files as in a chunk
3034             for (Int_t counter=0; counter<nmaxmerge; counter++) {
3035                nextfile = next();
3036                if (!nextfile) {
3037                   ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
3038                   delete listoffiles;
3039                   return kFALSE;
3040                }   
3041                snextfile = nextfile->GetName();
3042             }
3043             outputChunk = outputFile;
3044             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
3045             countChunk++;
3046             if (gSystem->AccessPathName(outputChunk)) continue;
3047             // Merged file with chunks up to <countChunk> found
3048             ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
3049             previousChunk = outputChunk;
3050             break;
3051          }
3052       }   
3053       countZero = nmaxmerge;
3054    
3055       while ((nextfile=next())) {
3056          snextfile = nextfile->GetName();
3057          // Loop 'find' results and get next LFN
3058          if (countZero == nmaxmerge) {
3059             // First file in chunk - create file merger and add previous chunk if any.
3060             fm = new TFileMerger(isGrid);
3061             fm->SetFastMethod(kTRUE);
3062             if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
3063             outputChunk = outputFile;
3064             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
3065          }
3066          // If last file found, put merged results in the output file
3067          if (nextfile == listoffiles->Last()) outputChunk = outputFile;
3068          // Add file to be merged and decrement chunk counter.
3069          fm->AddFile(snextfile);
3070          countZero--;
3071          if (countZero==0 || nextfile == listoffiles->Last()) {            
3072             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
3073             // Nothing found - skip this output
3074                ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
3075                merged = kFALSE;
3076                break;
3077             }
3078             fm->OutputFile(outputChunk);
3079             // Merge the outputs, then go to next chunk      
3080             if (!fm->Merge()) {
3081                ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
3082                merged = kFALSE;
3083                break;
3084             } else {
3085                ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
3086                gSystem->Unlink(previousChunk);
3087             }
3088             if (nextfile == listoffiles->Last()) break;
3089             countChunk++;
3090             countZero = nmaxmerge;
3091             previousChunk = outputChunk;
3092          }
3093       }
3094       delete listoffiles;
3095       delete fm;
3096       return merged;
3097    }
3098    // Merging stage different than 0.
3099    // Move to the begining of the requested chunk.
3100    fm = new TFileMerger(isGrid);
3101    fm->SetFastMethod(kTRUE);
3102    while ((nextfile=next())) fm->AddFile(nextfile->GetName());
3103    delete listoffiles;
3104    if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
3105       // Nothing found - skip this output
3106       ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
3107       delete fm;
3108       return kFALSE;
3109    }
3110    fm->OutputFile(outputFile);
3111    // Merge the outputs
3112    if (!fm->Merge()) {
3113       ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
3114       delete fm;
3115       return kFALSE;
3116    } else {
3117       ::Info("MergeOutput", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
3118    }
3119    delete fm;
3120    return kTRUE;
3121
3122
3123 //______________________________________________________________________________
3124 Bool_t AliAnalysisAlien::MergeOutputs()
3125 {
3126 // Merge analysis outputs existing in the AliEn space.
3127    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
3128    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
3129    if (!Connect()) {
3130       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
3131       return kFALSE;
3132    }
3133    if (fMergeViaJDL) {
3134       if (!TestBit(AliAnalysisGrid::kMerge)) {
3135          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
3136          return kFALSE; 
3137       }     
3138       if (fProductionMode) {
3139          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
3140          return kFALSE;
3141       }
3142       Info("MergeOutputs", "Submitting merging JDL");
3143       if (!SubmitMerging()) return kFALSE;
3144       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
3145       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
3146       return kFALSE;
3147    }   
3148    // Get the output path
3149    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3150    if (!DirectoryExists(fGridOutputDir)) {
3151       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
3152       return kFALSE;
3153    }
3154    if (!fOutputFiles.Length()) {
3155       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3156       return kFALSE;
3157    }
3158    // Check if fast read option was requested
3159    Info("MergeOutputs", "Started local merging of output files from: alien://%s \
3160         \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
3161    if (fFastReadOption) {
3162       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
3163              \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3164       gEnv->SetValue("XNet.ConnectTimeout",50);
3165       gEnv->SetValue("XNet.RequestTimeout",50);
3166       gEnv->SetValue("XNet.MaxRedirectCount",2);
3167       gEnv->SetValue("XNet.ReconnectTimeout",50);
3168       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
3169    }   
3170    // Make sure we change the temporary directory
3171    gSystem->Setenv("TMPDIR", gSystem->pwd());
3172    // Set temporary compilation directory to current one
3173    gSystem->SetBuildDir(gSystem->pwd(), kTRUE);   
3174    TObjArray *list = fOutputFiles.Tokenize(",");
3175    TIter next(list);
3176    TObjString *str;
3177    TString outputFile;
3178    Bool_t merged = kTRUE;
3179    while((str=(TObjString*)next())) {
3180       outputFile = str->GetString();
3181       Int_t index = outputFile.Index("@");
3182       if (index > 0) outputFile.Remove(index);
3183       TString outputChunk = outputFile;
3184       outputChunk.ReplaceAll(".root", "_*.root");
3185       // Skip already merged outputs
3186       if (!gSystem->AccessPathName(outputFile)) {
3187          if (fOverwriteMode) {
3188             Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
3189             gSystem->Unlink(outputFile);
3190             if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3191                Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
3192                      outputChunk.Data());
3193                gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
3194             }
3195          } else {   
3196             Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
3197             continue;
3198          }   
3199       } else {
3200          if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3201             Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
3202                   outputChunk.Data());
3203             gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
3204          }   
3205       }
3206       if (fMergeExcludes.Contains(outputFile.Data()) || 
3207           fRegisterExcludes.Contains(outputFile.Data())) continue;
3208       // Perform a 'find' command in the output directory, looking for registered outputs    
3209       merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
3210       if (!merged) {
3211          Error("MergeOutputs", "Terminate() will  NOT be executed");
3212          delete list;
3213          return kFALSE;
3214       }
3215       TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
3216       if (fileOpened) fileOpened->Close();
3217    } 
3218    delete list;
3219    return kTRUE;
3220 }   
3221
3222 //______________________________________________________________________________
3223 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
3224 {
3225 // Use the output files connected to output containers from the analysis manager
3226 // rather than the files defined by SetOutputFiles
3227    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
3228       Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
3229    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
3230 }
3231       
3232 //______________________________________________________________________________
3233 void AliAnalysisAlien::SetOutputFiles(const char *list)
3234 {
3235 // Manually set the output files list.
3236 // Removes duplicates. Not allowed if default outputs are not disabled.
3237    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
3238       Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
3239       return;
3240    }
3241    Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
3242    fOutputFiles = "";
3243    TString slist = list;
3244    if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
3245    TObjArray *arr = slist.Tokenize(" "); 
3246    TObjString *os;
3247    TIter next(arr);
3248    TString sout;
3249    while ((os=(TObjString*)next())) {
3250       sout = os->GetString();
3251       if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
3252       if (fOutputFiles.Contains(sout)) continue;
3253       if (!fOutputFiles.IsNull()) fOutputFiles += ",";
3254       fOutputFiles += sout;
3255    }
3256    delete arr;   
3257 }
3258
3259 //______________________________________________________________________________
3260 void AliAnalysisAlien::SetOutputArchive(const char *list)
3261 {
3262 // Manually set the output archive list. Free text - you are on your own...
3263 // Not allowed if default outputs are not disabled.
3264    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
3265       Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
3266       return;
3267    }
3268    Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
3269    fOutputArchive = list;
3270 }
3271
3272 //______________________________________________________________________________
3273 void AliAnalysisAlien::SetProofParameter(const char *pname, const char *value)
3274 {
3275 // Set some PROOF special parameter.
3276    TPair *pair = dynamic_cast<TPair*>(fProofParam.FindObject(pname));
3277    if (pair) {
3278       TObject *old = pair->Key();
3279       TObject *val = pair->Value();
3280       fProofParam.Remove(old);
3281       delete old;
3282       delete val;
3283    }
3284    fProofParam.Add(new TObjString(pname), new TObjString(value));
3285 }
3286
3287 //______________________________________________________________________________
3288 const char *AliAnalysisAlien::GetProofParameter(const char *pname) const
3289 {
3290 // Returns a special PROOF parameter.
3291    TPair *pair = dynamic_cast<TPair*>(fProofParam.FindObject(pname));
3292    if (!pair) return 0;
3293    return pair->Value()->GetName();
3294 }      
3295
3296 //______________________________________________________________________________
3297 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
3298 {
3299 // Start remote grid analysis.
3300    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3301    Bool_t testMode = TestBit(AliAnalysisGrid::kTest);
3302    if (!mgr || !mgr->IsInitialized()) {
3303       Error("StartAnalysis", "You need an initialized analysis manager for this");
3304       return kFALSE;
3305    }
3306    // Are we in PROOF mode ?
3307    if (mgr->IsProofMode()) {
3308       if (testMode) Info("StartAnalysis", "##### Starting PROOF analysis with Proof Lite via the plugin #####");
3309       else Info("StartAnalysis", "##### Starting PROOF analysis on cluster <%s> via the plugin #####", fProofCluster.Data());
3310       if (fProofCluster.IsNull()) {
3311          Error("StartAnalysis", "You need to specify the proof cluster name via SetProofCluster");
3312          return kFALSE;
3313       }   
3314       if (fProofDataSet.IsNull() && !testMode) {
3315          Error("StartAnalysis", "You need to specify a dataset using SetProofDataSet()");
3316          return kFALSE;
3317       }   
3318       // Set the needed environment
3319       gEnv->SetValue("XSec.GSI.DelegProxy","2");
3320       // Do we need to reset PROOF ? The success of the Reset operation cannot be checked
3321       if (fProofReset && !testMode) {
3322          if (fProofReset==1) {
3323             Info("StartAnalysis", "Sending soft reset signal to proof cluster %s", fProofCluster.Data());
3324             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kFALSE);", fProofCluster.Data()));
3325          } else {         
3326             Info("StartAnalysis", "Sending hard reset signal to proof cluster %s", fProofCluster.Data());
3327             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kTRUE);", fProofCluster.Data()));
3328          }
3329          Info("StartAnalysis", "Stopping the analysis. Please use SetProofReset(0) to resume.");
3330          return kFALSE;
3331       }
3332       
3333       if (!testMode) {
3334         // Check if there is an old active session
3335         Long_t nsessions = gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->QuerySessions(\"\")->GetEntries();", fProofCluster.Data()));
3336         if (nsessions) {
3337           Error("StartAnalysis","You have to reset your old session first\n");
3338           return kFALSE;
3339         }
3340       }
3341       // Do we need to change the ROOT version ? The success of this cannot be checked.
3342       if (!fROOTVersion.IsNull() && !testMode) {
3343          gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->SetROOTVersion(\"VO_ALICE@ROOT::%s\");", 
3344                             fProofCluster.Data(), fROOTVersion.Data()));
3345       }
3346       // Connect to PROOF and check the status
3347       Long_t proof = 0;
3348       TString sworkers;
3349       if (fNproofWorkersPerSlave) sworkers = Form("workers=%dx", fNproofWorkersPerSlave);
3350       else if (fNproofWorkers) sworkers = Form("workers=%d", fNproofWorkers);
3351       if (!testMode) {
3352          if (!sworkers.IsNull()) 
3353             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\", \"%s\");", fProofCluster.Data(), sworkers.Data()));
3354          else   
3355             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\");", fProofCluster.Data()));
3356       } else {
3357          proof = gROOT->ProcessLine("TProof::Open(\"\");");
3358          if (!proof) {
3359             Error("StartAnalysis", "Could not start PROOF in test mode");
3360             return kFALSE;
3361          }   
3362       }
3363       if (!proof) {
3364          Error("StartAnalysis", "Could not connect to PROOF cluster <%s>", fProofCluster.Data());
3365          return kFALSE;
3366       }   
3367       if (fNproofWorkersPerSlave*fNproofWorkers > 0)
3368          gROOT->ProcessLine(Form("gProof->SetParallel(%d);", fNproofWorkers));
3369       // Set proof special parameters if any
3370       TIter nextpp(&fProofParam);
3371       TObject *proofparam;
3372       while ((proofparam=nextpp())) {
3373          TString svalue = GetProofParameter(proofparam->GetName());
3374          gROOT->ProcessLine(Form("gProof->SetParameter(\"%s\",%s);", proofparam->GetName(), svalue.Data()));
3375       }   
3376       // Is dataset existing ?
3377       if (!testMode) {
3378          TString dataset = fProofDataSet;
3379          Int_t index = dataset.Index("#");
3380          if (index>=0) dataset.Remove(index);
3381 //         if (!gROOT->ProcessLine(Form("gProof->ExistsDataSet(\"%s\");",fProofDataSet.Data()))) {
3382 //            Error("StartAnalysis", "Dataset %s not existing", fProofDataSet.Data());
3383 //            return kFALSE;
3384 //         }
3385 //         Info("StartAnalysis", "Dataset %s found", dataset.Data());
3386       }
3387       // Is ClearPackages() needed ?
3388       if (TestSpecialBit(kClearPackages)) {
3389          Info("StartAnalysis", "ClearPackages signal sent to PROOF. Use SetClearPackages(kFALSE) to reset this.");
3390          gROOT->ProcessLine("gProof->ClearPackages();");
3391       }
3392       // Is a given aliroot mode requested ?
3393       TList optionsList;
3394       TString parLibs;
3395       if (!fAliRootMode.IsNull()) {
3396          TString alirootMode = fAliRootMode;
3397          if (alirootMode == "default") alirootMode = "";
3398          Info("StartAnalysis", "You are requesting AliRoot mode: %s", fAliRootMode.Data());
3399          optionsList.SetOwner();
3400          optionsList.Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));
3401          // Check the additional libs to be loaded
3402          TString extraLibs;
3403          Bool_t parMode = kFALSE;
3404          if (!alirootMode.IsNull()) extraLibs = "ANALYSIS:OADB:ANALYSISalice";
3405          // Parse the extra libs for .so or .dylib
3406          if (fAdditionalLibs.Length()) {
3407             TString additionalLibs = fAdditionalLibs;
3408             additionalLibs.Strip();
3409             if (additionalLibs.Length() && fFriendLibs.Length())
3410                additionalLibs += " ";
3411             additionalLibs += fFriendLibs;
3412             TObjArray *list = additionalLibs.Tokenize(" ");
3413             TIter next(list);
3414             TObjString *str;
3415             while((str=(TObjString*)next())) {
3416                if (str->GetString().Contains(".so") ||
3417                    str->GetString().Contains(".dylib") ) {
3418                   if (parMode) {
3419                      Warning("StartAnalysis", "Plugin does not support loading libs after par files in PROOF mode. Library %s and following will not load on workers", str->GetName());
3420                      break;
3421                   }   
3422                   TString stmp = str->GetName();
3423                   if (stmp.BeginsWith("lib")) stmp.Remove(0,3);
3424                   stmp.ReplaceAll(".so","");
3425                   stmp.ReplaceAll(".dylib","");
3426                   if (!extraLibs.IsNull()) extraLibs += ":";
3427                   extraLibs += stmp;
3428                   continue;
3429                }
3430                if (str->GetString().Contains(".par")) {
3431                   // The first par file found in the list will not allow any further .so
3432                   parMode = kTRUE;
3433                   if (!parLibs.IsNull()) parLibs += ":";
3434                   parLibs += str->GetName();
3435                   continue;
3436                }   
3437             }
3438             if (list) delete list;            
3439          }
3440          if (!extraLibs.IsNull()) {
3441            Info("StartAnalysis", "Adding extra libs: %s",extraLibs.Data());
3442            optionsList.Add(new TNamed("ALIROOT_EXTRA_LIBS",extraLibs.Data()));
3443          }
3444          // Check extra includes
3445          if (!fIncludePath.IsNull()) {
3446             TString includePath = fIncludePath;
3447             includePath.ReplaceAll(" ",":");
3448             includePath.ReplaceAll("$ALICE_ROOT/","");
3449             includePath.ReplaceAll("${ALICE_ROOT}/","");
3450             includePath.ReplaceAll("-I","");
3451             includePath.Remove(TString::kTrailing, ':');
3452             Info("StartAnalysis", "Adding extra includes: %s",includePath.Data()); 
3453             optionsList.Add(new TNamed("ALIROOT_EXTRA_INCLUDES",includePath.Data()));
3454          }
3455          // Check if connection to grid is requested
3456          if (TestSpecialBit(kProofConnectGrid)) 
3457             optionsList.Add(new TNamed("ALIROOT_ENABLE_ALIEN", "1"));
3458          // Enable AliRoot par
3459          if (testMode) {
3460          // Enable proof lite package
3461             TString alirootLite = gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
3462             for (Int_t i=0; i<optionsList.GetSize(); i++) {
3463                TNamed *obj = (TNamed*)optionsList.At(i);
3464                printf("%s  %s\n", obj->GetName(), obj->GetTitle());
3465             }   
3466             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");",alirootLite.Data()))
3467               && !gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\", (TList*)%p);",alirootLite.Data(),&optionsList))) {
3468                   Info("StartAnalysis", "AliRootProofLite enabled");
3469             } else {                      
3470                Error("StartAnalysis", "There was an error trying to enable package AliRootProofLite.par");
3471                return kFALSE;
3472             }   
3473          } else {
3474            if ( ! fAliROOTVersion.IsNull() ) {
3475              if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"VO_ALICE@AliRoot::%s\", (TList*)%p, kTRUE);", 
3476                                          fAliROOTVersion.Data(), &optionsList))) {
3477                 Error("StartAnalysis", "There was an error trying to enable package VO_ALICE@AliRoot::%s", fAliROOTVersion.Data());
3478                 return kFALSE;
3479              }
3480            }
3481          }
3482          // Enable first par files from fAdditionalLibs
3483          if (!parLibs.IsNull()) {
3484             TObjArray *list = parLibs.Tokenize(":");
3485             TIter next(list);
3486             TObjString *package;
3487             while((package=(TObjString*)next())) {
3488                TString spkg = package->GetName();
3489                spkg.ReplaceAll(".par", "");
3490                gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
3491                if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
3492                   TString enablePackage = (testMode)?Form("gProof->EnablePackage(\"%s\",kFALSE);", package->GetName()):Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName());
3493                   if (gROOT->ProcessLine(enablePackage)) {
3494                      Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
3495                      return kFALSE;
3496                   }
3497                } else {
3498                   Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
3499                   return kFALSE;
3500                }
3501             }
3502             if (list) delete list; 
3503          }
3504       } else {
3505          if ((fAdditionalLibs.Contains(".so") || fAdditionalLibs.Contains(".dylib")) && 
3506              !testMode) {
3507             Error("StartAnalysis", "You request additional libs to be loaded but did not enabled any AliRoot mode. Please refer to: \
3508                    \n http://aaf.cern.ch/node/83 and use a parameter for SetAliRootMode()");
3509             return kFALSE;       
3510          }
3511       }
3512       // Enable par files if requested
3513       if (fPackages && fPackages->GetEntries()) {
3514          TIter next(fPackages);
3515          TObject *package;
3516          while ((package=next())) {
3517             // Skip packages already enabled
3518             if (parLibs.Contains(package->GetName())) continue;
3519             TString spkg = package->GetName();
3520             spkg.ReplaceAll(".par", "");
3521             gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
3522             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
3523                if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName()))) {
3524                   Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
3525                   return kFALSE;
3526                }
3527             } else {
3528                Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
3529                return kFALSE;
3530             }
3531          }
3532       }
3533       // Do we need to load analysis source files ?
3534       // NOTE: don't load on client since this is anyway done by the user to attach his task.
3535       if (fAnalysisSource.Length()) {
3536          TObjArray *list = fAnalysisSource.Tokenize(" ");
3537          TIter next(list);
3538          TObjString *str;
3539          while((str=(TObjString*)next())) {
3540             gROOT->ProcessLine(Form("gProof->Load(\"%s+g\", kTRUE);", str->GetName()));
3541          }
3542          if (list) delete list;
3543       }
3544       if (testMode) {
3545       // Register dataset to proof lite.
3546          if (fFileForTestMode.IsNull()) {
3547             Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
3548             return kFALSE;
3549          }
3550          if (gSystem->AccessPathName(fFileForTestMode)) {
3551             Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
3552             return kFALSE;
3553          }   
3554          TFileCollection *coll = new TFileCollection();
3555          coll->AddFromFile(fFileForTestMode);
3556          gROOT->ProcessLine(Form("gProof->RegisterDataSet(\"test_collection\", (TFileCollection*)%p, \"OV\");", coll));
3557          gROOT->ProcessLine("gProof->ShowDataSets()");
3558       }
3559       return kTRUE;
3560    }
3561    
3562    // Check if output files have to be taken from the analysis manager
3563    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
3564       // Add output files and AOD files
3565       fOutputFiles = GetListOfFiles("outaod");
3566       // Add extra files registered to the analysis manager
3567       TString extra = GetListOfFiles("ext");
3568       if (!extra.IsNull()) {
3569          extra.ReplaceAll(".root", "*.root");
3570          if (!fOutputFiles.IsNull()) fOutputFiles += ",";
3571          fOutputFiles += extra;
3572       }
3573       // Compose the output archive.
3574       fOutputArchive = "log_archive.zip:std*@disk=1 ";
3575       if (mgr->IsCollectThroughput())
3576          fOutputArchive += Form("root_archive.zip:%s,*.stat@disk=%d %s@disk=%d",fOutputFiles.Data(),fNreplicas, mgr->GetFileInfoLog(),fNreplicas);
3577       else
3578          fOutputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",fOutputFiles.Data(),fNreplicas);
3579    }
3580 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
3581    if (TestBit(AliAnalysisGrid::kOffline)) {
3582       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
3583       \n                         there nor any job run. You can revise the JDL and analysis \
3584       \n                         macro then run the same in \"submit\" mode.");
3585    } else if (TestBit(AliAnalysisGrid::kTest)) {
3586       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
3587       \n                         dataset.");
3588    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
3589       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
3590       \n                         space and job submitted.");
3591    } else if (TestBit(AliAnalysisGrid::kMerge)) {
3592       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
3593       if (fMergeViaJDL) CheckInputData();
3594       return kTRUE;
3595    } else {
3596       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
3597    }   
3598       
3599    Print();   
3600    if (!Connect()) {
3601       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
3602       return kFALSE;
3603    }
3604    if (IsCheckCopy() && gGrid) CheckFileCopy(gGrid->GetHomeDirectory());
3605    if (!CheckInputData()) {
3606       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
3607       return kFALSE;
3608    }   
3609    if (!CreateDataset(fDataPattern)) {
3610       TString serror;
3611       if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
3612       if (fRunNumbers.Length()) serror = "run numbers";
3613       if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
3614       serror += Form("\n   or data pattern <%s>", fDataPattern.Data());
3615       Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
3616       return kFALSE;
3617    }   
3618    WriteAnalysisFile();
3619    WriteAnalysisMacro();
3620    WriteExecutable();
3621    WriteValidationScript();
3622    if (fMergeViaJDL) {
3623       WriteMergingMacro();
3624       WriteMergeExecutable();
3625       WriteValidationScript(kTRUE);
3626    }   
3627    if (!CreateJDL()) return kFALSE;
3628    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
3629    if (testMode) {
3630       // Locally testing the analysis
3631       Info("StartAnalysis", "\n_______________________________________________________________________ \
3632       \n   Running analysis script in a daughter shell as on a worker node \
3633       \n_______________________________________________________________________");
3634       TObjArray *list = fOutputFiles.Tokenize(",");
3635       TIter next(list);
3636       TObjString *str;
3637       TString outputFile;
3638       while((str=(TObjString*)next())) {
3639          outputFile = str->GetString();
3640          Int_t index = outputFile.Index("@");
3641          if (index > 0) outputFile.Remove(index);         
3642          if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
3643       }
3644       delete list;
3645       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
3646       gSystem->Exec(Form("bash %s",fValidationScript.Data()));
3647 //      gSystem->Exec("cat stdout");
3648       return kFALSE;
3649    }
3650    // Check if submitting is managed by LPM manager
3651    if (fProductionMode) {
3652       //TString prodfile = fJDLName;
3653       //prodfile.ReplaceAll(".jdl", ".prod");
3654       //WriteProductionFile(prodfile);
3655       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
3656       return kFALSE;
3657    }   
3658    // Submit AliEn job(s)
3659    gGrid->Cd(fGridOutputDir);
3660    TGridResult *res;
3661    TString jobID = "";
3662    fGridJobIDs = "";
3663    fGridStages = "";
3664    if (!fRunNumbers.Length() && !fRunRange[0]) {
3665       // Submit a given xml or a set of runs
3666       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
3667       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
3668       if (res) {
3669          const char *cjobId = res->GetKey(0,"jobId");
3670          if (!cjobId) {
3671             gGrid->Stdout();
3672             gGrid->Stderr();
3673             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
3674             return kFALSE;
3675          } else {
3676             Info("StartAnalysis", "\n_______________________________________________________________________ \
3677             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
3678             \n_______________________________________________________________________",
3679                    fJDLName.Data(), cjobId);
3680             jobID = cjobId;      
3681             if (jobID.Atoi()) { 
3682               if (!fGridJobIDs.IsNull()) fGridJobIDs.Append(" ");
3683               fGridJobIDs.Append(jobID);
3684               if (!fGridStages.IsNull()) fGridStages.Append(" ");
3685               fGridStages.Append("full");
3686             }
3687          }          
3688          delete res;
3689       } else {
3690          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
3691          return kFALSE;      
3692       }   
3693    } else {
3694       // Submit for a range of enumeration of runs.
3695       if (!Submit()) return kFALSE;
3696       jobID = fGridJobIDs;
3697    }   
3698          
3699    if (fDropToShell) {
3700       Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
3701       \n You may exit at any time and terminate the job later using the option <terminate> \
3702       \n ##################################################################################", jobID.Data());
3703       gSystem->Exec("aliensh");
3704    } else {
3705       Info("StartAnalysis", "\n#### SUBMITTED JOB %s TO ALIEN QUEUE #### \
3706       \n Remember to terminate the job later using the option <terminate> \
3707       \n ##################################################################################", jobID.Data());
3708    }   
3709    return kTRUE;
3710 }
3711
3712 //______________________________________________________________________________
3713 const char *AliAnalysisAlien::GetListOfFiles(const char *type)
3714 {
3715 // Get a comma-separated list of output files of the requested type.
3716 // Type can be (case unsensitive):
3717 //    aod - list of aod files (std, extensions and filters)
3718 //    out - list of output files connected to containers (but not aod's or extras)
3719 //    ext - list of extra files registered to the manager
3720 //    ter - list of files produced in terminate
3721    static TString files;
3722    files = "";
3723    TString stype = type;
3724    stype.ToLower();
3725    TString aodfiles, extra;
3726    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3727    if (!mgr) {
3728       ::Error("GetListOfFiles", "Cannot call this without analysis manager");
3729       return files.Data();
3730    }
3731    if (mgr->GetOutputEventHandler()) {
3732       aodfiles = "";
3733       if (mgr->GetOutputEventHandler()->GetFillAOD())
3734          aodfiles = mgr->GetOutputEventHandler()->GetOutputFileName();
3735       TString extraaod = mgr->GetOutputEventHandler()->GetExtraOutputs(kTRUE);
3736       if (!extraaod.IsNull() && mgr->GetOutputEventHandler()->GetFillExtension()) {
3737          if (!aodfiles.IsNull()) aodfiles += ",";
3738          aodfiles += extraaod;
3739       }
3740    }
3741    if (stype.Contains("aod")) {
3742       files = aodfiles;
3743       if (stype == "aod") return files.Data();
3744    }  
3745    // Add output files that are not in the list of AOD files 
3746    TString outputfiles = "";
3747    TIter next(mgr->GetOutputs());
3748    AliAnalysisDataContainer *output;
3749    const char *filename = 0;
3750    while ((output=(AliAnalysisDataContainer*)next())) {
3751       filename = output->GetFileName();
3752       if (!(strcmp(filename, "default"))) continue;
3753       if (outputfiles.Contains(filename)) continue;
3754       if (aodfiles.Contains(filename))    continue;
3755       if (!outputfiles.IsNull() && strlen(filename)) outputfiles += ",";
3756       outputfiles += filename;
3757    }
3758    if (stype.Contains("out")) {
3759       if (!files.IsNull() && !outputfiles.IsNull()) files += ",";
3760       files += outputfiles;
3761       if (stype == "out") return files.Data();
3762    }   
3763    // Add extra files registered to the analysis manager
3764    TString sextra;
3765    extra = mgr->GetExtraFiles();
3766    if (!extra.IsNull()) {
3767       extra.Strip();
3768       extra.ReplaceAll(" ", ",");
3769       TObjArray *fextra = extra.Tokenize(",");
3770       TIter nextx(fextra);
3771       TObject *obj;
3772       while ((obj=nextx())) {
3773          if (aodfiles.Contains(obj->GetName())) continue;
3774          if (outputfiles.Contains(obj->GetName())) continue;
3775          if (sextra.Contains(obj->GetName())) continue;
3776          if (!sextra.IsNull()) sextra += ",";
3777          sextra += obj->GetName();
3778       }
3779       delete fextra;
3780       if (stype.Contains("ext")) {
3781          if (!files.IsNull() && !sextra.IsNull()) files += ",";
3782          files += sextra;
3783       }
3784    }   
3785    if (stype == "ext") return files.Data();
3786    TString termfiles;
3787    if (!fTerminateFiles.IsNull()) {
3788       fTerminateFiles.Strip();
3789       fTerminateFiles.ReplaceAll(" ",",");
3790       TObjArray *fextra = fTerminateFiles.Tokenize(",");
3791       TIter nextx(fextra);
3792       TObject *obj;
3793       while ((obj=nextx())) {
3794          if (aodfiles.Contains(obj->GetName())) continue;
3795          if (outputfiles.Contains(obj->GetName())) continue;
3796          if (termfiles.Contains(obj->GetName())) continue;
3797          if (sextra.Contains(obj->GetName())) continue;
3798          if (!termfiles.IsNull()) termfiles += ",";
3799          termfiles += obj->GetName();
3800       }
3801       delete fextra;
3802    }   
3803    if (stype.Contains("ter")) {
3804       if (!files.IsNull() && !termfiles.IsNull()) {
3805          files += ",";
3806          files += termfiles;
3807       }   
3808    }   
3809    return files.Data();
3810 }   
3811
3812 //______________________________________________________________________________
3813 Bool_t AliAnalysisAlien::Submit()
3814 {
3815 // Submit all master jobs.
3816    Int_t nmasterjobs = fInputFiles->GetEntries();
3817    Long_t tshoot = gSystem->Now();
3818    if (!fNsubmitted && !SubmitNext()) return kFALSE;
3819    while (fNsubmitted < nmasterjobs) {
3820       Long_t now = gSystem->Now();
3821       if ((now-tshoot)>30000) {
3822          tshoot = now;
3823          if (!SubmitNext()) return kFALSE;
3824       }   
3825    }
3826    return kTRUE;
3827 }
3828
3829 //______________________________________________________________________________
3830 Bool_t AliAnalysisAlien::SubmitMerging()
3831 {
3832 // Submit all merging jobs.
3833    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3834    gGrid->Cd(fGridOutputDir);
3835    TString mergeJDLName = fExecutable;
3836    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
3837    if (!fInputFiles) {
3838       Error("SubmitMerging", "You have to use explicit run numbers or run range to merge via JDL!");
3839       return kFALSE;
3840    }   
3841    Int_t ntosubmit = fInputFiles->GetEntries();
3842    for (Int_t i=0; i<ntosubmit; i++) {
3843       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3844       runOutDir.ReplaceAll(".xml", "");
3845       if (fOutputToRunNo) {
3846          // The output directory is the run number
3847          printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
3848          runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
3849       } else {
3850          if (!fRunNumbers.Length() && !fRunRange[0]) {
3851             // The output directory is the grid outdir
3852             printf("### Submitting merging job for the full output directory %s.\n", fGridOutputDir.Data());
3853             runOutDir = fGridOutputDir;
3854          } else {
3855             // The output directory is the master number in 3 digits format
3856             printf("### Submitting merging job for master <%03d>\n", i);
3857             runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
3858          }   
3859       }
3860       // Check now the number of merging stages.
3861       TObjArray *list = fOutputFiles.Tokenize(",");
3862       TIter next(list);
3863       TObjString *str;
3864       TString outputFile;
3865       while((str=(TObjString*)next())) {
3866          outputFile = str->GetString();
3867          Int_t index = outputFile.Index("@");
3868          if (index > 0) outputFile.Remove(index);
3869          if (!fMergeExcludes.Contains(outputFile) && 
3870              !fRegisterExcludes.Contains(outputFile)) break;
3871       }
3872       delete list;
3873       Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, mergeJDLName);
3874       if (!done && (i==ntosubmit-1)) return kFALSE;
3875       if (!fRunNumbers.Length() && !fRunRange[0]) break;
3876    }
3877    if (!ntosubmit) return kTRUE;
3878    if (fDropToShell) {
3879       Info("StartAnalysis", "\n #### STARTING AN ALIEN SHELL FOR YOU. You can exit any time or inspect your jobs in a different shell.##########\
3880                              \n Make sure your jobs are in a final state (you can resubmit failed ones via 'masterjob <id> resubmit ERROR_ALL')\
3881                              \n Rerun in 'terminate' mode to submit all merging stages, each AFTER the previous one completed. The final merged \
3882                              \n output will be written to your alien output directory, while separate stages in <Stage_n>. \
3883                              \n ################################################################################################################");
3884       gSystem->Exec("aliensh");
3885    } else {
3886       Info("StartAnalysis", "\n #### STARTED MERGING JOBS FOR YOU #### \
3887                              \n Make sure your jobs are in a final state (you can resubmit failed ones via 'masterjob <id> resubmit ERROR_ALL') \
3888                              \n Rerun in 'terminate' mode to submit all merging stages, each AFTER the previous one completed. The final merged \
3889                              \n output will be written to your alien output directory, while separate stages in <Stage_n>. \
3890                              \n ################################################################################################################");   
3891    }   
3892    return kTRUE;
3893 }
3894
3895 //______________________________________________________________________________
3896 Bool_t AliAnalysisAlien::SubmitNext()
3897 {
3898 // Submit next bunch of master jobs if the queue is free. The first master job is
3899 // submitted right away, while the next will not be unless the previous was split.
3900 // The plugin will not submit new master jobs if there are more that 500 jobs in
3901 // waiting phase.
3902    static Bool_t iscalled = kFALSE;
3903    static Int_t firstmaster = 0;
3904    static Int_t lastmaster = 0;
3905    static Int_t npermaster  = 0;
3906    if (iscalled) return kTRUE;
3907    iscalled = kTRUE;
3908    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
3909    Int_t ntosubmit = 0;
3910    TGridResult *res;
3911    TString jobID = "";
3912    Int_t nmasterjobs = fInputFiles->GetEntries();
3913    if (!fNsubmitted) {
3914       ntosubmit = 1;
3915       if (!IsUseSubmitPolicy()) {
3916          if (nmasterjobs>5)
3917             Info("SubmitNext","### Warning submit policy not used ! Submitting too many jobs at a time may be prohibitted. \
3918                 \n### You can use SetUseSubmitPolicy() to enable if you have problems.");
3919          ntosubmit = nmasterjobs;
3920       }   
3921    } else {
3922       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
3923       printf("=== master %d: %s\n", lastmaster, status.Data());
3924       // If last master not split, just return
3925       if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
3926       // No more than 100 waiting jobs
3927       if (nwaiting>500) {iscalled = kFALSE; return kTRUE;}
3928       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
3929       if (npermaster) ntosubmit = (500-nwaiting)/npermaster;
3930       if (!ntosubmit) ntosubmit = 1;
3931       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
3932              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
3933    }
3934    for (Int_t i=0; i<ntosubmit; i++) {
3935       // Submit for a range of enumeration of runs.
3936       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
3937       TString query;
3938       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
3939       runOutDir.ReplaceAll(".xml", "");
3940       if (fOutputToRunNo)
3941          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
3942       else
3943          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
3944       printf("********* %s\n",query.Data());
3945       res = gGrid->Command(query);
3946       if (res) {
3947          TString cjobId1 = res->GetKey(0,"jobId");
3948          if (!cjobId1.Length()) {
3949             iscalled = kFALSE;
3950             gGrid->Stdout();
3951             gGrid->Stderr();
3952             Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
3953             return kFALSE;
3954          } else {
3955             Info("StartAnalysis", "\n_______________________________________________________________________ \
3956             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
3957             \n_______________________________________________________________________",
3958                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
3959             if (!fGridJobIDs.IsNull()) fGridJobIDs.Append(" ");
3960             fGridJobIDs.Append(cjobId1);
3961             if (!fGridStages.IsNull()) fGridStages.Append(" ");
3962             fGridStages.Append("full");
3963             jobID += cjobId1;
3964             jobID += " ";
3965             lastmaster = cjobId1.Atoi();
3966             if (!firstmaster) firstmaster = lastmaster;
3967             fNsubmitted++;
3968          }          
3969          delete res;
3970       } else {
3971          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
3972          return kFALSE;
3973       }   
3974    }
3975    iscalled = kFALSE;
3976    return kTRUE;
3977 }
3978
3979 //______________________________________________________________________________
3980 void AliAnalysisAlien::WriteAnalysisFile()
3981 {
3982 // Write current analysis manager into the file <analysisFile>
3983    TString analysisFile = fExecutable;
3984    analysisFile.ReplaceAll(".sh", ".root");
3985    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3986       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3987       if (!mgr || !mgr->IsInitialized()) {
3988          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
3989          return;
3990       }
3991       // Check analysis type
3992       TObject *handler;
3993       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
3994       handler = (TObject*)mgr->GetInputEventHandler();
3995       if (handler) {
3996          if (handler->InheritsFrom("AliMultiInputEventHandler")) {
3997             AliMultiInputEventHandler *multiIH = (AliMultiInputEventHandler*)handler;
3998             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
3999             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
4000          } else {
4001             if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
4002             if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
4003          }
4004       }
4005       TDirectory *cdir = gDirectory;
4006       TFile *file = TFile::Open(analysisFile, "RECREATE");
4007       if (file) {
4008          // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
4009          if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
4010          // Unless merging makes no sense
4011          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
4012          mgr->Write();
4013          delete file;
4014          // Enable termination for local jobs
4015          mgr->SetSkipTerminate(kFALSE);
4016       }
4017       if (cdir) cdir->cd();
4018       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
4019    }   
4020    Bool_t copy = kTRUE;
4021    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4022    if (copy) {
4023       CdWork();
4024       TString workdir = gGrid->GetHomeDirectory();
4025       workdir += fGridWorkingDir;
4026       Info("WriteAnalysisFile", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
4027       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
4028       if (!copyLocal2Alien("WriteAnalysisFile",analysisFile.Data(), 
4029           Form("%s/%s", workdir.Data(),analysisFile.Data()))) Fatal("","Terminating");
4030    }   
4031 }
4032
4033 //______________________________________________________________________________
4034 void AliAnalysisAlien::WriteAnalysisMacro()
4035 {
4036 // Write the analysis macro that will steer the analysis in grid mode.
4037    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
4038       ofstream out;
4039       out.open(fAnalysisMacro.Data(), ios::out);
4040       if (!out.good()) {
4041          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
4042          return;
4043       }
4044       Bool_t hasSTEERBase = kFALSE;
4045       Bool_t hasESD = kFALSE;
4046       Bool_t hasAOD = kFALSE;
4047       Bool_t hasANALYSIS = kFALSE;
4048       Bool_t hasOADB = kFALSE;
4049       Bool_t hasANALYSISalice = kFALSE;
4050       Bool_t hasCORRFW = kFALSE;
4051       TString func = fAnalysisMacro;
4052       TString type = "ESD";
4053       TString comment = "// Analysis using ";
4054       if (fMCLoop) {
4055          type = "MCGEN";
4056          comment += "MCGEN";
4057       } else {
4058          if (IsUseMCchain()) {
4059             type = "MC";
4060             comment += "MC";
4061          } else {   
4062             if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
4063             if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
4064                type = "AOD";
4065                comment += "AOD";
4066             }   
4067          }
4068       }   
4069       if (type!="AOD" && fFriendChainName!="") {
4070          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
4071          return;
4072       }
4073       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
4074       else comment += " data";
4075       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
4076       func.ReplaceAll(".C", "");
4077       out << "void " << func.Data() << "()" << endl; 
4078       out << "{" << endl;
4079       out << comment.Data() << endl;
4080       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
4081       out << "   TStopwatch timer;" << endl;
4082       out << "   timer.Start();" << endl << endl;
4083       // Change temp directory to current one
4084       if (!IsLocalTest()) {  
4085          out << "// connect to AliEn and make the chain" << endl;
4086          out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
4087       }   
4088       out << "// Set temporary merging directory to current one" << endl;
4089       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
4090       out << "// Set temporary compilation directory to current one" << endl;
4091       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
4092       // Reset existing include path
4093       out << "// Reset existing include path and add current directory first in the search" << endl;
4094       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
4095       if (!fExecutableCommand.Contains("aliroot")) {
4096          out << "// load base root libraries" << endl;
4097          out << "   gSystem->Load(\"libTree\");" << endl;
4098          out << "   gSystem->Load(\"libGeom\");" << endl;
4099          out << "   gSystem->Load(\"libVMC\");" << endl;
4100          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
4101          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
4102       }   
4103       if (fAdditionalRootLibs.Length()) {
4104          // in principle libtree /lib geom libvmc etc. can go into this list, too
4105          out << "// Add aditional libraries" << endl;
4106          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
4107          TIter next(list);
4108          TObjString *str;
4109          while((str=(TObjString*)next())) {
4110             if (str->GetString().Contains(".so") || str->GetString().Contains(".dylib"))
4111             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
4112          }
4113          if (list) delete list;
4114       }
4115       out << "// Load analysis framework libraries" << endl;
4116       TString setupPar = "AliAnalysisAlien::SetupPar";
4117       if (!fPackages) {
4118          if (!fExecutableCommand.Contains("aliroot")) {         
4119             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
4120             out << "   gSystem->Load(\"libESD\");" << endl;
4121             out << "   gSystem->Load(\"libAOD\");" << endl;
4122          }   
4123          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
4124          out << "   gSystem->Load(\"libOADB\");" << endl;
4125          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
4126          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
4127       } else {
4128          TIter next(fPackages);
4129          TObject *obj;
4130          TString pkgname;
4131          while ((obj=next())) {
4132             pkgname = obj->GetName();
4133             if (pkgname == "STEERBase" ||
4134                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
4135             if (pkgname == "ESD" ||
4136                 pkgname == "ESD.par")       hasESD = kTRUE;
4137             if (pkgname == "AOD" ||
4138                 pkgname == "AOD.par")       hasAOD = kTRUE;
4139             if (pkgname == "ANALYSIS" ||
4140                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
4141             if (pkgname == "OADB" ||
4142                 pkgname == "OADB.par")      hasOADB = kTRUE;
4143             if (pkgname == "ANALYSISalice" ||
4144                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
4145             if (pkgname == "CORRFW" ||
4146                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
4147          }
4148          if (hasANALYSISalice) setupPar = "SetupPar";   
4149          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
4150          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
4151          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
4152          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
4153          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
4154          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
4155          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
4156          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
4157          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
4158          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
4159          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
4160          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
4161          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
4162          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
4163          out << "// Compile other par packages" << endl;
4164          next.Reset();
4165          while ((obj=next())) {
4166             pkgname = obj->GetName();
4167             if (pkgname == "STEERBase" ||
4168                 pkgname == "STEERBase.par" ||
4169                 pkgname == "ESD" ||
4170                 pkgname == "ESD.par" ||
4171                 pkgname == "AOD" ||
4172                 pkgname == "AOD.par" ||
4173                 pkgname == "ANALYSIS" ||
4174                 pkgname == "ANALYSIS.par" ||
4175                 pkgname == "OADB" ||
4176                 pkgname == "OADB.par" ||
4177                 pkgname == "ANALYSISalice" ||
4178                 pkgname == "ANALYSISalice.par" ||
4179                 pkgname == "CORRFW" ||
4180                 pkgname == "CORRFW.par") continue;
4181             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
4182          }   
4183       }   
4184       out << "// include path" << endl;
4185       // Get the include path from the interpreter and remove entries pointing to AliRoot
4186       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
4187       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
4188       out << "   TIter nextpath(listpaths);" << endl;
4189       out << "   TObjString *pname;" << endl;
4190       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
4191       out << "      TString current = pname->GetName();" << endl;
4192       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
4193       out << "      gSystem->AddIncludePath(current);" << endl;
4194       out << "   }" << endl;
4195       out << "   if (listpaths) delete listpaths;" << endl;
4196       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
4197       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
4198       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
4199       if (fMCLoop && !fGeneratorLibs.IsNull()) {
4200          out << "// MC generator libraries" << endl;
4201          TObjArray *list = fGeneratorLibs.Tokenize(" ");
4202          TIter next(list);
4203          TObjString *str;
4204          while((str=(TObjString*)next())) {
4205             out << "   gSystem->Load(\"" << str->GetName() << "\");" << endl;
4206          }
4207          delete list;
4208       }
4209       if (fAdditionalLibs.Length()) {
4210          out << "// Add aditional AliRoot libraries" << endl;
4211          TString additionalLibs = fAdditionalLibs;
4212          additionalLibs.Strip();
4213          if (additionalLibs.Length() && fFriendLibs.Length())
4214             additionalLibs += " ";
4215          additionalLibs += fFriendLibs;
4216          TObjArray *list = additionalLibs.Tokenize(" ");
4217          TIter next(list);
4218          TObjString *str;
4219          while((str=(TObjString*)next())) {
4220             if (str->GetString().Contains(".so") || str->GetString().Contains(".dylib"))
4221                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
4222             if (str->GetString().Contains(".par"))
4223                out << "   if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
4224          }
4225          delete list;
4226       }
4227       out << endl;
4228       out << "// analysis source to be compiled at runtime (if any)" << endl;
4229       if (fAnalysisSource.Length()) {
4230          TObjArray *list = fAnalysisSource.Tokenize(" ");
4231          TIter next(list);
4232          TObjString *str;
4233          while((str=(TObjString*)next())) {
4234             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
4235          }   
4236          if (list) delete list;
4237       }
4238       out << endl;
4239 //      out << "   printf(\"Currently load libraries:\\n\");" << endl;
4240 //      out << "   printf(\"%s\\n\", gSystem->GetLibraries());" << endl;
4241       if (fFastReadOption) {
4242          Warning("WriteAnalysisMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid jobs. This may skip some files that could be accessed !!! \
4243                 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
4244          out << "// fast xrootd reading enabled" << endl;
4245          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
4246          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
4247          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
4248          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
4249          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
4250          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
4251       } 
4252       out << "// read the analysis manager from file" << endl;
4253       TString analysisFile = fExecutable;
4254       analysisFile.ReplaceAll(".sh", ".root");
4255       out << "   AliAnalysisManager *mgr = AliAnalysisAlien::LoadAnalysisManager(\"" 
4256           << analysisFile << "\");" << endl;
4257       out << "   if (!mgr) return;" << endl;
4258       if (IsLocalTest()) {
4259          out << "   AliAnalysisAlien *plugin = new AliAnalysisAlien();" << endl;
4260          out << "   plugin->SetRunMode(\"test\");" << endl;
4261          if (fFileForTestMode.IsNull())
4262             out << "   plugin->SetFileForTestMode(\"data.txt\");" << endl;
4263          else   
4264             out << "   plugin->SetFileForTestMode(\"" << fFileForTestMode << "\");" << endl;
4265          out << "   plugin->SetNtestFiles(" << fNtestFiles << ");" << endl;
4266          if (!fFriendChainName.IsNull()) 
4267             out << "   plugin->SetFriendChainName(\"" << fFriendChainName << "\",\"" << fFriendLibs << "\");" << endl;
4268          if (IsUseMCchain())
4269             out << "   plugin->SetUseMCchain();" << endl;
4270          if (fMCLoop)
4271             out << "   plugin->SetMCLoop(kTRUE);" << endl;  
4272          out << "   mgr->SetGridHandler(plugin);" << endl;
4273          if (AliAnalysisManager::GetAnalysisManager()) {
4274             out << "   mgr->SetDebugLevel(" << AliAnalysisManager::GetAnalysisManager()->GetDebugLevel() << ");" << endl;
4275             out << "   mgr->SetNSysInfo(" << AliAnalysisManager::GetAnalysisManager()->GetNsysInfo() << ");" << endl;
4276          } else {
4277             out << "   mgr->SetDebugLevel(10);" << endl;
4278             out << "   mgr->SetNSysInfo(100);" << endl;
4279          }
4280       }
4281       out << "   mgr->PrintStatus();" << endl;
4282       if (AliAnalysisManager::GetAnalysisManager()) {
4283          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
4284             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
4285          } else {
4286             if (TestBit(AliAnalysisGrid::kTest))            
4287                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
4288             else
4289                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
4290          }
4291       }   
4292       if (!IsLocalTest()) {
4293          if (fMCLoop) {
4294             out << "   mgr->SetCacheSize(0);" << endl;
4295             out << "   mgr->EventLoop(" << fNMCevents << ");" << endl;
4296          } else {   
4297             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;   
4298             out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
4299          }   
4300       } else {
4301          if (fMCLoop) {
4302             out << "   mgr->SetCacheSize(0);" << endl;
4303             out << "   mgr->EventLoop(" << fNMCevents << ");" << endl;         
4304          } else {
4305             out << "   mgr->StartAnalysis(\"localfile\");" << endl;
4306          }   
4307       }   
4308       out << "   timer.Stop();" << endl;
4309       out << "   timer.Print();" << endl;
4310       out << "}" << endl << endl;
4311       if (!IsLocalTest() && !fMCLoop) {
4312          out <<"//________________________________________________________________________________" << endl;
4313          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
4314          out << "{" << endl;
4315          out << "// Create a chain using url's from xml file" << endl;
4316          out << "   TString filename;" << endl;
4317          out << "   Int_t run = 0;" << endl;
4318          if (IsUseMCchain()) {
4319             out << "   TString treename = \"TE\";" << endl;
4320          } else {   
4321             if (!fTreeName.IsNull()) {
4322                out << "   TString treename = \"" << fTreeName << "\";" << endl;
4323             } else {   
4324                out << "   TString treename = type;" << endl;
4325                out << "   treename.ToLower();" << endl;
4326                out << "   treename += \"Tree\";" << endl;
4327             }   
4328          }   
4329          out << "   printf(\"***************************************\\n\");" << endl;
4330          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
4331          out << "   printf(\"***************************************\\n\");" << endl;
4332          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
4333          out << "   if (!coll) {" << endl;
4334          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
4335          out << "      return NULL;" << endl;
4336          out << "   }" << endl;
4337          out << "   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();" << endl;
4338          out << "   TChain *chain = new TChain(treename);" << endl;
4339          if(!fFriendChainName.IsNull()) {
4340             out << "   TList *friends = new TList();" << endl;
4341             out << "   TIter nextfriend(friends);" << endl;
4342             out << "   TChain *cfriend = 0;" << endl;
4343             TObjArray *list = fFriendChainName.Tokenize(" ");
4344             TIter next(list);
4345             TObjString *str;
4346             while((str=(TObjString*)next())) {
4347                out << "   cfriend = new TChain(treename, \"" << str->GetName() << "\");" << endl;
4348                out << "   friends->Add(cfriend);" << endl;
4349                out << "   chain->AddFriend(cfriend);" << endl;
4350             }
4351             delete list;   
4352 //            out << "   TChain *chainFriend = new TChain(treename);" << endl;
4353          }
4354          out << "   coll->Reset();" << endl;
4355          out << "   while (coll->Next()) {" << endl;
4356          out << "      filename = coll->GetTURL("");" << endl;
4357          out << "      if (mgr) {" << endl;
4358          out << "         Int_t nrun = AliAnalysisManager::GetRunFromAlienPath(filename);" << endl;
4359          out << "         if (nrun && nrun != run) {" << endl;
4360          out << "            printf(\"### Run number detected from chain: %d\\n\", nrun);" << endl;
4361          out << "            mgr->SetRunFromPath(nrun);" << endl;
4362          out << "            run = nrun;" << endl;
4363          out << "         }" << endl;
4364          out << "      }" << endl;
4365          out << "      chain->Add(filename);" << endl;
4366          if(!fFriendChainName.IsNull()) {
4367             out << "      TString bpath=coll->GetTURL(\"\");" << endl;
4368             out << "      if (bpath.Index(\"#\") > -1) bpath.Remove(bpath.Index(\"#\"));" << endl;
4369             out << "      bpath = gSystem->DirName(bpath);" << endl;
4370             out << "      bpath += \"/\";" << endl;
4371             out << "      TString fileFriend;" << endl;
4372             out << "      nextfriend.Reset();" << endl;
4373             out << "      while ((cfriend=(TChain*)nextfriend())) {" << endl;
4374             out << "         fileFriend = bpath;" << endl;
4375             out << "         fileFriend += cfriend->GetTitle();" << endl;
4376             out << "         TFile *file = TFile::Open(fileFriend);" << endl;
4377             out << "         if (file) {" << endl;
4378             out << "            file->Close();" << endl;
4379             out << "            cfriend->Add(fileFriend.Data());" << endl;
4380             out << "         } else {" << endl;
4381             out << "            ::Fatal(\"CreateChain\", \"Cannot open friend file: %s\", fileFriend.Data());" << endl;
4382             out << "            return 0;" << endl;
4383             out << "         }" << endl;
4384             out << "      }" << endl;
4385          }
4386          out << "   }" << endl;
4387          out << "   if (!chain->GetNtrees()) {" << endl;
4388          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
4389          out << "      return NULL;" << endl;
4390          out << "   }" << endl;
4391          out << "   return chain;" << endl;
4392          out << "}" << endl << endl;
4393       }   
4394       if (hasANALYSISalice) {
4395          out <<"//________________________________________________________________________________" << endl;
4396          out << "Bool_t SetupPar(const char *package) {" << endl;
4397          out << "// Compile the package and set it up." << endl;
4398          out << "   TString pkgdir = package;" << endl;
4399          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
4400          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
4401          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
4402          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
4403          out << "   // Check for BUILD.sh and execute" << endl;
4404          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
4405          out << "      printf(\"*******************************\\n\");" << endl;
4406          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
4407          out << "      printf(\"*******************************\\n\");" << endl;
4408          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
4409          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
4410          out << "         gSystem->ChangeDirectory(cdir);" << endl;
4411          out << "         return kFALSE;" << endl;
4412          out << "      }" << endl;
4413          out << "   } else {" << endl;
4414          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
4415          out << "      gSystem->ChangeDirectory(cdir);" << endl;
4416          out << "      return kFALSE;" << endl;
4417          out << "   }" << endl;
4418          out << "   // Check for SETUP.C and execute" << endl;
4419          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
4420          out << "      printf(\"*******************************\\n\");" << endl;
4421          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
4422          out << "      printf(\"*******************************\\n\");" << endl;
4423          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
4424          out << "   } else {" << endl;
4425          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
4426          out << "      gSystem->ChangeDirectory(cdir);" << endl;
4427          out << "      return kFALSE;" << endl;
4428          out << "   }" << endl;
4429          out << "   // Restore original workdir" << endl;
4430          out << "   gSystem->ChangeDirectory(cdir);" << endl;
4431          out << "   return kTRUE;" << endl;
4432          out << "}" << endl;
4433       }
4434       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
4435    }   
4436    Bool_t copy = kTRUE;
4437    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4438    if (copy) {
4439       CdWork();
4440       TString workdir = gGrid->GetHomeDirectory();
4441       workdir += fGridWorkingDir;
4442       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
4443       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
4444 //      TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
4445       if (!copyLocal2Alien("WriteAnalysisMacro",fAnalysisMacro.Data(), 
4446            Form("alien://%s/%s", workdir.Data(), 
4447            fAnalysisMacro.Data()))) Fatal("","Terminating");
4448    }
4449 }
4450
4451 //______________________________________________________________________________
4452 void AliAnalysisAlien::WriteMergingMacro()
4453 {
4454 // Write a macro to merge the outputs per master job.
4455    if (!fMergeViaJDL) return;
4456    if (!fOutputFiles.Length()) {
4457       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
4458       return;
4459    }   
4460    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
4461    TString mergingMacro = fExecutable;
4462    mergingMacro.ReplaceAll(".sh","_merge.C");
4463    if (gGrid && !fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
4464    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
4465       ofstream out;
4466       out.open(mergingMacro.Data(), ios::out);
4467       if (!out.good()) {
4468          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
4469          return;
4470       }
4471       Bool_t hasSTEERBase = kFALSE;
4472       Bool_t hasESD = kFALSE;
4473       Bool_t hasAOD = kFALSE;
4474       Bool_t hasANALYSIS = kFALSE;
4475       Bool_t hasOADB = kFALSE;
4476       Bool_t hasANALYSISalice = kFALSE;
4477       Bool_t hasCORRFW = kFALSE;
4478       TString func = mergingMacro;
4479       TString comment;
4480       func.ReplaceAll(".C", "");
4481       out << "void " << func.Data() << "(const char *dir, Int_t stage=0)" << endl;
4482       out << "{" << endl;
4483       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
4484       out << "   TStopwatch timer;" << endl;
4485       out << "   timer.Start();" << endl << endl;
4486       // Reset existing include path
4487       out << "// Reset existing include path and add current directory first in the search" << endl;
4488       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
4489       if (!fExecutableCommand.Contains("aliroot")) {
4490          out << "// load base root libraries" << endl;
4491          out << "   gSystem->Load(\"libTree\");" << endl;
4492          out << "   gSystem->Load(\"libGeom\");" << endl;
4493          out << "   gSystem->Load(\"libVMC\");" << endl;
4494          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
4495          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
4496       }   
4497       if (fAdditionalRootLibs.Length()) {
4498          // in principle libtree /lib geom libvmc etc. can go into this list, too
4499          out << "// Add aditional libraries" << endl;
4500          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
4501          TIter next(list);
4502          TObjString *str;
4503          while((str=(TObjString*)next())) {
4504             if (str->GetString().Contains(".so") || str->GetString().Contains(".dylib"))
4505             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
4506          }
4507          if (list) delete list;
4508       }
4509       out << "// Load analysis framework libraries" << endl;
4510       if (!fPackages) {
4511          if (!fExecutableCommand.Contains("aliroot")) {
4512             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
4513             out << "   gSystem->Load(\"libESD\");" << endl;
4514             out << "   gSystem->Load(\"libAOD\");" << endl;
4515          }
4516          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
4517          out << "   gSystem->Load(\"libOADB\");" << endl;
4518          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
4519          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
4520       } else {
4521          TIter next(fPackages);
4522          TObject *obj;
4523          TString pkgname;
4524          TString setupPar = "AliAnalysisAlien::SetupPar";
4525          while ((obj=next())) {
4526             pkgname = obj->GetName();
4527             if (pkgname == "STEERBase" ||
4528                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
4529             if (pkgname == "ESD" ||
4530                 pkgname == "ESD.par")       hasESD = kTRUE;
4531             if (pkgname == "AOD" ||
4532                 pkgname == "AOD.par")       hasAOD = kTRUE;
4533             if (pkgname == "ANALYSIS" ||
4534                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
4535             if (pkgname == "OADB" ||
4536                 pkgname == "OADB.par")      hasOADB = kTRUE;
4537             if (pkgname == "ANALYSISalice" ||
4538                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
4539             if (pkgname == "CORRFW" ||
4540                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
4541          }   
4542          if (hasANALYSISalice) setupPar = "SetupPar";   
4543          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
4544          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
4545          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
4546          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
4547          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
4548          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
4549          out << "   gSystem->Load(\"libOADB\");" << endl;
4550          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
4551          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
4552          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
4553          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
4554          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
4555          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
4556          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
4557          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
4558          out << "// Compile other par packages" << endl;
4559          next.Reset();
4560          while ((obj=next())) {
4561             pkgname = obj->GetName();
4562             if (pkgname == "STEERBase" ||
4563                 pkgname == "STEERBase.par" ||
4564                 pkgname == "ESD" ||
4565                 pkgname == "ESD.par" ||
4566                 pkgname == "AOD" ||
4567                 pkgname == "AOD.par" ||
4568                 pkgname == "ANALYSIS" ||
4569                 pkgname == "ANALYSIS.par" ||
4570                 pkgname == "OADB" ||
4571                 pkgname == "OADB.par" ||
4572                 pkgname == "ANALYSISalice" ||
4573                 pkgname == "ANALYSISalice.par" ||
4574                 pkgname == "CORRFW" ||
4575                 pkgname == "CORRFW.par") continue;
4576             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
4577          }   
4578       }   
4579       out << "// include path" << endl;
4580       // Get the include path from the interpreter and remove entries pointing to AliRoot
4581       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
4582       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
4583       out << "   TIter nextpath(listpaths);" << endl;
4584       out << "   TObjString *pname;" << endl;
4585       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
4586       out << "      TString current = pname->GetName();" << endl;
4587       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
4588       out << "      gSystem->AddIncludePath(current);" << endl;
4589       out << "   }" << endl;
4590       out << "   if (listpaths) delete listpaths;" << endl;
4591       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
4592       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
4593       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
4594       if (fMCLoop && !fGeneratorLibs.IsNull()) {
4595          out << "// MC generator libraries" << endl;
4596          TObjArray *list = fGeneratorLibs.Tokenize(" ");
4597          TIter next(list);
4598          TObjString *str;
4599          while((str=(TObjString*)next())) {
4600             out << "   gSystem->Load(\"" << str->GetName() << "\");" << endl;
4601          }
4602          delete list;
4603       }
4604       if (fAdditionalLibs.Length()) {
4605          out << "// Add aditional AliRoot libraries" << endl;
4606          TString additionalLibs = fAdditionalLibs;
4607          additionalLibs.Strip();
4608          if (additionalLibs.Length() && fFriendLibs.Length())
4609             additionalLibs += " ";
4610          additionalLibs += fFriendLibs;
4611          TObjArray *list = additionalLibs.Tokenize(" ");
4612          TIter next(list);
4613          TObjString *str;
4614          while((str=(TObjString*)next())) {
4615             if (str->GetString().Contains(".so") || str->GetString().Contains(".dylib"))
4616                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
4617          }
4618          if (list) delete list;
4619       }
4620       out << endl;
4621       out << "// Analysis source to be compiled at runtime (if any)" << endl;
4622       if (fAnalysisSource.Length()) {
4623          TObjArray *list = fAnalysisSource.Tokenize(" ");
4624          TIter next(list);
4625          TObjString *str;
4626          while((str=(TObjString*)next())) {
4627             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
4628          }   
4629          if (list) delete list;
4630       }
4631       out << endl;      
4632
4633       if (fFastReadOption) {
4634          Warning("WriteMergingMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid merging jobs. Note that this may skip some files that could be accessed !!!");
4635          out << "// fast xrootd reading enabled" << endl;
4636          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
4637          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
4638          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
4639          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
4640          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
4641          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
4642       }
4643       // Change temp directory to current one
4644       out << "// Connect to AliEn" << endl;
4645       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
4646       out << "// Set temporary merging directory to current one" << endl;
4647       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
4648       out << "// Set temporary compilation directory to current one" << endl;
4649       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
4650       out << "   TString outputDir = dir;" << endl;  
4651       if (IsMergeAOD())
4652          out << "   TString outputFiles = \"" << GetListOfFiles("outaod") << "\";" << endl;
4653       else   
4654          out << "   TString outputFiles = \"" << GetListOfFiles("out") << "\";" << endl;
4655       out << "   TString mergeExcludes = \"" << fMergeExcludes << " " << fRegisterExcludes << "\";" << endl;
4656       out << "   TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
4657       out << "   TIter *iter = new TIter(list);" << endl;
4658       out << "   TObjString *str;" << endl;
4659       out << "   TString outputFile;" << endl;
4660       out << "   Bool_t merged = kTRUE;" << endl;
4661       TString analysisFile = fExecutable;
4662       analysisFile.ReplaceAll(".sh", ".root");
4663       out << "   AliAnalysisManager *mgr = AliAnalysisAlien::LoadAnalysisManager(\""
4664           << analysisFile << "\");" << endl;
4665       out << "   if (!mgr) {" << endl;
4666       out << "      printf(\"ERROR: Analysis manager could not be extracted from file \");" << endl;
4667       out << "      return;" << endl;
4668       out << "   }" << endl;
4669       if (IsLocalTest()) {
4670          out << "   printf(\"===================================\\n\");" << endl;      
4671          out << "   printf(\"Testing merging...\\n\");" << endl;
4672          out << "   printf(\"===================================\\n\");" << endl;
4673       }        
4674       out << "   while((str=(TObjString*)iter->Next())) {" << endl;
4675       out << "      outputFile = str->GetString();" << endl;
4676       out << "      if (outputFile.Contains(\"*\")) continue;" << endl;
4677       out << "      Int_t index = outputFile.Index(\"@\");" << endl;
4678       out << "      if (index > 0) outputFile.Remove(index);" << endl;
4679       out << "      // Skip already merged outputs" << endl;
4680       out << "      if (!gSystem->AccessPathName(outputFile)) {" << endl;
4681       out << "         printf(\"Output file <%s> found. Not merging again.\\n\",outputFile.Data());" << endl;
4682       out << "         continue;" << endl;
4683       out << "      }" << endl;
4684       out << "      if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
4685       out << "      merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage);" << endl;
4686       out << "      if (!merged) {" << endl;
4687       out << "         printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
4688       out << "         return;" << endl;
4689       out << "      }" << endl;
4690       out << "   }" << endl;
4691       if (mgr && mgr->IsCollectThroughput() && !IsLocalTest()) {
4692          out << "   TString infolog = \"" << mgr->GetFileInfoLog() << "\";" << endl;
4693          out << "   AliAnalysisAlien::MergeInfo(infolog, outputDir);" << endl;
4694       }
4695       out << "   // all outputs merged, validate" << endl;
4696       out << "   ofstream out;" << endl;
4697       out << "   out.open(\"outputs_valid\", ios::out);" << endl;
4698       out << "   out.close();" << endl;
4699       out << "   // read the analysis manager from file" << endl;
4700       if (IsLocalTest()) {
4701          out << "   printf(\"===================================\\n\");" << endl;      
4702          out << "   printf(\"Testing Terminate()...\\n\");" << endl;
4703          out << "   printf(\"===================================\\n\");" << endl;      
4704       } else {   
4705          out << "   if (!outputDir.Contains(\"Stage\")) return;" << endl;
4706       }   
4707       out << "   mgr->SetRunFromPath(mgr->GetRunFromAlienPath(dir));" << endl;
4708       out << "   mgr->SetSkipTerminate(kFALSE);" << endl;
4709       out << "   mgr->PrintStatus();" << endl;
4710       if (mgr) {
4711          if (mgr->GetDebugLevel()>3) {
4712             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
4713          } else {
4714             if (TestBit(AliAnalysisGrid::kTest))            
4715                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
4716             else
4717                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
4718          }
4719       }   
4720       out << "   TTree *tree = NULL;" << endl;
4721       out << "   mgr->StartAnalysis(\"gridterminate\", tree);" << endl;
4722       out << "}" << endl << endl;
4723       if (hasANALYSISalice) {
4724          out <<"//________________________________________________________________________________" << endl;
4725          out << "Bool_t SetupPar(const char *package) {" << endl;
4726          out << "// Compile the package and set it up." << endl;
4727          out << "   TString pkgdir = package;" << endl;
4728          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
4729          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
4730          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
4731          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
4732          out << "   // Check for BUILD.sh and execute" << endl;
4733          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
4734          out << "      printf(\"*******************************\\n\");" << endl;
4735          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
4736          out << "      printf(\"*******************************\\n\");" << endl;
4737          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
4738          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
4739          out << "         gSystem->ChangeDirectory(cdir);" << endl;
4740          out << "         return kFALSE;" << endl;
4741          out << "      }" << endl;
4742          out << "   } else {" << endl;
4743          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
4744          out << "      gSystem->ChangeDirectory(cdir);" << endl;
4745          out << "      return kFALSE;" << endl;
4746          out << "   }" << endl;
4747          out << "   // Check for SETUP.C and execute" << endl;
4748          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
4749          out << "      printf(\"*******************************\\n\");" << endl;
4750          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
4751          out << "      printf(\"*******************************\\n\");" << endl;
4752          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
4753          out << "   } else {" << endl;
4754          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
4755          out << "      gSystem->ChangeDirectory(cdir);" << endl;
4756          out << "      return kFALSE;" << endl;
4757          out << "   }" << endl;
4758          out << "   // Restore original workdir" << endl;
4759          out << "   gSystem->ChangeDirectory(cdir);" << endl;
4760          out << "   return kTRUE;" << endl;
4761          out << "}" << endl;
4762       }
4763    }   
4764    Bool_t copy = kTRUE;
4765    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4766    if (copy) {
4767       CdWork();
4768       TString workdir = gGrid->GetHomeDirectory();
4769       workdir += fGridWorkingDir;
4770       if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
4771       Info("WriteMergingMacro", "\n#####   Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
4772 //      TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
4773       if (!copyLocal2Alien("WriteMergeMacro",mergingMacro.Data(), 
4774            Form("%s/%s", workdir.Data(), mergingMacro.Data()))) Fatal("","Terminating");
4775    }
4776 }
4777
4778 //______________________________________________________________________________
4779 Bool_t AliAnalysisAlien::SetupPar(const char *package)
4780 {
4781 // Compile the par file archive pointed by <package>. This must be present in the current directory.
4782 // Note that for loading the compiled library. The current directory should have precedence in
4783 // LD_LIBRARY_PATH
4784    TString pkgdir = package;
4785    pkgdir.ReplaceAll(".par","");
4786    gSystem->Exec(TString::Format("tar xzf %s.par", pkgdir.Data()));
4787    TString cdir = gSystem->WorkingDirectory();
4788    gSystem->ChangeDirectory(pkgdir);
4789    // Check for BUILD.sh and execute
4790    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
4791       printf("**************************************************\n");
4792       printf("*** Building PAR archive %s\n", package);
4793       printf("**************************************************\n");
4794       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
4795          ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
4796          gSystem->ChangeDirectory(cdir);
4797          return kFALSE;
4798       }
4799    } else {
4800       ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
4801       gSystem->ChangeDirectory(cdir);
4802       return kFALSE;
4803    }
4804    // Check for SETUP.C and execute
4805    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
4806       printf("**************************************************\n");
4807       printf("*** Setup PAR archive %s\n", package);
4808       printf("**************************************************\n");
4809       gROOT->Macro("PROOF-INF/SETUP.C");
4810       printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
4811    } else {
4812       ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
4813       gSystem->ChangeDirectory(cdir);
4814       return kFALSE;
4815    }   
4816    // Restore original workdir
4817    gSystem->ChangeDirectory(cdir);
4818    return kTRUE;
4819 }
4820
4821 //______________________________________________________________________________
4822 void AliAnalysisAlien::WriteExecutable()
4823 {
4824 // Generate the alien executable script.
4825    // Patch executable with -x to catch error code
4826    if (fExecutableCommand.Contains("root") && 
4827        fExecutableCommand.Contains("-q") && 
4828        !fExecutableCommand.Contains("-x")) fExecutableCommand += " -x";
4829    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
4830       ofstream out;
4831       out.open(fExecutable.Data(), ios::out);
4832       if (out.bad()) {
4833          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
4834          return;
4835       }
4836       out << "#!/bin/bash" << endl;
4837       // Make sure we can properly compile par files
4838       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
4839       out << "echo \"=========================================\"" << endl; 
4840       out << "echo \"############## PATH : ##############\"" << endl;
4841       out << "echo $PATH" << endl;
4842       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
4843       out << "echo $LD_LIBRARY_PATH" << endl;
4844       out << "echo \"############## ROOTSYS : ##############\"" << endl;
4845       out << "echo $ROOTSYS" << endl;
4846       out << "echo \"############## which root : ##############\"" << endl;
4847       out << "which root" << endl;
4848       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
4849       out << "echo $ALICE_ROOT" << endl;
4850       out << "echo \"############## which aliroot : ##############\"" << endl;
4851       out << "which aliroot" << endl;
4852       out << "echo \"############## system limits : ##############\"" << endl;
4853       out << "ulimit -a" << endl;
4854       out << "echo \"############## memory : ##############\"" << endl;
4855       out << "free -m" << endl;
4856       out << "echo \"=========================================\"" << endl << endl;
4857       out << fExecutableCommand << " "; 
4858       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl;
4859       out << "RET=$?" << endl;
4860       out << "if [ \"$RET\" != \"0\" ];then" << endl;
4861       out << "  echo \"======== ERROR : " << fAnalysisMacro.Data() << " finished with NON zero code: $RET ========\"" << endl;
4862       out << "  if [ \"$RET\" -gt 128 ] && [ \"$RET\" -lt 160 ]; then"<<endl;
4863       out << "    let sig=\"$RET - 128\""<<endl;
4864       out << "    sigs='HUP INT QUIT ILL TRAP ABRT BUS FPE"<<endl;
4865       out << "    KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT"<<endl;
4866       out << "    CHLD CONT STOP TSTP TTIN TTOU URG XCPU"<<endl;
4867       out << "    XFSZ VTALRM PROF WINCH IO PWR SYS'"<<endl;
4868       out << "    sig=SIG`echo $sigs | awk '{ print $'\"$sig\"' }'`"<<endl;
4869       out << "    echo \"======== it appears to have been killed with signal: $sig ========\""<<endl;
4870       out << "  fi"<<endl;
4871       out << "  exit $RET"<< endl;
4872       out << "fi" << endl << endl ;
4873       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $RET ========\"" << endl;
4874       out << "echo \"############## memory after: ##############\"" << endl;
4875       out << "free -m" << endl;
4876    }   
4877    Bool_t copy = kTRUE;
4878    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4879    if (copy) {
4880       CdWork();
4881       TString workdir = gGrid->GetHomeDirectory();
4882       workdir += fGridWorkingDir;
4883       TString executable = TString::Format("%s/%s", workdir.Data(), fExecutable.Data());
4884       if (FileExists(executable)) gGrid->Rm(executable);
4885       Info("WriteExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
4886       if (!copyLocal2Alien("WriteExecutable",fExecutable.Data(), 
4887           executable.Data())) Fatal("","Terminating");
4888    } 
4889 }
4890
4891 //______________________________________________________________________________
4892 void AliAnalysisAlien::WriteMergeExecutable()
4893 {
4894 // Generate the alien executable script for the merging job.
4895    if (!fMergeViaJDL) return;
4896    TString mergeExec = fExecutable;
4897    mergeExec.ReplaceAll(".sh", "_merge.sh");
4898    if (!TestBit(AliAnalysisGrid::kSubmit)) {
4899       ofstream out;
4900       out.open(mergeExec.Data(), ios::out);
4901       if (out.bad()) {
4902          Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
4903          return;
4904       }
4905       out << "#!/bin/bash" << endl;
4906       // Make sure we can properly compile par files
4907       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
4908       out << "echo \"=========================================\"" << endl; 
4909       out << "echo \"############## PATH : ##############\"" << endl;
4910       out << "echo $PATH" << endl;
4911       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
4912       out << "echo $LD_LIBRARY_PATH" << endl;
4913       out << "echo \"############## ROOTSYS : ##############\"" << endl;
4914       out << "echo $ROOTSYS" << endl;
4915       out << "echo \"############## which root : ##############\"" << endl;
4916       out << "which root" << endl;
4917       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
4918       out << "echo $ALICE_ROOT" << endl;
4919       out << "echo \"############## which aliroot : ##############\"" << endl;
4920       out << "which aliroot" << endl;
4921       out << "echo \"############## system limits : ##############\"" << endl;
4922       out << "ulimit -a" << endl;
4923       out << "echo \"############## memory : ##############\"" << endl;
4924       out << "free -m" << endl;
4925       out << "echo \"=========================================\"" << endl << endl;
4926       TString mergeMacro = fExecutable;
4927       mergeMacro.ReplaceAll(".sh", "_merge.C");
4928       if (IsOneStageMerging())
4929          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
4930       else
4931          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2)\"" << endl;
4932       out << fExecutableCommand << " " << "$ARG" << endl; 
4933       out << "RET=$?" << endl;
4934       out << "if [ \"$RET\" != \"0\" ];then" << endl;
4935       out << "  echo \"======== ERROR : " << fAnalysisMacro.Data() << " finished with NON zero code: $RET ========\"" << endl;
4936       out << "  if [ \"$RET\" -gt 128 ] && [ \"$RET\" -lt 160 ]; then"<<endl;
4937       out << "    let sig=\"$RET - 128\""<<endl;
4938       out << "    sigs='HUP INT QUIT ILL TRAP ABRT BUS FPE"<<endl;
4939       out << "    KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT"<<endl;
4940       out << "    CHLD CONT STOP TSTP TTIN TTOU URG XCPU"<<endl;
4941       out << "    XFSZ VTALRM PROF WINCH IO PWR SYS'"<<endl;
4942       out << "    sig=SIG`echo $sigs | awk '{ print $'\"$sig\"' }'`"<<endl;
4943       out << "    echo \"======== it appears to have been killed with signal: $sig ========\""<<endl;
4944       out << "  fi"<<endl;
4945       out << "  exit $RET"<< endl;
4946       out << "fi" << endl << endl ;
4947       out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
4948       out << "echo \"############## memory after: ##############\"" << endl;
4949       out << "free -m" << endl;
4950    }   
4951    Bool_t copy = kTRUE;
4952    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4953    if (copy) {
4954       CdWork();
4955       TString workdir = gGrid->GetHomeDirectory();
4956       workdir += fGridWorkingDir;
4957       TString executable = TString::Format("%s/%s", workdir.Data(), mergeExec.Data());
4958       if (FileExists(executable)) gGrid->Rm(executable);
4959       Info("WriteMergeExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
4960       if (!copyLocal2Alien("WriteMergeExecutable",mergeExec.Data(), 
4961           executable.Data())) Fatal("","Terminating");
4962    } 
4963 }
4964
4965 //______________________________________________________________________________
4966 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
4967 {
4968 // Write the production file to be submitted by LPM manager. The format is:
4969 // First line: full_path_to_jdl estimated_no_subjobs_per_master
4970 // Next lines: full_path_to_dataset XXX (XXX is a string)
4971 // To submit, one has to: submit jdl XXX for all lines
4972    ofstream out;
4973    out.open(filename, ios::out);
4974    if (out.bad()) {
4975       Error("WriteProductionFile", "Bad file name: %s", filename);
4976       return;
4977    }
4978    TString workdir;
4979    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice"))
4980       workdir = gGrid->GetHomeDirectory();
4981    workdir += fGridWorkingDir;
4982    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
4983    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
4984    out << locjdl << " " << njobspermaster << endl;
4985    Int_t nmasterjobs = fInputFiles->GetEntries();
4986    for (Int_t i=0; i<nmasterjobs; i++) {
4987       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
4988       runOutDir.ReplaceAll(".xml", "");
4989       if (fOutputToRunNo)
4990          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
4991       else
4992          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
4993    }
4994    if (gGrid) {
4995       Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
4996       if (FileExists(filename)) gGrid->Rm(filename);
4997 //      TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
4998       if (!copyLocal2Alien("WriteProductionFile", filename, 
4999           Form("%s/%s", workdir.Data(),filename))) Fatal("","Terminating");
5000    }   
5001 }
5002
5003 //______________________________________________________________________________
5004 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
5005 {
5006 // Generate the alien validation script.
5007    // Generate the validation script
5008    TObjString *os;
5009    if (fValidationScript.IsNull()) {
5010       fValidationScript = fExecutable;
5011       fValidationScript.ReplaceAll(".sh", "_validation.sh");
5012    }   
5013    TString validationScript = fValidationScript;
5014    if (merge) validationScript.ReplaceAll(".sh", "_merge.sh");
5015    if (!Connect()) {
5016       Error("WriteValidationScript", "Alien connection required");
5017       return;
5018    }
5019    if (!fTerminateFiles.IsNull()) {
5020       fTerminateFiles.Strip();
5021       fTerminateFiles.ReplaceAll(" ",",");
5022    }   
5023    TString outStream = "";
5024    if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
5025    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
5026       ofstream out;
5027       out.open(validationScript, ios::out);
5028       out << "#!/bin/bash" << endl;
5029       out << "##################################################" << endl;
5030       out << "validateout=`dirname $0`" << endl;
5031       out << "validatetime=`date`" << endl;
5032       out << "validated=\"0\";" << endl;
5033       out << "error=0" << endl;
5034       out << "if [ -z $validateout ]" << endl;
5035       out << "then" << endl;
5036       out << "    validateout=\".\"" << endl;
5037       out << "fi" << endl << endl;
5038       out << "cd $validateout;" << endl;
5039       out << "validateworkdir=`pwd`;" << endl << endl;
5040       out << "echo \"*******************************************************\"" << outStream << endl;
5041       out << "echo \"* Automatically generated validation script           *\""  << outStream << endl;
5042       out << "" << endl;
5043       out << "echo \"* Time:    $validatetime \""  << outStream << endl;
5044       out << "echo \"* Dir:     $validateout\""  << outStream << endl;
5045       out << "echo \"* Workdir: $validateworkdir\""  << outStream << endl;
5046       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
5047       out << "ls -la ./"  << outStream << endl;
5048       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl << endl;
5049       out << "##################################################" << endl;
5050       out << "" << endl;
5051
5052       out << "if [ ! -f stderr ] ; then" << endl;
5053       out << "   error=1" << endl;
5054       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << outStream << endl;
5055       out << "   echo \"Error = $error\" " << outStream << endl;
5056       out << "fi" << endl;
5057
5058       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
5059       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
5060       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
5061       out << "glibcErr=`grep -Ei '\\*\\*\\* glibc detected \\*\\*\\*' stderr`" << endl;
5062       out << "" << endl;
5063
5064       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
5065       out << "   error=1" << endl;
5066       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << outStream << endl;
5067       out << "   echo \"$parArch\" " << outStream << endl;
5068       out << "   echo \"Error = $error\" " << outStream << endl;
5069       out << "fi" << endl;
5070
5071       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
5072       out << "   error=1" << endl;
5073       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << outStream << endl;
5074       out << "   echo \"$segViol\" " << outStream << endl;
5075       out << "   echo \"Error = $error\" " << outStream << endl;
5076       out << "fi" << endl;
5077
5078       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
5079       out << "   error=1" << endl;
5080       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << outStream << endl;
5081       out << "   echo \"$segFault\" " << outStream << endl;
5082       out << "   echo \"Error = $error\" " << outStream << endl;
5083       out << "fi" << endl;
5084
5085       out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
5086       out << "   error=1" << endl;
5087       out << "   echo \"* ########## Job not validated - *** glibc detected ***  ###\" " << outStream << endl;
5088       out << "   echo \"$glibcErr\" " << outStream << endl;
5089       out << "   echo \"Error = $error\" " << outStream << endl;
5090       out << "fi" << endl;
5091
5092       // Part dedicated to the specific analyses running into the train
5093
5094       TString outputFiles = fOutputFiles;
5095       if (merge && !fTerminateFiles.IsNull()) {
5096          if (!outputFiles.IsNull()) outputFiles += ",";
5097          outputFiles += fTerminateFiles;
5098       }
5099       TObjArray *arr = outputFiles.Tokenize(",");
5100       TIter next1(arr);
5101       TString outputFile;
5102       while (!merge && (os=(TObjString*)next1())) { 
5103          // No need to validate outputs produced by merging since the merging macro does this
5104          outputFile = os->GetString();
5105          Int_t index = outputFile.Index("@");
5106          if (index > 0) outputFile.Remove(index);
5107          if (fTerminateFiles.Contains(outputFile)) continue;
5108          if (outputFile.Contains("*")) continue;
5109          out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
5110          out << "   error=1" << endl;
5111          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\""  << outStream << endl;
5112          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
5113          out << "fi" << endl;
5114       }   
5115       delete arr;
5116       out << "if ! [ -f outputs_valid ] ; then" << endl;
5117       out << "   error=1" << endl;
5118       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
5119       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
5120       out << "fi" << endl;
5121       
5122       out << "if [ $error = 0 ] ; then" << endl;
5123       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << outStream << endl;
5124       if (!IsKeepLogs()) {
5125          out << "   echo \"* === Logs std* will be deleted === \"" << endl;
5126          outStream = "";
5127          out << "   rm -f std*" << endl;
5128       }            
5129       out << "fi" << endl;
5130
5131       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
5132       out << "echo \"*******************************************************\""  << outStream << endl;
5133       out << "cd -" << endl;
5134       out << "exit $error" << endl;
5135    }    
5136    Bool_t copy = kTRUE;
5137    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
5138    if (copy) {
5139       CdWork();
5140       TString workdir = gGrid->GetHomeDirectory();
5141       workdir += fGridWorkingDir;
5142       Info("WriteValidationScript", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
5143       if (FileExists(validationScript)) gGrid->Rm(validationScript);
5144 //      TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
5145       if (!copyLocal2Alien("WriteValidationScript", validationScript.Data(), 
5146           Form("%s/%s",workdir.Data(), validationScript.Data()))) Fatal("","Terminating");
5147    } 
5148 }