Implement comparison of sim and rec CDB's, by default for the TPC/RecoParam only
[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(" ","");
774          if (lib.BeginsWith("lib")) lib.Remove(0, 3);
775          lib.Prepend("lib");
776          Int_t loaded = strlen(gSystem->GetLibraries(lib,"",kFALSE));
777          if (!loaded) loaded = gSystem->Load(lib);
778          if (loaded < 0) {
779             Error("LoadModules", "Cannot load library for friends %s", lib.Data());
780             return kFALSE;
781          }
782       }
783       delete list;
784    }
785    return kTRUE;
786 }   
787
788 //______________________________________________________________________________
789 void AliAnalysisAlien::SetRunPrefix(const char *prefix)
790 {
791 // Set the run number format. Can be a prefix or a format like "%09d"
792    fRunPrefix = prefix;
793    if (!fRunPrefix.Contains("%")) fRunPrefix += "%d";
794 }   
795
796 //______________________________________________________________________________
797 void AliAnalysisAlien::AddIncludePath(const char *path)
798 {
799 // Add include path in the remote analysis macro.
800    TString p(path);
801    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
802    else                  fIncludePath += Form("-I%s ", path);
803 }
804
805 //______________________________________________________________________________
806 void AliAnalysisAlien::AddRunNumber(Int_t run)
807 {
808 // Add a run number to the list of runs to be processed.
809    if (fRunNumbers.Length()) fRunNumbers += " ";
810    fRunNumbers += Form(fRunPrefix.Data(), run);
811 }   
812
813 //______________________________________________________________________________
814 void AliAnalysisAlien::AddRunList(const char* runList)
815 {
816 // Add several runs into the list of runs; they are expected to be separated by a blank character.  
817   TString    sList = runList;
818   TObjArray *list  = sList.Tokenize(" ");
819   Int_t n = list->GetEntries();
820   for (Int_t i = 0; i < n; i++) {
821     TObjString *os = (TObjString*)list->At(i);
822     AddRunNumber(os->GetString().Atoi());
823   }
824   delete list;
825 }
826
827 //______________________________________________________________________________
828 void AliAnalysisAlien::AddRunNumber(const char* run)
829 {
830 // Add a run number to the list of runs to be processed.
831    TString runs = run;
832    TObjString *os;
833    TObjArray *arr = runs.Tokenize(" ");
834    TIter next(arr);
835    TString prefix; 
836    prefix.Append(fRunPrefix, fRunPrefix.Index("%d"));
837    while ((os=(TObjString*)next())){
838        if (fRunNumbers.Length()) fRunNumbers += " ";
839        fRunNumbers += Form("%s%s", prefix.Data(), os->GetString().Data());
840    }
841    delete arr;
842 }   
843
844 //______________________________________________________________________________
845 void AliAnalysisAlien::AddDataFile(const char *lfn)
846 {
847 // Adds a data file to the input to be analysed. The file should be a valid LFN
848 // or point to an existing file in the alien workdir.
849    if (!fInputFiles) fInputFiles = new TObjArray();
850    fInputFiles->Add(new TObjString(lfn));
851 }
852
853 //______________________________________________________________________________
854 void AliAnalysisAlien::AddExternalPackage(const char *package)
855 {
856 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
857    if (fExternalPackages) fExternalPackages += " ";
858    fExternalPackages += package;
859 }   
860       
861 //______________________________________________________________________________
862 Bool_t AliAnalysisAlien::Connect()
863 {
864 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
865    if (gGrid && gGrid->IsConnected()) return kTRUE;
866    if (fProductionMode) return kTRUE;
867    if (!gGrid) {
868       Info("Connect", "Trying to connect to AliEn ...");
869       TGrid::Connect("alien://");
870    }
871    if (!gGrid || !gGrid->IsConnected()) {
872       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
873       return kFALSE;
874    }  
875    fUser = gGrid->GetUser();
876    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
877    return kTRUE;
878 }
879
880 //______________________________________________________________________________
881 void AliAnalysisAlien::CdWork()
882 {
883 // Check validity of alien workspace. Create directory if possible.
884    if (!Connect()) {
885       Error("CdWork", "Alien connection required");
886       return;
887    } 
888    TString homedir = gGrid->GetHomeDirectory();
889    TString workdir = homedir + fGridWorkingDir;
890    if (DirectoryExists(workdir)) {
891       gGrid->Cd(workdir);
892       return;
893    }   
894    // Work directory not existing - create it
895    gGrid->Cd(homedir);
896    if (gGrid->Mkdir(workdir, "-p")) {
897       gGrid->Cd(fGridWorkingDir);
898       Info("CdWork", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
899    } else {
900       Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
901               workdir.Data(), homedir.Data());
902       fGridWorkingDir = "";
903    }          
904 }
905
906 //______________________________________________________________________________
907 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
908 {
909 // Check if file copying is possible.
910    if (fProductionMode) return kTRUE;
911    TString salienpath(alienpath);
912    if (salienpath.Contains(" ")) {
913       Error("CheckFileCopy", "path: <%s> contains blancs - FIX IT !",alienpath);
914       return kFALSE;
915    }   
916    if (!Connect()) {
917       Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
918       return kFALSE;
919    }
920    Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
921         \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
922    // Check if alien_CLOSE_SE is defined
923    TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
924    if (!closeSE.IsNull()) {
925       Info("CheckFileCopy", "Your current close storage is pointing to: \
926            \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
927    } else {
928       Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
929    }        
930    // Check if grid directory exists.
931    if (!DirectoryExists(alienpath)) {
932       Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
933       return kFALSE;
934    }
935    TString stest = "plugin_test_copy";
936    TFile f(stest, "RECREATE");
937    // User may not have write permissions to current directory 
938    if (f.IsZombie()) {
939       Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
940             gSystem->WorkingDirectory());
941       return kFALSE;
942    }
943    f.Close();
944    if (FileExists(Form("alien://%s/%s",alienpath, stest.Data()))) gGrid->Rm(Form("alien://%s/%s",alienpath, stest.Data()));
945    if (!TFile::Cp(stest.Data(), Form("alien://%s/%s",alienpath, stest.Data()))) {
946       Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
947            \n# 1. Make sure you have write permissions there. If this is the case: \
948            \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
949            \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
950            \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
951            \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
952       gSystem->Unlink(stest.Data());
953       return kFALSE;
954    }   
955    gSystem->Unlink(stest.Data());
956    gGrid->Rm(Form("%s/%s",alienpath,stest.Data()));
957    Info("CheckFileCopy", "### ...SUCCESS ###");
958    return kTRUE;
959 }   
960
961 //______________________________________________________________________________
962 Bool_t AliAnalysisAlien::CheckInputData()
963 {
964 // Check validity of input data. If necessary, create xml files.
965    if (fProductionMode) return kTRUE;
966    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
967       if (!fGridDataDir.Length()) {
968          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
969          return kFALSE;
970       }
971       if (fMergeViaJDL) {
972          Error("CheckInputData", "Merging via jdl works only with run numbers, run range or provided xml");
973          return kFALSE;
974       }   
975       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
976       if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
977          TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode) 
978       return kTRUE;
979    }
980    // Process declared files
981    Bool_t isCollection = kFALSE;
982    Bool_t isXml = kFALSE;
983    Bool_t useTags = kFALSE;
984    Bool_t checked = kFALSE;
985    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
986    TString file;
987    TString workdir = gGrid->GetHomeDirectory();
988    workdir += fGridWorkingDir;
989    if (fInputFiles) {
990       TObjString *objstr;
991       TIter next(fInputFiles);
992       while ((objstr=(TObjString*)next())) {
993          file = workdir;
994          file += "/";
995          file += objstr->GetString();
996          // Store full lfn path
997          if (FileExists(file)) objstr->SetString(file);
998          else {
999             file = objstr->GetName();
1000             if (!FileExists(objstr->GetName())) {
1001                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
1002                      objstr->GetName(), workdir.Data());
1003                return kFALSE;
1004             }         
1005          }
1006          Bool_t iscoll, isxml, usetags;
1007          CheckDataType(file, iscoll, isxml, usetags);
1008          if (!checked) {
1009             checked = kTRUE;
1010             isCollection = iscoll;
1011             isXml = isxml;
1012             useTags = usetags;
1013             TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
1014          } else {
1015             if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
1016                Error("CheckInputData", "Some conflict was found in the types of inputs");
1017                return kFALSE;
1018             } 
1019          }
1020       }
1021    }
1022    // Process requested run numbers
1023    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
1024    // Check validity of alien data directory
1025    if (!fGridDataDir.Length()) {
1026       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
1027       return kFALSE;
1028    }
1029    if (!DirectoryExists(fGridDataDir)) {
1030       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
1031       return kFALSE;
1032    }
1033    if (isCollection) {
1034       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
1035       return kFALSE;   
1036    }
1037    
1038    if (checked && !isXml) {
1039       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
1040       return kFALSE;   
1041    }
1042    // Check validity of run number(s)
1043    TObjArray *arr;
1044    TObjString *os;
1045    TString format;
1046    Int_t nruns = 0;
1047    TString schunk, schunk2;
1048    TString path;
1049    if (!checked) {
1050       checked = kTRUE;
1051       useTags = fDataPattern.Contains("tag");
1052       TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
1053    }   
1054    if (useTags != fDataPattern.Contains("tag")) {
1055       Error("CheckInputData", "Cannot mix input files using/not using tags");
1056       return kFALSE;
1057    }
1058    if (fRunNumbers.Length()) {
1059       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
1060       arr = fRunNumbers.Tokenize(" ");
1061       TIter next(arr);
1062       while ((os=(TObjString*)next())) {
1063          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
1064          if (!DirectoryExists(path)) {
1065             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
1066             continue;
1067          }
1068          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
1069          TString msg = "\n#####   file: ";
1070          msg += path;
1071          msg += " type: xml_collection;";
1072          if (useTags) msg += " using_tags: Yes";
1073          else          msg += " using_tags: No";
1074          Info("CheckDataType", "%s", msg.Data());
1075          if (fNrunsPerMaster<2) {
1076             AddDataFile(Form("%s.xml", os->GetString().Data()));
1077          } else {
1078             nruns++;
1079             if (((nruns-1)%fNrunsPerMaster) == 0) {
1080                schunk = os->GetString();
1081             }   
1082             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
1083             schunk += Form("_%s.xml", os->GetString().Data());
1084             AddDataFile(schunk);
1085          }   
1086       }
1087       delete arr;   
1088    } else {
1089       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
1090       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1091          format = Form("%%s/%s ", fRunPrefix.Data());
1092          path = Form(format.Data(), fGridDataDir.Data(), irun);
1093          if (!DirectoryExists(path)) {
1094             continue;
1095          }
1096          format = Form("%%s/%s.xml", fRunPrefix.Data());
1097          path = Form(format.Data(), workdir.Data(),irun);
1098          TString msg = "\n#####   file: ";
1099          msg += path;
1100          msg += " type: xml_collection;";
1101          if (useTags) msg += " using_tags: Yes";
1102          else          msg += " using_tags: No";
1103          Info("CheckDataType", "%s", msg.Data());
1104          if (fNrunsPerMaster<2) {
1105             format = Form("%s.xml", fRunPrefix.Data());
1106             AddDataFile(Form(format.Data(),irun));
1107          } else {
1108             nruns++;
1109             if (((nruns-1)%fNrunsPerMaster) == 0) {
1110                schunk = Form(fRunPrefix.Data(),irun);
1111             }
1112             format = Form("_%s.xml", fRunPrefix.Data());
1113             schunk2 = Form(format.Data(), irun);
1114             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
1115             schunk += schunk2;
1116             AddDataFile(schunk);
1117          }   
1118       }
1119       if (!fInputFiles) {
1120          schunk += schunk2;
1121          AddDataFile(schunk);
1122       }   
1123    }
1124    return kTRUE;      
1125 }   
1126
1127 //______________________________________________________________________________
1128 Int_t AliAnalysisAlien::CopyLocalDataset(const char *griddir, const char *pattern, Int_t nfiles, const char *output, const char *archivefile, const char *outputdir)
1129 {
1130 // Copy data from the given grid directory according a pattern and make a local
1131 // dataset.
1132 // 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
1133    if (!Connect()) {
1134       Error("CopyLocalDataset", "Cannot copy local dataset with no grid connection");
1135       return 0;
1136    }
1137    if (!DirectoryExists(griddir)) {
1138       Error("CopyLocalDataset", "Data directory %s not existing.", griddir);
1139       return 0;
1140    }
1141    TString command = Form("find -z -l %d %s %s", nfiles, griddir, pattern);
1142    printf("Running command: %s\n", command.Data());
1143    TGridResult *res = gGrid->Command(command);
1144    Int_t nfound = res->GetEntries();
1145    if (!nfound) {
1146       Error("CopyLocalDataset", "No file found in <%s> having pattern <%s>", griddir, pattern);
1147       return 0;
1148    }
1149    printf("... found %d files. Copying locally ...\n", nfound);
1150    
1151    // archives
1152    TObjArray* additionalArchives = 0;
1153    if (strlen(archivefile) > 0 && TString(archivefile).Contains(";")) {
1154       additionalArchives = TString(archivefile).Tokenize(";");
1155       archivefile = additionalArchives->At(0)->GetName();
1156       additionalArchives->RemoveAt(0);
1157       additionalArchives->Compress();
1158    }
1159    
1160    // Copy files locally
1161    ofstream out;
1162    out.open(output, ios::out);
1163    TMap *map;
1164    TString turl, dirname, filename, temp;
1165    TString cdir = gSystem->WorkingDirectory();
1166    gSystem->MakeDirectory(outputdir);
1167    gSystem->ChangeDirectory(outputdir);
1168    Int_t ncopied = 0;
1169    for (Int_t i=0; i<nfound; i++) {
1170       map = (TMap*)res->At(i);
1171       turl = map->GetValue("turl")->GetName();
1172       filename = gSystem->BaseName(turl.Data());
1173       dirname = gSystem->DirName(turl.Data());
1174       dirname = gSystem->BaseName(dirname.Data());
1175       gSystem->MakeDirectory(dirname);
1176       
1177       TString source(turl);
1178       TString targetFileName(filename);
1179       
1180       if (strlen(archivefile) > 0) {
1181 // TODO here the archive in which the file resides should be determined
1182 // however whereis returns only a guid, and guid2lfn does not work
1183 // Therefore we use the one provided as argument for now
1184          source = Form("%s/%s", gSystem->DirName(source.Data()), archivefile);
1185          targetFileName = archivefile;
1186       }
1187       if (TFile::Cp(source, Form("file:./%s/%s", dirname.Data(), targetFileName.Data()))) {
1188          Bool_t success = kTRUE;
1189          if (additionalArchives) {
1190             for (Int_t j=0; j<additionalArchives->GetEntriesFast(); j++) {
1191                TString target;
1192                target.Form("./%s/%s", dirname.Data(), additionalArchives->At(j)->GetName());
1193                gSystem->MakeDirectory(gSystem->DirName(target));
1194                success &= TFile::Cp(Form("%s/%s", gSystem->DirName(source.Data()), additionalArchives->At(j)->GetName()), Form("file:%s", target.Data()));
1195             }
1196          }
1197
1198          if (success) {
1199             if (strlen(archivefile) > 0) targetFileName = Form("%s#%s", targetFileName.Data(), gSystem->BaseName(turl.Data()));
1200             out << cdir << Form("/%s/%s/%s", outputdir, dirname.Data(), targetFileName.Data()) << endl;
1201             ncopied++;
1202          }
1203       }
1204    }
1205    gSystem->ChangeDirectory(cdir);
1206    delete res;
1207    delete additionalArchives;
1208    return ncopied;
1209 }   
1210
1211 //______________________________________________________________________________
1212 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
1213 {
1214 // Create dataset for the grid data directory + run number.
1215    const Int_t gMaxEntries = 15000;
1216    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
1217    if (!Connect()) {
1218       Error("CreateDataset", "Cannot create dataset with no grid connection");
1219       return kFALSE;
1220    }   
1221
1222    // Cd workspace
1223    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
1224    TString workdir = gGrid->GetHomeDirectory();
1225    workdir += fGridWorkingDir;
1226
1227    // Compose the 'find' command arguments
1228    TString format;
1229    TString command;
1230    TString delimiter = pattern;
1231    delimiter.Strip();
1232    if (delimiter.Contains(" ")) delimiter = "";
1233    else delimiter = " ";
1234    TString options = "-x collection ";
1235    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
1236    else options += Form("-l %d ", gMaxEntries);  // Protection for the find command
1237    TString conditions = "";
1238    Int_t nstart = 0;
1239    Int_t ncount = 0;
1240    Int_t stage = 0;
1241    TString file;
1242    TString path;
1243    Int_t nruns = 0;
1244    TString schunk, schunk2;
1245    TGridCollection *cbase=0, *cadd=0;
1246    if (!fRunNumbers.Length() && !fRunRange[0]) {
1247       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
1248       // Make a single data collection from data directory.
1249       path = fGridDataDir;
1250       if (!DirectoryExists(path)) {
1251          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
1252          return kFALSE;
1253       } 
1254 //      CdWork();
1255       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1256       else file = Form("%s.xml", gSystem->BaseName(path));
1257       while (1) {
1258          ncount = 0;
1259          stage++;
1260          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1261             command = "find ";
1262             command += Form("%s -o %d ",options.Data(), nstart);
1263             command += path;
1264             command += delimiter;
1265             command += pattern;
1266             command += conditions;
1267             printf("command: %s\n", command.Data());
1268             TGridResult *res = gGrid->Command(command);
1269             if (res) delete res;
1270             // Write standard output to file
1271             gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage, file.Data()));
1272             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1273             Bool_t nullFile = kFALSE;
1274             if (!hasGrep) {
1275                 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1276             } else {
1277                nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1278                if (nullFile) {
1279                   Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
1280                   gSystem->Exec("rm -f __tmp*");
1281                   return kFALSE;
1282                }
1283                TString line;
1284                ifstream in;
1285                in.open("__tmp__");
1286                in >> line;
1287                in.close();
1288                gSystem->Exec("rm -f __tmp__");
1289                ncount = line.Atoi();
1290             }         
1291          }
1292          if (ncount == gMaxEntries) {
1293             Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1294             cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1295             if (!cbase) cbase = cadd;
1296             else {
1297                cbase->Add(cadd);
1298                delete cadd;
1299             }   
1300             nstart += ncount;
1301          } else {
1302             if (cbase) {
1303                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1304                printf("... please wait - TAlienCollection::Add() scales badly...\n");
1305                cbase->Add(cadd);
1306                delete cadd;
1307                cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1308                delete cbase; cbase = 0;               
1309             } else {
1310                TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1311             }
1312             gSystem->Exec("rm -f __tmp*");   
1313             Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1314             break;
1315          }
1316       }
1317       Bool_t fileExists = FileExists(file);
1318       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
1319          // Copy xml file to alien space
1320          if (fileExists) gGrid->Rm(file);
1321          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1322          if (!FileExists(file)) {
1323             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1324             return kFALSE;
1325          }
1326          // Update list of files to be processed.
1327       }
1328       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
1329       return kTRUE;
1330    }   
1331    // Several runs
1332    Bool_t nullResult = kTRUE;
1333    if (fRunNumbers.Length()) {
1334       TObjArray *arr = fRunNumbers.Tokenize(" ");
1335       TObjString *os;
1336       TIter next(arr);
1337       while ((os=(TObjString*)next())) {
1338          nstart = 0;
1339          stage = 0;
1340          path = Form("%s/%s", fGridDataDir.Data(), os->GetString().Data());
1341          if (!DirectoryExists(path)) continue;
1342 //         CdWork();
1343          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1344          else file = Form("%s.xml", os->GetString().Data());
1345          // If local collection file does not exist, create it via 'find' command.
1346          while (1) {
1347             ncount = 0;
1348             stage++;
1349             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1350                command = "find ";
1351                command +=  Form("%s -o %d ",options.Data(), nstart);
1352                command += path;
1353                command += delimiter;
1354                command += pattern;
1355                command += conditions;
1356                TGridResult *res = gGrid->Command(command);
1357                if (res) delete res;
1358                // Write standard output to file
1359                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1360                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1361                Bool_t nullFile = kFALSE;
1362                if (!hasGrep) {
1363                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1364                } else {
1365                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1366                   if (nullFile) {
1367                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1368                      gSystem->Exec("rm -f __tmp*");
1369                      fRunNumbers.ReplaceAll(os->GetString().Data(), "");
1370                      break;
1371                   }   
1372                   TString line;
1373                   ifstream in;
1374                   in.open("__tmp__");
1375                   in >> line;
1376                   in.close();
1377                   gSystem->Exec("rm -f __tmp__");   
1378                   ncount = line.Atoi();
1379                }
1380                nullResult = kFALSE;         
1381             }
1382             if (ncount == gMaxEntries) {
1383                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1384                if (fNrunsPerMaster > 1) {
1385                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1386                           file.Data(),gMaxEntries);
1387                   return kFALSE;
1388                }           
1389                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1390                if (!cbase) cbase = cadd;
1391                else {
1392                   cbase->Add(cadd);
1393                   delete cadd;
1394                }   
1395                nstart += ncount;
1396             } else {
1397                if (cbase && fNrunsPerMaster<2) {
1398                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1399                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1400                   cbase->Add(cadd);
1401                   delete cadd;
1402                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1403                   delete cbase; cbase = 0;               
1404                } else {
1405                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1406                }
1407                gSystem->Exec("rm -f __tmp*");   
1408                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1409                break;
1410             }
1411          }   
1412          if (TestBit(AliAnalysisGrid::kTest)) break;
1413          // Check if there is one run per master job.
1414          if (fNrunsPerMaster<2) {
1415             if (FileExists(file)) {
1416                if (fOverwriteMode) gGrid->Rm(file);
1417                else {
1418                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1419                   continue;
1420                }   
1421             }        
1422             // Copy xml file to alien space
1423             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1424             if (!FileExists(file)) {
1425                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1426                delete arr;
1427                return kFALSE;
1428             }
1429          } else {
1430             nruns++;
1431             if (((nruns-1)%fNrunsPerMaster) == 0) {
1432                schunk = os->GetString();
1433                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1434             } else {
1435                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1436                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
1437                cbase->Add(cadd);
1438                delete cadd;
1439             }
1440             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
1441                continue;
1442             }   
1443             schunk += Form("_%s.xml", os->GetString().Data());
1444             if (FileExists(schunk)) {               
1445                if (fOverwriteMode) gGrid->Rm(file);
1446                else {
1447                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1448                   continue;
1449                }   
1450             }        
1451             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
1452             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1453             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1454             if (!FileExists(schunk)) {
1455                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1456                delete arr;
1457                return kFALSE;
1458             }
1459          }
1460       }   
1461       delete arr;
1462       if (nullResult) {
1463          Error("CreateDataset", "No valid dataset corresponding to the query!");
1464          return kFALSE;
1465       }
1466    } else {
1467       // Process a full run range.
1468       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1469          format = Form("%%s/%s", fRunPrefix.Data());
1470          nstart = 0;
1471          stage = 0;
1472          path = Form(format.Data(), fGridDataDir.Data(), irun);
1473          if (!DirectoryExists(path)) continue;
1474 //         CdWork();
1475          format = Form("%s.xml", fRunPrefix.Data());
1476          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1477          else file = Form(format.Data(), irun);
1478          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
1479             if (fOverwriteMode) gGrid->Rm(file);
1480             else {
1481                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1482                continue;
1483             }   
1484          }
1485          // If local collection file does not exist, create it via 'find' command.
1486          while (1) {
1487             ncount = 0;
1488             stage++;
1489             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1490                command = "find ";
1491                command +=  Form("%s -o %d ",options.Data(), nstart);
1492                command += path;
1493                command += delimiter;
1494                command += pattern;
1495                command += conditions;
1496                TGridResult *res = gGrid->Command(command);
1497                if (res) delete res;
1498                // Write standard output to file
1499                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1500                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1501                Bool_t nullFile = kFALSE;
1502                if (!hasGrep) {
1503                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1504                } else {
1505                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1506                   if (nullFile) {
1507                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1508                      gSystem->Exec("rm -f __tmp*");
1509                      break;
1510                   }   
1511                   TString line;
1512                   ifstream in;
1513                   in.open("__tmp__");
1514                   in >> line;
1515                   in.close();
1516                   gSystem->Exec("rm -f __tmp__");   
1517                   ncount = line.Atoi();
1518                }
1519                nullResult = kFALSE;         
1520             }   
1521             if (ncount == gMaxEntries) {
1522                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1523                if (fNrunsPerMaster > 1) {
1524                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1525                           file.Data(),gMaxEntries);
1526                   return kFALSE;
1527                }           
1528                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1529                if (!cbase) cbase = cadd;
1530                else {
1531                   cbase->Add(cadd);
1532                   delete cadd;
1533                }   
1534                nstart += ncount;
1535             } else {
1536                if (cbase && fNrunsPerMaster<2) {
1537                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1538                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1539                   cbase->Add(cadd);
1540                   delete cadd;
1541                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1542                   delete cbase; cbase = 0;               
1543                } else {
1544                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1545                }
1546                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1547                break;
1548             }
1549          }   
1550          if (TestBit(AliAnalysisGrid::kTest)) break;
1551          // Check if there is one run per master job.
1552          if (fNrunsPerMaster<2) {
1553             if (FileExists(file)) {
1554                if (fOverwriteMode) gGrid->Rm(file);
1555                else {
1556                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1557                   continue;
1558                }   
1559             }        
1560             // Copy xml file to alien space
1561             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1562             if (!FileExists(file)) {
1563                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1564                return kFALSE;
1565             }
1566          } else {
1567             nruns++;
1568             // Check if the collection for the chunk exist locally.
1569             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
1570             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
1571                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
1572                else continue;
1573             }   
1574             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
1575             if (((nruns-1)%fNrunsPerMaster) == 0) {
1576                schunk = Form(fRunPrefix.Data(), irun);
1577                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1578             } else {
1579                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1580                cbase->Add(cadd);
1581                delete cadd;
1582             }
1583             format = Form("%%s_%s.xml", fRunPrefix.Data());
1584             schunk2 = Form(format.Data(), schunk.Data(), irun);
1585             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
1586                continue;
1587             }   
1588             schunk = schunk2;
1589             if (FileExists(schunk)) {
1590                if (fOverwriteMode) gGrid->Rm(schunk);
1591                else {
1592                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1593                   continue;
1594                }   
1595             }        
1596             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
1597             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1598             if (FileExists(schunk)) {
1599                if (fOverwriteMode) gGrid->Rm(schunk);
1600                else {
1601                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
1602                   continue;
1603                }   
1604             }   
1605             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1606             if (!FileExists(schunk)) {
1607                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1608                return kFALSE;
1609             }
1610          }   
1611       }
1612       if (nullResult) {
1613          Error("CreateDataset", "No valid dataset corresponding to the query!");
1614          return kFALSE;
1615       }      
1616    }      
1617    return kTRUE;
1618 }
1619
1620 //______________________________________________________________________________
1621 Bool_t AliAnalysisAlien::CreateJDL()
1622 {
1623 // Generate a JDL file according to current settings. The name of the file is 
1624 // specified by fJDLName.
1625    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1626    Bool_t error = kFALSE;
1627    TObjArray *arr = 0;
1628    Bool_t copy = kTRUE;
1629    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1630    Bool_t generate = kTRUE;
1631    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
1632    if (!Connect()) {
1633       Error("CreateJDL", "Alien connection required");
1634       return kFALSE;
1635    }   
1636    // Check validity of alien workspace
1637    TString workdir;
1638    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1639    if (!fProductionMode &&  !TestBit(AliAnalysisGrid::kTest)) CdWork();
1640    workdir += fGridWorkingDir;
1641    if (generate) {
1642       TObjString *os;
1643       if (!fInputFiles && !fMCLoop) {
1644          Error("CreateJDL()", "Define some input files for your analysis.");
1645          error = kTRUE;
1646       }
1647       // Compose list of input files   
1648       // Check if output files were defined
1649       if (!fOutputFiles.Length()) {
1650          Error("CreateJDL", "You must define at least one output file");
1651          error = kTRUE;
1652       }   
1653       // Check if an output directory was defined and valid
1654       if (!fGridOutputDir.Length()) {
1655          Error("CreateJDL", "You must define AliEn output directory");
1656          error = kTRUE;
1657       } else {
1658          if (!fProductionMode) {
1659             if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1660             if (!DirectoryExists(fGridOutputDir)) {
1661                if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1662                   Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1663                } else {
1664                   Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1665                   // error = kTRUE;
1666                }
1667             } else {
1668                Warning("CreateJDL", "#### Output directory %s exists! If this contains old data, jobs will fail with ERROR_SV !!! ###", fGridOutputDir.Data());
1669             }   
1670             gGrid->Cd(workdir);
1671          }   
1672       }   
1673       // Exit if any error up to now
1674       if (error) return kFALSE;   
1675       // Set JDL fields
1676       if (!fUser.IsNull()) {
1677          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1678          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1679       }
1680       TString executable = fExecutable;
1681       if (!executable.BeginsWith("/")) 
1682          executable.Prepend(Form("%s/", workdir.Data()));
1683       fGridJDL->SetExecutable(executable, "This is the startup script");
1684       TString mergeExec = executable;
1685       mergeExec.ReplaceAll(".sh", "_merge.sh");
1686       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
1687       mergeExec.ReplaceAll(".sh", ".C");
1688       fMergingJDL->AddToInputSandbox(Form("LF:%s", mergeExec.Data()), "List of input files to be uploaded to workers");
1689       if (!fArguments.IsNull())
1690          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
1691       if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
1692       else {
1693          if (fProductionMode)  fMergingJDL->SetArguments("wn.xml $4");    // xml, stage
1694          else                  fMergingJDL->SetArguments("wn.xml $2");    // xml, stage
1695      }               
1696
1697       fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1698       fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1699       fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1700       fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1701         
1702       if (fMaxInitFailed > 0) {
1703          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1704          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1705       }   
1706       if (fSplitMaxInputFileNumber > 0 && !fMCLoop) {
1707          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1708          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1709       }
1710       if (!IsOneStageMerging()) {
1711          fMergingJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"",fMaxMergeFiles));
1712          fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1713       }   
1714       if (fSplitMode.Length()) {
1715          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1716          fGridJDL->SetDescription("Split", "We split per SE or file");
1717       }
1718       fMergingJDL->SetValue("Split", "\"se\""); 
1719       fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1720       if (!fAliROOTVersion.IsNull()) {
1721          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1722          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1723       }   
1724       if (!fROOTVersion.IsNull()) {
1725          fGridJDL->AddToPackages("ROOT", fROOTVersion);
1726          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1727       }   
1728       if (!fAPIVersion.IsNull()) {
1729          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1730          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1731       }   
1732       if (!fExternalPackages.IsNull()) {
1733          arr = fExternalPackages.Tokenize(" ");
1734          TIter next(arr);
1735          while ((os=(TObjString*)next())) {
1736             TString pkgname = os->GetString();
1737             Int_t index = pkgname.Index("::");
1738             TString pkgversion = pkgname(index+2, pkgname.Length());
1739             pkgname.Remove(index);
1740             fGridJDL->AddToPackages(pkgname, pkgversion);
1741             fMergingJDL->AddToPackages(pkgname, pkgversion);
1742          }   
1743          delete arr;   
1744       }   
1745       if (!fMCLoop) {
1746          fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1747          fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1748       }   
1749       fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1750       fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1751       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1752       TString analysisFile = fExecutable;
1753       analysisFile.ReplaceAll(".sh", ".root");
1754       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1755       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1756       if (fAdditionalLibs.Length()) {
1757          arr = fAdditionalLibs.Tokenize(" ");
1758          TIter next(arr);
1759          while ((os=(TObjString*)next())) {
1760             if (os->GetString().Contains(".so")) continue;
1761             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1762             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1763          }   
1764          delete arr;   
1765       }
1766       if (fPackages) {
1767          TIter next(fPackages);
1768          TObject *obj;
1769          while ((obj=next())) {
1770             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1771             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1772          }
1773       }
1774       const char *comment = "List of output files and archives";
1775       if (fOutputArchive.Length()) {
1776          TString outputArchive = fOutputArchive;
1777          if (!fRegisterExcludes.IsNull()) {
1778             arr = fRegisterExcludes.Tokenize(" ");
1779             TIter next1(arr);
1780             while ((os=(TObjString*)next1())) {
1781                outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1782                outputArchive.ReplaceAll(os->GetString(),"");
1783             } 
1784             delete arr;
1785          }     
1786          arr = outputArchive.Tokenize(" ");
1787          TIter next(arr);
1788          Bool_t first = kTRUE;
1789          while ((os=(TObjString*)next())) {
1790             if (!os->GetString().Contains("@") && fCloseSE.Length())
1791                fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
1792             else
1793                fGridJDL->AddToSet("Output", os->GetString());
1794             if (first) fGridJDL->AddToSetDescription("Output", comment);
1795             first = kFALSE;   
1796          }      
1797          delete arr;
1798          // Output archive for the merging jdl
1799          if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1800             outputArchive = "log_archive.zip:std*@disk=1 ";
1801             // Add normal output files, extra files + terminate files
1802             TString files;
1803             if (IsMergeAOD()) files = GetListOfFiles("outaodextter");
1804             else files = GetListOfFiles("outextter");
1805             // Do not register files in fRegisterExcludes
1806             if (!fRegisterExcludes.IsNull()) {
1807                arr = fRegisterExcludes.Tokenize(" ");
1808                TIter next1(arr);
1809                while ((os=(TObjString*)next1())) {
1810                   files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1811                   files.ReplaceAll(os->GetString(),"");
1812                }   
1813                delete arr;
1814             }
1815             files.ReplaceAll(".root", "*.root");
1816             
1817             if (mgr->IsCollectThroughput())
1818                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d %s@disk=%d",files.Data(),fNreplicas, mgr->GetFileInfoLog(),fNreplicas);
1819             else
1820                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",files.Data(),fNreplicas);
1821          } else {
1822             TString files = fOutputArchive;
1823             files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1824             outputArchive = files;
1825          }   
1826          arr = outputArchive.Tokenize(" ");
1827          TIter next2(arr);
1828          first = kTRUE;
1829          while ((os=(TObjString*)next2())) {
1830             TString currentfile = os->GetString();
1831             if (!currentfile.Contains("@") && fCloseSE.Length())
1832                fMergingJDL->AddToSet("Output", Form("%s@%s",currentfile.Data(), fCloseSE.Data()));
1833             else
1834                fMergingJDL->AddToSet("Output", currentfile);
1835             if (first) fMergingJDL->AddToSetDescription("Output", comment);
1836             first = kFALSE;   
1837          }      
1838          delete arr;         
1839       }      
1840       arr = fOutputFiles.Tokenize(",");
1841       TIter next(arr);
1842       Bool_t first = kTRUE;
1843       while ((os=(TObjString*)next())) {
1844          // Ignore ouputs in jdl that are also in outputarchive
1845          TString sout = os->GetString();
1846          sout.ReplaceAll("*", "");
1847          sout.ReplaceAll(".root", "");
1848          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1849          if (fOutputArchive.Contains(sout)) continue;
1850          // Ignore fRegisterExcludes
1851          if (fRegisterExcludes.Contains(sout)) continue;
1852          if (!first) comment = NULL;
1853          if (!os->GetString().Contains("@") && fCloseSE.Length())
1854             fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1855          else
1856             fGridJDL->AddToSet("Output", os->GetString());
1857          if (first) fGridJDL->AddToSetDescription("Output", comment); 
1858          if (fMergeExcludes.Contains(sout)) continue;   
1859          if (!os->GetString().Contains("@") && fCloseSE.Length())
1860             fMergingJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1861          else
1862             fMergingJDL->AddToSet("Output", os->GetString());
1863          if (first) fMergingJDL->AddToSetDescription("Output", comment);
1864          first = kFALSE;
1865       }   
1866       delete arr;
1867       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1868       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1869       TString validationScript = fValidationScript;
1870       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1871       validationScript.ReplaceAll(".sh", "_merge.sh");
1872       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1873       if (fMasterResubmitThreshold) {
1874          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1875          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1876       }   
1877       // Write a jdl with 2 input parameters: collection name and output dir name.
1878       WriteJDL(copy);
1879    }
1880    // Copy jdl to grid workspace   
1881    if (copy) {
1882       // Check if an output directory was defined and valid
1883       if (!fGridOutputDir.Length()) {
1884          Error("CreateJDL", "You must define AliEn output directory");
1885          return kFALSE;
1886       } else {
1887          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1888          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1889             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1890                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1891             } else {
1892                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1893                return kFALSE;
1894             }
1895          }
1896          gGrid->Cd(workdir);
1897       }   
1898       if (TestBit(AliAnalysisGrid::kSubmit)) {
1899          TString mergeJDLName = fExecutable;
1900          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1901          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1902          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1903          if (fProductionMode) {
1904             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1905             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1906          }   
1907          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1908          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1909          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1910          if (!copyLocal2Alien("CreateJDL", fJDLName, locjdl)) 
1911             Fatal("","Terminating");
1912 //         TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1913          if (fMergeViaJDL) {
1914             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1915 //            TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1916             if (!copyLocal2Alien("CreateJDL", mergeJDLName.Data(), locjdl1)) 
1917                Fatal("","Terminating");
1918          }   
1919       }
1920       if (fAdditionalLibs.Length()) {
1921          arr = fAdditionalLibs.Tokenize(" ");
1922          TObjString *os;
1923          TIter next(arr);
1924          while ((os=(TObjString*)next())) {
1925             if (os->GetString().Contains(".so")) continue;
1926             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1927             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1928 //            TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1929             if (!copyLocal2Alien("CreateJDL", os->GetString().Data(), 
1930                 Form("%s/%s", workdir.Data(), os->GetString().Data())))
1931               Fatal("","Terminating");
1932          }   
1933          delete arr;   
1934       }
1935       if (fPackages) {
1936          TIter next(fPackages);
1937          TObject *obj;
1938          while ((obj=next())) {
1939             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1940             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1941 //            TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1942             if (!copyLocal2Alien("CreateJDL",obj->GetName(), 
1943                 Form("%s/%s", workdir.Data(), obj->GetName()))) 
1944               Fatal("","Terminating"); 
1945          }   
1946       }      
1947    } 
1948    return kTRUE;
1949 }
1950
1951 //______________________________________________________________________________
1952 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1953 {
1954 // Writes one or more JDL's corresponding to findex. If findex is negative,
1955 // all run numbers are considered in one go (jdl). For non-negative indices
1956 // they correspond to the indices in the array fInputFiles.
1957    if (!fInputFiles && !fMCLoop) return kFALSE;
1958    TObject *os;
1959    TString workdir;
1960    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1961    workdir += fGridWorkingDir;
1962    TString stageName = "$2";
1963    if (fProductionMode) stageName = "$4";
1964    if (!fMergeDirName.IsNull()) {
1965      fMergingJDL->AddToInputDataCollection(Form("LF:$1/%s/Stage_%s.xml,nodownload",fMergeDirName.Data(),stageName.Data()), "Collection of files to be merged for current stage");
1966      fMergingJDL->SetOutputDirectory(Form("$1/%s/Stage_%s/#alien_counter_03i#",fMergeDirName.Data(),stageName.Data()), "Output directory");
1967    } else {
1968      fMergingJDL->AddToInputDataCollection(Form("LF:$1/Stage_%s.xml,nodownload",stageName.Data()), "Collection of files to be merged for current stage");
1969      fMergingJDL->SetOutputDirectory(Form("$1/Stage_%s/#alien_counter_03i#",stageName.Data()), "Output directory");
1970    }
1971    if (fProductionMode) {
1972       TIter next(fInputFiles);
1973       while ((os=next())) {
1974          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1975       }
1976       if (!fOutputToRunNo)
1977          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
1978       else  
1979          fGridJDL->SetOutputDirectory(fGridOutputDir);
1980    } else {            
1981       if (!fRunNumbers.Length() && !fRunRange[0]) {
1982          // One jdl with no parameters in case input data is specified by name.
1983          TIter next(fInputFiles);
1984          while ((os=next()))
1985             fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1986          if (!fOutputSingle.IsNull())
1987             fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1988          else {
1989             fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1990 //            fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1991          }   
1992       } else {
1993          // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1994          fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1995          if (!fOutputSingle.IsNull()) {
1996             if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1997             else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1998          } else {   
1999             fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
2000          }   
2001       }
2002    }
2003       
2004    // Generate the JDL as a string
2005    TString sjdl = fGridJDL->Generate();
2006    TString sjdl1 = fMergingJDL->Generate();
2007    // Final merge jdl
2008    if (!fMergeDirName.IsNull()) {
2009      fMergingJDL->SetOutputDirectory(Form("$1/%s",fMergeDirName.Data()), "Output directory");
2010      fMergingJDL->AddToInputSandbox(Form("LF:$1/%s/Stage_%s.xml",fMergeDirName.Data(),stageName.Data()));
2011    } else {  
2012      fMergingJDL->SetOutputDirectory("$1", "Output directory");
2013      fMergingJDL->AddToInputSandbox(Form("LF:$1/Stage_%s.xml",stageName.Data()));
2014    }  
2015    TString sjdl2 = fMergingJDL->Generate();
2016    Int_t index, index1;
2017    sjdl.ReplaceAll("\",\"", "\",\n   \"");
2018    sjdl.ReplaceAll("(member", "\n   (member");
2019    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2020    sjdl.ReplaceAll("{", "{\n   ");
2021    sjdl.ReplaceAll("};", "\n};");
2022    sjdl.ReplaceAll("{\n   \n", "{\n");
2023    sjdl.ReplaceAll("\n\n", "\n");
2024    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
2025    sjdl1.ReplaceAll("\",\"", "\",\n   \"");
2026    sjdl1.ReplaceAll("(member", "\n   (member");
2027    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2028    sjdl1.ReplaceAll("{", "{\n   ");
2029    sjdl1.ReplaceAll("};", "\n};");
2030    sjdl1.ReplaceAll("{\n   \n", "{\n");
2031    sjdl1.ReplaceAll("\n\n", "\n");
2032    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
2033    sjdl2.ReplaceAll("\",\"", "\",\n   \"");
2034    sjdl2.ReplaceAll("(member", "\n   (member");
2035    sjdl2.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2036    sjdl2.ReplaceAll("{", "{\n   ");
2037    sjdl2.ReplaceAll("};", "\n};");
2038    sjdl2.ReplaceAll("{\n   \n", "{\n");
2039    sjdl2.ReplaceAll("\n\n", "\n");
2040    sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
2041    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2042    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
2043    index = sjdl.Index("JDLVariables");
2044    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
2045    sjdl += "Workdirectorysize = {\"5000MB\"};";
2046    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2047    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2048    index = fJobTag.Index(":");
2049    if (index < 0) index = fJobTag.Length();
2050    TString jobTag = fJobTag;
2051    if (fProductionMode) jobTag.Insert(index,"_Stage$4");
2052    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:%s_Merging\"\n};\n", jobTag.Data()));
2053    if (fProductionMode) {   
2054      sjdl1.Prepend("# Generated merging jdl (production mode) \
2055                     \n# $1 = full alien path to output directory to be merged \
2056                     \n# $2 = train number \
2057                     \n# $3 = production (like LHC10b) \
2058                     \n# $4 = merging stage \
2059                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2060      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2061      sjdl2.Prepend("# Generated merging jdl \
2062                     \n# $1 = full alien path to output directory to be merged \
2063                     \n# $2 = train number \
2064                     \n# $3 = production (like LHC10b) \
2065                     \n# $4 = merging stage \
2066                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2067    } else {
2068      sjdl1.Prepend("# Generated merging jdl \
2069                     \n# $1 = full alien path to output directory to be merged \
2070                     \n# $2 = merging stage \
2071                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2072      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2073      sjdl2.Prepend("# Generated merging jdl \
2074                     \n# $1 = full alien path to output directory to be merged \
2075                     \n# $2 = merging stage \
2076                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2077    }
2078    index = sjdl1.Index("JDLVariables");
2079    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
2080    index = sjdl2.Index("JDLVariables");
2081    if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
2082    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2083    sjdl2 += "Workdirectorysize = {\"5000MB\"};";
2084    index = sjdl2.Index("Split =");
2085    if (index>=0) {
2086       index1 = sjdl2.Index("\n", index);
2087       sjdl2.Remove(index, index1-index+1);
2088    }
2089    index = sjdl2.Index("SplitMaxInputFileNumber");
2090    if (index>=0) {
2091       index1 = sjdl2.Index("\n", index);
2092       sjdl2.Remove(index, index1-index+1);
2093    }
2094    index = sjdl2.Index("InputDataCollection");
2095    if (index>=0) {
2096       index1 = sjdl2.Index(";", index);
2097       sjdl2.Remove(index, index1-index+1);
2098    }
2099    index = sjdl2.Index("InputDataListFormat");
2100    if (index>=0) {
2101       index1 = sjdl2.Index("\n", index);
2102       sjdl2.Remove(index, index1-index+1);
2103    }
2104    index = sjdl2.Index("InputDataList");
2105    if (index>=0) {
2106       index1 = sjdl2.Index("\n", index);
2107       sjdl2.Remove(index, index1-index+1);
2108    }
2109    sjdl2.ReplaceAll("wn.xml", Form("Stage_%s.xml",stageName.Data()));
2110    // Write jdl to file
2111    ofstream out;
2112    out.open(fJDLName.Data(), ios::out);
2113    if (out.bad()) {
2114       Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
2115       return kFALSE;
2116    }
2117    out << sjdl << endl;
2118    out.close();
2119    TString mergeJDLName = fExecutable;
2120    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2121    if (fMergeViaJDL) {
2122       ofstream out1;
2123       out1.open(mergeJDLName.Data(), ios::out);
2124       if (out1.bad()) {
2125          Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
2126          return kFALSE;
2127       }
2128       out1 << sjdl1 << endl;
2129       out1.close();
2130       ofstream out2;
2131       TString finalJDL = mergeJDLName;
2132       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2133       out2.open(finalJDL.Data(), ios::out);
2134       if (out2.bad()) {
2135          Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
2136          return kFALSE;
2137       }
2138       out2 << sjdl2 << endl;
2139       out2.close();
2140    }   
2141
2142    // Copy jdl to grid workspace   
2143    if (!copy) {
2144       Info("WriteJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
2145    } else {
2146       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
2147       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
2148       TString finalJDL = mergeJDLName;
2149       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2150       TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
2151       if (fProductionMode) {
2152          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2153          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
2154          locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
2155       }   
2156       if (FileExists(locjdl)) gGrid->Rm(locjdl);
2157       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
2158       if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
2159       Info("WriteJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
2160 //      TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
2161       if (!copyLocal2Alien("WriteJDL",fJDLName.Data(),locjdl.Data())) 
2162          Fatal("","Terminating");
2163       if (fMergeViaJDL) {
2164          Info("WriteJDL", "\n#####   Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
2165 //         TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
2166 //         TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
2167          if (!copyLocal2Alien("WriteJDL",mergeJDLName.Data(),locjdl1.Data()))
2168             Fatal("","Terminating");
2169          if (!copyLocal2Alien("WriteJDL",finalJDL.Data(),locjdl2.Data()))
2170            Fatal("","Terminating");
2171       }   
2172    } 
2173    return kTRUE;
2174 }
2175
2176 //______________________________________________________________________________
2177 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
2178 {
2179 // Returns true if file exists.
2180    if (!gGrid) return kFALSE;
2181    TString slfn = lfn;
2182    slfn.ReplaceAll("alien://","");
2183    TGridResult *res = gGrid->Ls(slfn);
2184    if (!res) return kFALSE;
2185    TMap *map = dynamic_cast<TMap*>(res->At(0));
2186    if (!map) {
2187       delete res;
2188       return kFALSE;
2189    }   
2190    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
2191    if (!objs || !objs->GetString().Length()) {
2192       delete res;
2193       return kFALSE;
2194    }
2195    delete res;   
2196    return kTRUE;
2197 }
2198
2199 //______________________________________________________________________________
2200 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
2201 {
2202 // Returns true if directory exists. Can be also a path.
2203    if (!gGrid) return kFALSE;
2204    // Check if dirname is a path
2205    TString dirstripped = dirname;
2206    dirstripped = dirstripped.Strip();
2207    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
2208    TString dir = gSystem->BaseName(dirstripped);
2209    dir += "/";
2210    TString path = gSystem->DirName(dirstripped);
2211    TGridResult *res = gGrid->Ls(path, "-F");
2212    if (!res) return kFALSE;
2213    TIter next(res);
2214    TMap *map;
2215    TObject *obj;
2216    while ((map=dynamic_cast<TMap*>(next()))) {
2217       obj = map->GetValue("name");
2218       if (!obj) break;
2219       if (dir == obj->GetName()) {
2220          delete res;
2221          return kTRUE;
2222       }
2223    }
2224    delete res;
2225    return kFALSE;
2226 }      
2227
2228 //______________________________________________________________________________
2229 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
2230 {
2231 // Check input data type.
2232    isCollection = kFALSE;
2233    isXml = kFALSE;
2234    useTags = kFALSE;
2235    if (!gGrid) {
2236       Error("CheckDataType", "No connection to grid");
2237       return;
2238    }
2239    isCollection = IsCollection(lfn);
2240    TString msg = "\n#####   file: ";
2241    msg += lfn;
2242    if (isCollection) {
2243       msg += " type: raw_collection;";
2244    // special treatment for collections
2245       isXml = kFALSE;
2246       // check for tag files in the collection
2247       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
2248       if (!res) {
2249          msg += " using_tags: No (unknown)";
2250          Info("CheckDataType", "%s", msg.Data());
2251          return;
2252       }   
2253       const char* typeStr = res->GetKey(0, "origLFN");
2254       if (!typeStr || !strlen(typeStr)) {
2255          msg += " using_tags: No (unknown)";
2256          Info("CheckDataType", "%s", msg.Data());
2257          return;
2258       }   
2259       TString file = typeStr;
2260       useTags = file.Contains(".tag");
2261       if (useTags) msg += " using_tags: Yes";
2262       else          msg += " using_tags: No";
2263       Info("CheckDataType", "%s", msg.Data());
2264       return;
2265    }
2266    TString slfn(lfn);
2267    slfn.ToLower();
2268    isXml = slfn.Contains(".xml");
2269    if (isXml) {
2270    // Open xml collection and check if there are tag files inside
2271       msg += " type: xml_collection;";
2272       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
2273       if (!coll) {
2274          msg += " using_tags: No (unknown)";
2275          Info("CheckDataType", "%s", msg.Data());
2276          return;
2277       }   
2278       TMap *map = coll->Next();
2279       if (!map) {
2280          msg += " using_tags: No (unknown)";
2281          Info("CheckDataType", "%s", msg.Data());
2282          return;
2283       }   
2284       map = (TMap*)map->GetValue("");
2285       TString file;
2286       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
2287       useTags = file.Contains(".tag");
2288       delete coll;
2289       if (useTags) msg += " using_tags: Yes";
2290       else          msg += " using_tags: No";
2291       Info("CheckDataType", "%s", msg.Data());
2292       return;
2293    }
2294    useTags = slfn.Contains(".tag");
2295    if (slfn.Contains(".root")) msg += " type: root file;";
2296    else                        msg += " type: unknown file;";
2297    if (useTags) msg += " using_tags: Yes";
2298    else          msg += " using_tags: No";
2299    Info("CheckDataType", "%s", msg.Data());
2300 }
2301
2302 //______________________________________________________________________________
2303 void AliAnalysisAlien::EnablePackage(const char *package)
2304 {
2305 // Enables a par file supposed to exist in the current directory.
2306    TString pkg(package);
2307    pkg.ReplaceAll(".par", "");
2308    pkg += ".par";
2309    if (gSystem->AccessPathName(pkg)) {
2310       Fatal("EnablePackage", "Package %s not found", pkg.Data());
2311       return;
2312    }
2313    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
2314       Info("EnablePackage", "AliEn plugin will use .par packages");
2315    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
2316    if (!fPackages) {
2317       fPackages = new TObjArray();
2318       fPackages->SetOwner();
2319    }
2320    fPackages->Add(new TObjString(pkg));
2321 }      
2322
2323 //______________________________________________________________________________
2324 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
2325 {
2326 // Make a tree from files having the location specified in fFileForTestMode. 
2327 // Inspired from JF's CreateESDChain.
2328    if (fFileForTestMode.IsNull()) {
2329       Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2330       return NULL;
2331    }
2332    if (gSystem->AccessPathName(fFileForTestMode)) {
2333       Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2334       return NULL;
2335    }   
2336    // Open the file
2337    ifstream in;
2338    in.open(fFileForTestMode);
2339    Int_t count = 0;
2340     // Read the input list of files and add them to the chain
2341    TString line;
2342    TString streeName(treeName);
2343    if (IsUseMCchain()) streeName = "TE";
2344    TChain *chain = new TChain(streeName);
2345    TList *friends = new TList();
2346    TChain *cfriend = 0;
2347    if (!fFriendChainName.IsNull()) {
2348       TObjArray *list = fFriendChainName.Tokenize(" ");
2349       TIter next(list);
2350       TObjString *str;
2351       while((str=(TObjString*)next())) {
2352          cfriend = new TChain(streeName, str->GetName());
2353          friends->Add(cfriend);
2354          chain->AddFriend(cfriend);
2355       }
2356       delete list;
2357    } 
2358    TString bpath;
2359    TIter nextfriend(friends);
2360    while (in.good())
2361    {
2362       in >> line;
2363       if (line.IsNull() || line.BeginsWith("#")) continue;
2364       if (count++ == fNtestFiles) break;
2365       TString esdFile(line);
2366       TFile *file = TFile::Open(esdFile);
2367       if (file && !file->IsZombie()) {
2368          chain->Add(esdFile);
2369          file->Close();
2370          if (!fFriendChainName.IsNull()) {
2371             if (esdFile.Index("#") > -1)
2372                esdFile.Remove(esdFile.Index("#"));
2373             bpath = gSystem->DirName(esdFile);
2374             bpath += "/";
2375             TString fileFriend;
2376             nextfriend.Reset();
2377             while ((cfriend=(TChain*)nextfriend())) {
2378                fileFriend = bpath;
2379                fileFriend += cfriend->GetTitle();
2380                file = TFile::Open(fileFriend);
2381                if (file && !file->IsZombie()) {
2382                   file->Close();
2383                   cfriend->Add(fileFriend);
2384                } else {
2385                   Fatal("GetChainForTestMode", "Cannot open friend file: %s", fileFriend.Data());
2386                   return 0;
2387                } 
2388             }     
2389          }
2390       } else {
2391          Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
2392       }   
2393    }
2394    in.close();
2395    if (!chain->GetListOfFiles()->GetEntries()) {
2396        Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
2397        delete chain;
2398        friends->Delete();
2399        delete friends;
2400        return NULL;
2401    }
2402    return chain;
2403 }    
2404
2405 //______________________________________________________________________________
2406 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
2407 {
2408 // Get job status for all jobs with jobid>jobidstart.
2409    static char mstatus[20];
2410    mstatus[0] = '\0';
2411    nrunning = 0;
2412    nwaiting = 0;
2413    nerror   = 0;
2414    ndone    = 0;
2415    TGridJobStatusList *list = gGrid->Ps("");
2416    if (!list) return mstatus;
2417    Int_t nentries = list->GetSize();
2418    TGridJobStatus *status;
2419    Int_t pid;
2420    for (Int_t ijob=0; ijob<nentries; ijob++) {
2421       status = (TGridJobStatus *)list->At(ijob);
2422       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)%p)->GetKey(\"queueId\"));", status));
2423       if (pid<jobidstart) continue;
2424       if (pid == lastid) {
2425          gROOT->ProcessLine(Form("sprintf((char*)%p,((TAlienJobStatus*)%p)->GetKey(\"status\"));",mstatus, status));
2426       }   
2427       switch (status->GetStatus()) {
2428          case TGridJobStatus::kWAITING:
2429             nwaiting++; break;
2430          case TGridJobStatus::kRUNNING:
2431             nrunning++; break;
2432          case TGridJobStatus::kABORTED:
2433          case TGridJobStatus::kFAIL:
2434          case TGridJobStatus::kUNKNOWN:
2435             nerror++; break;
2436          case TGridJobStatus::kDONE:
2437             ndone++;
2438       }
2439    }
2440    list->Delete();
2441    delete list;
2442    return mstatus;
2443 }
2444
2445 //______________________________________________________________________________
2446 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
2447 {
2448 // Returns true if file is a collection. Functionality duplicated from
2449 // TAlien::Type() because we don't want to directly depend on TAlien.
2450    if (!gGrid) {
2451       Error("IsCollection", "No connection to grid");
2452       return kFALSE;
2453    }
2454    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
2455    if (!res) return kFALSE;
2456    const char* typeStr = res->GetKey(0, "type");
2457    if (!typeStr || !strlen(typeStr)) return kFALSE;
2458    if (!strcmp(typeStr, "collection")) return kTRUE;
2459    delete res;
2460    return kFALSE;
2461 }   
2462
2463 //______________________________________________________________________________
2464 Bool_t AliAnalysisAlien::IsSingleOutput() const
2465 {
2466 // Check if single-ouput option is on.
2467    return (!fOutputSingle.IsNull());
2468 }
2469
2470 //______________________________________________________________________________
2471 Long64_t AliAnalysisAlien::RunMacroAndExtractLibs(const char* macro, const char *args, TString &libs)
2472 {
2473 // Tries to run the specified macro and return the libraries that it loads.
2474    TString expname;
2475    if (strlen(macro)) expname = gSystem->ExpandPathName(macro);
2476    if (expname.IsNull() || gSystem->AccessPathName(expname)) {
2477       ::Error("RunMacroAndExtractLibs","Cannot find macro %s in current directory", macro);
2478       return -1;
2479    }   
2480    TString oldlibs = gSystem->GetLibraries();
2481    TMacro m(expname);
2482    Int_t error = 0;
2483    Long64_t retval = m.Exec(args, &error);
2484    if (error != TInterpreter::kNoError)
2485    {
2486       ::Error("RunMacroAndExtractLibs", "Macro interpretation %s failed", macro);
2487       return -1;
2488    }
2489    libs = gSystem->GetLibraries();
2490    libs.ReplaceAll(oldlibs, "");
2491    libs.Strip(TString::kLeading);
2492    TObjArray *libTokens = libs.Tokenize(" ");
2493    libs = "";
2494    for (Int_t i=0; i<libTokens->GetEntries(); i++) {
2495      if (!libs.IsNull()) libs += " ";
2496      libs += gSystem->BaseName(libTokens->At(i)->GetName());
2497    }
2498    delete libTokens;
2499    return retval;
2500 }   
2501       
2502 //______________________________________________________________________________
2503 void AliAnalysisAlien::Print(Option_t *) const
2504 {
2505 // Print current plugin settings.
2506    printf("### AliEn analysis plugin current settings ###\n");
2507    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2508    if (mgr && mgr->IsProofMode()) {
2509       TString proofType = "=   PLUGIN IN PROOF MODE ON CLUSTER:_________________";
2510       if (TestBit(AliAnalysisGrid::kTest))
2511          proofType = "=   PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
2512       printf("%s %s\n", proofType.Data(), fProofCluster.Data());
2513       if (!fProofDataSet.IsNull())
2514       printf("=   Requested data set:___________________________ %s\n", fProofDataSet.Data());
2515       if (fProofReset==1)
2516       printf("=   Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2517       if (fProofReset>1)   
2518       printf("=   Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2519       if (!fROOTVersion.IsNull())
2520       printf("=   ROOT version requested________________________ %s\n", fROOTVersion.Data());
2521       else
2522       printf("=   ROOT version requested________________________ default\n");
2523       printf("=   AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
2524       if (!fAliRootMode.IsNull())
2525       printf("=   Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());  
2526       if (fNproofWorkers)
2527       printf("=   Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
2528       if  (fNproofWorkersPerSlave)
2529       printf("=   Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
2530       if (TestSpecialBit(kClearPackages))
2531       printf("=   ClearPackages requested...\n");
2532       if (fIncludePath.Data())
2533       printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2534       printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2535       if (fPackages && fPackages->GetEntries()) {
2536          TIter next(fPackages);
2537          TObject *obj;
2538          TString list;
2539          while ((obj=next())) list += obj->GetName();
2540          printf("=   Par files to be used: ________________________ %s\n", list.Data());
2541       } 
2542       if (TestSpecialBit(kProofConnectGrid))
2543       printf("=   Requested PROOF connection to grid\n");
2544       return;
2545    }
2546    printf("=   OverwriteMode:________________________________ %d\n", fOverwriteMode);
2547    if (fOverwriteMode) {
2548       printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
2549             \n*****       To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
2550    }
2551    printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
2552    printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO:Print");
2553    printf("=   Production mode:______________________________ %d\n", fProductionMode);
2554    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
2555    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
2556    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
2557    if (fUser.Length()) 
2558    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
2559    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
2560    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
2561    TString basedatadir = fGridDataDir;
2562    TString pattern = fDataPattern;
2563    pattern.Strip();
2564    Int_t ind = pattern.Index(" ");
2565    if (ind>=0) {
2566       basedatadir += "/%run%/";
2567       basedatadir += pattern(0, ind);
2568       pattern = pattern(ind+1, pattern.Length());
2569    }   
2570    printf("=   Data base directory path requested: __________ %s\n", basedatadir.Data());
2571    printf("=   Data search pattern: _________________________ %s\n", pattern.Data());
2572    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
2573    if (fRunNumbers.Length()) 
2574    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
2575    if (fRunRange[0])
2576    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
2577    if (!fRunRange[0] && !fRunNumbers.Length()) {
2578       TIter next(fInputFiles);
2579       TObject *obj;
2580       TString list;
2581       while ((obj=next())) list += obj->GetName();
2582       printf("=   Input files to be processed: _________________ %s\n", list.Data());
2583    }
2584    if (TestBit(AliAnalysisGrid::kTest))
2585    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
2586    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
2587    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
2588    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
2589    printf("=   List of outputs that should not be registered: %s\n", fRegisterExcludes.Data());
2590    printf("=   List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
2591    printf("=====================================================================\n");
2592    printf("=   Job price: ___________________________________ %d\n", fPrice);
2593    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
2594    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
2595    if (fMaxInitFailed>0) 
2596    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
2597    if (fMasterResubmitThreshold>0) 
2598    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
2599    printf("=   Number of replicas for the output files_______ %d\n", fNreplicas);
2600    if (fNrunsPerMaster>0)
2601    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
2602    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
2603    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
2604    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
2605    if (fArguments.Length()) 
2606    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
2607    if (fExecutableArgs.Length()) 
2608    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
2609    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
2610    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
2611    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2612    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
2613    if (fDatasetName)
2614    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
2615    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
2616    if (fIncludePath.Data())
2617    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2618    if (fCloseSE.Length())
2619    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
2620    if (fFriendChainName.Length())
2621    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
2622    if (fPackages && fPackages->GetEntries()) {
2623       TIter next(fPackages);
2624       TObject *obj;
2625       TString list;
2626       while ((obj=next())) list += obj->GetName();
2627       printf("=   Par files to be used: ________________________ %s\n", list.Data());
2628    }   
2629 }
2630
2631 //______________________________________________________________________________
2632 void AliAnalysisAlien::SetDefaults()
2633 {
2634 // Set default values for everything. What cannot be filled will be left empty.
2635    if (fGridJDL) delete fGridJDL;
2636    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2637    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2638    fPrice                      = 1;
2639    fTTL                        = 30000;
2640    fSplitMaxInputFileNumber    = 100;
2641    fMaxInitFailed              = 0;
2642    fMasterResubmitThreshold    = 0;
2643    fNtestFiles                 = 10;
2644    fNreplicas                  = 2;
2645    fRunRange[0]                = 0;
2646    fRunRange[1]                = 0;
2647    fRunPrefix                  = "%d";
2648    fNrunsPerMaster             = 1;
2649    fMaxMergeFiles              = 100;
2650    fRunNumbers                 = "";
2651    fExecutable                 = "analysis.sh";
2652    fExecutableCommand          = "root -b -q -x";
2653    fArguments                  = "";
2654    fExecutableArgs             = "";
2655    fAnalysisMacro              = "myAnalysis.C";
2656    fAnalysisSource             = "";
2657    fAdditionalLibs             = "";
2658    fSplitMode                  = "se";
2659    fAPIVersion                 = "";
2660    fROOTVersion                = "";
2661    fAliROOTVersion             = "";
2662    fUser                       = "";  // Your alien user name
2663    fGridWorkingDir             = "";
2664    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
2665    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
2666    fFriendChainName            = "";
2667    fGridOutputDir              = "output";
2668    fOutputArchive              = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
2669    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
2670    fInputFormat                = "xml-single";
2671    fJDLName                    = "analysis.jdl";
2672    fJobTag                     = "Automatically generated analysis JDL";
2673    fMergeExcludes              = "";
2674    fMergeViaJDL                = 0;
2675    SetUseCopy(kTRUE);
2676    SetCheckCopy(kTRUE);
2677    SetDefaultOutputs(kTRUE);
2678    fOverwriteMode              = 1;
2679 }   
2680
2681 //______________________________________________________________________________
2682 void AliAnalysisAlien::SetFriendChainName(const char *name, const char *libnames)
2683 {
2684    // Set file name for the chain of friends and optionally additional libs to be loaded.
2685    // Libs should be separated by blancs.
2686    fFriendChainName = name;
2687    fFriendChainName.ReplaceAll(",", " ");
2688    fFriendChainName.Strip();
2689    fFriendChainName.ReplaceAll("  ", " ");
2690    
2691    fFriendLibs = libnames;
2692    if (fFriendLibs.Length()) {
2693      if(!fFriendLibs.Contains(".so"))
2694        Fatal("SetFriendChainName()", "You should provide explicit library names (with extension)");
2695      fFriendLibs.ReplaceAll(",", " ");
2696      fFriendLibs.Strip();
2697      fFriendLibs.ReplaceAll("  ", " ");
2698    }
2699 }
2700
2701 //______________________________________________________________________________
2702 void AliAnalysisAlien::SetRootVersionForProof(const char *version)
2703 {
2704 // Obsolete method. Use SetROOTVersion instead
2705    Warning("SetRootVersionForProof", "Obsolete. Use SetROOTVersion instead");
2706    if (fROOTVersion.IsNull()) SetROOTVersion(version);
2707    else Error("SetRootVersionForProof", "ROOT version already set to %s", fROOTVersion.Data());
2708 }
2709    
2710 //______________________________________________________________________________
2711 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
2712 {
2713 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
2714    // First check if the result is already in the output directory.
2715    if (FileExists(Form("%s/%s",aliendir,filename))) {
2716       printf("Final merged results found. Not merging again.\n");
2717       return kFALSE;
2718    }
2719    // Now check the last stage done.
2720    Int_t stage = 0;
2721    while (1) {
2722       if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
2723       stage++;
2724    }
2725    // Next stage of merging
2726    stage++;
2727    TString pattern = "*root_archive.zip";
2728    if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
2729    TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
2730    if (res) delete res;
2731    // Write standard output to file
2732    gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
2733    // Count the number of files inside
2734    ifstream ifile;
2735    ifile.open(Form("Stage_%d.xml",stage));
2736    if (!ifile.good()) {
2737       ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
2738       return kFALSE;
2739    }   
2740    TString line;
2741    Int_t nfiles = 0;
2742    while (!ifile.eof()) {
2743       ifile >> line;
2744       if (line.Contains("/event")) nfiles++;
2745    }
2746    ifile.close();
2747    if (!nfiles) {
2748       ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
2749       return kFALSE;
2750    } else {
2751       printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
2752    }   
2753    // Copy the file in the output directory
2754    printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
2755 //   TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
2756    if (!copyLocal2Alien("CheckMergedFiles", Form("Stage_%d.xml",stage), 
2757         Form("%s/Stage_%d.xml",aliendir,stage))) Fatal("","Terminating");
2758    // Check if this is the last stage to be done.
2759    Bool_t laststage = (nfiles<nperchunk);
2760    if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
2761    Int_t jobId = 0;
2762    if (laststage) {
2763       printf("### Submiting final merging stage %d\n", stage);
2764       TString finalJDL = jdl;
2765       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2766       TString query = Form("submit %s %s %d", finalJDL.Data(), aliendir, stage);
2767       jobId = SubmitSingleJob(query);
2768    } else {
2769       printf("### Submiting merging stage %d\n", stage);
2770       TString query = Form("submit %s %s %d", jdl, aliendir, stage);
2771       jobId = SubmitSingleJob(query);
2772    }
2773    if (!jobId) return kFALSE;           
2774
2775    if (!fGridJobIDs.IsNull()) fGridJobIDs.Append(" ");
2776    fGridJobIDs.Append(Form("%d", jobId));
2777    if (!fGridStages.IsNull()) fGridStages.Append(" ");
2778    fGridStages.Append(Form("%s_merge_stage%d", 
2779                            laststage ? "final" : "partial", stage));
2780
2781    return kTRUE;   
2782 }        
2783
2784 //______________________________________________________________________________
2785 AliAnalysisManager *AliAnalysisAlien::LoadAnalysisManager(const char *fname)
2786 {
2787 // Loat the analysis manager from a file.
2788    TFile *file = TFile::Open(fname);
2789    if (!file) {
2790       ::Error("LoadAnalysisManager", "Cannot open file %s", fname);
2791       return 0;
2792    }   
2793    TIter nextkey(file->GetListOfKeys());
2794    AliAnalysisManager *mgr = 0;
2795    TKey *key;
2796    while ((key=(TKey*)nextkey())) {
2797       if (!strcmp(key->GetClassName(), "AliAnalysisManager"))
2798          mgr = (AliAnalysisManager*)file->Get(key->GetName());
2799    }
2800    if (!mgr) 
2801       ::Error("LoadAnalysisManager", "No analysis manager found in file %s", fname);
2802    return mgr;
2803 }      
2804
2805 //______________________________________________________________________________
2806 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
2807 {
2808 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
2809    if (!gGrid) return 0;
2810    printf("=> %s ------> ",query);
2811    TGridResult *res = gGrid->Command(query);
2812    if (!res) return 0;
2813    TString jobId = res->GetKey(0,"jobId");
2814    delete res;
2815    if (jobId.IsNull()) {
2816       printf("submission failed. Reason:\n");
2817       gGrid->Stdout();
2818       gGrid->Stderr();
2819       ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
2820       return 0;
2821    }
2822    Int_t ijobId = jobId.Atoi();
2823    printf(" Job id: '%s' (%d)\n", jobId.Data(), ijobId);
2824    return ijobId; 
2825 }  
2826
2827 //______________________________________________________________________________
2828 Bool_t AliAnalysisAlien::MergeInfo(const char *output, const char *collection)
2829 {
2830 // Merges a collection of output files using concatenation.
2831    TString scoll(collection);
2832    if (!scoll.Contains(".xml")) return kFALSE;
2833    TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", collection));
2834    if (!coll) {
2835       ::Error("MergeInfo", "Input XML %s collection empty.", collection);
2836       return kFALSE;
2837    }
2838    // Iterate grid collection
2839    TString outtmp;
2840    Bool_t merged = kFALSE;
2841    Int_t ifile = 0;
2842    while (coll->Next()) {
2843       TString fname = gSystem->DirName(coll->GetTURL());
2844       fname += "/";
2845       fname += output;
2846       outtmp = Form("%d_%s", ifile, output);
2847       if (!TFile::Cp(fname, outtmp)) {
2848          ::Error("MergeInfo", "Could not copy %s", fname.Data());
2849          continue;
2850       }
2851       ifile++;
2852       if (ifile<2) {
2853          gSystem->Exec(Form("cp %s lastmerged", outtmp.Data()));
2854          continue;
2855       }
2856       gSystem->Exec(Form("cat lastmerged %s > tempmerged", outtmp.Data()));
2857       gSystem->Exec("cp tempmerged lastmerged");
2858    }
2859    if (ifile) {
2860       gSystem->Exec(Form("cp lastmerged %s", output));
2861       gSystem->Exec(Form("rm tempmerged lastmerged *_%s", output));
2862       merged = kTRUE;
2863    }
2864    return merged;
2865 }   
2866
2867 //______________________________________________________________________________
2868 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
2869 {
2870 // Merge given output files from basedir. Basedir can be an alien output directory
2871 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
2872 // files in a group (ignored for xml input). Merging can be done in stages:
2873 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
2874 // stage=1 : works with an xml of all root_archive.zip in the output directory
2875 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
2876    TString outputFile = output;
2877    TString command;
2878    TString outputChunk;
2879    TString previousChunk = "";
2880    TObjArray *listoffiles = new TObjArray();
2881 //   listoffiles->SetOwner();
2882    Int_t countChunk = 0;
2883    Int_t countZero = nmaxmerge;
2884    Bool_t merged = kTRUE;
2885    Bool_t isGrid = kTRUE;
2886    Int_t index = outputFile.Index("@");
2887    if (index > 0) outputFile.Remove(index);
2888    TString inputFile = outputFile;
2889    TString sbasedir = basedir;
2890    if (sbasedir.Contains(".xml")) {
2891       // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
2892       nmaxmerge = 9999999;
2893       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
2894       if (!coll) {
2895          ::Error("MergeOutput", "Input XML collection empty.");
2896          return kFALSE;
2897       }
2898       // Iterate grid collection
2899       while (coll->Next()) {
2900          TString fname = gSystem->DirName(coll->GetTURL());
2901          fname += "/";
2902          fname += inputFile;      
2903          listoffiles->Add(new TNamed(fname.Data(),""));
2904       }   
2905    } else if (sbasedir.Contains(".txt")) {
2906       // The file having the .txt extension is expected to contain a list of
2907       // folders where the output files will be looked. For alien folders,
2908       // the full folder LFN is expected (starting with alien://)
2909       // Assume lfn's on each line
2910       TString line;
2911       ifstream in;
2912       in.open(sbasedir);
2913       if (in.fail()) {
2914          ::Error("MergeOutput", "File %s cannot be opened. Merging stopped." ,sbasedir.Data());
2915          return kTRUE;
2916       }           
2917       Int_t nfiles = 0;
2918       while (in.good()) {
2919          in >> line;
2920          if (line.IsNull() || line.BeginsWith("#")) continue;
2921          line.Strip();
2922          if (!line.Contains("alien:")) isGrid = kFALSE;
2923          line += "/";
2924          line += outputFile;
2925          nfiles++;
2926          listoffiles->Add(new TNamed(line.Data(),""));
2927       }
2928       in.close();
2929       if (!nfiles) {
2930          ::Error("MergeOutput","Input file %s contains no files to be merged\n", sbasedir.Data());
2931          delete listoffiles;
2932          return kFALSE;
2933       }
2934    } else {   
2935       command = Form("find %s/ *%s", basedir, inputFile.Data());
2936       printf("command: %s\n", command.Data());
2937       TGridResult *res = gGrid->Command(command);
2938       if (!res) {
2939          ::Error("MergeOutput","No result for the find command\n");
2940          delete listoffiles;
2941          return kFALSE;
2942       }     
2943       TIter nextmap(res);
2944       TMap *map = 0;
2945       while ((map=(TMap*)nextmap())) {
2946          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
2947          if (!objs || !objs->GetString().Length()) {
2948             // Nothing found - skip this output
2949             delete res;
2950             delete listoffiles;
2951             return kFALSE;
2952          }
2953          listoffiles->Add(new TNamed(objs->GetName(),""));
2954       }
2955       delete res;
2956    }
2957    if (!listoffiles->GetEntries()) {
2958       ::Error("MergeOutput","No result for the find command\n");
2959       delete listoffiles;
2960       return kFALSE;
2961    }     
2962
2963    TFileMerger *fm = 0;
2964    TIter next0(listoffiles);
2965    TObjArray *listoffilestmp = new TObjArray();
2966    listoffilestmp->SetOwner();
2967    TObject *nextfile;
2968    TString snextfile;
2969    // Keep only the files at upper level
2970    Int_t countChar = 0;
2971    while ((nextfile=next0())) {
2972       snextfile = nextfile->GetName();
2973       Int_t crtCount = snextfile.CountChar('/');
2974       if (nextfile == listoffiles->First()) countChar = crtCount;
2975       if (crtCount < countChar) countChar = crtCount;
2976    }
2977    next0.Reset();
2978    while ((nextfile=next0())) {
2979       snextfile = nextfile->GetName();
2980       Int_t crtCount = snextfile.CountChar('/');
2981       if (crtCount > countChar) {
2982          delete nextfile;
2983          continue;
2984       }   
2985       listoffilestmp->Add(nextfile);
2986    }
2987    delete listoffiles;
2988    listoffiles = listoffilestmp;  // Now contains 'good' files
2989    listoffiles->Print();
2990    TIter next(listoffiles);   
2991    // Check if there is a merge operation to resume. Works only for stage 0 or 1.
2992    outputChunk = outputFile;
2993    outputChunk.ReplaceAll(".root", "_*.root");
2994    // Check for existent temporary merge files
2995    // Check overwrite mode and remove previous partial results if needed
2996    // Preserve old merging functionality for stage 0.
2997    if (stage==0) {
2998       if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2999          while (1) {
3000             // Skip as many input files as in a chunk
3001             for (Int_t counter=0; counter<nmaxmerge; counter++) {
3002                nextfile = next();
3003                if (!nextfile) {
3004                   ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
3005                   delete listoffiles;
3006                   return kFALSE;
3007                }   
3008                snextfile = nextfile->GetName();
3009             }
3010             outputChunk = outputFile;
3011             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
3012             countChunk++;
3013             if (gSystem->AccessPathName(outputChunk)) continue;
3014             // Merged file with chunks up to <countChunk> found
3015             ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
3016             previousChunk = outputChunk;
3017             break;
3018          }
3019       }   
3020       countZero = nmaxmerge;
3021    
3022       while ((nextfile=next())) {
3023          snextfile = nextfile->GetName();
3024          // Loop 'find' results and get next LFN
3025          if (countZero == nmaxmerge) {
3026             // First file in chunk - create file merger and add previous chunk if any.
3027             fm = new TFileMerger(isGrid);
3028             fm->SetFastMethod(kTRUE);
3029             if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
3030             outputChunk = outputFile;
3031             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
3032          }
3033          // If last file found, put merged results in the output file
3034          if (nextfile == listoffiles->Last()) outputChunk = outputFile;
3035          // Add file to be merged and decrement chunk counter.
3036          fm->AddFile(snextfile);
3037          countZero--;
3038          if (countZero==0 || nextfile == listoffiles->Last()) {            
3039             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
3040             // Nothing found - skip this output
3041                ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
3042                merged = kFALSE;
3043                break;
3044             }
3045             fm->OutputFile(outputChunk);
3046             // Merge the outputs, then go to next chunk      
3047             if (!fm->Merge()) {
3048                ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
3049                merged = kFALSE;
3050                break;
3051             } else {
3052                ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
3053                gSystem->Unlink(previousChunk);
3054             }
3055             if (nextfile == listoffiles->Last()) break;
3056             countChunk++;
3057             countZero = nmaxmerge;
3058             previousChunk = outputChunk;
3059          }
3060       }
3061       delete listoffiles;
3062       delete fm;
3063       return merged;
3064    }
3065    // Merging stage different than 0.
3066    // Move to the begining of the requested chunk.
3067    fm = new TFileMerger(isGrid);
3068    fm->SetFastMethod(kTRUE);
3069    while ((nextfile=next())) fm->AddFile(nextfile->GetName());
3070    delete listoffiles;
3071    if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
3072       // Nothing found - skip this output
3073       ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
3074       delete fm;
3075       return kFALSE;
3076    }
3077    fm->OutputFile(outputFile);
3078    // Merge the outputs
3079    if (!fm->Merge()) {
3080       ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
3081       delete fm;
3082       return kFALSE;
3083    } else {
3084       ::Info("MergeOutput", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
3085    }
3086    delete fm;
3087    return kTRUE;
3088
3089
3090 //______________________________________________________________________________
3091 Bool_t AliAnalysisAlien::MergeOutputs()
3092 {
3093 // Merge analysis outputs existing in the AliEn space.
3094    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
3095    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
3096    if (!Connect()) {
3097       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
3098       return kFALSE;
3099    }
3100    if (fMergeViaJDL) {
3101       if (!TestBit(AliAnalysisGrid::kMerge)) {
3102          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
3103          return kFALSE; 
3104       }     
3105       if (fProductionMode) {
3106          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
3107          return kFALSE;
3108       }
3109       Info("MergeOutputs", "Submitting merging JDL");
3110       if (!SubmitMerging()) return kFALSE;
3111       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
3112       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
3113       return kFALSE;
3114    }   
3115    // Get the output path
3116    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3117    if (!DirectoryExists(fGridOutputDir)) {
3118       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
3119       return kFALSE;
3120    }
3121    if (!fOutputFiles.Length()) {
3122       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3123       return kFALSE;
3124    }
3125    // Check if fast read option was requested
3126    Info("MergeOutputs", "Started local merging of output files from: alien://%s \
3127         \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
3128    if (fFastReadOption) {
3129       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
3130              \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3131       gEnv->SetValue("XNet.ConnectTimeout",50);
3132       gEnv->SetValue("XNet.RequestTimeout",50);
3133       gEnv->SetValue("XNet.MaxRedirectCount",2);
3134       gEnv->SetValue("XNet.ReconnectTimeout",50);
3135       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
3136    }   
3137    // Make sure we change the temporary directory
3138    gSystem->Setenv("TMPDIR", gSystem->pwd());
3139    // Set temporary compilation directory to current one
3140    gSystem->SetBuildDir(gSystem->pwd(), kTRUE);   
3141    TObjArray *list = fOutputFiles.Tokenize(",");
3142    TIter next(list);
3143    TObjString *str;
3144    TString outputFile;
3145    Bool_t merged = kTRUE;
3146    while((str=(TObjString*)next())) {
3147       outputFile = str->GetString();
3148       Int_t index = outputFile.Index("@");
3149       if (index > 0) outputFile.Remove(index);
3150       TString outputChunk = outputFile;
3151       outputChunk.ReplaceAll(".root", "_*.root");
3152       // Skip already merged outputs
3153       if (!gSystem->AccessPathName(outputFile)) {
3154          if (fOverwriteMode) {
3155             Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
3156             gSystem->Unlink(outputFile);
3157             if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3158                Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
3159                      outputChunk.Data());
3160                gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
3161             }
3162          } else {   
3163             Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
3164             continue;
3165          }   
3166       } else {
3167          if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3168             Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",