RelVal: more retries w/pauses on VM + small fixes
[u/mrichter/AliRoot.git] / ANALYSIS / AliAnalysisAlien.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 // Author: Mihaela Gheata, 01/09/2008
17
18 //==============================================================================
19 //   AliAnalysisAlien - AliEn utility class. Provides interface for creating
20 // a personalized JDL, finding and creating a dataset.
21 //==============================================================================
22
23 #include "AliAnalysisAlien.h"
24
25 #include "Riostream.h"
26 #include "TEnv.h"
27 #include "TKey.h"
28 #include "TBits.h"
29 #include "TError.h"
30 #include "TROOT.h"
31 #include "TSystem.h"
32 #include "TInterpreter.h"
33 #include "TFile.h"
34 #include "TFileCollection.h"
35 #include "TChain.h"
36 #include "TObjString.h"
37 #include "TObjArray.h"
38 #include "TMacro.h"
39 #include "TGrid.h"
40 #include "TGridResult.h"
41 #include "TGridCollection.h"
42 #include "TGridJDL.h"
43 #include "TGridJobStatusList.h"
44 #include "TGridJobStatus.h"
45 #include "TFileMerger.h"
46 #include "AliAnalysisManager.h"
47 #include "AliAnalysisTaskCfg.h"
48 #include "AliVEventHandler.h"
49 #include "AliAnalysisDataContainer.h"
50 #include "AliMultiInputEventHandler.h"
51
52 using std::ofstream;
53 using std::ifstream;
54 using std::ios;
55 using std::endl;
56 ClassImp(AliAnalysisAlien)
57 #if 0
58 ;
59 #endif  
60
61 namespace {
62   Bool_t copyLocal2Alien(const char* where, const char* loc, const char* rem)
63   {
64     TString sl(Form("file:%s", loc));
65     TString sr(Form("alien://%s", rem));
66     Bool_t ret = TFile::Cp(sl, sr);
67     if (!ret) { 
68       Warning(where, "Failed to copy %s to %s", sl.Data(), sr.Data());
69     }
70     return ret;
71   }
72 }
73     
74 //______________________________________________________________________________
75 AliAnalysisAlien::AliAnalysisAlien()
76                  :AliAnalysisGrid(),
77                   fGridJDL(NULL),
78                   fMergingJDL(NULL),
79                   fPrice(0),
80                   fTTL(0),
81                   fSplitMaxInputFileNumber(0),
82                   fMaxInitFailed(0),
83                   fMasterResubmitThreshold(0),
84                   fNtestFiles(0),
85                   fNrunsPerMaster(0),
86                   fMaxMergeFiles(0),
87                   fMaxMergeStages(0),
88                   fNsubmitted(0),
89                   fProductionMode(0),
90                   fOutputToRunNo(0),
91                   fMergeViaJDL(0),
92                   fFastReadOption(0),
93                   fOverwriteMode(1),
94                   fNreplicas(2),
95                   fNproofWorkers(0),
96                   fNproofWorkersPerSlave(0),
97                   fProofReset(0),
98                   fNMCevents(0),
99                   fNMCjobs(0),
100                   fRunNumbers(),
101                   fExecutable(),
102                   fExecutableCommand(),
103                   fArguments(),
104                   fExecutableArgs(),
105                   fAnalysisMacro(),
106                   fAnalysisSource(),
107                   fValidationScript(),
108                   fAdditionalRootLibs(),
109                   fAdditionalLibs(),
110                   fGeneratorLibs(),
111                   fSplitMode(),
112                   fAPIVersion(),
113                   fROOTVersion(),
114                   fAliROOTVersion(),
115                   fExternalPackages(),
116                   fUser(),
117                   fGridWorkingDir(),
118                   fGridDataDir(),
119                   fDataPattern(),
120                   fGridOutputDir(),
121                   fOutputArchive(),
122                   fOutputFiles(),
123                   fInputFormat(),
124                   fDatasetName(),
125                   fJDLName(),
126                   fTerminateFiles(),
127                             fMergeExcludes(),
128                   fRegisterExcludes(),
129                   fIncludePath(),
130                   fCloseSE(),
131                   fFriendChainName(),
132                   fJobTag(),
133                   fOutputSingle(),
134                   fRunPrefix(),
135                   fProofCluster(),
136                   fProofDataSet(),
137                   fFileForTestMode(),
138                   fAliRootMode(),
139                   fProofProcessOpt(),
140                   fMergeDirName(),
141                   fInputFiles(0),
142                   fPackages(0),
143                   fModules(0),
144                   fProofParam(),
145                   fDropToShell(true),
146                   fMCLoop(false),
147                   fGridJobIDs(""),
148                   fGridStages(""),
149                   fFriendLibs(""),
150                   fTreeName()
151 {
152 // Dummy ctor.
153    SetDefaults();
154 }
155
156 //______________________________________________________________________________
157 AliAnalysisAlien::AliAnalysisAlien(const char *name)
158                  :AliAnalysisGrid(name),
159                   fGridJDL(NULL),
160                   fMergingJDL(NULL),
161                   fPrice(0),
162                   fTTL(0),
163                   fSplitMaxInputFileNumber(0),
164                   fMaxInitFailed(0),
165                   fMasterResubmitThreshold(0),
166                   fNtestFiles(0),
167                   fNrunsPerMaster(0),
168                   fMaxMergeFiles(0),
169                   fMaxMergeStages(0),
170                   fNsubmitted(0),
171                   fProductionMode(0),
172                   fOutputToRunNo(0),
173                   fMergeViaJDL(0),
174                   fFastReadOption(0),
175                   fOverwriteMode(1),
176                   fNreplicas(2),
177                   fNproofWorkers(0),
178                   fNproofWorkersPerSlave(0),
179                   fProofReset(0),
180                   fNMCevents(0),
181                   fNMCjobs(0),
182                   fRunNumbers(),
183                   fExecutable(),
184                   fExecutableCommand(),
185                   fArguments(),
186                   fExecutableArgs(),
187                   fAnalysisMacro(),
188                   fAnalysisSource(),
189                   fValidationScript(),
190                   fAdditionalRootLibs(),
191                   fAdditionalLibs(),
192                   fGeneratorLibs(),
193                   fSplitMode(),
194                   fAPIVersion(),
195                   fROOTVersion(),
196                   fAliROOTVersion(),
197                   fExternalPackages(),
198                   fUser(),
199                   fGridWorkingDir(),
200                   fGridDataDir(),
201                   fDataPattern(),
202                   fGridOutputDir(),
203                   fOutputArchive(),
204                   fOutputFiles(),
205                   fInputFormat(),
206                   fDatasetName(),
207                   fJDLName(),
208                   fTerminateFiles(),
209                   fMergeExcludes(),
210                   fRegisterExcludes(),
211                   fIncludePath(),
212                   fCloseSE(),
213                   fFriendChainName(),
214                   fJobTag(),
215                   fOutputSingle(),
216                   fRunPrefix(),
217                   fProofCluster(),
218                   fProofDataSet(),
219                   fFileForTestMode(),
220                   fAliRootMode(),
221                   fProofProcessOpt(),
222                   fMergeDirName(),
223                   fInputFiles(0),
224                   fPackages(0),
225                   fModules(0),
226                   fProofParam(),
227                   fDropToShell(true),
228                   fMCLoop(false),
229                   fGridJobIDs(""),
230                   fGridStages(""),
231                   fFriendLibs(""),
232                   fTreeName()
233 {
234 // Default ctor.
235    SetDefaults();
236 }
237
238 //______________________________________________________________________________
239 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
240                  :AliAnalysisGrid(other),
241                   fGridJDL(NULL),
242                   fMergingJDL(NULL),
243                   fPrice(other.fPrice),
244                   fTTL(other.fTTL),
245                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
246                   fMaxInitFailed(other.fMaxInitFailed),
247                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
248                   fNtestFiles(other.fNtestFiles),
249                   fNrunsPerMaster(other.fNrunsPerMaster),
250                   fMaxMergeFiles(other.fMaxMergeFiles),
251                   fMaxMergeStages(other.fMaxMergeStages),
252                   fNsubmitted(other.fNsubmitted),
253                   fProductionMode(other.fProductionMode),
254                   fOutputToRunNo(other.fOutputToRunNo),
255                   fMergeViaJDL(other.fMergeViaJDL),
256                   fFastReadOption(other.fFastReadOption),
257                   fOverwriteMode(other.fOverwriteMode),
258                   fNreplicas(other.fNreplicas),
259                   fNproofWorkers(other.fNproofWorkers),
260                   fNproofWorkersPerSlave(other.fNproofWorkersPerSlave),
261                   fProofReset(other.fProofReset),
262                   fNMCevents(other.fNMCevents),
263                   fNMCjobs(other.fNMCjobs),
264                   fRunNumbers(other.fRunNumbers),
265                   fExecutable(other.fExecutable),
266                   fExecutableCommand(other.fExecutableCommand),
267                   fArguments(other.fArguments),
268                   fExecutableArgs(other.fExecutableArgs),
269                   fAnalysisMacro(other.fAnalysisMacro),
270                   fAnalysisSource(other.fAnalysisSource),
271                   fValidationScript(other.fValidationScript),
272                   fAdditionalRootLibs(other.fAdditionalRootLibs),
273                   fAdditionalLibs(other.fAdditionalLibs),
274                   fGeneratorLibs(other.fGeneratorLibs),
275                   fSplitMode(other.fSplitMode),
276                   fAPIVersion(other.fAPIVersion),
277                   fROOTVersion(other.fROOTVersion),
278                   fAliROOTVersion(other.fAliROOTVersion),
279                   fExternalPackages(other.fExternalPackages),
280                   fUser(other.fUser),
281                   fGridWorkingDir(other.fGridWorkingDir),
282                   fGridDataDir(other.fGridDataDir),
283                   fDataPattern(other.fDataPattern),
284                   fGridOutputDir(other.fGridOutputDir),
285                   fOutputArchive(other.fOutputArchive),
286                   fOutputFiles(other.fOutputFiles),
287                   fInputFormat(other.fInputFormat),
288                   fDatasetName(other.fDatasetName),
289                   fJDLName(other.fJDLName),
290                   fTerminateFiles(other.fTerminateFiles),
291                   fMergeExcludes(other.fMergeExcludes),
292                   fRegisterExcludes(other.fRegisterExcludes),
293                   fIncludePath(other.fIncludePath),
294                   fCloseSE(other.fCloseSE),
295                   fFriendChainName(other.fFriendChainName),
296                   fJobTag(other.fJobTag),
297                   fOutputSingle(other.fOutputSingle),
298                   fRunPrefix(other.fRunPrefix),
299                   fProofCluster(other.fProofCluster),
300                   fProofDataSet(other.fProofDataSet),
301                   fFileForTestMode(other.fFileForTestMode),
302                   fAliRootMode(other.fAliRootMode),
303                   fProofProcessOpt(other.fProofProcessOpt),
304                   fMergeDirName(other.fMergeDirName),
305                   fInputFiles(0),
306                   fPackages(0),
307                   fModules(0),
308                   fProofParam(),
309                   fDropToShell(other.fDropToShell),
310                   fMCLoop(other.fMCLoop),
311                   fGridJobIDs(other.fGridJobIDs),
312                   fGridStages(other.fGridStages),
313                   fFriendLibs(other.fFriendLibs),
314                   fTreeName(other.fTreeName)
315 {
316 // Copy ctor.
317    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
318    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
319    fRunRange[0] = other.fRunRange[0];
320    fRunRange[1] = other.fRunRange[1];
321    if (other.fInputFiles) {
322       fInputFiles = new TObjArray();
323       TIter next(other.fInputFiles);
324       TObject *obj;
325       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
326       fInputFiles->SetOwner();
327    }   
328    if (other.fPackages) {
329       fPackages = new TObjArray();
330       TIter next(other.fPackages);
331       TObject *obj;
332       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
333       fPackages->SetOwner();
334    }   
335    if (other.fModules) {
336       fModules = new TObjArray();
337       fModules->SetOwner();
338       TIter next(other.fModules);
339       AliAnalysisTaskCfg *mod, *crt;
340       while ((crt=(AliAnalysisTaskCfg*)next())) {
341          mod = new AliAnalysisTaskCfg(*crt);
342          fModules->Add(mod);
343       }
344    }   
345 }
346
347 //______________________________________________________________________________
348 AliAnalysisAlien::~AliAnalysisAlien()
349 {
350 // Destructor.
351    delete fGridJDL;
352    delete fMergingJDL;
353    delete fInputFiles;
354    delete fPackages;
355    delete fModules;
356    fProofParam.DeleteAll();
357 }   
358
359 //______________________________________________________________________________
360 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
361 {
362 // Assignment.
363    if (this != &other) {
364       AliAnalysisGrid::operator=(other);
365       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
366       fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
367       fPrice                   = other.fPrice;
368       fTTL                     = other.fTTL;
369       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
370       fMaxInitFailed           = other.fMaxInitFailed;
371       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
372       fNtestFiles              = other.fNtestFiles;
373       fNrunsPerMaster          = other.fNrunsPerMaster;
374       fMaxMergeFiles           = other.fMaxMergeFiles;
375       fMaxMergeStages          = other.fMaxMergeStages;
376       fNsubmitted              = other.fNsubmitted;
377       fProductionMode          = other.fProductionMode;
378       fOutputToRunNo           = other.fOutputToRunNo;
379       fMergeViaJDL             = other.fMergeViaJDL;
380       fFastReadOption          = other.fFastReadOption;
381       fOverwriteMode           = other.fOverwriteMode;
382       fNreplicas               = other.fNreplicas;
383       fNproofWorkers           = other.fNproofWorkers;
384       fNproofWorkersPerSlave   = other.fNproofWorkersPerSlave;
385       fProofReset              = other.fProofReset;
386       fNMCevents               = other.fNMCevents;
387       fNMCjobs                 = other.fNMCjobs;
388       fRunNumbers              = other.fRunNumbers;
389       fExecutable              = other.fExecutable;
390       fExecutableCommand       = other.fExecutableCommand;
391       fArguments               = other.fArguments;
392       fExecutableArgs          = other.fExecutableArgs;
393       fAnalysisMacro           = other.fAnalysisMacro;
394       fAnalysisSource          = other.fAnalysisSource;
395       fValidationScript        = other.fValidationScript;
396       fAdditionalRootLibs      = other.fAdditionalRootLibs;
397       fAdditionalLibs          = other.fAdditionalLibs;
398       fGeneratorLibs           = other.fGeneratorLibs;
399       fSplitMode               = other.fSplitMode;
400       fAPIVersion              = other.fAPIVersion;
401       fROOTVersion             = other.fROOTVersion;
402       fAliROOTVersion          = other.fAliROOTVersion;
403       fExternalPackages        = other.fExternalPackages;
404       fUser                    = other.fUser;
405       fGridWorkingDir          = other.fGridWorkingDir;
406       fGridDataDir             = other.fGridDataDir;
407       fDataPattern             = other.fDataPattern;
408       fGridOutputDir           = other.fGridOutputDir;
409       fOutputArchive           = other.fOutputArchive;
410       fOutputFiles             = other.fOutputFiles;
411       fInputFormat             = other.fInputFormat;
412       fDatasetName             = other.fDatasetName;
413       fJDLName                 = other.fJDLName;
414       fTerminateFiles          = other.fTerminateFiles;
415       fMergeExcludes           = other.fMergeExcludes;
416       fRegisterExcludes        = other.fRegisterExcludes;
417       fIncludePath             = other.fIncludePath;
418       fCloseSE                 = other.fCloseSE;
419       fFriendChainName         = other.fFriendChainName;
420       fJobTag                  = other.fJobTag;
421       fOutputSingle            = other.fOutputSingle;
422       fRunPrefix               = other.fRunPrefix;
423       fProofCluster            = other.fProofCluster;
424       fProofDataSet            = other.fProofDataSet;
425       fFileForTestMode         = other.fFileForTestMode;
426       fAliRootMode             = other.fAliRootMode;
427       fProofProcessOpt         = other.fProofProcessOpt;
428       fMergeDirName            = other.fMergeDirName;
429       fDropToShell             = other.fDropToShell;
430       fMCLoop                  = other.fMCLoop;
431       fGridJobIDs              = other.fGridJobIDs;
432       fGridStages              = other.fGridStages;
433       fFriendLibs              = other.fFriendLibs;
434       fTreeName                = other.fTreeName;
435       if (other.fInputFiles) {
436          fInputFiles = new TObjArray();
437          TIter next(other.fInputFiles);
438          TObject *obj;
439          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
440          fInputFiles->SetOwner();
441       }   
442       if (other.fPackages) {
443          fPackages = new TObjArray();
444          TIter next(other.fPackages);
445          TObject *obj;
446          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
447          fPackages->SetOwner();
448       }   
449       if (other.fModules) {
450          fModules = new TObjArray();
451          fModules->SetOwner();
452          TIter next(other.fModules);
453          AliAnalysisTaskCfg *mod, *crt;
454          while ((crt=(AliAnalysisTaskCfg*)next())) {
455             mod = new AliAnalysisTaskCfg(*crt);
456             fModules->Add(mod);
457          }
458       }   
459    }
460    return *this;
461 }
462
463 //______________________________________________________________________________
464 void AliAnalysisAlien::AddAdditionalLibrary(const char *name)
465 {
466 // Add a single additional library to be loaded. Extension must be present.
467    TString lib(name);
468    if (!lib.Contains(".")) {
469       Error("AddAdditionalLibrary", "Extension not defined for %s", name);
470       return;
471    }
472    if (fAdditionalLibs.Contains(name)) {
473       Warning("AddAdditionalLibrary", "Library %s already added.", name);
474       return;
475    }
476    if (!fAdditionalLibs.IsNull()) fAdditionalLibs += " ";
477    fAdditionalLibs += lib;
478 }   
479
480 //______________________________________________________________________________
481 void AliAnalysisAlien::AddModule(AliAnalysisTaskCfg *module)
482 {
483 // Adding a module. Checks if already existing. Becomes owned by this.
484    if (!module) return;
485    if (GetModule(module->GetName())) {
486       Error("AddModule", "A module having the same name %s already added", module->GetName());
487       return;
488    }
489    if (!fModules) {
490       fModules = new TObjArray();
491       fModules->SetOwner();
492    }
493    fModules->Add(module);
494 }
495
496 //______________________________________________________________________________
497 void AliAnalysisAlien::AddModules(TObjArray *list)
498 {
499 // Adding a list of modules. Checks if already existing. Becomes owned by this.
500    TIter next(list);
501    AliAnalysisTaskCfg *module;
502    while ((module = (AliAnalysisTaskCfg*)next())) AddModule(module);
503 }   
504
505 //______________________________________________________________________________
506 Bool_t AliAnalysisAlien::CheckDependencies()
507 {
508 // Check if all dependencies are satisfied. Reorder modules if needed.
509    Int_t nmodules = GetNmodules();
510    if (!nmodules) {
511       Warning("CheckDependencies", "No modules added yet to check their dependencies");
512       return kTRUE;
513    }   
514    AliAnalysisTaskCfg *mod = 0;
515    AliAnalysisTaskCfg *dep = 0;
516    TString depname;
517    Int_t i, j, k;
518    for (i=0; i<nmodules; i++) {
519       mod = (AliAnalysisTaskCfg*) fModules->At(i);
520       Int_t ndeps = mod->GetNdeps();
521       Int_t istart = i;
522       for (j=0; j<ndeps; j++) {
523          depname = mod->GetDependency(j);
524          dep = GetModule(depname);
525          if (!dep) {
526             Error("CheckDependencies","Dependency %s not added for module %s",
527                    depname.Data(), mod->GetName());
528             return kFALSE;
529          }
530          if (dep->NeedsDependency(mod->GetName())) {
531             Error("CheckDependencies","Modules %s and %s circularly depend on each other",
532                    mod->GetName(), dep->GetName());
533             return kFALSE;
534          }                  
535          Int_t idep = fModules->IndexOf(dep);
536          // The dependency task must come first
537          if (idep>i) {
538             // Remove at idep and move all objects below up one slot
539             // down to index i included.
540             fModules->RemoveAt(idep);
541             for (k=idep-1; k>=i; k--) fModules->AddAt(fModules->RemoveAt(k),k+1);
542             fModules->AddAt(dep, i++);
543          }
544          //Redo from istart if dependencies were inserted
545          if (i>istart) i=istart-1;
546       }
547    }
548    return kTRUE;
549 }      
550
551 //______________________________________________________________________________
552 AliAnalysisManager *AliAnalysisAlien::CreateAnalysisManager(const char *name, const char *filename)
553 {
554 // Create the analysis manager and optionally execute the macro in filename.
555    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
556    if (mgr) {
557       mgr->SetMCLoop(fMCLoop);
558       return mgr;
559    }   
560    mgr = new AliAnalysisManager(name);
561    mgr->SetGridHandler((AliAnalysisGrid*)this);
562    mgr->SetMCLoop(fMCLoop);
563    if (strlen(filename)) {
564       TString line = gSystem->ExpandPathName(filename);
565       line.Prepend(".x ");
566       gROOT->ProcessLine(line.Data());
567    }
568    return mgr;
569 }      
570       
571 //______________________________________________________________________________
572 Int_t AliAnalysisAlien::GetNmodules() const
573 {
574 // Get number of modules.
575    if (!fModules) return 0;
576    return fModules->GetEntries();
577 }
578
579 //______________________________________________________________________________
580 AliAnalysisTaskCfg *AliAnalysisAlien::GetModule(const char *name)
581 {
582 // Get a module by name.
583    if (!fModules) return 0;
584    return (AliAnalysisTaskCfg*)fModules->FindObject(name);
585 }
586    
587 //______________________________________________________________________________
588 Bool_t AliAnalysisAlien::LoadModule(AliAnalysisTaskCfg *mod)
589 {
590 // Load a given module.
591    if (mod->IsLoaded()) return kTRUE;
592    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
593    if (!mgr) {
594       Error("LoadModule", "No analysis manager created yet. Use CreateAnalysisManager first.");
595       return kFALSE;
596    }   
597    Int_t ndeps = mod->GetNdeps();
598    TString depname;
599    for (Int_t j=0; j<ndeps; j++) {
600       depname = mod->GetDependency(j);
601       AliAnalysisTaskCfg *dep = GetModule(depname);
602       if (!dep) {
603          Error("LoadModule","Dependency %s not existing for module %s",
604                 depname.Data(), mod->GetName());
605          return kFALSE;
606       }
607       if (!LoadModule(dep)) {
608          Error("LoadModule","Dependency %s for module %s could not be loaded",
609                 depname.Data(), mod->GetName());
610          return kFALSE;
611       }
612    }
613    // Load libraries for the module
614    if (!mod->CheckLoadLibraries()) {
615       Error("LoadModule", "Cannot load all libraries for module %s", mod->GetName());
616       return kFALSE;
617    }
618    // Check if a custom file name was requested
619    if (strlen(mod->GetOutputFileName())) mgr->SetCommonFileName(mod->GetOutputFileName());
620
621    // Check if a custom terminate file name was requested
622    if (strlen(mod->GetTerminateFileName())) {
623       if (!fTerminateFiles.IsNull()) fTerminateFiles += ",";
624       fTerminateFiles += mod->GetTerminateFileName();
625    }   
626
627    // Execute the macro
628    if (mod->ExecuteMacro()<0) {
629       Error("LoadModule", "Executing the macro %s with arguments: %s for module %s returned a negative value",
630              mod->GetMacroName(), mod->GetMacroArgs(), mod->GetName());
631       return kFALSE;
632    }
633    // Configure dependencies
634    if (mod->GetConfigMacro() && mod->ExecuteConfigMacro()<0) {
635       Error("LoadModule", "There was an error executing the deps config macro %s for module %s",
636             mod->GetConfigMacro()->GetTitle(), mod->GetName());
637       return kFALSE;
638    }
639    // Adjust extra libraries
640    Int_t nlibs = mod->GetNlibs();
641    TString lib;
642    for (Int_t i=0; i<nlibs; i++) {
643       lib = mod->GetLibrary(i);
644       lib = Form("lib%s.so", lib.Data());
645       if (fAdditionalLibs.Contains(lib)) continue;
646       if (!fAdditionalLibs.IsNull()) fAdditionalLibs += " ";
647       fAdditionalLibs += lib;
648    }
649    return kTRUE;
650 }
651
652 //______________________________________________________________________________
653 Bool_t AliAnalysisAlien::GenerateTrain(const char *name)
654 {
655 // Generate the full train.
656    fAdditionalLibs = "";
657    if (!LoadModules()) return kFALSE;
658    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
659    if (!mgr->InitAnalysis()) return kFALSE;
660    mgr->RunLocalInit();
661    mgr->PrintStatus();
662    Int_t productionMode = fProductionMode;
663    SetProductionMode();
664    TString macro = fAnalysisMacro;
665    TString executable = fExecutable;
666    TString validation = fValidationScript;
667    TString execCommand = fExecutableCommand;
668    SetAnalysisMacro(Form("%s.C", name));
669    SetExecutable(Form("%s.sh", name));
670 //   SetExecutableCommand("aliroot -b -q ");
671    SetValidationScript(Form("%s_validation.sh", name));
672    StartAnalysis();
673    SetProductionMode(productionMode);
674    fAnalysisMacro = macro;
675    fExecutable = executable;
676    fExecutableCommand = execCommand;
677    fValidationScript = validation;
678    return kTRUE;   
679 }   
680
681 //______________________________________________________________________________
682 Bool_t AliAnalysisAlien::GenerateTest(const char *name, const char *modname)
683 {
684 // Generate test macros for a single module or for the full train.
685    fAdditionalLibs = "";
686    if (strlen(modname)) {
687       if (!CheckDependencies()) return kFALSE;
688       AliAnalysisTaskCfg *mod = GetModule(modname);
689       if (!mod) {
690          Error("GenerateTest", "cannot generate test for inexistent module %s", modname);
691          return kFALSE;
692       }
693       if (!LoadModule(mod)) return kFALSE;
694       if (!LoadFriendLibs()) return kFALSE;
695    } else if (!LoadModules()) return kFALSE;
696    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
697    if (!mgr->InitAnalysis()) return kFALSE;
698    mgr->RunLocalInit();
699    mgr->PrintStatus();
700    SetLocalTest(kTRUE);
701    Int_t productionMode = fProductionMode;
702    SetProductionMode();
703    TString macro = fAnalysisMacro;
704    TString executable = fExecutable;
705    TString validation = fValidationScript;
706    TString execCommand = fExecutableCommand;
707    SetAnalysisMacro(Form("%s.C", name));
708    SetExecutable(Form("%s.sh", name));
709       fOutputFiles = GetListOfFiles("outaod");
710       // Add extra files registered to the analysis manager
711       TString extra = GetListOfFiles("ext");
712       if (!extra.IsNull()) {
713          extra.ReplaceAll(".root", "*.root");
714          if (!fOutputFiles.IsNull()) fOutputFiles += ",";
715          fOutputFiles += extra;
716       }
717 //   SetExecutableCommand("aliroot -b -q ");
718    SetValidationScript(Form("%s_validation.sh", name));
719    WriteAnalysisFile();   
720    WriteAnalysisMacro();
721    WriteExecutable();
722    WriteValidationScript();   
723    WriteMergingMacro();
724    WriteMergeExecutable();
725    WriteValidationScript(kTRUE);
726    SetLocalTest(kFALSE);
727    SetProductionMode(productionMode);
728    fAnalysisMacro = macro;
729    fExecutable = executable;
730    fExecutableCommand = execCommand;
731    fValidationScript = validation;
732    return kTRUE;   
733 }
734
735 //______________________________________________________________________________
736 Bool_t AliAnalysisAlien::LoadModules()
737 {
738 // Load all modules by executing the AddTask macros. Checks first the dependencies.
739    fAdditionalLibs = "";
740    Int_t nmodules = GetNmodules();
741    if (!nmodules) {
742       Warning("LoadModules", "No module to be loaded");
743       return kTRUE;
744    }   
745    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
746    if (!mgr) {
747       Error("LoadModules", "No analysis manager created yet. Use CreateAnalysisManager first.");
748       return kFALSE;
749    }   
750    if (!CheckDependencies()) return kFALSE;
751    nmodules = GetNmodules();
752    AliAnalysisTaskCfg *mod;
753    for (Int_t imod=0; imod<nmodules; imod++) {
754       mod = (AliAnalysisTaskCfg*)fModules->At(imod);
755       if (!LoadModule(mod)) return kFALSE;
756    }
757    // Load additional friend libraries
758    return LoadFriendLibs();
759 }      
760
761 //______________________________________________________________________________
762 Bool_t AliAnalysisAlien::LoadFriendLibs() const
763 {
764 // Load libraries required for reading friends.
765    if (fFriendLibs.Length()) {
766       TObjArray *list = 0;
767       TString lib;
768       if (fFriendLibs.Contains(",")) list  = fFriendLibs.Tokenize(",");
769       else                           list  = fFriendLibs.Tokenize(" ");
770       for (Int_t ilib=0; ilib<list->GetEntriesFast(); ilib++) {
771          lib = list->At(ilib)->GetName();
772          lib.ReplaceAll(".so","");
773          lib.ReplaceAll(".dylib","");
774          lib.ReplaceAll(" ","");
775          if (lib.BeginsWith("lib")) lib.Remove(0, 3);
776          lib.Prepend("lib");
777          Int_t loaded = strlen(gSystem->GetLibraries(lib,"",kFALSE));
778          if (!loaded) loaded = gSystem->Load(lib);
779          if (loaded < 0) {
780             Error("LoadModules", "Cannot load library for friends %s", lib.Data());
781             return kFALSE;
782          }
783       }
784       delete list;
785    }
786    return kTRUE;
787 }   
788
789 //______________________________________________________________________________
790 void AliAnalysisAlien::SetRunPrefix(const char *prefix)
791 {
792 // Set the run number format. Can be a prefix or a format like "%09d"
793    fRunPrefix = prefix;
794    if (!fRunPrefix.Contains("%")) fRunPrefix += "%d";
795 }   
796
797 //______________________________________________________________________________
798 void AliAnalysisAlien::AddIncludePath(const char *path)
799 {
800 // Add include path in the remote analysis macro.
801    TString p(path);
802    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
803    else                  fIncludePath += Form("-I%s ", path);
804 }
805
806 //______________________________________________________________________________
807 void AliAnalysisAlien::AddRunNumber(Int_t run)
808 {
809 // Add a run number to the list of runs to be processed.
810    if (fRunNumbers.Length()) fRunNumbers += " ";
811    fRunNumbers += Form(fRunPrefix.Data(), run);
812 }   
813
814 //______________________________________________________________________________
815 void AliAnalysisAlien::AddRunList(const char* runList)
816 {
817 // Add several runs into the list of runs; they are expected to be separated by a blank character.  
818   TString    sList = runList;
819   TObjArray *list  = sList.Tokenize(" ");
820   Int_t n = list->GetEntries();
821   for (Int_t i = 0; i < n; i++) {
822     TObjString *os = (TObjString*)list->At(i);
823     AddRunNumber(os->GetString().Atoi());
824   }
825   delete list;
826 }
827
828 //______________________________________________________________________________
829 void AliAnalysisAlien::AddRunNumber(const char* run)
830 {
831 // Add a run number to the list of runs to be processed.
832    TString runs = run;
833    TObjString *os;
834    TObjArray *arr = runs.Tokenize(" ");
835    TIter next(arr);
836    TString prefix; 
837    prefix.Append(fRunPrefix, fRunPrefix.Index("%d"));
838    while ((os=(TObjString*)next())){
839        if (fRunNumbers.Length()) fRunNumbers += " ";
840        fRunNumbers += Form("%s%s", prefix.Data(), os->GetString().Data());
841    }
842    delete arr;
843 }   
844
845 //______________________________________________________________________________
846 void AliAnalysisAlien::AddDataFile(const char *lfn)
847 {
848 // Adds a data file to the input to be analysed. The file should be a valid LFN
849 // or point to an existing file in the alien workdir.
850    if (!fInputFiles) fInputFiles = new TObjArray();
851    fInputFiles->Add(new TObjString(lfn));
852 }
853
854 //______________________________________________________________________________
855 void AliAnalysisAlien::AddExternalPackage(const char *package)
856 {
857 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
858    if (fExternalPackages) fExternalPackages += " ";
859    fExternalPackages += package;
860 }   
861       
862 //______________________________________________________________________________
863 Bool_t AliAnalysisAlien::Connect()
864 {
865 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
866    if (gGrid && gGrid->IsConnected()) return kTRUE;
867    if (fProductionMode) return kTRUE;
868    if (!gGrid) {
869       Info("Connect", "Trying to connect to AliEn ...");
870       TGrid::Connect("alien://");
871    }
872    if (!gGrid || !gGrid->IsConnected()) {
873       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
874       return kFALSE;
875    }  
876    fUser = gGrid->GetUser();
877    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
878    return kTRUE;
879 }
880
881 //______________________________________________________________________________
882 void AliAnalysisAlien::CdWork()
883 {
884 // Check validity of alien workspace. Create directory if possible.
885    if (!Connect()) {
886       Error("CdWork", "Alien connection required");
887       return;
888    } 
889    TString homedir = gGrid->GetHomeDirectory();
890    TString workdir = homedir + fGridWorkingDir;
891    if (DirectoryExists(workdir)) {
892       gGrid->Cd(workdir);
893       return;
894    }   
895    // Work directory not existing - create it
896    gGrid->Cd(homedir);
897    if (gGrid->Mkdir(workdir, "-p")) {
898       gGrid->Cd(fGridWorkingDir);
899       Info("CdWork", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
900    } else {
901       Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
902               workdir.Data(), homedir.Data());
903       fGridWorkingDir = "";
904    }          
905 }
906
907 //______________________________________________________________________________
908 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
909 {
910 // Check if file copying is possible.
911    if (fProductionMode) return kTRUE;
912    TString salienpath(alienpath);
913    if (salienpath.Contains(" ")) {
914       Error("CheckFileCopy", "path: <%s> contains blancs - FIX IT !",alienpath);
915       return kFALSE;
916    }   
917    if (!Connect()) {
918       Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
919       return kFALSE;
920    }
921    Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
922         \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
923    // Check if alien_CLOSE_SE is defined
924    TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
925    if (!closeSE.IsNull()) {
926       Info("CheckFileCopy", "Your current close storage is pointing to: \
927            \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
928    } else {
929       Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
930    }        
931    // Check if grid directory exists.
932    if (!DirectoryExists(alienpath)) {
933       Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
934       return kFALSE;
935    }
936    TString stest = "plugin_test_copy";
937    TFile f(stest, "RECREATE");
938    // User may not have write permissions to current directory 
939    if (f.IsZombie()) {
940       Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
941             gSystem->WorkingDirectory());
942       return kFALSE;
943    }
944    f.Close();
945    if (FileExists(Form("alien://%s/%s",alienpath, stest.Data()))) gGrid->Rm(Form("alien://%s/%s",alienpath, stest.Data()));
946    if (!TFile::Cp(stest.Data(), Form("alien://%s/%s",alienpath, stest.Data()))) {
947       Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
948            \n# 1. Make sure you have write permissions there. If this is the case: \
949            \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
950            \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
951            \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
952            \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
953       gSystem->Unlink(stest.Data());
954       return kFALSE;
955    }   
956    gSystem->Unlink(stest.Data());
957    gGrid->Rm(Form("%s/%s",alienpath,stest.Data()));
958    Info("CheckFileCopy", "### ...SUCCESS ###");
959    return kTRUE;
960 }   
961
962 //______________________________________________________________________________
963 Bool_t AliAnalysisAlien::CheckInputData()
964 {
965 // Check validity of input data. If necessary, create xml files.
966    if (fProductionMode) return kTRUE;
967    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
968       if (!fGridDataDir.Length()) {
969          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
970          return kFALSE;
971       }
972       if (fMergeViaJDL) {
973          Error("CheckInputData", "Merging via jdl works only with run numbers, run range or provided xml");
974          return kFALSE;
975       }   
976       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
977       if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
978          TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode) 
979       return kTRUE;
980    }
981    // Process declared files
982    Bool_t isCollection = kFALSE;
983    Bool_t isXml = kFALSE;
984    Bool_t useTags = kFALSE;
985    Bool_t checked = kFALSE;
986    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
987    TString file;
988    TString workdir = gGrid->GetHomeDirectory();
989    workdir += fGridWorkingDir;
990    if (fInputFiles) {
991       TObjString *objstr;
992       TIter next(fInputFiles);
993       while ((objstr=(TObjString*)next())) {
994          file = workdir;
995          file += "/";
996          file += objstr->GetString();
997          // Store full lfn path
998          if (FileExists(file)) objstr->SetString(file);
999          else {
1000             file = objstr->GetName();
1001             if (!FileExists(objstr->GetName())) {
1002                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
1003                      objstr->GetName(), workdir.Data());
1004                return kFALSE;
1005             }         
1006          }
1007          Bool_t iscoll, isxml, usetags;
1008          CheckDataType(file, iscoll, isxml, usetags);
1009          if (!checked) {
1010             checked = kTRUE;
1011             isCollection = iscoll;
1012             isXml = isxml;
1013             useTags = usetags;
1014             TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
1015          } else {
1016             if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
1017                Error("CheckInputData", "Some conflict was found in the types of inputs");
1018                return kFALSE;
1019             } 
1020          }
1021       }
1022    }
1023    // Process requested run numbers
1024    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
1025    // Check validity of alien data directory
1026    if (!fGridDataDir.Length()) {
1027       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
1028       return kFALSE;
1029    }
1030    if (!DirectoryExists(fGridDataDir)) {
1031       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
1032       return kFALSE;
1033    }
1034    if (isCollection) {
1035       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
1036       return kFALSE;   
1037    }
1038    
1039    if (checked && !isXml) {
1040       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
1041       return kFALSE;   
1042    }
1043    // Check validity of run number(s)
1044    TObjArray *arr;
1045    TObjString *os;
1046    TString format;
1047    Int_t nruns = 0;
1048    TString schunk, schunk2;
1049    TString path;
1050    if (!checked) {
1051       checked = kTRUE;
1052       useTags = fDataPattern.Contains("tag");
1053       TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
1054    }   
1055    if (useTags != fDataPattern.Contains("tag")) {
1056       Error("CheckInputData", "Cannot mix input files using/not using tags");
1057       return kFALSE;
1058    }
1059    if (fRunNumbers.Length()) {
1060       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
1061       arr = fRunNumbers.Tokenize(" ");
1062       TIter next(arr);
1063       while ((os=(TObjString*)next())) {
1064          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
1065          if (!DirectoryExists(path)) {
1066             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
1067             continue;
1068          }
1069          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
1070          TString msg = "\n#####   file: ";
1071          msg += path;
1072          msg += " type: xml_collection;";
1073          if (useTags) msg += " using_tags: Yes";
1074          else          msg += " using_tags: No";
1075          Info("CheckDataType", "%s", msg.Data());
1076          if (fNrunsPerMaster<2) {
1077             AddDataFile(Form("%s.xml", os->GetString().Data()));
1078          } else {
1079             nruns++;
1080             if (((nruns-1)%fNrunsPerMaster) == 0) {
1081                schunk = os->GetString();
1082             }   
1083             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
1084             schunk += Form("_%s.xml", os->GetString().Data());
1085             AddDataFile(schunk);
1086          }   
1087       }
1088       delete arr;   
1089    } else {
1090       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
1091       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1092          format = Form("%%s/%s ", fRunPrefix.Data());
1093          path = Form(format.Data(), fGridDataDir.Data(), irun);
1094          if (!DirectoryExists(path)) {
1095             continue;
1096          }
1097          format = Form("%%s/%s.xml", fRunPrefix.Data());
1098          path = Form(format.Data(), workdir.Data(),irun);
1099          TString msg = "\n#####   file: ";
1100          msg += path;
1101          msg += " type: xml_collection;";
1102          if (useTags) msg += " using_tags: Yes";
1103          else          msg += " using_tags: No";
1104          Info("CheckDataType", "%s", msg.Data());
1105          if (fNrunsPerMaster<2) {
1106             format = Form("%s.xml", fRunPrefix.Data());
1107             AddDataFile(Form(format.Data(),irun));
1108          } else {
1109             nruns++;
1110             if (((nruns-1)%fNrunsPerMaster) == 0) {
1111                schunk = Form(fRunPrefix.Data(),irun);
1112             }
1113             format = Form("_%s.xml", fRunPrefix.Data());
1114             schunk2 = Form(format.Data(), irun);
1115             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
1116             schunk += schunk2;
1117             AddDataFile(schunk);
1118          }   
1119       }
1120       if (!fInputFiles) {
1121          schunk += schunk2;
1122          AddDataFile(schunk);
1123       }   
1124    }
1125    return kTRUE;      
1126 }   
1127
1128 //______________________________________________________________________________
1129 Int_t AliAnalysisAlien::CopyLocalDataset(const char *griddir, const char *pattern, Int_t nfiles, const char *output, const char *archivefile, const char *outputdir)
1130 {
1131 // Copy data from the given grid directory according a pattern and make a local
1132 // dataset.
1133 // archivefile (optional) results in that the archive containing the file <pattern> is copied. archivefile can contain a list of files (semicolon-separated) which are all copied
1134    if (!Connect()) {
1135       Error("CopyLocalDataset", "Cannot copy local dataset with no grid connection");
1136       return 0;
1137    }
1138    if (!DirectoryExists(griddir)) {
1139       Error("CopyLocalDataset", "Data directory %s not existing.", griddir);
1140       return 0;
1141    }
1142    TString command = Form("find -z -l %d %s %s", nfiles, griddir, pattern);
1143    printf("Running command: %s\n", command.Data());
1144    TGridResult *res = gGrid->Command(command);
1145    Int_t nfound = res->GetEntries();
1146    if (!nfound) {
1147       Error("CopyLocalDataset", "No file found in <%s> having pattern <%s>", griddir, pattern);
1148       return 0;
1149    }
1150    printf("... found %d files. Copying locally ...\n", nfound);
1151    
1152    // archives
1153    TObjArray* additionalArchives = 0;
1154    if (strlen(archivefile) > 0 && TString(archivefile).Contains(";")) {
1155       additionalArchives = TString(archivefile).Tokenize(";");
1156       archivefile = additionalArchives->At(0)->GetName();
1157       additionalArchives->RemoveAt(0);
1158       additionalArchives->Compress();
1159    }
1160    
1161    // Copy files locally
1162    ofstream out;
1163    out.open(output, ios::out);
1164    TMap *map;
1165    TString turl, dirname, filename, temp;
1166    TString cdir = gSystem->WorkingDirectory();
1167    gSystem->MakeDirectory(outputdir);
1168    gSystem->ChangeDirectory(outputdir);
1169    Int_t ncopied = 0;
1170    for (Int_t i=0; i<nfound; i++) {
1171       map = (TMap*)res->At(i);
1172       turl = map->GetValue("turl")->GetName();
1173       filename = gSystem->BaseName(turl.Data());
1174       dirname = gSystem->DirName(turl.Data());
1175       dirname = gSystem->BaseName(dirname.Data());
1176       gSystem->MakeDirectory(dirname);
1177       
1178       TString source(turl);
1179       TString targetFileName(filename);
1180       
1181       if (strlen(archivefile) > 0) {
1182 // TODO here the archive in which the file resides should be determined
1183 // however whereis returns only a guid, and guid2lfn does not work
1184 // Therefore we use the one provided as argument for now
1185          source = Form("%s/%s", gSystem->DirName(source.Data()), archivefile);
1186          targetFileName = archivefile;
1187       }
1188       if (TFile::Cp(source, Form("file:./%s/%s", dirname.Data(), targetFileName.Data()))) {
1189          Bool_t success = kTRUE;
1190          if (additionalArchives) {
1191             for (Int_t j=0; j<additionalArchives->GetEntriesFast(); j++) {
1192                TString target;
1193                target.Form("./%s/%s", dirname.Data(), additionalArchives->At(j)->GetName());
1194                gSystem->MakeDirectory(gSystem->DirName(target));
1195                success &= TFile::Cp(Form("%s/%s", gSystem->DirName(source.Data()), additionalArchives->At(j)->GetName()), Form("file:%s", target.Data()));
1196             }
1197          }
1198
1199          if (success) {
1200             if (strlen(archivefile) > 0) targetFileName = Form("%s#%s", targetFileName.Data(), gSystem->BaseName(turl.Data()));
1201             out << cdir << Form("/%s/%s/%s", outputdir, dirname.Data(), targetFileName.Data()) << endl;
1202             ncopied++;
1203          }
1204       }
1205    }
1206    gSystem->ChangeDirectory(cdir);
1207    delete res;
1208    delete additionalArchives;
1209    return ncopied;
1210 }   
1211
1212 //______________________________________________________________________________
1213 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
1214 {
1215 // Create dataset for the grid data directory + run number.
1216    const Int_t gMaxEntries = 15000;
1217    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
1218    if (!Connect()) {
1219       Error("CreateDataset", "Cannot create dataset with no grid connection");
1220       return kFALSE;
1221    }   
1222
1223    // Cd workspace
1224    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
1225    TString workdir = gGrid->GetHomeDirectory();
1226    workdir += fGridWorkingDir;
1227
1228    // Compose the 'find' command arguments
1229    TString format;
1230    TString command;
1231    TString delimiter = pattern;
1232    delimiter.Strip();
1233    if (delimiter.Contains(" ")) delimiter = "";
1234    else delimiter = " ";
1235    TString options = "-x collection ";
1236    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
1237    else options += Form("-l %d ", gMaxEntries);  // Protection for the find command
1238    TString conditions = "";
1239    Int_t nstart = 0;
1240    Int_t ncount = 0;
1241    Int_t stage = 0;
1242    TString file;
1243    TString path;
1244    Int_t nruns = 0;
1245    TString schunk, schunk2;
1246    TGridCollection *cbase=0, *cadd=0;
1247    if (!fRunNumbers.Length() && !fRunRange[0]) {
1248       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
1249       // Make a single data collection from data directory.
1250       path = fGridDataDir;
1251       if (!DirectoryExists(path)) {
1252          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
1253          return kFALSE;
1254       } 
1255 //      CdWork();
1256       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1257       else file = Form("%s.xml", gSystem->BaseName(path));
1258       while (1) {
1259          ncount = 0;
1260          stage++;
1261          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1262             command = "find ";
1263             command += Form("%s -o %d ",options.Data(), nstart);
1264             command += path;
1265             command += delimiter;
1266             command += pattern;
1267             command += conditions;
1268             printf("command: %s\n", command.Data());
1269             TGridResult *res = gGrid->Command(command);
1270             if (res) delete res;
1271             // Write standard output to file
1272             gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage, file.Data()));
1273             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1274             Bool_t nullFile = kFALSE;
1275             if (!hasGrep) {
1276                 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1277             } else {
1278                nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1279                if (nullFile) {
1280                   Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
1281                   gSystem->Exec("rm -f __tmp*");
1282                   return kFALSE;
1283                }
1284                TString line;
1285                ifstream in;
1286                in.open("__tmp__");
1287                in >> line;
1288                in.close();
1289                gSystem->Exec("rm -f __tmp__");
1290                ncount = line.Atoi();
1291             }         
1292          }
1293          if (ncount == gMaxEntries) {
1294             Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1295             cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1296             if (!cbase) cbase = cadd;
1297             else {
1298                cbase->Add(cadd);
1299                delete cadd;
1300             }   
1301             nstart += ncount;
1302          } else {
1303             if (cbase) {
1304                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1305                printf("... please wait - TAlienCollection::Add() scales badly...\n");
1306                cbase->Add(cadd);
1307                delete cadd;
1308                cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1309                delete cbase; cbase = 0;               
1310             } else {
1311                TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1312             }
1313             gSystem->Exec("rm -f __tmp*");   
1314             Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1315             break;
1316          }
1317       }
1318       Bool_t fileExists = FileExists(file);
1319       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
1320          // Copy xml file to alien space
1321          if (fileExists) gGrid->Rm(file);
1322          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1323          if (!FileExists(file)) {
1324             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1325             return kFALSE;
1326          }
1327          // Update list of files to be processed.
1328       }
1329       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
1330       return kTRUE;
1331    }   
1332    // Several runs
1333    Bool_t nullResult = kTRUE;
1334    if (fRunNumbers.Length()) {
1335       TObjArray *arr = fRunNumbers.Tokenize(" ");
1336       TObjString *os;
1337       TIter next(arr);
1338       while ((os=(TObjString*)next())) {
1339          nstart = 0;
1340          stage = 0;
1341          path = Form("%s/%s", fGridDataDir.Data(), os->GetString().Data());
1342          if (!DirectoryExists(path)) continue;
1343 //         CdWork();
1344          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1345          else file = Form("%s.xml", os->GetString().Data());
1346          // If local collection file does not exist, create it via 'find' command.
1347          while (1) {
1348             ncount = 0;
1349             stage++;
1350             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1351                command = "find ";
1352                command +=  Form("%s -o %d ",options.Data(), nstart);
1353                command += path;
1354                command += delimiter;
1355                command += pattern;
1356                command += conditions;
1357                TGridResult *res = gGrid->Command(command);
1358                if (res) delete res;
1359                // Write standard output to file
1360                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1361                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1362                Bool_t nullFile = kFALSE;
1363                if (!hasGrep) {
1364                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1365                } else {
1366                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1367                   if (nullFile) {
1368                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1369                      gSystem->Exec("rm -f __tmp*");
1370                      fRunNumbers.ReplaceAll(os->GetString().Data(), "");
1371                      break;
1372                   }   
1373                   TString line;
1374                   ifstream in;
1375                   in.open("__tmp__");
1376                   in >> line;
1377                   in.close();
1378                   gSystem->Exec("rm -f __tmp__");   
1379                   ncount = line.Atoi();
1380                }
1381                nullResult = kFALSE;         
1382             }
1383             if (ncount == gMaxEntries) {
1384                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1385                if (fNrunsPerMaster > 1) {
1386                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1387                           file.Data(),gMaxEntries);
1388                   return kFALSE;
1389                }           
1390                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1391                if (!cbase) cbase = cadd;
1392                else {
1393                   cbase->Add(cadd);
1394                   delete cadd;
1395                }   
1396                nstart += ncount;
1397             } else {
1398                if (cbase && fNrunsPerMaster<2) {
1399                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1400                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1401                   cbase->Add(cadd);
1402                   delete cadd;
1403                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1404                   delete cbase; cbase = 0;               
1405                } else {
1406                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1407                }
1408                gSystem->Exec("rm -f __tmp*");   
1409                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1410                break;
1411             }
1412          }   
1413          if (TestBit(AliAnalysisGrid::kTest)) break;
1414          // Check if there is one run per master job.
1415          if (fNrunsPerMaster<2) {
1416             if (FileExists(file)) {
1417                if (fOverwriteMode) gGrid->Rm(file);
1418                else {
1419                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1420                   continue;
1421                }   
1422             }        
1423             // Copy xml file to alien space
1424             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1425             if (!FileExists(file)) {
1426                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1427                delete arr;
1428                return kFALSE;
1429             }
1430          } else {
1431             nruns++;
1432             if (((nruns-1)%fNrunsPerMaster) == 0) {
1433                schunk = os->GetString();
1434                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1435             } else {
1436                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1437                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
1438                cbase->Add(cadd);
1439                delete cadd;
1440             }
1441             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
1442                continue;
1443             }   
1444             schunk += Form("_%s.xml", os->GetString().Data());
1445             if (FileExists(schunk)) {               
1446                if (fOverwriteMode) gGrid->Rm(file);
1447                else {
1448                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1449                   continue;
1450                }   
1451             }        
1452             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
1453             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1454             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1455             if (!FileExists(schunk)) {
1456                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1457                delete arr;
1458                return kFALSE;
1459             }
1460          }
1461       }   
1462       delete arr;
1463       if (nullResult) {
1464          Error("CreateDataset", "No valid dataset corresponding to the query!");
1465          return kFALSE;
1466       }
1467    } else {
1468       // Process a full run range.
1469       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1470          format = Form("%%s/%s", fRunPrefix.Data());
1471          nstart = 0;
1472          stage = 0;
1473          path = Form(format.Data(), fGridDataDir.Data(), irun);
1474          if (!DirectoryExists(path)) continue;
1475 //         CdWork();
1476          format = Form("%s.xml", fRunPrefix.Data());
1477          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1478          else file = Form(format.Data(), irun);
1479          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
1480             if (fOverwriteMode) gGrid->Rm(file);
1481             else {
1482                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1483                continue;
1484             }   
1485          }
1486          // If local collection file does not exist, create it via 'find' command.
1487          while (1) {
1488             ncount = 0;
1489             stage++;
1490             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1491                command = "find ";
1492                command +=  Form("%s -o %d ",options.Data(), nstart);
1493                command += path;
1494                command += delimiter;
1495                command += pattern;
1496                command += conditions;
1497                TGridResult *res = gGrid->Command(command);
1498                if (res) delete res;
1499                // Write standard output to file
1500                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1501                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1502                Bool_t nullFile = kFALSE;
1503                if (!hasGrep) {
1504                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1505                } else {
1506                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1507                   if (nullFile) {
1508                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1509                      gSystem->Exec("rm -f __tmp*");
1510                      break;
1511                   }   
1512                   TString line;
1513                   ifstream in;
1514                   in.open("__tmp__");
1515                   in >> line;
1516                   in.close();
1517                   gSystem->Exec("rm -f __tmp__");   
1518                   ncount = line.Atoi();
1519                }
1520                nullResult = kFALSE;         
1521             }   
1522             if (ncount == gMaxEntries) {
1523                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1524                if (fNrunsPerMaster > 1) {
1525                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1526                           file.Data(),gMaxEntries);
1527                   return kFALSE;
1528                }           
1529                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1530                if (!cbase) cbase = cadd;
1531                else {
1532                   cbase->Add(cadd);
1533                   delete cadd;
1534                }   
1535                nstart += ncount;
1536             } else {
1537                if (cbase && fNrunsPerMaster<2) {
1538                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1539                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1540                   cbase->Add(cadd);
1541                   delete cadd;
1542                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1543                   delete cbase; cbase = 0;               
1544                } else {
1545                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1546                }
1547                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1548                break;
1549             }
1550          }   
1551          if (TestBit(AliAnalysisGrid::kTest)) break;
1552          // Check if there is one run per master job.
1553          if (fNrunsPerMaster<2) {
1554             if (FileExists(file)) {
1555                if (fOverwriteMode) gGrid->Rm(file);
1556                else {
1557                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1558                   continue;
1559                }   
1560             }        
1561             // Copy xml file to alien space
1562             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1563             if (!FileExists(file)) {
1564                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1565                return kFALSE;
1566             }
1567          } else {
1568             nruns++;
1569             // Check if the collection for the chunk exist locally.
1570             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
1571             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
1572                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
1573                else continue;
1574             }   
1575             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
1576             if (((nruns-1)%fNrunsPerMaster) == 0) {
1577                schunk = Form(fRunPrefix.Data(), irun);
1578                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1579             } else {
1580                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1581                cbase->Add(cadd);
1582                delete cadd;
1583             }
1584             format = Form("%%s_%s.xml", fRunPrefix.Data());
1585             schunk2 = Form(format.Data(), schunk.Data(), irun);
1586             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
1587                continue;
1588             }   
1589             schunk = schunk2;
1590             if (FileExists(schunk)) {
1591                if (fOverwriteMode) gGrid->Rm(schunk);
1592                else {
1593                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1594                   continue;
1595                }   
1596             }        
1597             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
1598             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1599             if (FileExists(schunk)) {
1600                if (fOverwriteMode) gGrid->Rm(schunk);
1601                else {
1602                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
1603                   continue;
1604                }   
1605             }   
1606             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1607             if (!FileExists(schunk)) {
1608                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1609                return kFALSE;
1610             }
1611          }   
1612       }
1613       if (nullResult) {
1614          Error("CreateDataset", "No valid dataset corresponding to the query!");
1615          return kFALSE;
1616       }      
1617    }      
1618    return kTRUE;
1619 }
1620
1621 //______________________________________________________________________________
1622 Bool_t AliAnalysisAlien::CreateJDL()
1623 {
1624 // Generate a JDL file according to current settings. The name of the file is 
1625 // specified by fJDLName.
1626    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1627    Bool_t error = kFALSE;
1628    TObjArray *arr = 0;
1629    Bool_t copy = kTRUE;
1630    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1631    Bool_t generate = kTRUE;
1632    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
1633    if (!Connect()) {
1634       Error("CreateJDL", "Alien connection required");
1635       return kFALSE;
1636    }   
1637    // Check validity of alien workspace
1638    TString workdir;
1639    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1640    if (!fProductionMode &&  !TestBit(AliAnalysisGrid::kTest)) CdWork();
1641    workdir += fGridWorkingDir;
1642    if (generate) {
1643       TObjString *os;
1644       if (!fInputFiles && !fMCLoop) {
1645          Error("CreateJDL()", "Define some input files for your analysis.");
1646          error = kTRUE;
1647       }
1648       // Compose list of input files   
1649       // Check if output files were defined
1650       if (!fOutputFiles.Length()) {
1651          Error("CreateJDL", "You must define at least one output file");
1652          error = kTRUE;
1653       }   
1654       // Check if an output directory was defined and valid
1655       if (!fGridOutputDir.Length()) {
1656          Error("CreateJDL", "You must define AliEn output directory");
1657          error = kTRUE;
1658       } else {
1659          if (!fProductionMode) {
1660             if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1661             if (!DirectoryExists(fGridOutputDir)) {
1662                if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1663                   Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1664                } else {
1665                   Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1666                   // error = kTRUE;
1667                }
1668             } else {
1669                Warning("CreateJDL", "#### Output directory %s exists! If this contains old data, jobs will fail with ERROR_SV !!! ###", fGridOutputDir.Data());
1670             }   
1671             gGrid->Cd(workdir);
1672          }   
1673       }   
1674       // Exit if any error up to now
1675       if (error) return kFALSE;   
1676       // Set JDL fields
1677       if (!fUser.IsNull()) {
1678          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1679          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1680       }
1681       TString executable = fExecutable;
1682       if (!executable.BeginsWith("/")) 
1683          executable.Prepend(Form("%s/", workdir.Data()));
1684       fGridJDL->SetExecutable(executable, "This is the startup script");
1685       TString mergeExec = executable;
1686       mergeExec.ReplaceAll(".sh", "_merge.sh");
1687       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
1688       mergeExec.ReplaceAll(".sh", ".C");
1689       fMergingJDL->AddToInputSandbox(Form("LF:%s", mergeExec.Data()), "List of input files to be uploaded to workers");
1690       if (!fArguments.IsNull())
1691          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
1692       if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
1693       else {
1694          if (fProductionMode)  fMergingJDL->SetArguments("wn.xml $4");    // xml, stage
1695          else                  fMergingJDL->SetArguments("wn.xml $2");    // xml, stage
1696      }               
1697
1698       fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1699       fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1700       fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1701       fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1702         
1703       if (fMaxInitFailed > 0) {
1704          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1705          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1706       }   
1707       if (fSplitMaxInputFileNumber > 0 && !fMCLoop) {
1708          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1709          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1710       }
1711       if (!IsOneStageMerging()) {
1712          fMergingJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"",fMaxMergeFiles));
1713          fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1714       }   
1715       if (fSplitMode.Length()) {
1716          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1717          fGridJDL->SetDescription("Split", "We split per SE or file");
1718       }
1719       fMergingJDL->SetValue("Split", "\"se\""); 
1720       fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1721       if (!fAliROOTVersion.IsNull()) {
1722          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1723          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1724       }   
1725       if (!fROOTVersion.IsNull()) {
1726          fGridJDL->AddToPackages("ROOT", fROOTVersion);
1727          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1728       }   
1729       if (!fAPIVersion.IsNull()) {
1730          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1731          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1732       }   
1733       if (!fExternalPackages.IsNull()) {
1734          arr = fExternalPackages.Tokenize(" ");
1735          TIter next(arr);
1736          while ((os=(TObjString*)next())) {
1737             TString pkgname = os->GetString();
1738             Int_t index = pkgname.Index("::");
1739             TString pkgversion = pkgname(index+2, pkgname.Length());
1740             pkgname.Remove(index);
1741             fGridJDL->AddToPackages(pkgname, pkgversion);
1742             fMergingJDL->AddToPackages(pkgname, pkgversion);
1743          }   
1744          delete arr;   
1745       }   
1746       if (!fMCLoop) {
1747          fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1748          fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1749       }   
1750       fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1751       fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1752       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1753       TString analysisFile = fExecutable;
1754       analysisFile.ReplaceAll(".sh", ".root");
1755       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1756       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1757       if (fAdditionalLibs.Length()) {
1758          arr = fAdditionalLibs.Tokenize(" ");
1759          TIter next(arr);
1760          while ((os=(TObjString*)next())) {
1761             if (os->GetString().Contains(".so") ||
1762                 os->GetString().Contains(".dylib")) continue;
1763             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1764             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1765          }   
1766          delete arr;   
1767       }
1768       if (fPackages) {
1769          TIter next(fPackages);
1770          TObject *obj;
1771          while ((obj=next())) {
1772             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1773             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1774          }
1775       }
1776       const char *comment = "List of output files and archives";
1777       if (fOutputArchive.Length()) {
1778          TString outputArchive = fOutputArchive;
1779          if (!fRegisterExcludes.IsNull()) {
1780             arr = fRegisterExcludes.Tokenize(" ");
1781             TIter next1(arr);
1782             while ((os=(TObjString*)next1())) {
1783                outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1784                outputArchive.ReplaceAll(os->GetString(),"");
1785             } 
1786             delete arr;
1787          }     
1788          arr = outputArchive.Tokenize(" ");
1789          TIter next(arr);
1790          Bool_t first = kTRUE;
1791          while ((os=(TObjString*)next())) {
1792             if (!os->GetString().Contains("@") && fCloseSE.Length())
1793                fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data()));
1794             else
1795                fGridJDL->AddToSet("Output", os->GetString());
1796             if (first) fGridJDL->AddToSetDescription("Output", comment);
1797             first = kFALSE;   
1798          }      
1799          delete arr;
1800          // Output archive for the merging jdl
1801          if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1802             outputArchive = "log_archive.zip:std*@disk=1 ";
1803             // Add normal output files, extra files + terminate files
1804             TString files;
1805             if (IsMergeAOD()) files = GetListOfFiles("outaodextter");
1806             else files = GetListOfFiles("outextter");
1807             // Do not register files in fRegisterExcludes
1808             if (!fRegisterExcludes.IsNull()) {
1809                arr = fRegisterExcludes.Tokenize(" ");
1810                TIter next1(arr);
1811                while ((os=(TObjString*)next1())) {
1812                   files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1813                   files.ReplaceAll(os->GetString(),"");
1814                }   
1815                delete arr;
1816             }
1817             files.ReplaceAll(".root", "*.root");
1818             
1819             if (mgr->IsCollectThroughput())
1820                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d %s@disk=%d",files.Data(),fNreplicas, mgr->GetFileInfoLog(),fNreplicas);
1821             else
1822                outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",files.Data(),fNreplicas);
1823          } else {
1824             TString files = fOutputArchive;
1825             files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1826             outputArchive = files;
1827          }   
1828          arr = outputArchive.Tokenize(" ");
1829          TIter next2(arr);
1830          first = kTRUE;
1831          while ((os=(TObjString*)next2())) {
1832             TString currentfile = os->GetString();
1833             if (!currentfile.Contains("@") && fCloseSE.Length())
1834                fMergingJDL->AddToSet("Output", Form("%s@%s",currentfile.Data(), fCloseSE.Data()));
1835             else
1836                fMergingJDL->AddToSet("Output", currentfile);
1837             if (first) fMergingJDL->AddToSetDescription("Output", comment);
1838             first = kFALSE;   
1839          }      
1840          delete arr;         
1841       }      
1842       arr = fOutputFiles.Tokenize(",");
1843       TIter next(arr);
1844       Bool_t first = kTRUE;
1845       while ((os=(TObjString*)next())) {
1846          // Ignore ouputs in jdl that are also in outputarchive
1847          TString sout = os->GetString();
1848          sout.ReplaceAll("*", "");
1849          sout.ReplaceAll(".root", "");
1850          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1851          if (fOutputArchive.Contains(sout)) continue;
1852          // Ignore fRegisterExcludes
1853          if (fRegisterExcludes.Contains(sout)) continue;
1854          if (!first) comment = NULL;
1855          if (!os->GetString().Contains("@") && fCloseSE.Length())
1856             fGridJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1857          else
1858             fGridJDL->AddToSet("Output", os->GetString());
1859          if (first) fGridJDL->AddToSetDescription("Output", comment); 
1860          if (fMergeExcludes.Contains(sout)) continue;   
1861          if (!os->GetString().Contains("@") && fCloseSE.Length())
1862             fMergingJDL->AddToSet("Output", Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
1863          else
1864             fMergingJDL->AddToSet("Output", os->GetString());
1865          if (first) fMergingJDL->AddToSetDescription("Output", comment);
1866          first = kFALSE;
1867       }   
1868       delete arr;
1869       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1870       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1871       TString validationScript = fValidationScript;
1872       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1873       validationScript.ReplaceAll(".sh", "_merge.sh");
1874       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1875       if (fMasterResubmitThreshold) {
1876          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1877          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1878       }   
1879       // Write a jdl with 2 input parameters: collection name and output dir name.
1880       WriteJDL(copy);
1881    }
1882    // Copy jdl to grid workspace   
1883    if (copy) {
1884       // Check if an output directory was defined and valid
1885       if (!fGridOutputDir.Length()) {
1886          Error("CreateJDL", "You must define AliEn output directory");
1887          return kFALSE;
1888       } else {
1889          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1890          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1891             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1892                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1893             } else {
1894                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1895                return kFALSE;
1896             }
1897          }
1898          gGrid->Cd(workdir);
1899       }   
1900       if (TestBit(AliAnalysisGrid::kSubmit)) {
1901          TString mergeJDLName = fExecutable;
1902          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1903          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1904          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1905          if (fProductionMode) {
1906             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1907             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1908          }   
1909          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1910          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1911          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1912          if (!copyLocal2Alien("CreateJDL", fJDLName, locjdl)) 
1913             Fatal("","Terminating");
1914 //         TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1915          if (fMergeViaJDL) {
1916             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1917 //            TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1918             if (!copyLocal2Alien("CreateJDL", mergeJDLName.Data(), locjdl1)) 
1919                Fatal("","Terminating");
1920          }   
1921       }
1922       if (fAdditionalLibs.Length()) {
1923          arr = fAdditionalLibs.Tokenize(" ");
1924          TObjString *os;
1925          TIter next(arr);
1926          while ((os=(TObjString*)next())) {
1927             if (os->GetString().Contains(".so") ||
1928                 os->GetString().Contains(".dylib")) continue;
1929             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1930             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1931 //            TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1932             if (!copyLocal2Alien("CreateJDL", os->GetString().Data(), 
1933                 Form("%s/%s", workdir.Data(), os->GetString().Data())))
1934               Fatal("","Terminating");
1935          }   
1936          delete arr;   
1937       }
1938       if (fPackages) {
1939          TIter next(fPackages);
1940          TObject *obj;
1941          while ((obj=next())) {
1942             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1943             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1944 //            TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1945             if (!copyLocal2Alien("CreateJDL",obj->GetName(), 
1946                 Form("%s/%s", workdir.Data(), obj->GetName()))) 
1947               Fatal("","Terminating"); 
1948          }   
1949       }      
1950    } 
1951    return kTRUE;
1952 }
1953
1954 //______________________________________________________________________________
1955 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1956 {
1957 // Writes one or more JDL's corresponding to findex. If findex is negative,
1958 // all run numbers are considered in one go (jdl). For non-negative indices
1959 // they correspond to the indices in the array fInputFiles.
1960    if (!fInputFiles && !fMCLoop) return kFALSE;
1961    TObject *os;
1962    TString workdir;
1963    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1964    workdir += fGridWorkingDir;
1965    TString stageName = "$2";
1966    if (fProductionMode) stageName = "$4";
1967    if (!fMergeDirName.IsNull()) {
1968      fMergingJDL->AddToInputDataCollection(Form("LF:$1/%s/Stage_%s.xml,nodownload",fMergeDirName.Data(),stageName.Data()), "Collection of files to be merged for current stage");
1969      fMergingJDL->SetOutputDirectory(Form("$1/%s/Stage_%s/#alien_counter_03i#",fMergeDirName.Data(),stageName.Data()), "Output directory");
1970    } else {
1971      fMergingJDL->AddToInputDataCollection(Form("LF:$1/Stage_%s.xml,nodownload",stageName.Data()), "Collection of files to be merged for current stage");
1972      fMergingJDL->SetOutputDirectory(Form("$1/Stage_%s/#alien_counter_03i#",stageName.Data()), "Output directory");
1973    }
1974    if (fProductionMode) {
1975       TIter next(fInputFiles);
1976       while ((os=next())) {
1977          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1978       }
1979       if (!fOutputToRunNo)
1980          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
1981       else  
1982          fGridJDL->SetOutputDirectory(fGridOutputDir);
1983    } else {            
1984       if (!fRunNumbers.Length() && !fRunRange[0]) {
1985          // One jdl with no parameters in case input data is specified by name.
1986          TIter next(fInputFiles);
1987          while ((os=next()))
1988             fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1989          if (!fOutputSingle.IsNull())
1990             fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1991          else {
1992             fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1993 //            fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1994          }   
1995       } else {
1996          // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1997          fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1998          if (!fOutputSingle.IsNull()) {
1999             if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
2000             else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
2001          } else {   
2002             fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
2003          }   
2004       }
2005    }
2006       
2007    // Generate the JDL as a string
2008    TString sjdl = fGridJDL->Generate();
2009    TString sjdl1 = fMergingJDL->Generate();
2010    // Final merge jdl
2011    if (!fMergeDirName.IsNull()) {
2012      fMergingJDL->SetOutputDirectory(Form("$1/%s",fMergeDirName.Data()), "Output directory");
2013      fMergingJDL->AddToInputSandbox(Form("LF:$1/%s/Stage_%s.xml",fMergeDirName.Data(),stageName.Data()));
2014    } else {  
2015      fMergingJDL->SetOutputDirectory("$1", "Output directory");
2016      fMergingJDL->AddToInputSandbox(Form("LF:$1/Stage_%s.xml",stageName.Data()));
2017    }  
2018    TString sjdl2 = fMergingJDL->Generate();
2019    Int_t index, index1;
2020    sjdl.ReplaceAll("\",\"", "\",\n   \"");
2021    sjdl.ReplaceAll("(member", "\n   (member");
2022    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2023    sjdl.ReplaceAll("{", "{\n   ");
2024    sjdl.ReplaceAll("};", "\n};");
2025    sjdl.ReplaceAll("{\n   \n", "{\n");
2026    sjdl.ReplaceAll("\n\n", "\n");
2027    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
2028    sjdl1.ReplaceAll("\",\"", "\",\n   \"");
2029    sjdl1.ReplaceAll("(member", "\n   (member");
2030    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2031    sjdl1.ReplaceAll("{", "{\n   ");
2032    sjdl1.ReplaceAll("};", "\n};");
2033    sjdl1.ReplaceAll("{\n   \n", "{\n");
2034    sjdl1.ReplaceAll("\n\n", "\n");
2035    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
2036    sjdl2.ReplaceAll("\",\"", "\",\n   \"");
2037    sjdl2.ReplaceAll("(member", "\n   (member");
2038    sjdl2.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
2039    sjdl2.ReplaceAll("{", "{\n   ");
2040    sjdl2.ReplaceAll("};", "\n};");
2041    sjdl2.ReplaceAll("{\n   \n", "{\n");
2042    sjdl2.ReplaceAll("\n\n", "\n");
2043    sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
2044    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2045    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
2046    index = sjdl.Index("JDLVariables");
2047    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
2048    sjdl += "Workdirectorysize = {\"5000MB\"};";
2049    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2050    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
2051    index = fJobTag.Index(":");
2052    if (index < 0) index = fJobTag.Length();
2053    TString jobTag = fJobTag;
2054    if (fProductionMode) jobTag.Insert(index,"_Stage$4");
2055    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:%s_Merging\"\n};\n", jobTag.Data()));
2056    if (fProductionMode) {   
2057      sjdl1.Prepend("# Generated merging jdl (production mode) \
2058                     \n# $1 = full alien path to output directory to be merged \
2059                     \n# $2 = train number \
2060                     \n# $3 = production (like LHC10b) \
2061                     \n# $4 = merging stage \
2062                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2063      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2064      sjdl2.Prepend("# Generated merging jdl \
2065                     \n# $1 = full alien path to output directory to be merged \
2066                     \n# $2 = train number \
2067                     \n# $3 = production (like LHC10b) \
2068                     \n# $4 = merging stage \
2069                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2070    } else {
2071      sjdl1.Prepend("# Generated merging jdl \
2072                     \n# $1 = full alien path to output directory to be merged \
2073                     \n# $2 = merging stage \
2074                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2075      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
2076      sjdl2.Prepend("# Generated merging jdl \
2077                     \n# $1 = full alien path to output directory to be merged \
2078                     \n# $2 = merging stage \
2079                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
2080    }
2081    index = sjdl1.Index("JDLVariables");
2082    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
2083    index = sjdl2.Index("JDLVariables");
2084    if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
2085    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
2086    sjdl2 += "Workdirectorysize = {\"5000MB\"};";
2087    index = sjdl2.Index("Split =");
2088    if (index>=0) {
2089       index1 = sjdl2.Index("\n", index);
2090       sjdl2.Remove(index, index1-index+1);
2091    }
2092    index = sjdl2.Index("SplitMaxInputFileNumber");
2093    if (index>=0) {
2094       index1 = sjdl2.Index("\n", index);
2095       sjdl2.Remove(index, index1-index+1);
2096    }
2097    index = sjdl2.Index("InputDataCollection");
2098    if (index>=0) {
2099       index1 = sjdl2.Index(";", index);
2100       sjdl2.Remove(index, index1-index+1);
2101    }
2102    index = sjdl2.Index("InputDataListFormat");
2103    if (index>=0) {
2104       index1 = sjdl2.Index("\n", index);
2105       sjdl2.Remove(index, index1-index+1);
2106    }
2107    index = sjdl2.Index("InputDataList");
2108    if (index>=0) {
2109       index1 = sjdl2.Index("\n", index);
2110       sjdl2.Remove(index, index1-index+1);
2111    }
2112    sjdl2.ReplaceAll("wn.xml", Form("Stage_%s.xml",stageName.Data()));
2113    // Write jdl to file
2114    ofstream out;
2115    out.open(fJDLName.Data(), ios::out);
2116    if (out.bad()) {
2117       Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
2118       return kFALSE;
2119    }
2120    out << sjdl << endl;
2121    out.close();
2122    TString mergeJDLName = fExecutable;
2123    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2124    if (fMergeViaJDL) {
2125       ofstream out1;
2126       out1.open(mergeJDLName.Data(), ios::out);
2127       if (out1.bad()) {
2128          Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
2129          return kFALSE;
2130       }
2131       out1 << sjdl1 << endl;
2132       out1.close();
2133       ofstream out2;
2134       TString finalJDL = mergeJDLName;
2135       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2136       out2.open(finalJDL.Data(), ios::out);
2137       if (out2.bad()) {
2138          Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
2139          return kFALSE;
2140       }
2141       out2 << sjdl2 << endl;
2142       out2.close();
2143    }   
2144
2145    // Copy jdl to grid workspace   
2146    if (!copy) {
2147       Info("WriteJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
2148    } else {
2149       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
2150       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
2151       TString finalJDL = mergeJDLName;
2152       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2153       TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
2154       if (fProductionMode) {
2155          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2156          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
2157          locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
2158       }   
2159       if (FileExists(locjdl)) gGrid->Rm(locjdl);
2160       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
2161       if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
2162       Info("WriteJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
2163 //      TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
2164       if (!copyLocal2Alien("WriteJDL",fJDLName.Data(),locjdl.Data())) 
2165          Fatal("","Terminating");
2166       if (fMergeViaJDL) {
2167          Info("WriteJDL", "\n#####   Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
2168 //         TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
2169 //         TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
2170          if (!copyLocal2Alien("WriteJDL",mergeJDLName.Data(),locjdl1.Data()))
2171             Fatal("","Terminating");
2172          if (!copyLocal2Alien("WriteJDL",finalJDL.Data(),locjdl2.Data()))
2173            Fatal("","Terminating");
2174       }   
2175    } 
2176    return kTRUE;
2177 }
2178
2179 //______________________________________________________________________________
2180 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
2181 {
2182 // Returns true if file exists.
2183    if (!gGrid) return kFALSE;
2184    TString slfn = lfn;
2185    slfn.ReplaceAll("alien://","");
2186    TGridResult *res = gGrid->Ls(slfn);
2187    if (!res) return kFALSE;
2188    TMap *map = dynamic_cast<TMap*>(res->At(0));
2189    if (!map) {
2190       delete res;
2191       return kFALSE;
2192    }   
2193    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
2194    if (!objs || !objs->GetString().Length()) {
2195       delete res;
2196       return kFALSE;
2197    }
2198    delete res;   
2199    return kTRUE;
2200 }
2201
2202 //______________________________________________________________________________
2203 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
2204 {
2205 // Returns true if directory exists. Can be also a path.
2206 // Since there is not API in TAlien, we use the Cd trick:
2207    if (!gGrid) return kFALSE;
2208    // Backup current path
2209    TString cpath = gGrid->Pwd();
2210    TString command = "cd ";
2211    TString sdir(dirname);
2212    sdir.ReplaceAll("alien://", "");
2213    command += sdir;
2214    TGridResult *res = gGrid->Command(command);
2215    if (!res) {
2216       gGrid->Cd(cpath);
2217       return kFALSE;
2218    }   
2219    TMap *map = (TMap*)res->At(0);
2220    if (!map) {
2221       gGrid->Cd(cpath);
2222       delete res;
2223       return kFALSE;
2224    }
2225    TString sval = map->GetValue("__result__")->GetName();
2226    Bool_t retval = (Bool_t)sval.Atoi();
2227    gGrid->Cd(cpath);
2228    delete res;
2229    return retval;
2230 }   
2231
2232 //______________________________________________________________________________
2233 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
2234 {
2235 // Check input data type.
2236    isCollection = kFALSE;
2237    isXml = kFALSE;
2238    useTags = kFALSE;
2239    if (!gGrid) {
2240       Error("CheckDataType", "No connection to grid");
2241       return;
2242    }
2243    isCollection = IsCollection(lfn);
2244    TString msg = "\n#####   file: ";
2245    msg += lfn;
2246    if (isCollection) {
2247       msg += " type: raw_collection;";
2248    // special treatment for collections
2249       isXml = kFALSE;
2250       // check for tag files in the collection
2251       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
2252       if (!res) {
2253          msg += " using_tags: No (unknown)";
2254          Info("CheckDataType", "%s", msg.Data());
2255          return;
2256       }   
2257       const char* typeStr = res->GetKey(0, "origLFN");
2258       if (!typeStr || !strlen(typeStr)) {
2259          msg += " using_tags: No (unknown)";
2260          Info("CheckDataType", "%s", msg.Data());
2261          return;
2262       }   
2263       TString file = typeStr;
2264       useTags = file.Contains(".tag");
2265       if (useTags) msg += " using_tags: Yes";
2266       else          msg += " using_tags: No";
2267       Info("CheckDataType", "%s", msg.Data());
2268       return;
2269    }
2270    TString slfn(lfn);
2271    slfn.ToLower();
2272    isXml = slfn.Contains(".xml");
2273    if (isXml) {
2274    // Open xml collection and check if there are tag files inside
2275       msg += " type: xml_collection;";
2276       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
2277       if (!coll) {
2278          msg += " using_tags: No (unknown)";
2279          Info("CheckDataType", "%s", msg.Data());
2280          return;
2281       }   
2282       TMap *map = coll->Next();
2283       if (!map) {
2284          msg += " using_tags: No (unknown)";
2285          Info("CheckDataType", "%s", msg.Data());
2286          return;
2287       }   
2288       map = (TMap*)map->GetValue("");
2289       TString file;
2290       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
2291       useTags = file.Contains(".tag");
2292       delete coll;
2293       if (useTags) msg += " using_tags: Yes";
2294       else          msg += " using_tags: No";
2295       Info("CheckDataType", "%s", msg.Data());
2296       return;
2297    }
2298    useTags = slfn.Contains(".tag");
2299    if (slfn.Contains(".root")) msg += " type: root file;";
2300    else                        msg += " type: unknown file;";
2301    if (useTags) msg += " using_tags: Yes";
2302    else          msg += " using_tags: No";
2303    Info("CheckDataType", "%s", msg.Data());
2304 }
2305
2306 //______________________________________________________________________________
2307 void AliAnalysisAlien::EnablePackage(const char *package)
2308 {
2309 // Enables a par file supposed to exist in the current directory.
2310    TString pkg(package);
2311    pkg.ReplaceAll(".par", "");
2312    pkg += ".par";
2313    if (gSystem->AccessPathName(pkg)) {
2314       Fatal("EnablePackage", "Package %s not found", pkg.Data());
2315       return;
2316    }
2317    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
2318       Info("EnablePackage", "AliEn plugin will use .par packages");
2319    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
2320    if (!fPackages) {
2321       fPackages = new TObjArray();
2322       fPackages->SetOwner();
2323    }
2324    fPackages->Add(new TObjString(pkg));
2325 }      
2326
2327 //______________________________________________________________________________
2328 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
2329 {
2330 // Make a tree from files having the location specified in fFileForTestMode. 
2331 // Inspired from JF's CreateESDChain.
2332    if (fFileForTestMode.IsNull()) {
2333       Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2334       return NULL;
2335    }
2336    if (gSystem->AccessPathName(fFileForTestMode)) {
2337       Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2338       return NULL;
2339    }   
2340    // Open the file
2341    ifstream in;
2342    in.open(fFileForTestMode);
2343    Int_t count = 0;
2344     // Read the input list of files and add them to the chain
2345    TString line;
2346    TString streeName(treeName);
2347    if (IsUseMCchain()) streeName = "TE";
2348    TChain *chain = new TChain(streeName);
2349    TList *friends = new TList();
2350    TChain *cfriend = 0;
2351    if (!fFriendChainName.IsNull()) {
2352       TObjArray *list = fFriendChainName.Tokenize(" ");
2353       TIter next(list);
2354       TObjString *str;
2355       while((str=(TObjString*)next())) {
2356          cfriend = new TChain(streeName, str->GetName());
2357          friends->Add(cfriend);
2358          chain->AddFriend(cfriend);
2359       }
2360       delete list;
2361    } 
2362    TString bpath;
2363    TIter nextfriend(friends);
2364    while (in.good())
2365    {
2366       in >> line;
2367       if (line.IsNull() || line.BeginsWith("#")) continue;
2368       if (count++ == fNtestFiles) break;
2369       TString esdFile(line);
2370       TFile *file = TFile::Open(esdFile);
2371       if (file && !file->IsZombie()) {
2372          chain->Add(esdFile);
2373          file->Close();
2374          if (!fFriendChainName.IsNull()) {
2375             if (esdFile.Index("#") > -1)
2376                esdFile.Remove(esdFile.Index("#"));
2377             bpath = gSystem->DirName(esdFile);
2378             bpath += "/";
2379             TString fileFriend;
2380             nextfriend.Reset();
2381             while ((cfriend=(TChain*)nextfriend())) {
2382                fileFriend = bpath;
2383                fileFriend += cfriend->GetTitle();
2384                file = TFile::Open(fileFriend);
2385                if (file && !file->IsZombie()) {
2386                   file->Close();
2387                   cfriend->Add(fileFriend);
2388                } else {
2389                   Fatal("GetChainForTestMode", "Cannot open friend file: %s", fileFriend.Data());
2390                   return 0;
2391                } 
2392             }     
2393          }
2394       } else {
2395          Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
2396       }   
2397    }
2398    in.close();
2399    if (!chain->GetListOfFiles()->GetEntries()) {
2400        Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
2401        delete chain;
2402        friends->Delete();
2403        delete friends;
2404        return NULL;
2405    }
2406    return chain;
2407 }    
2408
2409 //______________________________________________________________________________
2410 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
2411 {
2412 // Get job status for all jobs with jobid>jobidstart.
2413    static char mstatus[20];
2414    mstatus[0] = '\0';
2415    nrunning = 0;
2416    nwaiting = 0;
2417    nerror   = 0;
2418    ndone    = 0;
2419    TGridJobStatusList *list = gGrid->Ps("");
2420    if (!list) return mstatus;
2421    Int_t nentries = list->GetSize();
2422    TGridJobStatus *status;
2423    Int_t pid;
2424    for (Int_t ijob=0; ijob<nentries; ijob++) {
2425       status = (TGridJobStatus *)list->At(ijob);
2426       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)%p)->GetKey(\"queueId\"));", status));
2427       if (pid<jobidstart) continue;
2428       if (pid == lastid) {
2429          gROOT->ProcessLine(Form("sprintf((char*)%p,((TAlienJobStatus*)%p)->GetKey(\"status\"));",mstatus, status));
2430       }   
2431       switch (status->GetStatus()) {
2432          case TGridJobStatus::kWAITING:
2433             nwaiting++; break;
2434          case TGridJobStatus::kRUNNING:
2435             nrunning++; break;
2436          case TGridJobStatus::kABORTED:
2437          case TGridJobStatus::kFAIL:
2438          case TGridJobStatus::kUNKNOWN:
2439             nerror++; break;
2440          case TGridJobStatus::kDONE:
2441             ndone++;
2442       }
2443    }
2444    list->Delete();
2445    delete list;
2446    return mstatus;
2447 }
2448
2449 //______________________________________________________________________________
2450 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
2451 {
2452 // Returns true if file is a collection. Functionality duplicated from
2453 // TAlien::Type() because we don't want to directly depend on TAlien.
2454    if (!gGrid) {
2455       Error("IsCollection", "No connection to grid");
2456       return kFALSE;
2457    }
2458    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
2459    if (!res) return kFALSE;
2460    const char* typeStr = res->GetKey(0, "type");
2461    if (!typeStr || !strlen(typeStr)) return kFALSE;
2462    if (!strcmp(typeStr, "collection")) return kTRUE;
2463    delete res;
2464    return kFALSE;
2465 }   
2466
2467 //______________________________________________________________________________
2468 Bool_t AliAnalysisAlien::IsSingleOutput() const
2469 {
2470 // Check if single-ouput option is on.
2471    return (!fOutputSingle.IsNull());
2472 }
2473
2474 //______________________________________________________________________________
2475 Long64_t AliAnalysisAlien::RunMacroAndExtractLibs(const char* macro, const char *args, TString &libs)
2476 {
2477 // Tries to run the specified macro and return the libraries that it loads.
2478    TString expname;
2479    if (strlen(macro)) expname = gSystem->ExpandPathName(macro);
2480    if (expname.IsNull() || gSystem->AccessPathName(expname)) {
2481       ::Error("RunMacroAndExtractLibs","Cannot find macro %s in current directory", macro);
2482       return -1;
2483    }   
2484    TString oldlibs = gSystem->GetLibraries();
2485    TMacro m(expname);
2486    Int_t error = 0;
2487    Long64_t retval = m.Exec(args, &error);
2488    if (error != TInterpreter::kNoError)
2489    {
2490       ::Error("RunMacroAndExtractLibs", "Macro interpretation %s failed", macro);
2491       return -1;
2492    }
2493    libs = gSystem->GetLibraries();
2494    libs.ReplaceAll(oldlibs, "");
2495    libs.Strip(TString::kLeading);
2496    TObjArray *libTokens = libs.Tokenize(" ");
2497    libs = "";
2498    for (Int_t i=0; i<libTokens->GetEntries(); i++) {
2499      if (!libs.IsNull()) libs += " ";
2500      libs += gSystem->BaseName(libTokens->At(i)->GetName());
2501    }
2502    delete libTokens;
2503    return retval;
2504 }   
2505       
2506 //______________________________________________________________________________
2507 void AliAnalysisAlien::Print(Option_t *) const
2508 {
2509 // Print current plugin settings.
2510    printf("### AliEn analysis plugin current settings ###\n");
2511    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2512    if (mgr && mgr->IsProofMode()) {
2513       TString proofType = "=   PLUGIN IN PROOF MODE ON CLUSTER:_________________";
2514       if (TestBit(AliAnalysisGrid::kTest))
2515          proofType = "=   PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
2516       printf("%s %s\n", proofType.Data(), fProofCluster.Data());
2517       if (!fProofDataSet.IsNull())
2518       printf("=   Requested data set:___________________________ %s\n", fProofDataSet.Data());
2519       if (fProofReset==1)
2520       printf("=   Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2521       if (fProofReset>1)   
2522       printf("=   Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2523       if (!fROOTVersion.IsNull())
2524       printf("=   ROOT version requested________________________ %s\n", fROOTVersion.Data());
2525       else
2526       printf("=   ROOT version requested________________________ default\n");
2527       printf("=   AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
2528       if (!fAliRootMode.IsNull())
2529       printf("=   Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());  
2530       if (fNproofWorkers)
2531       printf("=   Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
2532       if  (fNproofWorkersPerSlave)
2533       printf("=   Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
2534       if (TestSpecialBit(kClearPackages))
2535       printf("=   ClearPackages requested...\n");
2536       if (fIncludePath.Data())
2537       printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2538       printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2539       if (fPackages && fPackages->GetEntries()) {
2540          TIter next(fPackages);
2541          TObject *obj;
2542          TString list;
2543          while ((obj=next())) list += obj->GetName();
2544          printf("=   Par files to be used: ________________________ %s\n", list.Data());
2545       } 
2546       if (TestSpecialBit(kProofConnectGrid))
2547       printf("=   Requested PROOF connection to grid\n");
2548       return;
2549    }
2550    printf("=   OverwriteMode:________________________________ %d\n", fOverwriteMode);
2551    if (fOverwriteMode) {
2552       printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
2553             \n*****       To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
2554    }
2555    printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
2556    printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO:Print");
2557    printf("=   Production mode:______________________________ %d\n", fProductionMode);
2558    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
2559    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
2560    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
2561    if (fUser.Length()) 
2562    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
2563    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
2564    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
2565    TString basedatadir = fGridDataDir;
2566    TString pattern = fDataPattern;
2567    pattern.Strip();
2568    Int_t ind = pattern.Index(" ");
2569    if (ind>=0) {
2570       basedatadir += "/%run%/";
2571       basedatadir += pattern(0, ind);
2572       pattern = pattern(ind+1, pattern.Length());
2573    }   
2574    printf("=   Data base directory path requested: __________ %s\n", basedatadir.Data());
2575    printf("=   Data search pattern: _________________________ %s\n", pattern.Data());
2576    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
2577    if (fRunNumbers.Length()) 
2578    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
2579    if (fRunRange[0])
2580    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
2581    if (!fRunRange[0] && !fRunNumbers.Length()) {
2582       TIter next(fInputFiles);
2583       TObject *obj;
2584       TString list;
2585       while ((obj=next())) list += obj->GetName();
2586       printf("=   Input files to be processed: _________________ %s\n", list.Data());
2587    }
2588    if (TestBit(AliAnalysisGrid::kTest))
2589    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
2590    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
2591    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
2592    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
2593    printf("=   List of outputs that should not be registered: %s\n", fRegisterExcludes.Data());
2594    printf("=   List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
2595    printf("=====================================================================\n");
2596    printf("=   Job price: ___________________________________ %d\n", fPrice);
2597    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
2598    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
2599    if (fMaxInitFailed>0) 
2600    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
2601    if (fMasterResubmitThreshold>0) 
2602    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
2603    printf("=   Number of replicas for the output files_______ %d\n", fNreplicas);
2604    if (fNrunsPerMaster>0)
2605    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
2606    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
2607    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
2608    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
2609    if (fArguments.Length()) 
2610    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
2611    if (fExecutableArgs.Length()) 
2612    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
2613    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
2614    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
2615    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2616    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
2617    if (fDatasetName)
2618    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
2619    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
2620    if (fIncludePath.Data())
2621    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2622    if (fCloseSE.Length())
2623    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
2624    if (fFriendChainName.Length())
2625    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
2626    if (fPackages && fPackages->GetEntries()) {
2627       TIter next(fPackages);
2628       TObject *obj;
2629       TString list;
2630       while ((obj=next())) list += obj->GetName();
2631       printf("=   Par files to be used: ________________________ %s\n", list.Data());
2632    }   
2633 }
2634
2635 //______________________________________________________________________________
2636 void AliAnalysisAlien::SetDefaults()
2637 {
2638 // Set default values for everything. What cannot be filled will be left empty.
2639    if (fGridJDL) delete fGridJDL;
2640    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2641    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2642    fPrice                      = 1;
2643    fTTL                        = 30000;
2644    fSplitMaxInputFileNumber    = 100;
2645    fMaxInitFailed              = 0;
2646    fMasterResubmitThreshold    = 0;
2647    fNtestFiles                 = 10;
2648    fNreplicas                  = 2;
2649    fRunRange[0]                = 0;
2650    fRunRange[1]                = 0;
2651    fRunPrefix                  = "%d";
2652    fNrunsPerMaster             = 1;
2653    fMaxMergeFiles              = 100;
2654    fRunNumbers                 = "";
2655    fExecutable                 = "analysis.sh";
2656    fExecutableCommand          = "root -b -q -x";
2657    fArguments                  = "";
2658    fExecutableArgs             = "";
2659    fAnalysisMacro              = "myAnalysis.C";
2660    fAnalysisSource             = "";
2661    fAdditionalLibs             = "";
2662    fSplitMode                  = "se";
2663    fAPIVersion                 = "";
2664    fROOTVersion                = "";
2665    fAliROOTVersion             = "";
2666    fUser                       = "";  // Your alien user name
2667    fGridWorkingDir             = "";
2668    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
2669    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
2670    fFriendChainName            = "";
2671    fGridOutputDir              = "output";
2672    fOutputArchive              = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
2673    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
2674    fInputFormat                = "xml-single";
2675    fJDLName                    = "analysis.jdl";
2676    fJobTag                     = "Automatically generated analysis JDL";
2677    fMergeExcludes              = "";
2678    fMergeViaJDL                = 0;
2679    SetUseCopy(kTRUE);
2680    SetCheckCopy(kTRUE);
2681    SetDefaultOutputs(kTRUE);
2682    fOverwriteMode              = 1;
2683 }   
2684
2685 //______________________________________________________________________________
2686 void AliAnalysisAlien::SetFriendChainName(const char *name, const char *libnames)
2687 {
2688    // Set file name for the chain of friends and optionally additional libs to be loaded.
2689    // Libs should be separated by blancs.
2690    fFriendChainName = name;
2691    fFriendChainName.ReplaceAll(",", " ");
2692    fFriendChainName.Strip();
2693    fFriendChainName.ReplaceAll("  ", " ");
2694    
2695    fFriendLibs = libnames;
2696    if (fFriendLibs.Length()) {
2697      if(!fFriendLibs.Contains(".so") && 
2698         !fFriendLibs.Contains(".dylib"))
2699        Fatal("SetFriendChainName()", "You should provide explicit library names (with extension)");
2700      fFriendLibs.ReplaceAll(",", " ");
2701      fFriendLibs.Strip();
2702      fFriendLibs.ReplaceAll("  ", " ");
2703    }
2704 }
2705
2706 //______________________________________________________________________________
2707 void AliAnalysisAlien::SetRootVersionForProof(const char *version)
2708 {
2709 // Obsolete method. Use SetROOTVersion instead
2710    Warning("SetRootVersionForProof", "Obsolete. Use SetROOTVersion instead");
2711    if (fROOTVersion.IsNull()) SetROOTVersion(version);
2712    else Error("SetRootVersionForProof", "ROOT version already set to %s", fROOTVersion.Data());
2713 }
2714    
2715 //______________________________________________________________________________
2716 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
2717 {
2718 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
2719    // First check if the result is already in the output directory.
2720    if (FileExists(Form("%s/%s",aliendir,filename))) {
2721       printf("Final merged results found. Not merging again.\n");
2722       return kFALSE;
2723    }
2724    // Now check the last stage done.
2725    Int_t stage = 0;
2726    while (1) {
2727       if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
2728       stage++;
2729    }
2730    // Next stage of merging
2731    stage++;
2732    TString pattern = "*root_archive.zip";
2733    if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
2734    TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
2735    if (res) delete res;
2736    // Write standard output to file
2737    gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
2738    // Count the number of files inside
2739    ifstream ifile;
2740    ifile.open(Form("Stage_%d.xml",stage));
2741    if (!ifile.good()) {
2742       ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
2743       return kFALSE;
2744    }   
2745    TString line;
2746    Int_t nfiles = 0;
2747    while (!ifile.eof()) {
2748       ifile >> line;
2749       if (line.Contains("/event")) nfiles++;
2750    }
2751    ifile.close();
2752    if (!nfiles) {
2753       ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
2754       return kFALSE;
2755    } else {
2756       printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
2757    }   
2758    // Copy the file in the output directory
2759    printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
2760 //   TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
2761    if (!copyLocal2Alien("CheckMergedFiles", Form("Stage_%d.xml",stage), 
2762         Form("%s/Stage_%d.xml",aliendir,stage))) Fatal("","Terminating");
2763    // Check if this is the last stage to be done.
2764    Bool_t laststage = (nfiles<nperchunk);
2765    if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
2766    Int_t jobId = 0;
2767    if (laststage) {
2768       printf("### Submiting final merging stage %d\n", stage);
2769       TString finalJDL = jdl;
2770       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2771       TString query = Form("submit %s %s %d", finalJDL.Data(), aliendir, stage);
2772       jobId = SubmitSingleJob(query);
2773    } else {
2774       printf("### Submiting merging stage %d\n", stage);
2775       TString query = Form("submit %s %s %d", jdl, aliendir, stage);
2776       jobId = SubmitSingleJob(query);
2777    }
2778    if (!jobId) return kFALSE;           
2779
2780    if (!fGridJobIDs.IsNull()) fGridJobIDs.Append(" ");
2781    fGridJobIDs.Append(Form("%d", jobId));
2782    if (!fGridStages.IsNull()) fGridStages.Append(" ");
2783    fGridStages.Append(Form("%s_merge_stage%d", 
2784                            laststage ? "final" : "partial", stage));
2785
2786    return kTRUE;   
2787 }        
2788
2789 //______________________________________________________________________________
2790 AliAnalysisManager *AliAnalysisAlien::LoadAnalysisManager(const char *fname)
2791 {
2792 // Loat the analysis manager from a file.
2793    TFile *file = TFile::Open(fname);
2794    if (!file) {
2795       ::Error("LoadAnalysisManager", "Cannot open file %s", fname);
2796       return 0;
2797    }   
2798    TIter nextkey(file->GetListOfKeys());
2799    AliAnalysisManager *mgr = 0;
2800    TKey *key;
2801    while ((key=(TKey*)nextkey())) {
2802       if (!strcmp(key->GetClassName(), "AliAnalysisManager"))
2803          mgr = (AliAnalysisManager*)file->Get(key->GetName());
2804    }
2805    if (!mgr) 
2806       ::Error("LoadAnalysisManager", "No analysis manager found in file %s", fname);
2807    return mgr;
2808 }      
2809
2810 //______________________________________________________________________________
2811 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
2812 {
2813 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
2814    if (!gGrid) return 0;
2815    printf("=> %s ------> ",query);
2816    TGridResult *res = gGrid->Command(query);
2817    if (!res) return 0;
2818    TString jobId = res->GetKey(0,"jobId");
2819    delete res;
2820    if (jobId.IsNull()) {
2821       printf("submission failed. Reason:\n");
2822       gGrid->Stdout();
2823       gGrid->Stderr();
2824       ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
2825       return 0;
2826    }
2827    Int_t ijobId = jobId.Atoi();
2828    printf(" Job id: '%s' (%d)\n", jobId.Data(), ijobId);
2829    return ijobId; 
2830 }  
2831
2832 //______________________________________________________________________________
2833 Bool_t AliAnalysisAlien::MergeInfo(const char *output, const char *collection)
2834 {
2835 // Merges a collection of output files using concatenation.
2836    TString scoll(collection);
2837    if (!scoll.Contains(".xml")) return kFALSE;
2838    TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", collection));
2839    if (!coll) {
2840       ::Error("MergeInfo", "Input XML %s collection empty.", collection);
2841       return kFALSE;
2842    }
2843    // Iterate grid collection
2844    TString outtmp;
2845    Bool_t merged = kFALSE;
2846    Int_t ifile = 0;
2847    while (coll->Next()) {
2848       TString fname = gSystem->DirName(coll->GetTURL());
2849       fname += "/";
2850       fname += output;
2851       outtmp = Form("%d_%s", ifile, output);
2852       if (!TFile::Cp(fname, outtmp)) {
2853          ::Error("MergeInfo", "Could not copy %s", fname.Data());
2854          continue;
2855       }
2856       ifile++;
2857       if (ifile<2) {
2858          gSystem->Exec(Form("cp %s lastmerged", outtmp.Data()));
2859          continue;
2860       }
2861       gSystem->Exec(Form("cat lastmerged %s > tempmerged", outtmp.Data()));
2862       gSystem->Exec("cp tempmerged lastmerged");
2863    }
2864    if (ifile) {
2865       gSystem->Exec(Form("cp lastmerged %s", output));
2866       gSystem->Exec(Form("rm tempmerged lastmerged *_%s", output));
2867       merged = kTRUE;
2868    }
2869    return merged;
2870 }   
2871
2872 //______________________________________________________________________________
2873 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
2874 {
2875 // Merge given output files from basedir. Basedir can be an alien output directory
2876 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
2877 // files in a group (ignored for xml input). Merging can be done in stages:
2878 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
2879 // stage=1 : works with an xml of all root_archive.zip in the output directory
2880 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
2881    TString outputFile = output;
2882    TString command;
2883    TString outputChunk;
2884    TString previousChunk = "";
2885    TObjArray *listoffiles = new TObjArray();
2886 //   listoffiles->SetOwner();
2887    Int_t countChunk = 0;
2888    Int_t countZero = nmaxmerge;
2889    Bool_t merged = kTRUE;
2890    Bool_t isGrid = kTRUE;
2891    Int_t index = outputFile.Index("@");
2892    if (index > 0) outputFile.Remove(index);
2893    TString inputFile = outputFile;
2894    TString sbasedir = basedir;
2895    if (sbasedir.Contains(".xml")) {
2896       // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
2897       nmaxmerge = 9999999;
2898       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
2899       if (!coll) {
2900          ::Error("MergeOutput", "Input XML collection empty.");
2901          return kFALSE;
2902       }
2903       // Iterate grid collection
2904       while (coll->Next()) {
2905          TString fname = gSystem->DirName(coll->GetTURL());
2906          fname += "/";
2907          fname += inputFile;      
2908          listoffiles->Add(new TNamed(fname.Data(),""));
2909       }   
2910    } else if (sbasedir.Contains(".txt")) {
2911       // The file having the .txt extension is expected to contain a list of
2912       // folders where the output files will be looked. For alien folders,
2913       // the full folder LFN is expected (starting with alien://)
2914       // Assume lfn's on each line
2915       TString line;
2916       ifstream in;
2917       in.open(sbasedir);
2918       if (in.fail()) {
2919          ::Error("MergeOutput", "File %s cannot be opened. Merging stopped." ,sbasedir.Data());
2920          return kTRUE;
2921       }           
2922       Int_t nfiles = 0;
2923       while (in.good()) {
2924          in >> line;
2925          if (line.IsNull() || line.BeginsWith("#")) continue;
2926          line.Strip();
2927          if (!line.Contains("alien:")) isGrid = kFALSE;
2928          line += "/";
2929          line += outputFile;
2930          nfiles++;
2931          listoffiles->Add(new TNamed(line.Data(),""));
2932       }
2933       in.close();
2934       if (!nfiles) {
2935          ::Error("MergeOutput","Input file %s contains no files to be merged\n", sbasedir.Data());
2936          delete listoffiles;
2937          return kFALSE;
2938       }
2939    } else {   
2940       command = Form("find %s/ *%s", basedir, inputFile.Data());
2941       printf("command: %s\n", command.Data());
2942       TGridResult *res = gGrid->Command(command);
2943       if (!res) {
2944          ::Error("MergeOutput","No result for the find command\n");
2945          delete listoffiles;
2946          return kFALSE;
2947       }     
2948       TIter nextmap(res);
2949       TMap *map = 0;
2950       while ((map=(TMap*)nextmap())) {
2951          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
2952          if (!objs || !objs->GetString().Length()) {
2953             // Nothing found - skip this output
2954             delete res;
2955             delete listoffiles;
2956             return kFALSE;
2957          }
2958          listoffiles->Add(new TNamed(objs->GetName(),""));
2959       }
2960       delete res;
2961    }
2962    if (!listoffiles->GetEntries()) {
2963       ::Error("MergeOutput","No result for the find command\n");
2964       delete listoffiles;
2965       return kFALSE;
2966    }     
2967
2968    TFileMerger *fm = 0;
2969    TIter next0(listoffiles);
2970    TObjArray *listoffilestmp = new TObjArray();
2971    listoffilestmp->SetOwner();
2972    TObject *nextfile;
2973    TString snextfile;
2974    // Keep only the files at upper level
2975    Int_t countChar = 0;
2976    while ((nextfile=next0())) {
2977       snextfile = nextfile->GetName();
2978       Int_t crtCount = snextfile.CountChar('/');
2979       if (nextfile == listoffiles->First()) countChar = crtCount;
2980       if (crtCount < countChar) countChar = crtCount;
2981    }
2982    next0.Reset();
2983    while ((nextfile=next0())) {
2984       snextfile = nextfile->GetName();
2985       Int_t crtCount = snextfile.CountChar('/');
2986       if (crtCount > countChar) {
2987          delete nextfile;
2988          continue;
2989       }   
2990       listoffilestmp->Add(nextfile);
2991    }
2992    delete listoffiles;
2993    listoffiles = listoffilestmp;  // Now contains 'good' files
2994    listoffiles->Print();
2995    TIter next(listoffiles);   
2996    // Check if there is a merge operation to resume. Works only for stage 0 or 1.
2997    outputChunk = outputFile;
2998    outputChunk.ReplaceAll(".root", "_*.root");
2999    // Check for existent temporary merge files
3000    // Check overwrite mode and remove previous partial results if needed
3001    // Preserve old merging functionality for stage 0.
3002    if (stage==0) {
3003       if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3004          while (1) {
3005             // Skip as many input files as in a chunk
3006             for (Int_t counter=0; counter<nmaxmerge; counter++) {
3007                nextfile = next();
3008                if (!nextfile) {
3009                   ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
3010                   delete listoffiles;
3011                   return kFALSE;
3012                }   
3013                snextfile = nextfile->GetName();
3014             }
3015             outputChunk = outputFile;
3016             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
3017             countChunk++;
3018             if (gSystem->AccessPathName(outputChunk)) continue;
3019             // Merged file with chunks up to <countChunk> found
3020             ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
3021             previousChunk = outputChunk;
3022             break;
3023          }
3024       }   
3025       countZero = nmaxmerge;
3026    
3027       while ((nextfile=next())) {
3028          snextfile = nextfile->GetName();
3029          // Loop 'find' results and get next LFN
3030          if (countZero == nmaxmerge) {
3031             // First file in chunk - create file merger and add previous chunk if any.
3032             fm = new TFileMerger(isGrid);
3033             fm->SetFastMethod(kTRUE);
3034             if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
3035             outputChunk = outputFile;
3036             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
3037          }
3038          // If last file found, put merged results in the output file
3039          if (nextfile == listoffiles->Last()) outputChunk = outputFile;
3040          // Add file to be merged and decrement chunk counter.
3041          fm->AddFile(snextfile);
3042          countZero--;
3043          if (countZero==0 || nextfile == listoffiles->Last()) {            
3044             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
3045             // Nothing found - skip this output
3046                ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
3047                merged = kFALSE;
3048                break;
3049             }
3050             fm->OutputFile(outputChunk);
3051             // Merge the outputs, then go to next chunk      
3052             if (!fm->Merge()) {
3053                ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
3054                merged = kFALSE;
3055                break;
3056             } else {
3057                ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
3058                gSystem->Unlink(previousChunk);
3059             }
3060             if (nextfile == listoffiles->Last()) break;
3061             countChunk++;
3062             countZero = nmaxmerge;
3063             previousChunk = outputChunk;
3064          }
3065       }
3066       delete listoffiles;
3067       delete fm;
3068       return merged;
3069    }
3070    // Merging stage different than 0.
3071    // Move to the begining of the requested chunk.
3072    fm = new TFileMerger(isGrid);
3073    fm->SetFastMethod(kTRUE);
3074    while ((nextfile=next())) fm->AddFile(nextfile->GetName());
3075    delete listoffiles;
3076    if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
3077       // Nothing found - skip this output
3078       ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
3079       delete fm;
3080       return kFALSE;
3081    }
3082    fm->OutputFile(outputFile);
3083    // Merge the outputs
3084    if (!fm->Merge()) {
3085       ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
3086       delete fm;
3087       return kFALSE;
3088    } else {
3089       ::Info("MergeOutput", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
3090    }
3091    delete fm;
3092    return kTRUE;
3093
3094
3095 //______________________________________________________________________________
3096 Bool_t AliAnalysisAlien::MergeOutputs()
3097 {
3098 // Merge analysis outputs existing in the AliEn space.
3099    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
3100    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
3101    if (!Connect()) {
3102       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
3103       return kFALSE;
3104    }
3105    if (fMergeViaJDL) {
3106       if (!TestBit(AliAnalysisGrid::kMerge)) {
3107          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
3108          return kFALSE; 
3109       }     
3110       if (fProductionMode) {
3111          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
3112          return kFALSE;
3113       }
3114       Info("MergeOutputs", "Submitting merging JDL");
3115       if (!SubmitMerging()) return kFALSE;
3116       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
3117       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
3118       return kFALSE;
3119    }   
3120    // Get the output path
3121    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3122    if (!DirectoryExists(fGridOutputDir)) {
3123       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
3124       return kFALSE;
3125    }
3126    if (!fOutputFiles.Length()) {
3127       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3128       return kFALSE;
3129    }
3130    // Check if fast read option was requested
3131    Info("MergeOutputs", "Started local merging of output files from: alien://%s \
3132         \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
3133    if (fFastReadOption) {
3134       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
3135              \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3136       gEnv->SetValue("XNet.ConnectTimeout",50);
3137       gEnv->SetValue("XNet.RequestTimeout",50);
3138       gEnv->SetValue("XNet.MaxRedirectCount",2);
3139       gEnv->SetValue("XNet.ReconnectTimeout",50);
3140       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
3141    }   
3142    // Make sure we change the temporary directory
3143    gSystem->Setenv("TMPDIR", gSystem->pwd());
3144    // Set temporary compilation directory to current one
3145    gSystem->SetBuildDir(gSystem->pwd(), kTRUE);   
3146    TObjArray *list = fOutputFiles.Tokenize(",");
3147    TIter next(list);
3148    TObjString *str;
3149    TString outputFile;
3150    Bool_t merged = kTRUE;
3151    while((str=(TObjString*)next())) {
3152       outputFile = str->GetString();
3153       Int_t index = outputFile.Index("@");
3154       if (index > 0) outputFile.Remove(index);
3155       TString outputChunk = outputFile;
3156       outputChunk.ReplaceAll(".root", "_*.root");
3157       // Skip already merged outputs
3158       if (!gSystem->AccessPathName(outputFile)) {
3159          if (fOverwriteMode) {
3160             Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
3161             gSystem->Unlink(outputFile);
3162             if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
3163                Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
3164                      outputChunk.Data());
3165                gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
3166             }
3167          } else {   
3168             Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
3169             conti