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