]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
Added separate flag to mark that the LocalInit phase was done + method AliAnalysisMan...
[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->RunLocalInit();
602    mgr->PrintStatus();
603    Int_t productionMode = fProductionMode;
604    SetProductionMode();
605    TString macro = fAnalysisMacro;
606    TString executable = fExecutable;
607    TString validation = fValidationScript;
608    TString execCommand = fExecutableCommand;
609    SetAnalysisMacro(Form("%s.C", name));
610    SetExecutable(Form("%s.sh", name));
611    SetExecutableCommand("aliroot -b -q ");
612    SetValidationScript(Form("%s_validation.sh", name));
613    StartAnalysis();
614    SetProductionMode(productionMode);
615    fAnalysisMacro = macro;
616    fExecutable = executable;
617    fExecutableCommand = execCommand;
618    fValidationScript = validation;
619    return kTRUE;   
620 }   
621
622 //______________________________________________________________________________
623 Bool_t AliAnalysisAlien::GenerateTest(const char *name, const char *modname)
624 {
625 // Generate test macros for a single module or for the full train.
626    fAdditionalLibs = "";
627    if (strlen(modname)) {
628       if (!CheckDependencies()) return kFALSE;
629       AliAnalysisTaskCfg *mod = GetModule(modname);
630       if (!mod) {
631          Error("GenerateTest", "cannot generate test for inexistent module %s", modname);
632          return kFALSE;
633       }
634       if (!LoadModule(mod)) return kFALSE;
635    } else if (!LoadModules()) return kFALSE;
636    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
637    if (!mgr->InitAnalysis()) return kFALSE;
638    mgr->RunLocalInit();
639    mgr->PrintStatus();
640    SetLocalTest(kTRUE);
641    Int_t productionMode = fProductionMode;
642    SetProductionMode();
643    TString macro = fAnalysisMacro;
644    TString executable = fExecutable;
645    TString validation = fValidationScript;
646    TString execCommand = fExecutableCommand;
647    SetAnalysisMacro(Form("%s.C", name));
648    SetExecutable(Form("%s.sh", name));
649    SetExecutableCommand("aliroot -b -q ");
650    SetValidationScript(Form("%s_validation.sh", name));
651    WriteAnalysisFile();   
652    WriteAnalysisMacro();
653    WriteExecutable();
654    WriteValidationScript();   
655    SetLocalTest(kFALSE);
656    SetProductionMode(productionMode);
657    fAnalysisMacro = macro;
658    fExecutable = executable;
659    fExecutableCommand = execCommand;
660    fValidationScript = validation;
661    return kTRUE;   
662 }
663
664 //______________________________________________________________________________
665 Bool_t AliAnalysisAlien::LoadModules()
666 {
667 // Load all modules by executing the AddTask macros. Checks first the dependencies.
668    fAdditionalLibs = "";
669    Int_t nmodules = GetNmodules();
670    if (!nmodules) {
671       Warning("LoadModules", "No module to be loaded");
672       return kTRUE;
673    }   
674    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
675    if (!mgr) {
676       Error("LoadModules", "No analysis manager created yet. Use CreateAnalysisManager first.");
677       return kFALSE;
678    }   
679    if (!CheckDependencies()) return kFALSE;
680    nmodules = GetNmodules();
681    AliAnalysisTaskCfg *mod;
682    for (Int_t imod=0; imod<nmodules; imod++) {
683       mod = (AliAnalysisTaskCfg*)fModules->At(imod);
684       if (!LoadModule(mod)) return kFALSE;
685    }
686    return kTRUE;
687 }      
688
689 //______________________________________________________________________________
690 void AliAnalysisAlien::SetRunPrefix(const char *prefix)
691 {
692 // Set the run number format. Can be a prefix or a format like "%09d"
693    fRunPrefix = prefix;
694    if (!fRunPrefix.Contains("%")) fRunPrefix += "%d";
695 }   
696
697 //______________________________________________________________________________
698 void AliAnalysisAlien::AddIncludePath(const char *path)
699 {
700 // Add include path in the remote analysis macro.
701    TString p(path);
702    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
703    else                  fIncludePath += Form("-I%s ", path);
704 }
705
706 //______________________________________________________________________________
707 void AliAnalysisAlien::AddRunNumber(Int_t run)
708 {
709 // Add a run number to the list of runs to be processed.
710    if (fRunNumbers.Length()) fRunNumbers += " ";
711    fRunNumbers += Form(fRunPrefix.Data(), run);
712 }   
713
714 //______________________________________________________________________________
715 void AliAnalysisAlien::AddRunList(const char* runList)
716 {
717 // Add several runs into the list of runs; they are expected to be separated by a blank character.  
718   TString    sList = runList;
719   TObjArray *list  = sList.Tokenize(" ");
720   Int_t n = list->GetEntries();
721   for (Int_t i = 0; i < n; i++) {
722     TObjString *os = (TObjString*)list->At(i);
723     AddRunNumber(os->GetString().Atoi());
724   }
725   delete list;
726 }
727
728 //______________________________________________________________________________
729 void AliAnalysisAlien::AddRunNumber(const char* run)
730 {
731 // Add a run number to the list of runs to be processed.
732    TString runs = run;
733    TObjString *os;
734    TObjArray *arr = runs.Tokenize(" ");
735    TIter next(arr);
736    TString prefix; 
737    prefix.Append(fRunPrefix, fRunPrefix.Index("%d"));
738    while ((os=(TObjString*)next())){
739        if (fRunNumbers.Length()) fRunNumbers += " ";
740        fRunNumbers += Form("%s%s", prefix.Data(), os->GetString().Data());
741    }
742    delete arr;
743 }   
744
745 //______________________________________________________________________________
746 void AliAnalysisAlien::AddDataFile(const char *lfn)
747 {
748 // Adds a data file to the input to be analysed. The file should be a valid LFN
749 // or point to an existing file in the alien workdir.
750    if (!fInputFiles) fInputFiles = new TObjArray();
751    fInputFiles->Add(new TObjString(lfn));
752 }
753
754 //______________________________________________________________________________
755 void AliAnalysisAlien::AddExternalPackage(const char *package)
756 {
757 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
758    if (fExternalPackages) fExternalPackages += " ";
759    fExternalPackages += package;
760 }   
761       
762 //______________________________________________________________________________
763 Bool_t AliAnalysisAlien::Connect()
764 {
765 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
766    if (gGrid && gGrid->IsConnected()) return kTRUE;
767    if (fProductionMode) return kTRUE;
768    if (!gGrid) {
769       Info("Connect", "Trying to connect to AliEn ...");
770       TGrid::Connect("alien://");
771    }
772    if (!gGrid || !gGrid->IsConnected()) {
773       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
774       return kFALSE;
775    }  
776    fUser = gGrid->GetUser();
777    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
778    return kTRUE;
779 }
780
781 //______________________________________________________________________________
782 void AliAnalysisAlien::CdWork()
783 {
784 // Check validity of alien workspace. Create directory if possible.
785    if (!Connect()) {
786       Error("CdWork", "Alien connection required");
787       return;
788    } 
789    TString homedir = gGrid->GetHomeDirectory();
790    TString workdir = homedir + fGridWorkingDir;
791    if (DirectoryExists(workdir)) {
792       gGrid->Cd(workdir);
793       return;
794    }   
795    // Work directory not existing - create it
796    gGrid->Cd(homedir);
797    if (gGrid->Mkdir(workdir, "-p")) {
798       gGrid->Cd(fGridWorkingDir);
799       Info("CdWork", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
800    } else {
801       Warning("CdWork", "Working directory %s cannot be created.\n Using %s instead.",
802               workdir.Data(), homedir.Data());
803       fGridWorkingDir = "";
804    }          
805 }
806
807 //______________________________________________________________________________
808 Bool_t AliAnalysisAlien::CheckFileCopy(const char *alienpath)
809 {
810 // Check if file copying is possible.
811    if (fProductionMode) return kTRUE;
812    if (!Connect()) {
813       Error("CheckFileCopy", "Not connected to AliEn. File copying cannot be tested.");
814       return kFALSE;
815    }
816    Info("CheckFileCopy", "Checking possibility to copy files to your AliEn home directory... \
817         \n +++ NOTE: You can disable this via: plugin->SetCheckCopy(kFALSE);");
818    // Check if alien_CLOSE_SE is defined
819    TString closeSE = gSystem->Getenv("alien_CLOSE_SE");
820    if (!closeSE.IsNull()) {
821       Info("CheckFileCopy", "Your current close storage is pointing to: \
822            \n      alien_CLOSE_SE = \"%s\"", closeSE.Data());
823    } else {
824       Warning("CheckFileCopy", "Your current close storage is empty ! Depending on your location, file copying may fail.");
825    }        
826    // Check if grid directory exists.
827    if (!DirectoryExists(alienpath)) {
828       Error("CheckFileCopy", "Alien path %s does not seem to exist", alienpath);
829       return kFALSE;
830    }
831    TFile f("plugin_test_copy", "RECREATE");
832    // User may not have write permissions to current directory 
833    if (f.IsZombie()) {
834       Error("CheckFileCopy", "Cannot create local test file. Do you have write access to current directory: <%s> ?",
835             gSystem->WorkingDirectory());
836       return kFALSE;
837    }
838    f.Close();
839    if (FileExists(Form("alien://%s/%s",alienpath, f.GetName()))) gGrid->Rm(Form("alien://%s/%s",alienpath, f.GetName()));
840    if (!TFile::Cp(f.GetName(), Form("alien://%s/%s",alienpath, f.GetName()))) {
841       Error("CheckFileCopy", "Cannot copy files to Alien destination: <%s> This may be temporary, or: \
842            \n# 1. Make sure you have write permissions there. If this is the case: \
843            \n# 2. Check the storage availability at: http://alimonitor.cern.ch/stats?page=SE/table \
844            \n#    Do:           export alien_CLOSE_SE=\"working_disk_SE\" \
845            \n#    To make this permanent put in in your .bashrc (in .alienshrc is not enough) \
846            \n#    Redo token:   rm /tmp/x509up_u$UID then: alien-token-init <username>", alienpath);
847       gSystem->Unlink(f.GetName());
848       return kFALSE;
849    }   
850    gSystem->Unlink(f.GetName());
851    gGrid->Rm(Form("%s%s",alienpath,f.GetName()));
852    Info("CheckFileCopy", "### ...SUCCESS ###");
853    return kTRUE;
854 }   
855
856 //______________________________________________________________________________
857 Bool_t AliAnalysisAlien::CheckInputData()
858 {
859 // Check validity of input data. If necessary, create xml files.
860    if (fProductionMode) return kTRUE;
861    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
862       if (!fGridDataDir.Length()) {
863          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
864          return kFALSE;
865       }
866       if (fMergeViaJDL) {
867          Error("CheckInputData", "Merging via jdl works only with run numbers, run range or provided xml");
868          return kFALSE;
869       }   
870       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
871       if (fDataPattern.Contains("tag") && TestBit(AliAnalysisGrid::kTest))
872          TObject::SetBit(AliAnalysisGrid::kUseTags, kTRUE); // ADDED (fix problem in determining the tag usage in test mode) 
873       return kTRUE;
874    }
875    // Process declared files
876    Bool_t isCollection = kFALSE;
877    Bool_t isXml = kFALSE;
878    Bool_t useTags = kFALSE;
879    Bool_t checked = kFALSE;
880    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
881    TString file;
882    TString workdir = gGrid->GetHomeDirectory();
883    workdir += fGridWorkingDir;
884    if (fInputFiles) {
885       TObjString *objstr;
886       TIter next(fInputFiles);
887       while ((objstr=(TObjString*)next())) {
888          file = workdir;
889          file += "/";
890          file += objstr->GetString();
891          // Store full lfn path
892          if (FileExists(file)) objstr->SetString(file);
893          else {
894             file = objstr->GetName();
895             if (!FileExists(objstr->GetName())) {
896                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
897                      objstr->GetName(), workdir.Data());
898                return kFALSE;
899             }         
900          }
901          Bool_t iscoll, isxml, usetags;
902          CheckDataType(file, iscoll, isxml, usetags);
903          if (!checked) {
904             checked = kTRUE;
905             isCollection = iscoll;
906             isXml = isxml;
907             useTags = usetags;
908             TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
909          } else {
910             if ((iscoll != isCollection) || (isxml != isXml) || (usetags != useTags)) {
911                Error("CheckInputData", "Some conflict was found in the types of inputs");
912                return kFALSE;
913             } 
914          }
915       }
916    }
917    // Process requested run numbers
918    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
919    // Check validity of alien data directory
920    if (!fGridDataDir.Length()) {
921       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
922       return kFALSE;
923    }
924    if (!DirectoryExists(fGridDataDir)) {
925       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
926       return kFALSE;
927    }
928    if (isCollection) {
929       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
930       return kFALSE;   
931    }
932    
933    if (checked && !isXml) {
934       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
935       return kFALSE;   
936    }
937    // Check validity of run number(s)
938    TObjArray *arr;
939    TObjString *os;
940    TString format;
941    Int_t nruns = 0;
942    TString schunk, schunk2;
943    TString path;
944    if (!checked) {
945       checked = kTRUE;
946       useTags = fDataPattern.Contains("tag");
947       TObject::SetBit(AliAnalysisGrid::kUseTags, useTags);
948    }   
949    if (useTags != fDataPattern.Contains("tag")) {
950       Error("CheckInputData", "Cannot mix input files using/not using tags");
951       return kFALSE;
952    }
953    if (fRunNumbers.Length()) {
954       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
955       arr = fRunNumbers.Tokenize(" ");
956       TIter next(arr);
957       while ((os=(TObjString*)next())) {
958          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
959          if (!DirectoryExists(path)) {
960             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
961             continue;
962          }
963          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
964          TString msg = "\n#####   file: ";
965          msg += path;
966          msg += " type: xml_collection;";
967          if (useTags) msg += " using_tags: Yes";
968          else          msg += " using_tags: No";
969          Info("CheckDataType", "%s", msg.Data());
970          if (fNrunsPerMaster<2) {
971             AddDataFile(Form("%s.xml", os->GetString().Data()));
972          } else {
973             nruns++;
974             if (((nruns-1)%fNrunsPerMaster) == 0) {
975                schunk = os->GetString();
976             }   
977             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
978             schunk += Form("_%s.xml", os->GetString().Data());
979             AddDataFile(schunk);
980          }   
981       }
982       delete arr;   
983    } else {
984       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
985       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
986          format = Form("%%s/%s ", fRunPrefix.Data());
987          path = Form(format.Data(), fGridDataDir.Data(), irun);
988          if (!DirectoryExists(path)) {
989             continue;
990          }
991          format = Form("%%s/%s.xml", fRunPrefix.Data());
992          path = Form(format.Data(), workdir.Data(),irun);
993          TString msg = "\n#####   file: ";
994          msg += path;
995          msg += " type: xml_collection;";
996          if (useTags) msg += " using_tags: Yes";
997          else          msg += " using_tags: No";
998          Info("CheckDataType", "%s", msg.Data());
999          if (fNrunsPerMaster<2) {
1000             format = Form("%s.xml", fRunPrefix.Data());
1001             AddDataFile(Form(format.Data(),irun));
1002          } else {
1003             nruns++;
1004             if (((nruns-1)%fNrunsPerMaster) == 0) {
1005                schunk = Form(fRunPrefix.Data(),irun);
1006             }
1007             format = Form("_%s.xml", fRunPrefix.Data());
1008             schunk2 = Form(format.Data(), irun);
1009             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
1010             schunk += schunk2;
1011             AddDataFile(schunk);
1012          }   
1013       }
1014       if (!fInputFiles) {
1015          schunk += schunk2;
1016          AddDataFile(schunk);
1017       }   
1018    }
1019    return kTRUE;      
1020 }   
1021
1022 //______________________________________________________________________________
1023 Bool_t AliAnalysisAlien::CopyLocalDataset(const char *griddir, const char *pattern, Int_t nfiles, const char *output, const char *archivefile, const char *outputdir)
1024 {
1025 // Copy data from the given grid directory according a pattern and make a local
1026 // dataset.
1027    if (!Connect()) {
1028       Error("CopyLocalDataset", "Cannot copy local dataset with no grid connection");
1029       return kFALSE;
1030    }
1031    if (!DirectoryExists(griddir)) {
1032       Error("CopyLocalDataset", "Data directory %s not existing.", griddir);
1033       return kFALSE;
1034    }
1035    TString command = Form("find -z -l %d %s %s", nfiles, griddir, pattern);
1036    printf("Running command: %s\n", command.Data());
1037    TGridResult *res = gGrid->Command(command);
1038    Int_t nfound = res->GetEntries();
1039    if (!nfound) {
1040       Error("CopyLocalDataset", "No file found in <%s> having pattern <%s>", griddir, pattern);
1041       return kFALSE;
1042    }
1043    printf("... found %d files. Copying locally ...\n", nfound);
1044    // Copy files locally
1045    ofstream out;
1046    out.open(output, ios::out);
1047    TMap *map;
1048    TString turl, dirname, filename, temp;
1049    TString cdir = gSystem->WorkingDirectory();
1050    gSystem->MakeDirectory(outputdir);
1051    gSystem->ChangeDirectory(outputdir);
1052    for (Int_t i=0; i<nfound; i++) {
1053       map = (TMap*)res->At(i);
1054       turl = map->GetValue("turl")->GetName();
1055       filename = gSystem->BaseName(turl.Data());
1056       dirname = gSystem->DirName(turl.Data());
1057       dirname = gSystem->BaseName(dirname.Data());
1058       gSystem->MakeDirectory(dirname);
1059       
1060       TString source(turl);
1061       TString targetFileName(filename);
1062       
1063       if (strlen(archivefile) > 0) {
1064         // TODO here the archive in which the file resides should be determined
1065         // however whereis returns only a guid, and guid2lfn does not work
1066         // Therefore we use the one provided as argument for now
1067         source = Form("%s/%s", gSystem->DirName(source.Data()), archivefile);
1068         targetFileName = archivefile;
1069       }
1070       if (TFile::Cp(source, Form("file:./%s/%s", dirname.Data(), targetFileName.Data()))) {
1071          if (strlen(archivefile) > 0) targetFileName = Form("%s#%s", targetFileName.Data(), gSystem->BaseName(turl.Data()));
1072          out << cdir << Form("/%s/%s/%s", outputdir, dirname.Data(), targetFileName.Data()) << endl;
1073       }
1074    }
1075    gSystem->ChangeDirectory(cdir);
1076    delete res;
1077    return kTRUE;
1078 }   
1079
1080 //______________________________________________________________________________
1081 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
1082 {
1083 // Create dataset for the grid data directory + run number.
1084    const Int_t gMaxEntries = 15000;
1085    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline)) return kTRUE;
1086    if (!Connect()) {
1087       Error("CreateDataset", "Cannot create dataset with no grid connection");
1088       return kFALSE;
1089    }   
1090
1091    // Cd workspace
1092    if (!TestBit(AliAnalysisGrid::kTest)) CdWork();
1093    TString workdir = gGrid->GetHomeDirectory();
1094    workdir += fGridWorkingDir;
1095
1096    // Compose the 'find' command arguments
1097    TString format;
1098    TString command;
1099    TString options = "-x collection ";
1100    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
1101    else options += Form("-l %d ", gMaxEntries);  // Protection for the find command
1102    TString conditions = "";
1103    Int_t nstart = 0;
1104    Int_t ncount = 0;
1105    Int_t stage = 0;
1106    TString file;
1107    TString path;
1108    Int_t nruns = 0;
1109    TString schunk, schunk2;
1110    TGridCollection *cbase=0, *cadd=0;
1111    if (!fRunNumbers.Length() && !fRunRange[0]) {
1112       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
1113       // Make a single data collection from data directory.
1114       path = fGridDataDir;
1115       if (!DirectoryExists(path)) {
1116          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
1117          return kFALSE;
1118       }   
1119 //      CdWork();
1120       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1121       else file = Form("%s.xml", gSystem->BaseName(path));
1122       while (1) {
1123          ncount = 0;
1124          stage++;
1125          if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1126             command = "find ";
1127             command += Form("%s -o %d ",options.Data(), nstart);
1128             command += path;
1129             command += " ";
1130             command += pattern;
1131             command += conditions;
1132             printf("command: %s\n", command.Data());
1133             TGridResult *res = gGrid->Command(command);
1134             if (res) delete res;
1135             // Write standard output to file
1136             gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage, file.Data()));
1137             Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1138             Bool_t nullFile = kFALSE;
1139             if (!hasGrep) {
1140                 Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1141             } else {
1142                nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1143                if (nullFile) {
1144                   Error("CreateDataset","Dataset %s produced by the previous find command is empty !", file.Data());
1145                   gSystem->Exec("rm -f __tmp*");
1146                   return kFALSE;
1147                }
1148                TString line;
1149                ifstream in;
1150                in.open("__tmp__");
1151                in >> line;
1152                in.close();
1153                gSystem->Exec("rm -f __tmp__");
1154                ncount = line.Atoi();
1155             }         
1156          }
1157          if (ncount == gMaxEntries) {
1158             Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1159             cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1160             if (!cbase) cbase = cadd;
1161             else {
1162                cbase->Add(cadd);
1163                delete cadd;
1164             }   
1165             nstart += ncount;
1166          } else {
1167             if (cbase) {
1168                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1169                printf("... please wait - TAlienCollection::Add() scales badly...\n");
1170                cbase->Add(cadd);
1171                delete cadd;
1172                cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1173                delete cbase; cbase = 0;               
1174             } else {
1175                TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1176             }
1177             gSystem->Exec("rm -f __tmp*");   
1178             Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1179             break;
1180          }
1181       }
1182       Bool_t fileExists = FileExists(file);
1183       if (!TestBit(AliAnalysisGrid::kTest) && (!fileExists || fOverwriteMode)) {
1184          // Copy xml file to alien space
1185          if (fileExists) gGrid->Rm(file);
1186          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1187          if (!FileExists(file)) {
1188             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1189             return kFALSE;
1190          }
1191          // Update list of files to be processed.
1192       }
1193       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
1194       return kTRUE;
1195    }   
1196    // Several runs
1197    Bool_t nullResult = kTRUE;
1198    if (fRunNumbers.Length()) {
1199       TObjArray *arr = fRunNumbers.Tokenize(" ");
1200       TObjString *os;
1201       TIter next(arr);
1202       while ((os=(TObjString*)next())) {
1203          nstart = 0;
1204          stage = 0;
1205          path = Form("%s/%s/ ", fGridDataDir.Data(), os->GetString().Data());
1206          if (!DirectoryExists(path)) continue;
1207 //         CdWork();
1208          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1209          else file = Form("%s.xml", os->GetString().Data());
1210          // If local collection file does not exist, create it via 'find' command.
1211          while (1) {
1212             ncount = 0;
1213             stage++;
1214             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1215                command = "find ";
1216                command +=  Form("%s -o %d ",options.Data(), nstart);
1217                command += path;
1218                command += pattern;
1219                command += conditions;
1220                TGridResult *res = gGrid->Command(command);
1221                if (res) delete res;
1222                // Write standard output to file
1223                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1224                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1225                Bool_t nullFile = kFALSE;
1226                if (!hasGrep) {
1227                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1228                } else {
1229                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1230                   if (nullFile) {
1231                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1232                      gSystem->Exec("rm -f __tmp*");
1233                      fRunNumbers.ReplaceAll(os->GetString().Data(), "");
1234                      break;
1235                   }   
1236                   TString line;
1237                   ifstream in;
1238                   in.open("__tmp__");
1239                   in >> line;
1240                   in.close();
1241                   gSystem->Exec("rm -f __tmp__");   
1242                   ncount = line.Atoi();
1243                }
1244                nullResult = kFALSE;         
1245             }
1246             if (ncount == gMaxEntries) {
1247                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1248                if (fNrunsPerMaster > 1) {
1249                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1250                           file.Data(),gMaxEntries);
1251                   return kFALSE;
1252                }           
1253                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1254                if (!cbase) cbase = cadd;
1255                else {
1256                   cbase->Add(cadd);
1257                   delete cadd;
1258                }   
1259                nstart += ncount;
1260             } else {
1261                if (cbase && fNrunsPerMaster<2) {
1262                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1263                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1264                   cbase->Add(cadd);
1265                   delete cadd;
1266                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1267                   delete cbase; cbase = 0;               
1268                } else {
1269                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1270                }
1271                gSystem->Exec("rm -f __tmp*");   
1272                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1273                break;
1274             }
1275          }   
1276          if (TestBit(AliAnalysisGrid::kTest)) break;
1277          // Check if there is one run per master job.
1278          if (fNrunsPerMaster<2) {
1279             if (FileExists(file)) {
1280                if (fOverwriteMode) gGrid->Rm(file);
1281                else {
1282                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1283                   continue;
1284                }   
1285             }        
1286             // Copy xml file to alien space
1287             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1288             if (!FileExists(file)) {
1289                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1290                delete arr;
1291                return kFALSE;
1292             }
1293          } else {
1294             nruns++;
1295             if (((nruns-1)%fNrunsPerMaster) == 0) {
1296                schunk = os->GetString();
1297                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1298             } else {
1299                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1300                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
1301                cbase->Add(cadd);
1302                delete cadd;
1303             }
1304             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
1305                continue;
1306             }   
1307             schunk += Form("_%s.xml", os->GetString().Data());
1308             if (FileExists(schunk)) {               
1309                if (fOverwriteMode) gGrid->Rm(file);
1310                else {
1311                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1312                   continue;
1313                }   
1314             }        
1315             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
1316             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1317             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1318             if (!FileExists(schunk)) {
1319                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1320                delete arr;
1321                return kFALSE;
1322             }
1323          }
1324       }   
1325       delete arr;
1326       if (nullResult) {
1327          Error("CreateDataset", "No valid dataset corresponding to the query!");
1328          return kFALSE;
1329       }
1330    } else {
1331       // Process a full run range.
1332       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1333          format = Form("%%s/%s ", fRunPrefix.Data());
1334          nstart = 0;
1335          stage = 0;
1336          path = Form(format.Data(), fGridDataDir.Data(), irun);
1337          if (!DirectoryExists(path)) continue;
1338 //         CdWork();
1339          format = Form("%s.xml", fRunPrefix.Data());
1340          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
1341          else file = Form(format.Data(), irun);
1342          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {         
1343             if (fOverwriteMode) gGrid->Rm(file);
1344             else {
1345                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1346                continue;
1347             }   
1348          }
1349          // If local collection file does not exist, create it via 'find' command.
1350          while (1) {
1351             ncount = 0;
1352             stage++;
1353             if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest) || fOverwriteMode) {
1354                command = "find ";
1355                command +=  Form("%s -o %d ",options.Data(), nstart);
1356                command += path;
1357                command += pattern;
1358                command += conditions;
1359                TGridResult *res = gGrid->Command(command);
1360                if (res) delete res;
1361                // Write standard output to file
1362                gROOT->ProcessLine(Form("gGrid->Stdout(); > __tmp%d__%s", stage,file.Data()));
1363                Bool_t hasGrep = (gSystem->Exec("grep --version 2>/dev/null > /dev/null")==0)?kTRUE:kFALSE;
1364                Bool_t nullFile = kFALSE;
1365                if (!hasGrep) {
1366                   Warning("CreateDataset", "'grep' command not available on this system - cannot validate the result of the grid 'find' command");
1367                } else {
1368                   nullFile = (gSystem->Exec(Form("grep -c /event __tmp%d__%s 2>/dev/null > __tmp__",stage,file.Data()))==0)?kFALSE:kTRUE;
1369                   if (nullFile) {
1370                      Warning("CreateDataset","Dataset %s produced by: <%s> is empty !", file.Data(), command.Data());
1371                      gSystem->Exec("rm -f __tmp*");
1372                      break;
1373                   }   
1374                   TString line;
1375                   ifstream in;
1376                   in.open("__tmp__");
1377                   in >> line;
1378                   in.close();
1379                   gSystem->Exec("rm -f __tmp__");   
1380                   ncount = line.Atoi();
1381                }
1382                nullResult = kFALSE;         
1383             }   
1384             if (ncount == gMaxEntries) {
1385                Info("CreateDataset", "Dataset %s has more than 15K entries. Trying to merge...", file.Data());
1386                if (fNrunsPerMaster > 1) {
1387                   Error("CreateDataset", "File %s has more than %d entries. Please set the number of runs per master to 1 !", 
1388                           file.Data(),gMaxEntries);
1389                   return kFALSE;
1390                }           
1391                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1392                if (!cbase) cbase = cadd;
1393                else {
1394                   cbase->Add(cadd);
1395                   delete cadd;
1396                }   
1397                nstart += ncount;
1398             } else {
1399                if (cbase && fNrunsPerMaster<2) {
1400                   cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"__tmp%d__%s\", 1000000);",stage,file.Data()));
1401                   printf("... please wait - TAlienCollection::Add() scales badly...\n");
1402                   cbase->Add(cadd);
1403                   delete cadd;
1404                   cbase->ExportXML(Form("file://%s", file.Data()),kFALSE,kFALSE, file, "Merged entries for a run");
1405                   delete cbase; cbase = 0;               
1406                } else {
1407                   TFile::Cp(Form("__tmp%d__%s",stage, file.Data()), file.Data());
1408                }
1409                Info("CreateDataset", "Created dataset %s with %d files", file.Data(), nstart+ncount);
1410                break;
1411             }
1412          }   
1413          if (TestBit(AliAnalysisGrid::kTest)) break;
1414          // Check if there is one run per master job.
1415          if (fNrunsPerMaster<2) {
1416             if (FileExists(file)) {
1417                if (fOverwriteMode) gGrid->Rm(file);
1418                else {
1419                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
1420                   continue;
1421                }   
1422             }        
1423             // Copy xml file to alien space
1424             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
1425             if (!FileExists(file)) {
1426                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
1427                return kFALSE;
1428             }
1429          } else {
1430             nruns++;
1431             // Check if the collection for the chunk exist locally.
1432             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
1433             if (FileExists(fInputFiles->At(nchunk)->GetName())) {
1434                if (fOverwriteMode) gGrid->Rm(fInputFiles->At(nchunk)->GetName());
1435                else continue;
1436             }   
1437             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
1438             if (((nruns-1)%fNrunsPerMaster) == 0) {
1439                schunk = Form(fRunPrefix.Data(), irun);
1440                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1441             } else {
1442                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
1443                cbase->Add(cadd);
1444                delete cadd;
1445             }
1446             format = Form("%%s_%s.xml", fRunPrefix.Data());
1447             schunk2 = Form(format.Data(), schunk.Data(), irun);
1448             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1] && schunk2 != fInputFiles->Last()->GetName()) {
1449                continue;
1450             }   
1451             schunk = schunk2;
1452             if (FileExists(schunk)) {
1453                if (fOverwriteMode) gGrid->Rm(schunk);
1454                else {
1455                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
1456                   continue;
1457                }   
1458             }        
1459             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
1460             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
1461             if (FileExists(schunk)) {
1462                if (fOverwriteMode) gGrid->Rm(schunk);
1463                else {
1464                   Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
1465                   continue;
1466                }   
1467             }   
1468             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
1469             if (!FileExists(schunk)) {
1470                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
1471                return kFALSE;
1472             }
1473          }   
1474       }
1475       if (nullResult) {
1476          Error("CreateDataset", "No valid dataset corresponding to the query!");
1477          return kFALSE;
1478       }      
1479    }      
1480    return kTRUE;
1481 }
1482
1483 //______________________________________________________________________________
1484 Bool_t AliAnalysisAlien::CreateJDL()
1485 {
1486 // Generate a JDL file according to current settings. The name of the file is 
1487 // specified by fJDLName.
1488    Bool_t error = kFALSE;
1489    TObjArray *arr = 0;
1490    Bool_t copy = kTRUE;
1491    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1492    Bool_t generate = kTRUE;
1493    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
1494    if (!Connect()) {
1495       Error("CreateJDL", "Alien connection required");
1496       return kFALSE;
1497    }   
1498    // Check validity of alien workspace
1499    TString workdir;
1500    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1501    if (!fProductionMode &&  !TestBit(AliAnalysisGrid::kTest)) CdWork();
1502    workdir += fGridWorkingDir;
1503    if (generate) {
1504       TObjString *os;
1505       if (!fInputFiles) {
1506          Error("CreateJDL()", "Define some input files for your analysis.");
1507          error = kTRUE;
1508       }
1509       // Compose list of input files   
1510       // Check if output files were defined
1511       if (!fOutputFiles.Length()) {
1512          Error("CreateJDL", "You must define at least one output file");
1513          error = kTRUE;
1514       }   
1515       // Check if an output directory was defined and valid
1516       if (!fGridOutputDir.Length()) {
1517          Error("CreateJDL", "You must define AliEn output directory");
1518          error = kTRUE;
1519       } else {
1520          if (!fProductionMode) {
1521             if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1522             if (!DirectoryExists(fGridOutputDir)) {
1523                if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1524                   Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1525                } else {
1526                   Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1527                   // error = kTRUE;
1528                }
1529             } else {
1530                Warning("CreateJDL", "#### Output directory %s exists! If this contains old data, jobs will fail with ERROR_SV !!! ###", fGridOutputDir.Data());
1531             }   
1532             gGrid->Cd(workdir);
1533          }   
1534       }   
1535       // Exit if any error up to now
1536       if (error) return kFALSE;   
1537       // Set JDL fields
1538       if (!fUser.IsNull()) {
1539          fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1540          fMergingJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
1541       }   
1542       fGridJDL->SetExecutable(fExecutable, "This is the startup script");
1543       TString mergeExec = fExecutable;
1544       mergeExec.ReplaceAll(".sh", "_merge.sh");
1545       fMergingJDL->SetExecutable(mergeExec, "This is the startup script");
1546       mergeExec.ReplaceAll(".sh", ".C");
1547       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),mergeExec.Data()), "List of input files to be uploaded to workers");
1548       if (!fArguments.IsNull())
1549          fGridJDL->SetArguments(fArguments, "Arguments for the executable command");
1550       if (IsOneStageMerging()) fMergingJDL->SetArguments(fGridOutputDir);
1551       else {
1552          if (fProductionMode)  fMergingJDL->SetArguments("wn.xml $4");    // xml, stage
1553          else                  fMergingJDL->SetArguments("wn.xml $2");    // xml, stage
1554      }               
1555
1556       fGridJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1557       fGridJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1558       fMergingJDL->SetValue("TTL", Form("\"%d\"",fTTL));
1559       fMergingJDL->SetDescription("TTL", Form("Time after which the job is killed (%d min.)", fTTL/60));
1560         
1561       if (fMaxInitFailed > 0) {
1562          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
1563          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
1564       }   
1565       if (fSplitMaxInputFileNumber > 0) {
1566          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
1567          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
1568       }
1569       if (!IsOneStageMerging()) {
1570          fMergingJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"",fMaxMergeFiles));
1571          fMergingJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be merged in one go");
1572       }   
1573       if (fSplitMode.Length()) {
1574          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
1575          fGridJDL->SetDescription("Split", "We split per SE or file");
1576       }
1577       fMergingJDL->SetValue("Split", "\"se\""); 
1578       fMergingJDL->SetDescription("Split", "We split per SE for merging in stages");
1579       if (!fAliROOTVersion.IsNull()) {
1580          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
1581          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
1582       }   
1583       if (!fROOTVersion.IsNull()) {
1584          fGridJDL->AddToPackages("ROOT", fROOTVersion);
1585          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
1586       }   
1587       if (!fAPIVersion.IsNull()) {
1588          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
1589          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
1590       }   
1591       if (!fExternalPackages.IsNull()) {
1592          arr = fExternalPackages.Tokenize(" ");
1593          TIter next(arr);
1594          while ((os=(TObjString*)next())) {
1595             TString pkgname = os->GetString();
1596             Int_t index = pkgname.Index("::");
1597             TString pkgversion = pkgname(index+2, pkgname.Length());
1598             pkgname.Remove(index);
1599             fGridJDL->AddToPackages(pkgname, pkgversion);
1600             fMergingJDL->AddToPackages(pkgname, pkgversion);
1601          }   
1602          delete arr;   
1603       }   
1604       fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1605       fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1606       fMergingJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
1607       fMergingJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
1608       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
1609       TString analysisFile = fExecutable;
1610       analysisFile.ReplaceAll(".sh", ".root");
1611       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1612       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
1613       if (fAdditionalLibs.Length()) {
1614          arr = fAdditionalLibs.Tokenize(" ");
1615          TIter next(arr);
1616          while ((os=(TObjString*)next())) {
1617             if (os->GetString().Contains(".so")) continue;
1618             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1619             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
1620          }   
1621          delete arr;   
1622       }
1623       if (fPackages) {
1624          TIter next(fPackages);
1625          TObject *obj;
1626          while ((obj=next())) {
1627             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1628             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
1629          }
1630       }
1631       if (fOutputArchive.Length()) {
1632          arr = fOutputArchive.Tokenize(" ");
1633          TIter next(arr);
1634          Bool_t first = kTRUE;
1635          const char *comment = "Files to be archived";
1636          const char *comment1 = comment;
1637          while ((os=(TObjString*)next())) {
1638             if (!first) comment = NULL;
1639             if (!os->GetString().Contains("@") && fCloseSE.Length())
1640                fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1641             else
1642                fGridJDL->AddToOutputArchive(os->GetString(), comment);
1643             first = kFALSE;   
1644          }      
1645          delete arr;
1646          // Output archive for the merging jdl
1647          TString outputArchive;
1648          if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1649             outputArchive = "log_archive.zip:std*@disk=1 ";
1650             // Add normal output files, extra files + terminate files
1651             TString files = GetListOfFiles("outextter");
1652             // Do not register files in fRegisterExcludes
1653             if (!fRegisterExcludes.IsNull()) {
1654                arr = fRegisterExcludes.Tokenize(" ");
1655                TIter next1(arr);
1656                while ((os=(TObjString*)next1())) {
1657                   files.ReplaceAll(Form("%s,",os->GetString().Data()),"");
1658                   files.ReplaceAll(os->GetString(),"");
1659                }   
1660                delete arr;
1661             }
1662             files.ReplaceAll(".root", "*.root");
1663             outputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",files.Data(),fNreplicas);
1664          } else {
1665             TString files = fOutputArchive;
1666             files.ReplaceAll(".root", "*.root"); // nreplicas etc should be already atttached by use
1667             outputArchive = files;
1668          }   
1669          arr = outputArchive.Tokenize(" ");
1670          TIter next2(arr);
1671          comment = comment1;
1672          first = kTRUE;
1673          while ((os=(TObjString*)next2())) {
1674             if (!first) comment = NULL;
1675             TString currentfile = os->GetString();
1676             if (!currentfile.Contains("@") && fCloseSE.Length())
1677                fMergingJDL->AddToOutputArchive(Form("%s@%s",currentfile.Data(), fCloseSE.Data()), comment);
1678             else
1679                fMergingJDL->AddToOutputArchive(currentfile, comment);
1680             first = kFALSE;   
1681          }      
1682          delete arr;         
1683       }      
1684       arr = fOutputFiles.Tokenize(",");
1685       TIter next(arr);
1686       Bool_t first = kTRUE;
1687       const char *comment = "Files to be saved";
1688       while ((os=(TObjString*)next())) {
1689          // Ignore ouputs in jdl that are also in outputarchive
1690          TString sout = os->GetString();
1691          sout.ReplaceAll("*", "");
1692          sout.ReplaceAll(".root", "");
1693          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1694          if (fOutputArchive.Contains(sout)) continue;
1695          // Ignore fRegisterExcludes
1696          if (fRegisterExcludes.Contains(sout)) continue;
1697          if (!first) comment = NULL;
1698          if (!os->GetString().Contains("@") && fCloseSE.Length())
1699             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1700          else
1701             fGridJDL->AddToOutputSandbox(os->GetString(), comment);
1702          first = kFALSE;
1703          if (fMergeExcludes.Contains(sout)) continue;   
1704          if (!os->GetString().Contains("@") && fCloseSE.Length())
1705             fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
1706          else
1707             fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1708       }   
1709       delete arr;
1710       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1711       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1712       TString validationScript = fValidationScript;
1713       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1714       validationScript.ReplaceAll(".sh", "_merge.sh");
1715       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1716       if (fMasterResubmitThreshold) {
1717          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1718          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1719       }   
1720       // Write a jdl with 2 input parameters: collection name and output dir name.
1721       WriteJDL(copy);
1722    }
1723    // Copy jdl to grid workspace   
1724    if (copy) {
1725       // Check if an output directory was defined and valid
1726       if (!fGridOutputDir.Length()) {
1727          Error("CreateJDL", "You must define AliEn output directory");
1728          return kFALSE;
1729       } else {
1730          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1731          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1732             if (gGrid->Mkdir(fGridOutputDir,"-p")) {
1733                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1734             } else {
1735                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1736                return kFALSE;
1737             }
1738          }
1739          gGrid->Cd(workdir);
1740       }   
1741       if (TestBit(AliAnalysisGrid::kSubmit)) {
1742          TString mergeJDLName = fExecutable;
1743          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1744          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1745          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1746          if (fProductionMode) {
1747             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1748             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1749          }   
1750          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1751          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1752          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1753          if (!copyLocal2Alien("CreateJDL", fJDLName, locjdl)) 
1754             Fatal("","Terminating");
1755 //         TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1756          if (fMergeViaJDL) {
1757             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1758 //            TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1759             if (!copyLocal2Alien("CreateJDL", mergeJDLName.Data(), locjdl1)) 
1760                Fatal("","Terminating");
1761          }   
1762       }
1763       if (fAdditionalLibs.Length()) {
1764          arr = fAdditionalLibs.Tokenize(" ");
1765          TObjString *os;
1766          TIter next(arr);
1767          while ((os=(TObjString*)next())) {
1768             if (os->GetString().Contains(".so")) continue;
1769             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1770             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1771 //            TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1772             if (!copyLocal2Alien("CreateJDL", os->GetString().Data(), 
1773                 Form("%s/%s", workdir.Data(), os->GetString().Data())))
1774               Fatal("","Terminating");
1775          }   
1776          delete arr;   
1777       }
1778       if (fPackages) {
1779          TIter next(fPackages);
1780          TObject *obj;
1781          while ((obj=next())) {
1782             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1783             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1784 //            TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1785             if (!copyLocal2Alien("CreateJDL",obj->GetName(), 
1786                 Form("%s/%s", workdir.Data(), obj->GetName()))) 
1787               Fatal("","Terminating"); 
1788          }   
1789       }      
1790    } 
1791    return kTRUE;
1792 }
1793
1794 //______________________________________________________________________________
1795 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1796 {
1797 // Writes one or more JDL's corresponding to findex. If findex is negative,
1798 // all run numbers are considered in one go (jdl). For non-negative indices
1799 // they correspond to the indices in the array fInputFiles.
1800    if (!fInputFiles) return kFALSE;
1801    TObject *os;
1802    TString workdir;
1803    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice")) workdir = gGrid->GetHomeDirectory();
1804    workdir += fGridWorkingDir;
1805    TString stageName = "$2";
1806    if (fProductionMode) stageName = "$4";
1807    if (!fMergeDirName.IsNull()) {
1808      fMergingJDL->AddToInputDataCollection(Form("LF:$1/%s/Stage_%s.xml,nodownload",fMergeDirName.Data(),stageName.Data()), "Collection of files to be merged for current stage");
1809      fMergingJDL->SetOutputDirectory(Form("$1/%s/Stage_%s/#alien_counter_03i#",fMergeDirName.Data(),stageName.Data()), "Output directory");
1810    } else {
1811      fMergingJDL->AddToInputDataCollection(Form("LF:$1/Stage_%s.xml,nodownload",stageName.Data()), "Collection of files to be merged for current stage");
1812      fMergingJDL->SetOutputDirectory(Form("$1/Stage_%s/#alien_counter_03i#",stageName.Data()), "Output directory");
1813    }
1814    if (fProductionMode) {
1815       TIter next(fInputFiles);
1816       while ((os=next())) {
1817          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1818       }
1819       if (!fOutputToRunNo)
1820          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_04i#", fGridOutputDir.Data()));
1821       else  
1822          fGridJDL->SetOutputDirectory(fGridOutputDir);
1823    } else {            
1824       if (!fRunNumbers.Length() && !fRunRange[0]) {
1825          // One jdl with no parameters in case input data is specified by name.
1826          TIter next(fInputFiles);
1827          while ((os=next()))
1828             fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetName()), "Input xml collections");
1829          if (!fOutputSingle.IsNull())
1830             fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1831          else {
1832             fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1833             fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1834          }   
1835       } else {
1836          // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1837          fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1838          if (!fOutputSingle.IsNull()) {
1839             if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1840             else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1841          } else {   
1842             fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1843          }   
1844       }
1845    }
1846       
1847    // Generate the JDL as a string
1848    TString sjdl = fGridJDL->Generate();
1849    TString sjdl1 = fMergingJDL->Generate();
1850    // Final merge jdl
1851    if (!fMergeDirName.IsNull()) {
1852      fMergingJDL->SetOutputDirectory(Form("$1/%s",fMergeDirName.Data()), "Output directory");
1853      fMergingJDL->AddToInputSandbox(Form("LF:$1/%s/Stage_%s.xml",fMergeDirName.Data(),stageName.Data()));
1854    } else {  
1855      fMergingJDL->SetOutputDirectory("$1", "Output directory");
1856      fMergingJDL->AddToInputSandbox(Form("LF:$1/Stage_%s.xml",stageName.Data()));
1857    }  
1858    TString sjdl2 = fMergingJDL->Generate();
1859    Int_t index, index1;
1860    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
1861    sjdl.ReplaceAll("(member", "\n   (member");
1862    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1863    sjdl.ReplaceAll("{", "{\n   ");
1864    sjdl.ReplaceAll("};", "\n};");
1865    sjdl.ReplaceAll("{\n   \n", "{\n");
1866    sjdl.ReplaceAll("\n\n", "\n");
1867    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1868    sjdl1.ReplaceAll("\"LF:", "\n   \"LF:");
1869    sjdl1.ReplaceAll("(member", "\n   (member");
1870    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1871    sjdl1.ReplaceAll("{", "{\n   ");
1872    sjdl1.ReplaceAll("};", "\n};");
1873    sjdl1.ReplaceAll("{\n   \n", "{\n");
1874    sjdl1.ReplaceAll("\n\n", "\n");
1875    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1876    sjdl2.ReplaceAll("\"LF:", "\n   \"LF:");
1877    sjdl2.ReplaceAll("(member", "\n   (member");
1878    sjdl2.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1879    sjdl2.ReplaceAll("{", "{\n   ");
1880    sjdl2.ReplaceAll("};", "\n};");
1881    sjdl2.ReplaceAll("{\n   \n", "{\n");
1882    sjdl2.ReplaceAll("\n\n", "\n");
1883    sjdl2.ReplaceAll("OutputDirectory", "OutputDir");
1884    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1885    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
1886    index = sjdl.Index("JDLVariables");
1887    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1888    sjdl += "Workdirectorysize = {\"5000MB\"};";
1889    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1890    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1891    index = fJobTag.Index(":");
1892    if (index < 0) index = fJobTag.Length();
1893    TString jobTag = fJobTag;
1894    if (fProductionMode) jobTag.Insert(index,"_Stage$4");
1895    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:%s_Merging\"\n};\n", jobTag.Data()));
1896    if (fProductionMode) {   
1897      sjdl1.Prepend("# Generated merging jdl (production mode) \
1898                     \n# $1 = full alien path to output directory to be merged \
1899                     \n# $2 = train number \
1900                     \n# $3 = production (like LHC10b) \
1901                     \n# $4 = merging stage \
1902                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1903      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
1904      sjdl2.Prepend("# Generated merging jdl \
1905                     \n# $1 = full alien path to output directory to be merged \
1906                     \n# $2 = train number \
1907                     \n# $3 = production (like LHC10b) \
1908                     \n# $4 = merging stage \
1909                     \n# Stage_<n>.xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1910    } else {
1911      sjdl1.Prepend("# Generated merging jdl \
1912                     \n# $1 = full alien path to output directory to be merged \
1913                     \n# $2 = merging stage \
1914                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1915      sjdl2.Prepend(Form("Jobtag = {\n   \"comment:%s_FinalMerging\"\n};\n", jobTag.Data()));
1916      sjdl2.Prepend("# Generated merging jdl \
1917                     \n# $1 = full alien path to output directory to be merged \
1918                     \n# $2 = merging stage \
1919                     \n# xml made via: find <OutputDir> *Stage<n-1>/*root_archive.zip\n");
1920    }
1921    index = sjdl1.Index("JDLVariables");
1922    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1923    index = sjdl2.Index("JDLVariables");
1924    if (index >= 0) sjdl2.Insert(index, "\n# JDL variables\n");
1925    sjdl1 += "Workdirectorysize = {\"5000MB\"};";
1926    sjdl2 += "Workdirectorysize = {\"5000MB\"};";
1927    index = sjdl2.Index("Split =");
1928    if (index>=0) {
1929       index1 = sjdl2.Index("\n", index);
1930       sjdl2.Remove(index, index1-index+1);
1931    }
1932    index = sjdl2.Index("SplitMaxInputFileNumber");
1933    if (index>=0) {
1934       index1 = sjdl2.Index("\n", index);
1935       sjdl2.Remove(index, index1-index+1);
1936    }
1937    index = sjdl2.Index("InputDataCollection");
1938    if (index>=0) {
1939       index1 = sjdl2.Index(";", index);
1940       sjdl2.Remove(index, index1-index+1);
1941    }
1942    index = sjdl2.Index("InputDataListFormat");
1943    if (index>=0) {
1944       index1 = sjdl2.Index("\n", index);
1945       sjdl2.Remove(index, index1-index+1);
1946    }
1947    index = sjdl2.Index("InputDataList");
1948    if (index>=0) {
1949       index1 = sjdl2.Index("\n", index);
1950       sjdl2.Remove(index, index1-index+1);
1951    }
1952    sjdl2.ReplaceAll("wn.xml", Form("Stage_%s.xml",stageName.Data()));
1953    // Write jdl to file
1954    ofstream out;
1955    out.open(fJDLName.Data(), ios::out);
1956    if (out.bad()) {
1957       Error("WriteJDL", "Bad file name: %s", fJDLName.Data());
1958       return kFALSE;
1959    }
1960    out << sjdl << endl;
1961    out.close();
1962    TString mergeJDLName = fExecutable;
1963    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1964    if (fMergeViaJDL) {
1965       ofstream out1;
1966       out1.open(mergeJDLName.Data(), ios::out);
1967       if (out1.bad()) {
1968          Error("WriteJDL", "Bad file name: %s", mergeJDLName.Data());
1969          return kFALSE;
1970       }
1971       out1 << sjdl1 << endl;
1972       out1.close();
1973       ofstream out2;
1974       TString finalJDL = mergeJDLName;
1975       finalJDL.ReplaceAll(".jdl", "_final.jdl");
1976       out2.open(finalJDL.Data(), ios::out);
1977       if (out2.bad()) {
1978          Error("WriteJDL", "Bad file name: %s", finalJDL.Data());
1979          return kFALSE;
1980       }
1981       out2 << sjdl2 << endl;
1982       out2.close();
1983    }   
1984
1985    // Copy jdl to grid workspace   
1986    if (!copy) {
1987       Info("WriteJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1988    } else {
1989       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1990       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1991       TString finalJDL = mergeJDLName;
1992       finalJDL.ReplaceAll(".jdl", "_final.jdl");
1993       TString locjdl2 = Form("%s/%s", fGridOutputDir.Data(),finalJDL.Data());
1994       if (fProductionMode) {
1995          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1996          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1997          locjdl2 = Form("%s/%s", workdir.Data(),finalJDL.Data());
1998       }   
1999       if (FileExists(locjdl)) gGrid->Rm(locjdl);
2000       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
2001       if (FileExists(locjdl2)) gGrid->Rm(locjdl2);
2002       Info("WriteJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
2003 //      TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
2004       if (!copyLocal2Alien("WriteJDL",fJDLName.Data(),locjdl.Data())) 
2005          Fatal("","Terminating");
2006       if (fMergeViaJDL) {
2007          Info("WriteJDL", "\n#####   Copying merging JDL files <%s> to your AliEn output directory", mergeJDLName.Data());
2008 //         TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
2009 //         TFile::Cp(Form("file:%s",finalJDL.Data()), Form("alien://%s", locjdl2.Data()));
2010          if (!copyLocal2Alien("WriteJDL",mergeJDLName.Data(),locjdl1.Data()))
2011             Fatal("","Terminating");
2012          if (!copyLocal2Alien("WriteJDL",finalJDL.Data(),locjdl2.Data()))
2013            Fatal("","Terminating");
2014       }   
2015    } 
2016    return kTRUE;
2017 }
2018
2019 //______________________________________________________________________________
2020 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
2021 {
2022 // Returns true if file exists.
2023    if (!gGrid) return kFALSE;
2024    TString slfn = lfn;
2025    slfn.ReplaceAll("alien://","");
2026    TGridResult *res = gGrid->Ls(slfn);
2027    if (!res) return kFALSE;
2028    TMap *map = dynamic_cast<TMap*>(res->At(0));
2029    if (!map) {
2030       delete res;
2031       return kFALSE;
2032    }   
2033    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
2034    if (!objs || !objs->GetString().Length()) {
2035       delete res;
2036       return kFALSE;
2037    }
2038    delete res;   
2039    return kTRUE;
2040 }
2041
2042 //______________________________________________________________________________
2043 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
2044 {
2045 // Returns true if directory exists. Can be also a path.
2046    if (!gGrid) return kFALSE;
2047    // Check if dirname is a path
2048    TString dirstripped = dirname;
2049    dirstripped = dirstripped.Strip();
2050    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
2051    TString dir = gSystem->BaseName(dirstripped);
2052    dir += "/";
2053    TString path = gSystem->DirName(dirstripped);
2054    TGridResult *res = gGrid->Ls(path, "-F");
2055    if (!res) return kFALSE;
2056    TIter next(res);
2057    TMap *map;
2058    TObject *obj;
2059    while ((map=dynamic_cast<TMap*>(next()))) {
2060       obj = map->GetValue("name");
2061       if (!obj) break;
2062       if (dir == obj->GetName()) {
2063          delete res;
2064          return kTRUE;
2065       }
2066    }
2067    delete res;
2068    return kFALSE;
2069 }      
2070
2071 //______________________________________________________________________________
2072 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &isCollection, Bool_t &isXml, Bool_t &useTags)
2073 {
2074 // Check input data type.
2075    isCollection = kFALSE;
2076    isXml = kFALSE;
2077    useTags = kFALSE;
2078    if (!gGrid) {
2079       Error("CheckDataType", "No connection to grid");
2080       return;
2081    }
2082    isCollection = IsCollection(lfn);
2083    TString msg = "\n#####   file: ";
2084    msg += lfn;
2085    if (isCollection) {
2086       msg += " type: raw_collection;";
2087    // special treatment for collections
2088       isXml = kFALSE;
2089       // check for tag files in the collection
2090       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
2091       if (!res) {
2092          msg += " using_tags: No (unknown)";
2093          Info("CheckDataType", "%s", msg.Data());
2094          return;
2095       }   
2096       const char* typeStr = res->GetKey(0, "origLFN");
2097       if (!typeStr || !strlen(typeStr)) {
2098          msg += " using_tags: No (unknown)";
2099          Info("CheckDataType", "%s", msg.Data());
2100          return;
2101       }   
2102       TString file = typeStr;
2103       useTags = file.Contains(".tag");
2104       if (useTags) msg += " using_tags: Yes";
2105       else          msg += " using_tags: No";
2106       Info("CheckDataType", "%s", msg.Data());
2107       return;
2108    }
2109    TString slfn(lfn);
2110    slfn.ToLower();
2111    isXml = slfn.Contains(".xml");
2112    if (isXml) {
2113    // Open xml collection and check if there are tag files inside
2114       msg += " type: xml_collection;";
2115       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
2116       if (!coll) {
2117          msg += " using_tags: No (unknown)";
2118          Info("CheckDataType", "%s", msg.Data());
2119          return;
2120       }   
2121       TMap *map = coll->Next();
2122       if (!map) {
2123          msg += " using_tags: No (unknown)";
2124          Info("CheckDataType", "%s", msg.Data());
2125          return;
2126       }   
2127       map = (TMap*)map->GetValue("");
2128       TString file;
2129       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
2130       useTags = file.Contains(".tag");
2131       delete coll;
2132       if (useTags) msg += " using_tags: Yes";
2133       else          msg += " using_tags: No";
2134       Info("CheckDataType", "%s", msg.Data());
2135       return;
2136    }
2137    useTags = slfn.Contains(".tag");
2138    if (slfn.Contains(".root")) msg += " type: root file;";
2139    else                        msg += " type: unknown file;";
2140    if (useTags) msg += " using_tags: Yes";
2141    else          msg += " using_tags: No";
2142    Info("CheckDataType", "%s", msg.Data());
2143 }
2144
2145 //______________________________________________________________________________
2146 void AliAnalysisAlien::EnablePackage(const char *package)
2147 {
2148 // Enables a par file supposed to exist in the current directory.
2149    TString pkg(package);
2150    pkg.ReplaceAll(".par", "");
2151    pkg += ".par";
2152    if (gSystem->AccessPathName(pkg)) {
2153       Fatal("EnablePackage", "Package %s not found", pkg.Data());
2154       return;
2155    }
2156    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
2157       Info("EnablePackage", "AliEn plugin will use .par packages");
2158    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
2159    if (!fPackages) {
2160       fPackages = new TObjArray();
2161       fPackages->SetOwner();
2162    }
2163    fPackages->Add(new TObjString(pkg));
2164 }      
2165
2166 //______________________________________________________________________________
2167 TChain *AliAnalysisAlien::GetChainForTestMode(const char *treeName) const
2168 {
2169 // Make a tree from files having the location specified in fFileForTestMode. 
2170 // Inspired from JF's CreateESDChain.
2171    if (fFileForTestMode.IsNull()) {
2172       Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
2173       return NULL;
2174    }
2175    if (gSystem->AccessPathName(fFileForTestMode)) {
2176       Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
2177       return NULL;
2178    }   
2179    // Open the file
2180    ifstream in;
2181    in.open(fFileForTestMode);
2182    Int_t count = 0;
2183     // Read the input list of files and add them to the chain
2184     TString line;
2185     TChain *chain = new TChain(treeName);
2186     while (in.good())
2187     {
2188       in >> line;
2189       if (line.IsNull()) continue;
2190       if (count++ == fNtestFiles) break;
2191       TString esdFile(line);
2192       TFile *file = TFile::Open(esdFile);
2193       if (file) {
2194          if (!file->IsZombie()) chain->Add(esdFile);
2195          file->Close();
2196       } else {
2197          Error("GetChainforTestMode", "Skipping un-openable file: %s", esdFile.Data());
2198       }   
2199     }
2200     in.close();
2201     if (!chain->GetListOfFiles()->GetEntries()) {
2202        Error("GetChainForTestMode", "No file from %s could be opened", fFileForTestMode.Data());
2203        delete chain;
2204        return NULL;
2205     }
2206 //    chain->ls();
2207     return chain;
2208 }    
2209
2210 //______________________________________________________________________________
2211 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
2212 {
2213 // Get job status for all jobs with jobid>jobidstart.
2214    static char mstatus[20];
2215    mstatus[0] = '\0';
2216    nrunning = 0;
2217    nwaiting = 0;
2218    nerror   = 0;
2219    ndone    = 0;
2220    TGridJobStatusList *list = gGrid->Ps("");
2221    if (!list) return mstatus;
2222    Int_t nentries = list->GetSize();
2223    TGridJobStatus *status;
2224    Int_t pid;
2225    for (Int_t ijob=0; ijob<nentries; ijob++) {
2226       status = (TGridJobStatus *)list->At(ijob);
2227       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)%p)->GetKey(\"queueId\"));", status));
2228       if (pid<jobidstart) continue;
2229       if (pid == lastid) {
2230          gROOT->ProcessLine(Form("sprintf((char*)%p,((TAlienJobStatus*)%p)->GetKey(\"status\"));",mstatus, status));
2231       }   
2232       switch (status->GetStatus()) {
2233          case TGridJobStatus::kWAITING:
2234             nwaiting++; break;
2235          case TGridJobStatus::kRUNNING:
2236             nrunning++; break;
2237          case TGridJobStatus::kABORTED:
2238          case TGridJobStatus::kFAIL:
2239          case TGridJobStatus::kUNKNOWN:
2240             nerror++; break;
2241          case TGridJobStatus::kDONE:
2242             ndone++;
2243       }
2244    }
2245    list->Delete();
2246    delete list;
2247    return mstatus;
2248 }
2249
2250 //______________________________________________________________________________
2251 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
2252 {
2253 // Returns true if file is a collection. Functionality duplicated from
2254 // TAlien::Type() because we don't want to directly depend on TAlien.
2255    if (!gGrid) {
2256       Error("IsCollection", "No connection to grid");
2257       return kFALSE;
2258    }
2259    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
2260    if (!res) return kFALSE;
2261    const char* typeStr = res->GetKey(0, "type");
2262    if (!typeStr || !strlen(typeStr)) return kFALSE;
2263    if (!strcmp(typeStr, "collection")) return kTRUE;
2264    delete res;
2265    return kFALSE;
2266 }   
2267
2268 //______________________________________________________________________________
2269 Bool_t AliAnalysisAlien::IsSingleOutput() const
2270 {
2271 // Check if single-ouput option is on.
2272    return (!fOutputSingle.IsNull());
2273 }
2274    
2275 //______________________________________________________________________________
2276 void AliAnalysisAlien::Print(Option_t *) const
2277 {
2278 // Print current plugin settings.
2279    printf("### AliEn analysis plugin current settings ###\n");
2280    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2281    if (mgr && mgr->IsProofMode()) {
2282       TString proofType = "=   PLUGIN IN PROOF MODE ON CLUSTER:_________________";
2283       if (TestBit(AliAnalysisGrid::kTest))
2284          proofType = "=   PLUGIN IN PROOF LITE MODE ON CLUSTER:____________";
2285       printf("%s %s\n", proofType.Data(), fProofCluster.Data());
2286       if (!fProofDataSet.IsNull())
2287       printf("=   Requested data set:___________________________ %s\n", fProofDataSet.Data());
2288       if (fProofReset==1)
2289       printf("=   Soft reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2290       if (fProofReset>1)   
2291       printf("=   Hard reset signal will be send to master______ CHANGE BEHAVIOR AFTER COMPLETION\n");      
2292       if (!fRootVersionForProof.IsNull())
2293       printf("=   ROOT version requested________________________ %s\n", fRootVersionForProof.Data());
2294       else
2295       printf("=   ROOT version requested________________________ default\n");
2296       printf("=   AliRoot version requested_____________________ %s\n", fAliROOTVersion.Data());
2297       if (!fAliRootMode.IsNull())
2298       printf("=   Requested AliRoot mode________________________ %s\n", fAliRootMode.Data());  
2299       if (fNproofWorkers)
2300       printf("=   Number of PROOF workers limited to____________ %d\n", fNproofWorkers);
2301       if  (fNproofWorkersPerSlave)
2302       printf("=   Maximum number of workers per slave___________ %d\n", fNproofWorkersPerSlave);
2303       if (TestSpecialBit(kClearPackages))
2304       printf("=   ClearPackages requested...\n");
2305       if (fIncludePath.Data())
2306       printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2307       printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2308       if (fPackages && fPackages->GetEntries()) {
2309          TIter next(fPackages);
2310          TObject *obj;
2311          TString list;
2312          while ((obj=next())) list += obj->GetName();
2313          printf("=   Par files to be used: ________________________ %s\n", list.Data());
2314       } 
2315       if (TestSpecialBit(kProofConnectGrid))
2316       printf("=   Requested PROOF connection to grid\n");
2317       return;
2318    }
2319    printf("=   OverwriteMode:________________________________ %d\n", fOverwriteMode);
2320    if (fOverwriteMode) {
2321       printf("***** NOTE: Overwrite mode will overwrite the input generated datasets and partial results from previous analysis. \
2322             \n*****       To disable, use: plugin->SetOverwriteMode(kFALSE);\n");
2323    }
2324    printf("=   Copy files to grid: __________________________ %s\n", (IsUseCopy())?"YES":"NO");
2325    printf("=   Check if files can be copied to grid: ________ %s\n", (IsCheckCopy())?"YES":"NO");
2326    printf("=   Production mode:______________________________ %d\n", fProductionMode);
2327    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
2328    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
2329    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
2330    if (fUser.Length()) 
2331    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
2332    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
2333    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
2334    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
2335    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
2336    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
2337    if (fRunNumbers.Length()) 
2338    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
2339    if (fRunRange[0])
2340    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
2341    if (!fRunRange[0] && !fRunNumbers.Length()) {
2342       TIter next(fInputFiles);
2343       TObject *obj;
2344       TString list;
2345       while ((obj=next())) list += obj->GetName();
2346       printf("=   Input files to be processed: _________________ %s\n", list.Data());
2347    }
2348    if (TestBit(AliAnalysisGrid::kTest))
2349    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
2350    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
2351    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
2352    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
2353    printf("=   List of outputs that should not be registered: %s\n", fRegisterExcludes.Data());
2354    printf("=   List of outputs produced during Terminate: ___ %s\n", fTerminateFiles.Data());
2355    printf("=====================================================================\n");
2356    printf("=   Job price: ___________________________________ %d\n", fPrice);
2357    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
2358    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
2359    if (fMaxInitFailed>0) 
2360    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
2361    if (fMasterResubmitThreshold>0) 
2362    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
2363    printf("=   Number of replicas for the output files_______ %d\n", fNreplicas);
2364    if (fNrunsPerMaster>0)
2365    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
2366    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
2367    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
2368    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
2369    if (fArguments.Length()) 
2370    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
2371    if (fExecutableArgs.Length()) 
2372    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
2373    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
2374    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
2375    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
2376    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
2377    if (fDatasetName)
2378    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
2379    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
2380    if (fIncludePath.Data())
2381    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
2382    if (fCloseSE.Length())
2383    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
2384    if (fFriendChainName.Length())
2385    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
2386    if (fPackages && fPackages->GetEntries()) {
2387       TIter next(fPackages);
2388       TObject *obj;
2389       TString list;
2390       while ((obj=next())) list += obj->GetName();
2391       printf("=   Par files to be used: ________________________ %s\n", list.Data());
2392    }   
2393 }
2394
2395 //______________________________________________________________________________
2396 void AliAnalysisAlien::SetDefaults()
2397 {
2398 // Set default values for everything. What cannot be filled will be left empty.
2399    if (fGridJDL) delete fGridJDL;
2400    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2401    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
2402    fPrice                      = 1;
2403    fTTL                        = 30000;
2404    fSplitMaxInputFileNumber    = 100;
2405    fMaxInitFailed              = 0;
2406    fMasterResubmitThreshold    = 0;
2407    fNtestFiles                 = 10;
2408    fNreplicas                  = 2;
2409    fRunRange[0]                = 0;
2410    fRunRange[1]                = 0;
2411    fRunPrefix                  = "%d";
2412    fNrunsPerMaster             = 1;
2413    fMaxMergeFiles              = 100;
2414    fRunNumbers                 = "";
2415    fExecutable                 = "analysis.sh";
2416    fExecutableCommand          = "root -b -q";
2417    fArguments                  = "";
2418    fExecutableArgs             = "";
2419    fAnalysisMacro              = "myAnalysis.C";
2420    fAnalysisSource             = "";
2421    fAdditionalLibs             = "";
2422    fSplitMode                  = "se";
2423    fAPIVersion                 = "";
2424    fROOTVersion                = "";
2425    fAliROOTVersion             = "";
2426    fUser                       = "";  // Your alien user name
2427    fGridWorkingDir             = "";
2428    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
2429    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
2430    fFriendChainName            = "";
2431    fGridOutputDir              = "output";
2432    fOutputArchive              = "log_archive.zip:std*@disk=1 root_archive.zip:*.root@disk=2";
2433    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
2434    fInputFormat                = "xml-single";
2435    fJDLName                    = "analysis.jdl";
2436    fJobTag                     = "Automatically generated analysis JDL";
2437    fMergeExcludes              = "";
2438    fMergeViaJDL                = 0;
2439    SetUseCopy(kTRUE);
2440    SetCheckCopy(kTRUE);
2441    SetDefaultOutputs(kTRUE);
2442    fOverwriteMode              = 1;
2443 }   
2444
2445 //______________________________________________________________________________
2446 Bool_t AliAnalysisAlien::CheckMergedFiles(const char *filename, const char *aliendir, Int_t nperchunk, const char *jdl)
2447 {
2448 // Checks current merge stage, makes xml for the next stage, counts number of files, submits next stage.
2449    // First check if the result is already in the output directory.
2450    if (FileExists(Form("%s/%s",aliendir,filename))) {
2451       printf("Final merged results found. Not merging again.\n");
2452       return kFALSE;
2453    }
2454    // Now check the last stage done.
2455    Int_t stage = 0;
2456    while (1) {
2457       if (!FileExists(Form("%s/Stage_%d.xml",aliendir, stage+1))) break;
2458       stage++;
2459    }
2460    // Next stage of merging
2461    stage++;
2462    TString pattern = "*root_archive.zip";
2463    if (stage>1) pattern = Form("Stage_%d/*root_archive.zip", stage-1);
2464    TGridResult *res = gGrid->Command(Form("find -x Stage_%d %s %s", stage, aliendir, pattern.Data()));
2465    if (res) delete res;
2466    // Write standard output to file
2467    gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", Form("Stage_%d.xml",stage)));
2468    // Count the number of files inside
2469    ifstream ifile;
2470    ifile.open(Form("Stage_%d.xml",stage));
2471    if (!ifile.good()) {
2472       ::Error("CheckMergedFiles", "Could not redirect result of the find command to file %s", Form("Stage_%d.xml",stage));
2473       return kFALSE;
2474    }   
2475    TString line;
2476    Int_t nfiles = 0;
2477    while (!ifile.eof()) {
2478       ifile >> line;
2479       if (line.Contains("/event")) nfiles++;
2480    }
2481    ifile.close();
2482    if (!nfiles) {
2483       ::Error("CheckMergedFiles", "Cannot start Stage_%d merging since Stage_%d did not produced yet output", stage, stage-1);
2484       return kFALSE;
2485    } else {
2486       printf("=== Stage_%d produced %d files\n", stage-1, nfiles);
2487    }   
2488    // Copy the file in the output directory
2489    printf("===> Copying collection %s in the output directory %s\n", Form("Stage_%d.xml",stage), aliendir);
2490 //   TFile::Cp(Form("Stage_%d.xml",stage), Form("alien://%s/Stage_%d.xml",aliendir,stage));
2491    if (!copyLocal2Alien("CheckMergedFiles", Form("Stage_%d.xml",stage), 
2492         Form("%s/Stage_%d.xml",aliendir,stage))) Fatal("","Terminating");
2493    // Check if this is the last stage to be done.
2494    Bool_t laststage = (nfiles<nperchunk);
2495    if (fMaxMergeStages && stage>=fMaxMergeStages) laststage = kTRUE;
2496    if (laststage) {
2497       printf("### Submiting final merging stage %d\n", stage);
2498       TString finalJDL = jdl;
2499       finalJDL.ReplaceAll(".jdl", "_final.jdl");
2500       TString query = Form("submit %s %s %d", finalJDL.Data(), aliendir, stage);
2501       Int_t jobId = SubmitSingleJob(query);
2502       if (!jobId) return kFALSE;      
2503    } else {
2504       printf("### Submiting merging stage %d\n", stage);
2505       TString query = Form("submit %s %s %d", jdl, aliendir, stage);
2506       Int_t jobId = SubmitSingleJob(query);
2507       if (!jobId) return kFALSE;           
2508    }
2509    return kTRUE;   
2510 }        
2511
2512 //______________________________________________________________________________
2513 AliAnalysisManager *AliAnalysisAlien::LoadAnalysisManager(const char *fname)
2514 {
2515 // Loat the analysis manager from a file.
2516    TFile *file = TFile::Open(fname);
2517    if (!file) {
2518       ::Error("LoadAnalysisManager", "Cannot open file %s", fname);
2519       return 0;
2520    }   
2521    TIter nextkey(file->GetListOfKeys());
2522    AliAnalysisManager *mgr = 0;
2523    TKey *key;
2524    while ((key=(TKey*)nextkey())) {
2525       if (!strcmp(key->GetClassName(), "AliAnalysisManager"))
2526          mgr = (AliAnalysisManager*)file->Get(key->GetName());
2527    }
2528    if (!mgr) 
2529       ::Error("LoadAnalysisManager", "No analysis manager found in file %s", fname);
2530    return mgr;
2531 }      
2532
2533 //______________________________________________________________________________
2534 Int_t AliAnalysisAlien::SubmitSingleJob(const char *query)
2535 {
2536 // Submits a single job corresponding to the query and returns job id. If 0 submission failed.
2537    if (!gGrid) return 0;
2538    printf("=> %s ------> ",query);
2539    TGridResult *res = gGrid->Command(query);
2540    if (!res) return 0;
2541    TString jobId = res->GetKey(0,"jobId");
2542    delete res;
2543    if (jobId.IsNull()) {
2544       printf("submission failed. Reason:\n");
2545       gGrid->Stdout();
2546       gGrid->Stderr();
2547       ::Error("SubmitSingleJob", "Your query %s could not be submitted", query);
2548       return 0;
2549    }
2550    printf(" Job id: %s\n", jobId.Data());
2551    return atoi(jobId);
2552 }  
2553
2554 //______________________________________________________________________________
2555 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge, Int_t stage)
2556 {
2557 // Merge given output files from basedir. Basedir can be an alien output directory
2558 // but also an xml file with root_archive.zip locations. The file merger will merge nmaxmerge
2559 // files in a group (ignored for xml input). Merging can be done in stages:
2560 // stage=0 : will merge all existing files in a single stage, supporting resume if run locally
2561 // stage=1 : works with an xml of all root_archive.zip in the output directory
2562 // stage>1 : works with an xml of all root_archive.zip in the Stage_<n-1> directory
2563    TString outputFile = output;
2564    TString command;
2565    TString outputChunk;
2566    TString previousChunk = "";
2567    TObjArray *listoffiles = new TObjArray();
2568 //   listoffiles->SetOwner();
2569    Int_t countChunk = 0;
2570    Int_t countZero = nmaxmerge;
2571    Bool_t merged = kTRUE;
2572    Int_t index = outputFile.Index("@");
2573    if (index > 0) outputFile.Remove(index);
2574    TString inputFile = outputFile;
2575    TString sbasedir = basedir;
2576    if (sbasedir.Contains(".xml")) {
2577       // Merge files pointed by the xml - ignore nmaxmerge and set ichunk to 0
2578       nmaxmerge = 9999999;
2579       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"%s\");", basedir));
2580       if (!coll) {
2581          ::Error("MergeOutput", "Input XML collection empty.");
2582          return kFALSE;
2583       }
2584       // Iterate grid collection
2585       while (coll->Next()) {
2586          TString fname = gSystem->DirName(coll->GetTURL());
2587          fname += "/";
2588          fname += inputFile;      
2589          listoffiles->Add(new TNamed(fname.Data(),""));
2590       }   
2591    } else {   
2592       command = Form("find %s/ *%s", basedir, inputFile.Data());
2593       printf("command: %s\n", command.Data());
2594       TGridResult *res = gGrid->Command(command);
2595       if (!res) {
2596          ::Error("MergeOutput","No result for the find command\n");
2597          delete listoffiles;
2598          return kFALSE;
2599       }     
2600       TIter nextmap(res);
2601       TMap *map = 0;
2602       while ((map=(TMap*)nextmap())) {
2603          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
2604          if (!objs || !objs->GetString().Length()) {
2605             // Nothing found - skip this output
2606             delete res;
2607             delete listoffiles;
2608             return kFALSE;
2609          }
2610          listoffiles->Add(new TNamed(objs->GetName(),""));
2611       }
2612       delete res;
2613    }
2614    if (!listoffiles->GetEntries()) {
2615       ::Error("MergeOutput","No result for the find command\n");
2616       delete listoffiles;
2617       return kFALSE;
2618    }     
2619
2620    TFileMerger *fm = 0;
2621    TIter next0(listoffiles);
2622    TObjArray *listoffilestmp = new TObjArray();
2623    listoffilestmp->SetOwner();
2624    TObject *nextfile;
2625    TString snextfile;
2626    // Keep only the files at upper level
2627    Int_t countChar = 0;
2628    while ((nextfile=next0())) {
2629       snextfile = nextfile->GetName();
2630       Int_t crtCount = snextfile.CountChar('/');
2631       if (nextfile == listoffiles->First()) countChar = crtCount;
2632       if (crtCount < countChar) countChar = crtCount;
2633    }
2634    next0.Reset();
2635    while ((nextfile=next0())) {
2636       snextfile = nextfile->GetName();
2637       Int_t crtCount = snextfile.CountChar('/');
2638       if (crtCount > countChar) {
2639          delete nextfile;
2640          continue;
2641       }   
2642       listoffilestmp->Add(nextfile);
2643    }
2644    delete listoffiles;
2645    listoffiles = listoffilestmp;  // Now contains 'good' files
2646    listoffiles->Print();
2647    TIter next(listoffiles);   
2648    // Check if there is a merge operation to resume. Works only for stage 0 or 1.
2649    outputChunk = outputFile;
2650    outputChunk.ReplaceAll(".root", "_*.root");
2651    // Check for existent temporary merge files
2652    // Check overwrite mode and remove previous partial results if needed
2653    // Preserve old merging functionality for stage 0.
2654    if (stage==0) {
2655       if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2656          while (1) {
2657             // Skip as many input files as in a chunk
2658             for (Int_t counter=0; counter<nmaxmerge; counter++) {
2659                nextfile = next();
2660                if (!nextfile) {
2661                   ::Error("MergeOutput", "Mismatch found. Please remove partial merged files from local dir.");
2662                   delete listoffiles;
2663                   return kFALSE;
2664                }   
2665                snextfile = nextfile->GetName();
2666             }
2667             outputChunk = outputFile;
2668             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2669             countChunk++;
2670             if (gSystem->AccessPathName(outputChunk)) continue;
2671             // Merged file with chunks up to <countChunk> found
2672             ::Info("MergeOutput", "Resume merging of <%s> from <%s>\n", outputFile.Data(), outputChunk.Data());
2673             previousChunk = outputChunk;
2674             break;
2675          }
2676       }   
2677       countZero = nmaxmerge;
2678    
2679       while ((nextfile=next())) {
2680          snextfile = nextfile->GetName();
2681          // Loop 'find' results and get next LFN
2682          if (countZero == nmaxmerge) {
2683             // First file in chunk - create file merger and add previous chunk if any.
2684             fm = new TFileMerger(kTRUE);
2685             fm->SetFastMethod(kTRUE);
2686             if (previousChunk.Length()) fm->AddFile(previousChunk.Data());
2687             outputChunk = outputFile;
2688             outputChunk.ReplaceAll(".root", Form("_%04d.root", countChunk));
2689          }
2690          // If last file found, put merged results in the output file
2691          if (nextfile == listoffiles->Last()) outputChunk = outputFile;
2692          // Add file to be merged and decrement chunk counter.
2693          fm->AddFile(snextfile);
2694          countZero--;
2695          if (countZero==0 || nextfile == listoffiles->Last()) {            
2696             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2697             // Nothing found - skip this output
2698                ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2699                merged = kFALSE;
2700                break;
2701             }
2702             fm->OutputFile(outputChunk);
2703             // Merge the outputs, then go to next chunk      
2704             if (!fm->Merge()) {
2705                ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2706                merged = kFALSE;
2707                break;
2708             } else {
2709                ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputChunk.Data());
2710                gSystem->Unlink(previousChunk);
2711             }
2712             if (nextfile == listoffiles->Last()) break;
2713             countChunk++;
2714             countZero = nmaxmerge;
2715             previousChunk = outputChunk;
2716          }
2717       }
2718       delete listoffiles;
2719       delete fm;
2720       return merged;
2721    }
2722    // Merging stage different than 0.
2723    // Move to the begining of the requested chunk.
2724    fm = new TFileMerger(kTRUE);
2725    fm->SetFastMethod(kTRUE);
2726    while ((nextfile=next())) fm->AddFile(nextfile->GetName());
2727    delete listoffiles;
2728    if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
2729       // Nothing found - skip this output
2730       ::Warning("MergeOutput", "No <%s> files found.", inputFile.Data());
2731       delete fm;
2732       return kFALSE;
2733    }
2734    fm->OutputFile(outputFile);
2735    // Merge the outputs
2736    if (!fm->Merge()) {
2737       ::Error("MergeOutput", "Could not merge all <%s> files", outputFile.Data());
2738       delete fm;
2739       return kFALSE;
2740    } else {
2741       ::Info("MergeOutput", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), outputFile.Data());
2742    }
2743    delete fm;
2744    return kTRUE;
2745
2746
2747 //______________________________________________________________________________
2748 Bool_t AliAnalysisAlien::MergeOutputs()
2749 {
2750 // Merge analysis outputs existing in the AliEn space.
2751    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
2752    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
2753    if (!Connect()) {
2754       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
2755       return kFALSE;
2756    }
2757    if (fMergeViaJDL) {
2758       if (!TestBit(AliAnalysisGrid::kMerge)) {
2759          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
2760          return kFALSE; 
2761       }     
2762       if (fProductionMode) {
2763          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
2764          return kFALSE;
2765       }
2766       Info("MergeOutputs", "Submitting merging JDL");
2767       if (!SubmitMerging()) return kFALSE;
2768       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
2769       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
2770       return kFALSE;
2771    }   
2772    // Get the output path
2773    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2774    if (!DirectoryExists(fGridOutputDir)) {
2775       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
2776       return kFALSE;
2777    }
2778    if (!fOutputFiles.Length()) {
2779       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2780       return kFALSE;
2781    }
2782    // Check if fast read option was requested
2783    Info("MergeOutputs", "Started local merging of output files from: alien://%s \
2784         \n======= overwrite mode = %d", fGridOutputDir.Data(), (Int_t)fOverwriteMode);
2785    if (fFastReadOption) {
2786       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. This may skip some files that could be accessed ! \
2787              \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
2788       gEnv->SetValue("XNet.ConnectTimeout",50);
2789       gEnv->SetValue("XNet.RequestTimeout",50);
2790       gEnv->SetValue("XNet.MaxRedirectCount",2);
2791       gEnv->SetValue("XNet.ReconnectTimeout",50);
2792       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
2793    }   
2794    // Make sure we change the temporary directory
2795    gSystem->Setenv("TMPDIR", gSystem->pwd());
2796    // Set temporary compilation directory to current one
2797    gSystem->SetBuildDir(gSystem->pwd(), kTRUE);   
2798    TObjArray *list = fOutputFiles.Tokenize(",");
2799    TIter next(list);
2800    TObjString *str;
2801    TString outputFile;
2802    Bool_t merged = kTRUE;
2803    while((str=(TObjString*)next())) {
2804       outputFile = str->GetString();
2805       Int_t index = outputFile.Index("@");
2806       if (index > 0) outputFile.Remove(index);
2807       TString outputChunk = outputFile;
2808       outputChunk.ReplaceAll(".root", "_*.root");
2809       // Skip already merged outputs
2810       if (!gSystem->AccessPathName(outputFile)) {
2811          if (fOverwriteMode) {
2812             Info("MergeOutputs", "Overwrite mode. Existing file %s was deleted.", outputFile.Data());
2813             gSystem->Unlink(outputFile);
2814             if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2815                Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2816                      outputChunk.Data());
2817                gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2818             }
2819          } else {   
2820             Info("MergeOutputs", "Output file <%s> found. Not merging again.", outputFile.Data());
2821             continue;
2822          }   
2823       } else {
2824          if (!gSystem->Exec(Form("ls %s 2>/dev/null", outputChunk.Data()))) {
2825             Info("MergeOutput", "Overwrite mode: partial merged files %s will removed",
2826                   outputChunk.Data());
2827             gSystem->Exec(Form("rm -f %s", outputChunk.Data()));
2828          }   
2829       }
2830       if (fMergeExcludes.Contains(outputFile.Data()) || 
2831           fRegisterExcludes.Contains(outputFile.Data())) continue;
2832       // Perform a 'find' command in the output directory, looking for registered outputs    
2833       merged = MergeOutput(outputFile, fGridOutputDir, fMaxMergeFiles);
2834       if (!merged) {
2835          Error("MergeOutputs", "Terminate() will  NOT be executed");
2836          return kFALSE;
2837       }
2838       TFile *fileOpened = (TFile*)gROOT->GetListOfFiles()->FindObject(outputFile);
2839       if (fileOpened) fileOpened->Close();
2840    } 
2841    return kTRUE;
2842 }   
2843
2844 //______________________________________________________________________________
2845 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
2846 {
2847 // Use the output files connected to output containers from the analysis manager
2848 // rather than the files defined by SetOutputFiles
2849    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
2850       Info("SetDefaultOutputs", "Plugin will use the output files taken from analysis manager");
2851    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
2852 }
2853       
2854 //______________________________________________________________________________
2855 void AliAnalysisAlien::SetOutputFiles(const char *list)
2856 {
2857 // Manually set the output files list.
2858 // Removes duplicates. Not allowed if default outputs are not disabled.
2859    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2860       Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
2861       return;
2862    }
2863    Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
2864    fOutputFiles = "";
2865    TString slist = list;
2866    if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
2867    TObjArray *arr = slist.Tokenize(" "); 
2868    TObjString *os;
2869    TIter next(arr);
2870    TString sout;
2871    while ((os=(TObjString*)next())) {
2872       sout = os->GetString();
2873       if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
2874       if (fOutputFiles.Contains(sout)) continue;
2875       if (!fOutputFiles.IsNull()) fOutputFiles += ",";
2876       fOutputFiles += sout;
2877    }
2878    delete arr;   
2879 }
2880
2881 //______________________________________________________________________________
2882 void AliAnalysisAlien::SetOutputArchive(const char *list)
2883 {
2884 // Manually set the output archive list. Free text - you are on your own...
2885 // Not allowed if default outputs are not disabled.
2886    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
2887       Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
2888       return;
2889    }
2890    Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
2891    fOutputArchive = list;
2892 }
2893
2894 //______________________________________________________________________________
2895 void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
2896 {
2897 // Setting a prefered output SE is not allowed anymore.
2898    Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
2899 }
2900
2901 //______________________________________________________________________________
2902 void AliAnalysisAlien::SetProofParameter(const char *pname, const char *value)
2903 {
2904 // Set some PROOF special parameter.
2905    TPair *pair = dynamic_cast<TPair*>(fProofParam.FindObject(pname));
2906    if (pair) {
2907       TObject *old = pair->Key();
2908       TObject *val = pair->Value();
2909       fProofParam.Remove(old);
2910       delete old;
2911       delete val;
2912    }
2913    fProofParam.Add(new TObjString(pname), new TObjString(value));
2914 }
2915
2916 //______________________________________________________________________________
2917 const char *AliAnalysisAlien::GetProofParameter(const char *pname) const
2918 {
2919 // Returns a special PROOF parameter.
2920    TPair *pair = dynamic_cast<TPair*>(fProofParam.FindObject(pname));
2921    if (!pair) return 0;
2922    return pair->Value()->GetName();
2923 }      
2924
2925 //______________________________________________________________________________
2926 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
2927 {
2928 // Start remote grid analysis.
2929    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2930    Bool_t testMode = TestBit(AliAnalysisGrid::kTest);
2931    if (!mgr || !mgr->IsInitialized()) {
2932       Error("StartAnalysis", "You need an initialized analysis manager for this");
2933       return kFALSE;
2934    }
2935    // Are we in PROOF mode ?
2936    if (mgr->IsProofMode()) {
2937       if (testMode) Info("StartAnalysis", "##### Starting PROOF analysis with Proof Lite via the plugin #####");
2938       else Info("StartAnalysis", "##### Starting PROOF analysis on cluster <%s> via the plugin #####", fProofCluster.Data());
2939       if (fProofCluster.IsNull()) {
2940          Error("StartAnalysis", "You need to specify the proof cluster name via SetProofCluster");
2941          return kFALSE;
2942       }   
2943       if (fProofDataSet.IsNull() && !testMode) {
2944          Error("StartAnalysis", "You need to specify a dataset using SetProofDataSet()");
2945          return kFALSE;
2946       }   
2947       // Set the needed environment
2948       gEnv->SetValue("XSec.GSI.DelegProxy","2");
2949       // Do we need to reset PROOF ? The success of the Reset operation cannot be checked
2950       if (fProofReset && !testMode) {
2951          if (fProofReset==1) {
2952             Info("StartAnalysis", "Sending soft reset signal to proof cluster %s", fProofCluster.Data());
2953             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kFALSE);", fProofCluster.Data()));
2954          } else {         
2955             Info("StartAnalysis", "Sending hard reset signal to proof cluster %s", fProofCluster.Data());
2956             gROOT->ProcessLine(Form("TProof::Reset(\"%s\", kTRUE);", fProofCluster.Data()));
2957          }
2958          Info("StartAnalysis", "Stopping the analysis. Please use SetProofReset(0) to resume.");
2959          return kFALSE;
2960       }
2961       
2962       if (!testMode) {
2963         // Check if there is an old active session
2964         Long_t nsessions = gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->QuerySessions(\"\")->GetEntries();", fProofCluster.Data()));
2965         if (nsessions) {
2966           Error("StartAnalysis","You have to reset your old session first\n");
2967           return kFALSE;
2968         }
2969       }
2970       // Do we need to change the ROOT version ? The success of this cannot be checked.
2971       if (!fRootVersionForProof.IsNull() && !testMode) {
2972          gROOT->ProcessLine(Form("TProof::Mgr(\"%s\")->SetROOTVersion(\"%s\");", 
2973                             fProofCluster.Data(), fRootVersionForProof.Data()));
2974       }
2975       // Connect to PROOF and check the status
2976       Long_t proof = 0;
2977       TString sworkers;
2978       if (fNproofWorkersPerSlave) sworkers = Form("workers=%dx", fNproofWorkersPerSlave);
2979       else if (fNproofWorkers) sworkers = Form("workers=%d", fNproofWorkers);
2980       if (!testMode) {
2981          if (!sworkers.IsNull()) 
2982             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\", \"%s\");", fProofCluster.Data(), sworkers.Data()));
2983          else   
2984             proof = gROOT->ProcessLine(Form("TProof::Open(\"%s\");", fProofCluster.Data()));
2985       } else {
2986          proof = gROOT->ProcessLine("TProof::Open(\"\");");
2987          if (!proof) {
2988             Error("StartAnalysis", "Could not start PROOF in test mode");
2989             return kFALSE;
2990          }   
2991       }
2992       if (!proof) {
2993          Error("StartAnalysis", "Could not connect to PROOF cluster <%s>", fProofCluster.Data());
2994          return kFALSE;
2995       }   
2996       if (fNproofWorkersPerSlave*fNproofWorkers > 0)
2997          gROOT->ProcessLine(Form("gProof->SetParallel(%d);", fNproofWorkers));
2998       // Set proof special parameters if any
2999       TIter nextpp(&fProofParam);
3000       TObject *proofparam;
3001       while ((proofparam=nextpp())) {
3002          TString svalue = GetProofParameter(proofparam->GetName());
3003          gROOT->ProcessLine(Form("gProof->SetParameter(\"%s\",%s);", proofparam->GetName(), svalue.Data()));
3004       }   
3005       // Is dataset existing ?
3006       if (!testMode) {
3007          TString dataset = fProofDataSet;
3008          Int_t index = dataset.Index("#");
3009          if (index>=0) dataset.Remove(index);
3010 //         if (!gROOT->ProcessLine(Form("gProof->ExistsDataSet(\"%s\");",fProofDataSet.Data()))) {
3011 //            Error("StartAnalysis", "Dataset %s not existing", fProofDataSet.Data());
3012 //            return kFALSE;
3013 //         }
3014 //         Info("StartAnalysis", "Dataset %s found", dataset.Data());
3015       }
3016       // Is ClearPackages() needed ?
3017       if (TestSpecialBit(kClearPackages)) {
3018          Info("StartAnalysis", "ClearPackages signal sent to PROOF. Use SetClearPackages(kFALSE) to reset this.");
3019          gROOT->ProcessLine("gProof->ClearPackages();");
3020       }
3021       // Is a given aliroot mode requested ?
3022       TList optionsList;
3023       TString parLibs;
3024       if (!fAliRootMode.IsNull()) {
3025          TString alirootMode = fAliRootMode;
3026          if (alirootMode == "default") alirootMode = "";
3027          Info("StartAnalysis", "You are requesting AliRoot mode: %s", fAliRootMode.Data());
3028          optionsList.SetOwner();
3029          optionsList.Add(new TNamed("ALIROOT_MODE", alirootMode.Data()));
3030          // Check the additional libs to be loaded
3031          TString extraLibs;
3032          Bool_t parMode = kFALSE;
3033          if (!alirootMode.IsNull()) extraLibs = "ANALYSIS:OADB:ANALYSISalice";
3034          // Parse the extra libs for .so
3035          if (fAdditionalLibs.Length()) {
3036             TObjArray *list = fAdditionalLibs.Tokenize(" ");
3037             TIter next(list);
3038             TObjString *str;
3039             while((str=(TObjString*)next())) {
3040                if (str->GetString().Contains(".so")) {
3041                   if (parMode) {
3042                      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());
3043                      break;
3044                   }   
3045                   TString stmp = str->GetName();
3046                   if (stmp.BeginsWith("lib")) stmp.Remove(0,3);
3047                   stmp.ReplaceAll(".so","");
3048                   if (!extraLibs.IsNull()) extraLibs += ":";
3049                   extraLibs += stmp;
3050                   continue;
3051                }
3052                if (str->GetString().Contains(".par")) {
3053                   // The first par file found in the list will not allow any further .so
3054                   parMode = kTRUE;
3055                   if (!parLibs.IsNull()) parLibs += ":";
3056                   parLibs += str->GetName();
3057                   continue;
3058                }   
3059             }
3060             if (list) delete list;            
3061          }
3062         if (!extraLibs.IsNull()) {
3063           Info("StartAnalysis", "Adding extra libs: %s",extraLibs.Data());
3064           optionsList.Add(new TNamed("ALIROOT_EXTRA_LIBS",extraLibs.Data()));
3065         }
3066          // Check extra includes
3067          if (!fIncludePath.IsNull()) {
3068             TString includePath = fIncludePath;
3069             includePath.ReplaceAll(" ",":");
3070             includePath.ReplaceAll("$ALICE_ROOT/","");
3071             includePath.ReplaceAll("${ALICE_ROOT}/","");
3072             includePath.ReplaceAll("-I","");
3073             includePath.Remove(TString::kTrailing, ':');
3074             Info("StartAnalysis", "Adding extra includes: %s",includePath.Data()); 
3075             optionsList.Add(new TNamed("ALIROOT_EXTRA_INCLUDES",includePath.Data()));
3076          }
3077          // Check if connection to grid is requested
3078          if (TestSpecialBit(kProofConnectGrid)) 
3079             optionsList.Add(new TNamed("ALIROOT_ENABLE_ALIEN", "1"));
3080          // Enable AliRoot par
3081          if (testMode) {
3082          // Enable proof lite package
3083             TString alirootLite = gSystem->ExpandPathName("$ALICE_ROOT/ANALYSIS/macros/AliRootProofLite.par");
3084             for (Int_t i=0; i<optionsList.GetSize(); i++) {
3085                TNamed *obj = (TNamed*)optionsList.At(i);
3086                printf("%s  %s\n", obj->GetName(), obj->GetTitle());
3087             }   
3088             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");",alirootLite.Data()))
3089               && !gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\", (TList*)%p);",alirootLite.Data(),&optionsList))) {
3090                   Info("StartAnalysis", "AliRootProofLite enabled");
3091             } else {                      
3092                Error("StartAnalysis", "There was an error trying to enable package AliRootProofLite.par");
3093                return kFALSE;
3094             }   
3095          } else {
3096            if ( ! fAliROOTVersion.IsNull() ) {
3097              if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"VO_ALICE@AliRoot::%s\", (TList*)%p, kTRUE);", 
3098                                          fAliROOTVersion.Data(), &optionsList))) {
3099                 Error("StartAnalysis", "There was an error trying to enable package VO_ALICE@AliRoot::%s", fAliROOTVersion.Data());
3100                 return kFALSE;
3101              }
3102            }
3103          }
3104          // Enable first par files from fAdditionalLibs
3105          if (!parLibs.IsNull()) {
3106             TObjArray *list = parLibs.Tokenize(":");
3107             TIter next(list);
3108             TObjString *package;
3109             while((package=(TObjString*)next())) {
3110                TString spkg = package->GetName();
3111                spkg.ReplaceAll(".par", "");
3112                gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
3113                if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
3114                   TString enablePackage = (testMode)?Form("gProof->EnablePackage(\"%s\",kFALSE);", package->GetName()):Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName());
3115                   if (gROOT->ProcessLine(enablePackage)) {
3116                      Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
3117                      return kFALSE;
3118                   }
3119                } else {
3120                   Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
3121                   return kFALSE;
3122                }
3123             }
3124             if (list) delete list; 
3125          }
3126       } else {
3127          if (fAdditionalLibs.Contains(".so") && !testMode) {
3128             Error("StartAnalysis", "You request additional libs to be loaded but did not enabled any AliRoot mode. Please refer to: \
3129                    \n http://aaf.cern.ch/node/83 and use a parameter for SetAliRootMode()");
3130             return kFALSE;       
3131          }
3132       }
3133       // Enable par files if requested
3134       if (fPackages && fPackages->GetEntries()) {
3135          TIter next(fPackages);
3136          TObject *package;
3137          while ((package=next())) {
3138             // Skip packages already enabled
3139             if (parLibs.Contains(package->GetName())) continue;
3140             TString spkg = package->GetName();
3141             spkg.ReplaceAll(".par", "");
3142             gSystem->Exec(TString::Format("rm -rf %s", spkg.Data()));
3143             if (!gROOT->ProcessLine(Form("gProof->UploadPackage(\"%s\");", package->GetName()))) {
3144                if (gROOT->ProcessLine(Form("gProof->EnablePackage(\"%s\",kTRUE);", package->GetName()))) {
3145                   Error("StartAnalysis", "There was an error trying to enable package %s", package->GetName());
3146                   return kFALSE;
3147                }
3148             } else {
3149                Error("StartAnalysis", "There was an error trying to upload package %s", package->GetName());
3150                return kFALSE;
3151             }
3152          }
3153       }
3154       // Do we need to load analysis source files ?
3155       // NOTE: don't load on client since this is anyway done by the user to attach his task.
3156       if (fAnalysisSource.Length()) {
3157          TObjArray *list = fAnalysisSource.Tokenize(" ");
3158          TIter next(list);
3159          TObjString *str;
3160          while((str=(TObjString*)next())) {
3161             gROOT->ProcessLine(Form("gProof->Load(\"%s+g\", kTRUE);", str->GetName()));
3162          }
3163          if (list) delete list;
3164       }
3165       if (testMode) {
3166       // Register dataset to proof lite.
3167          if (fFileForTestMode.IsNull()) {
3168             Error("GetChainForTestMode", "For proof test mode please use SetFileForTestMode() pointing to a file that contains data file locations.");
3169             return kFALSE;
3170          }
3171          if (gSystem->AccessPathName(fFileForTestMode)) {
3172             Error("GetChainForTestMode", "File not found: %s", fFileForTestMode.Data());
3173             return kFALSE;
3174          }   
3175          TFileCollection *coll = new TFileCollection();
3176          coll->AddFromFile(fFileForTestMode);
3177          gROOT->ProcessLine(Form("gProof->RegisterDataSet(\"test_collection\", (TFileCollection*)%p, \"OV\");", coll));
3178          gROOT->ProcessLine("gProof->ShowDataSets()");
3179       }
3180       return kTRUE;
3181    }
3182    
3183    // Check if output files have to be taken from the analysis manager
3184    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
3185       // Add output files and AOD files
3186       fOutputFiles = GetListOfFiles("outaod");
3187       // Add extra files registered to the analysis manager
3188       TString extra = GetListOfFiles("ext");
3189       if (!extra.IsNull()) {
3190          extra.ReplaceAll(".root", "*.root");
3191          if (!fOutputFiles.IsNull()) fOutputFiles += ",";
3192          fOutputFiles += extra;
3193       }
3194       // Compose the output archive.
3195       fOutputArchive = "log_archive.zip:std*@disk=1 ";
3196       fOutputArchive += Form("root_archive.zip:%s,*.stat@disk=%d",fOutputFiles.Data(),fNreplicas);
3197    }
3198 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
3199    if (TestBit(AliAnalysisGrid::kOffline)) {
3200       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
3201       \n                         there nor any job run. You can revise the JDL and analysis \
3202       \n                         macro then run the same in \"submit\" mode.");
3203    } else if (TestBit(AliAnalysisGrid::kTest)) {
3204       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
3205       \n                         dataset.");
3206    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
3207       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
3208       \n                         space and job submitted.");
3209    } else if (TestBit(AliAnalysisGrid::kMerge)) {
3210       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
3211       if (fMergeViaJDL) CheckInputData();
3212       return kTRUE;
3213    } else {
3214       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
3215    }   
3216       
3217    Print();   
3218    if (!Connect()) {
3219       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
3220       return kFALSE;
3221    }
3222    if (IsCheckCopy() && gGrid) CheckFileCopy(gGrid->GetHomeDirectory());
3223    if (!CheckInputData()) {
3224       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
3225       return kFALSE;
3226    }   
3227    if (!CreateDataset(fDataPattern)) {
3228       TString serror;
3229       if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
3230       if (fRunNumbers.Length()) serror = "run numbers";
3231       if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
3232       serror += Form("\n   or data pattern <%s>", fDataPattern.Data());
3233       Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
3234       return kFALSE;
3235    }   
3236    WriteAnalysisFile();
3237    WriteAnalysisMacro();
3238    WriteExecutable();
3239    WriteValidationScript();
3240    if (fMergeViaJDL) {
3241       WriteMergingMacro();
3242       WriteMergeExecutable();
3243       WriteValidationScript(kTRUE);
3244    }   
3245    if (!CreateJDL()) return kFALSE;
3246    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
3247    if (testMode) {
3248       // Locally testing the analysis
3249       Info("StartAnalysis", "\n_______________________________________________________________________ \
3250       \n   Running analysis script in a daughter shell as on a worker node \
3251       \n_______________________________________________________________________");
3252       TObjArray *list = fOutputFiles.Tokenize(",");
3253       TIter next(list);
3254       TObjString *str;
3255       TString outputFile;
3256       while((str=(TObjString*)next())) {
3257          outputFile = str->GetString();
3258          Int_t index = outputFile.Index("@");
3259          if (index > 0) outputFile.Remove(index);         
3260          if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
3261       }
3262       delete list;
3263       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
3264       gSystem->Exec(Form("bash %s",fValidationScript.Data()));
3265 //      gSystem->Exec("cat stdout");
3266       return kFALSE;
3267    }
3268    // Check if submitting is managed by LPM manager
3269    if (fProductionMode) {
3270       TString prodfile = fJDLName;
3271       prodfile.ReplaceAll(".jdl", ".prod");
3272       WriteProductionFile(prodfile);
3273       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
3274       return kFALSE;
3275    }   
3276    // Submit AliEn job(s)
3277    gGrid->Cd(fGridOutputDir);
3278    TGridResult *res;
3279    TString jobID = "";
3280    if (!fRunNumbers.Length() && !fRunRange[0]) {
3281       // Submit a given xml or a set of runs
3282       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
3283       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
3284       if (res) {
3285          const char *cjobId = res->GetKey(0,"jobId");
3286          if (!cjobId) {
3287             gGrid->Stdout();
3288             gGrid->Stderr();
3289             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
3290             return kFALSE;
3291          } else {
3292             Info("StartAnalysis", "\n_______________________________________________________________________ \
3293             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
3294             \n_______________________________________________________________________",
3295                    fJDLName.Data(), cjobId);
3296             jobID = cjobId;      
3297          }          
3298          delete res;
3299       } else {
3300          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
3301          return kFALSE;      
3302       }   
3303    } else {
3304       // Submit for a range of enumeration of runs.
3305       if (!Submit()) return kFALSE;
3306    }   
3307          
3308    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
3309    \n You may exit at any time and terminate the job later using the option <terminate> \
3310    \n ##################################################################################", jobID.Data());
3311    gSystem->Exec("aliensh");
3312    return kTRUE;
3313 }
3314
3315 //______________________________________________________________________________
3316 const char *AliAnalysisAlien::GetListOfFiles(const char *type)
3317 {
3318 // Get a comma-separated list of output files of the requested type.
3319 // Type can be (case unsensitive):
3320 //    aod - list of aod files (std, extensions and filters)
3321 //    out - list of output files connected to containers (but not aod's or extras)
3322 //    ext - list of extra files registered to the manager
3323 //    ter - list of files produced in terminate
3324    static TString files;
3325    files = "";
3326    TString stype = type;
3327    stype.ToLower();
3328    TString aodfiles, extra;
3329    AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3330    if (!mgr) {
3331       ::Error("GetListOfFiles", "Cannot call this without analysis manager");
3332       return files.Data();
3333    }
3334    if (mgr->GetOutputEventHandler()) {
3335       aodfiles = mgr->GetOutputEventHandler()->GetOutputFileName();
3336       TString extraaod = mgr->GetOutputEventHandler()->GetExtraOutputs();
3337       if (!extraaod.IsNull()) {
3338          aodfiles += ",";
3339          aodfiles += extraaod;
3340       }
3341    }
3342    if (stype.Contains("aod")) {
3343       files = aodfiles;
3344       if (stype == "aod") return files.Data();
3345    }  
3346    // Add output files that are not in the list of AOD files 
3347    TString outputfiles = "";
3348    TIter next(mgr->GetOutputs());
3349    AliAnalysisDataContainer *output;
3350    const char *filename = 0;
3351    while ((output=(AliAnalysisDataContainer*)next())) {
3352       filename = output->GetFileName();
3353       if (!(strcmp(filename, "default"))) continue;
3354       if (outputfiles.Contains(filename)) continue;
3355       if (aodfiles.Contains(filename))    continue;
3356       if (!outputfiles.IsNull()) outputfiles += ",";
3357       outputfiles += filename;
3358    }
3359    if (stype.Contains("out")) {
3360       if (!files.IsNull()) files += ",";
3361       files += outputfiles;
3362       if (stype == "out") return files.Data();
3363    }   
3364    // Add extra files registered to the analysis manager
3365    TString sextra;
3366    extra = mgr->GetExtraFiles();
3367    if (!extra.IsNull()) {
3368       extra.Strip();
3369       extra.ReplaceAll(" ", ",");
3370       TObjArray *fextra = extra.Tokenize(",");
3371       TIter nextx(fextra);
3372       TObject *obj;
3373       while ((obj=nextx())) {
3374          if (aodfiles.Contains(obj->GetName())) continue;
3375          if (outputfiles.Contains(obj->GetName())) continue;
3376          if (sextra.Contains(obj->GetName())) continue;
3377          if (!sextra.IsNull()) sextra += ",";
3378          sextra += obj->GetName();
3379       }
3380       delete fextra;
3381       if (stype.Contains("ext")) {
3382          if (!files.IsNull()) files += ",";
3383          files += sextra;
3384       }
3385    }   
3386    if (stype == "ext") return files.Data();
3387    TString termfiles;
3388    if (!fTerminateFiles.IsNull()) {
3389       fTerminateFiles.Strip();
3390       fTerminateFiles.ReplaceAll(" ",",");
3391       TObjArray *fextra = fTerminateFiles.Tokenize(",");
3392       TIter nextx(fextra);
3393       TObject *obj;
3394       while ((obj=nextx())) {
3395          if (aodfiles.Contains(obj->GetName())) continue;
3396          if (outputfiles.Contains(obj->GetName())) continue;
3397          if (termfiles.Contains(obj->GetName())) continue;
3398          if (sextra.Contains(obj->GetName())) continue;
3399          if (!termfiles.IsNull()) termfiles += ",";
3400          termfiles += obj->GetName();
3401       }
3402       delete fextra;
3403    }   
3404    if (stype.Contains("ter")) {
3405       if (!files.IsNull() && !termfiles.IsNull()) {
3406          files += ",";
3407          files += termfiles;
3408       }   
3409    }   
3410    return files.Data();
3411 }   
3412
3413 //______________________________________________________________________________
3414 Bool_t AliAnalysisAlien::Submit()
3415 {
3416 // Submit all master jobs.
3417    Int_t nmasterjobs = fInputFiles->GetEntries();
3418    Long_t tshoot = gSystem->Now();
3419    if (!fNsubmitted && !SubmitNext()) return kFALSE;
3420    while (fNsubmitted < nmasterjobs) {
3421       Long_t now = gSystem->Now();
3422       if ((now-tshoot)>30000) {
3423          tshoot = now;
3424          if (!SubmitNext()) return kFALSE;
3425       }   
3426    }
3427    return kTRUE;
3428 }
3429
3430 //______________________________________________________________________________
3431 Bool_t AliAnalysisAlien::SubmitMerging()
3432 {
3433 // Submit all merging jobs.
3434    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3435    gGrid->Cd(fGridOutputDir);
3436    TString mergeJDLName = fExecutable;
3437    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
3438    if (!fInputFiles) {
3439       Error("SubmitMerging", "You have to use explicit run numbers or run range to merge via JDL!");
3440       return kFALSE;
3441    }   
3442    Int_t ntosubmit = fInputFiles->GetEntries();
3443    for (Int_t i=0; i<ntosubmit; i++) {
3444       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
3445       runOutDir.ReplaceAll(".xml", "");
3446       if (fOutputToRunNo) {
3447          // The output directory is the run number
3448          printf("### Submitting merging job for run <%s>\n", runOutDir.Data());
3449          runOutDir = Form("%s/%s", fGridOutputDir.Data(), runOutDir.Data());
3450       } else {
3451          if (!fRunNumbers.Length() && !fRunRange[0]) {
3452             // The output directory is the grid outdir
3453             printf("### Submitting merging job for the full output directory %s.\n", fGridOutputDir.Data());
3454             runOutDir = fGridOutputDir;
3455          } else {
3456             // The output directory is the master number in 3 digits format
3457             printf("### Submitting merging job for master <%03d>\n", i);
3458             runOutDir = Form("%s/%03d",fGridOutputDir.Data(), i);
3459          }   
3460       }
3461       // Check now the number of merging stages.
3462       TObjArray *list = fOutputFiles.Tokenize(",");
3463       TIter next(list);
3464       TObjString *str;
3465       TString outputFile;
3466       while((str=(TObjString*)next())) {
3467          outputFile = str->GetString();
3468          Int_t index = outputFile.Index("@");
3469          if (index > 0) outputFile.Remove(index);
3470          if (!fMergeExcludes.Contains(outputFile) && 
3471              !fRegisterExcludes.Contains(outputFile)) break;
3472       }
3473       delete list;
3474       Bool_t done = CheckMergedFiles(outputFile, runOutDir, fMaxMergeFiles, mergeJDLName);
3475       if (!done && (i==ntosubmit-1)) return kFALSE;
3476       if (!fRunNumbers.Length() && !fRunRange[0]) break;
3477    }
3478    if (!ntosubmit) return kTRUE;
3479    Info("StartAnalysis", "\n #### STARTING AN ALIEN SHELL FOR YOU. You can exit any time or inspect your jobs in a different shell.##########\
3480                           \n Make sure your jobs are in a final state (you can resubmit failed ones via 'masterjob <id> resubmit ERROR_ALL')\
3481                           \n Rerun in 'terminate' mode to submit all merging stages, each AFTER the previous one completed. The final merged \
3482                           \n output will be written to your alien output directory, while separate stages in <Stage_n>. \
3483                           \n ################################################################################################################");
3484    gSystem->Exec("aliensh");
3485    return kTRUE;
3486 }
3487
3488 //______________________________________________________________________________
3489 Bool_t AliAnalysisAlien::SubmitNext()
3490 {
3491 // Submit next bunch of master jobs if the queue is free. The first master job is
3492 // submitted right away, while the next will not be unless the previous was split.
3493 // The plugin will not submit new master jobs if there are more that 500 jobs in
3494 // waiting phase.
3495    static Bool_t iscalled = kFALSE;
3496    static Int_t firstmaster = 0;
3497    static Int_t lastmaster = 0;
3498    static Int_t npermaster  = 0;
3499    if (iscalled) return kTRUE;
3500    iscalled = kTRUE;
3501    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
3502    Int_t ntosubmit = 0;
3503    TGridResult *res;
3504    TString jobID = "";
3505    Int_t nmasterjobs = fInputFiles->GetEntries();
3506    if (!fNsubmitted) {
3507       ntosubmit = 1;
3508       if (!IsUseSubmitPolicy()) {
3509          if (nmasterjobs>5)
3510             Info("SubmitNext","### Warning submit policy not used ! Submitting too many jobs at a time may be prohibitted. \
3511                 \n### You can use SetUseSubmitPolicy() to enable if you have problems.");
3512          ntosubmit = nmasterjobs;
3513       }   
3514    } else {
3515       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
3516       printf("=== master %d: %s\n", lastmaster, status.Data());
3517       // If last master not split, just return
3518       if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
3519       // No more than 100 waiting jobs
3520       if (nwaiting>500) {iscalled = kFALSE; return kTRUE;}
3521       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
3522       if (npermaster) ntosubmit = (500-nwaiting)/npermaster;
3523       if (!ntosubmit) ntosubmit = 1;
3524       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
3525              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
3526    }
3527    for (Int_t i=0; i<ntosubmit; i++) {
3528       // Submit for a range of enumeration of runs.
3529       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
3530       TString query;
3531       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
3532       runOutDir.ReplaceAll(".xml", "");
3533       if (fOutputToRunNo)
3534          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
3535       else
3536          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
3537       printf("********* %s\n",query.Data());
3538       res = gGrid->Command(query);
3539       if (res) {
3540          TString cjobId1 = res->GetKey(0,"jobId");
3541          if (!cjobId1.Length()) {
3542             iscalled = kFALSE;
3543             gGrid->Stdout();
3544             gGrid->Stderr();
3545             Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
3546             return kFALSE;
3547          } else {
3548             Info("StartAnalysis", "\n_______________________________________________________________________ \
3549             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
3550             \n_______________________________________________________________________",
3551                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
3552             jobID += cjobId1;
3553             jobID += " ";
3554             lastmaster = cjobId1.Atoi();
3555             if (!firstmaster) firstmaster = lastmaster;
3556             fNsubmitted++;
3557          }          
3558          delete res;
3559       } else {
3560          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
3561          return kFALSE;
3562       }   
3563    }
3564    iscalled = kFALSE;
3565    return kTRUE;
3566 }
3567
3568 //______________________________________________________________________________
3569 void AliAnalysisAlien::WriteAnalysisFile()
3570 {
3571 // Write current analysis manager into the file <analysisFile>
3572    TString analysisFile = fExecutable;
3573    analysisFile.ReplaceAll(".sh", ".root");
3574    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3575       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3576       if (!mgr || !mgr->IsInitialized()) {
3577          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
3578          return;
3579       }
3580       // Check analysis type
3581       TObject *handler;
3582       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
3583       handler = (TObject*)mgr->GetInputEventHandler();
3584       if (handler) {
3585          if (handler->InheritsFrom("AliMultiInputEventHandler")) {
3586             AliMultiInputEventHandler *multiIH = (AliMultiInputEventHandler*)handler;
3587             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
3588             if (multiIH->GetFirstInputEventHandler()->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
3589          } else {
3590             if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
3591             if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
3592          }
3593       }
3594       TDirectory *cdir = gDirectory;
3595       TFile *file = TFile::Open(analysisFile, "RECREATE");
3596       if (file) {
3597          // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
3598          if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
3599          // Unless merging makes no sense
3600          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
3601          mgr->Write();
3602          delete file;
3603          // Enable termination for local jobs
3604          mgr->SetSkipTerminate(kFALSE);
3605       }
3606       if (cdir) cdir->cd();
3607       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
3608    }   
3609    Bool_t copy = kTRUE;
3610    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3611    if (copy) {
3612       CdWork();
3613       TString workdir = gGrid->GetHomeDirectory();
3614       workdir += fGridWorkingDir;
3615       Info("WriteAnalysisFile", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
3616       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
3617       if (!copyLocal2Alien("WriteAnalysisFile",analysisFile.Data(), 
3618           Form("%s/%s", workdir.Data(),analysisFile.Data()))) Fatal("","Terminating");
3619    }   
3620 }
3621
3622 //______________________________________________________________________________
3623 void AliAnalysisAlien::WriteAnalysisMacro()
3624 {
3625 // Write the analysis macro that will steer the analysis in grid mode.
3626    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3627       ofstream out;
3628       out.open(fAnalysisMacro.Data(), ios::out);
3629       if (!out.good()) {
3630          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3631          return;
3632       }
3633       Bool_t hasSTEERBase = kFALSE;
3634       Bool_t hasESD = kFALSE;
3635       Bool_t hasAOD = kFALSE;
3636       Bool_t hasANALYSIS = kFALSE;
3637       Bool_t hasOADB = kFALSE;
3638       Bool_t hasANALYSISalice = kFALSE;
3639       Bool_t hasCORRFW = kFALSE;
3640       TString func = fAnalysisMacro;
3641       TString type = "ESD";
3642       TString comment = "// Analysis using ";
3643       if (IsUseMCchain()) {
3644          type = "MC";
3645          comment += "MC";
3646       } else {   
3647          if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
3648          if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
3649             type = "AOD";
3650             comment += "AOD";
3651          }   
3652       }
3653       if (type!="AOD" && fFriendChainName!="") {
3654          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
3655          return;
3656       }
3657       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
3658       else comment += " data";
3659       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
3660       func.ReplaceAll(".C", "");
3661       out << "void " << func.Data() << "()" << endl; 
3662       out << "{" << endl;
3663       out << comment.Data() << endl;
3664       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
3665       out << "   TStopwatch timer;" << endl;
3666       out << "   timer.Start();" << endl << endl;
3667       // Change temp directory to current one
3668       out << "// Set temporary merging directory to current one" << endl;
3669       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
3670       out << "// Set temporary compilation directory to current one" << endl;
3671       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
3672       // Reset existing include path
3673       out << "// Reset existing include path and add current directory first in the search" << endl;
3674       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
3675       if (!fExecutableCommand.Contains("aliroot")) {
3676          out << "// load base root libraries" << endl;
3677          out << "   gSystem->Load(\"libTree\");" << endl;
3678          out << "   gSystem->Load(\"libGeom\");" << endl;
3679          out << "   gSystem->Load(\"libVMC\");" << endl;
3680          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
3681          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
3682       }   
3683       if (fAdditionalRootLibs.Length()) {
3684          // in principle libtree /lib geom libvmc etc. can go into this list, too
3685          out << "// Add aditional libraries" << endl;
3686          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
3687          TIter next(list);
3688          TObjString *str;
3689          while((str=(TObjString*)next())) {
3690             if (str->GetString().Contains(".so"))
3691             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3692          }
3693          if (list) delete list;
3694       }
3695       out << "// Load analysis framework libraries" << endl;
3696       TString setupPar = "AliAnalysisAlien::SetupPar";
3697       if (!fPackages) {
3698          if (!fExecutableCommand.Contains("aliroot")) {         
3699             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3700             out << "   gSystem->Load(\"libESD\");" << endl;
3701             out << "   gSystem->Load(\"libAOD\");" << endl;
3702          }   
3703          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3704          out << "   gSystem->Load(\"libOADB\");" << endl;
3705          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3706          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3707       } else {
3708          TIter next(fPackages);
3709          TObject *obj;
3710          TString pkgname;
3711          while ((obj=next())) {
3712             pkgname = obj->GetName();
3713             if (pkgname == "STEERBase" ||
3714                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
3715             if (pkgname == "ESD" ||
3716                 pkgname == "ESD.par")       hasESD = kTRUE;
3717             if (pkgname == "AOD" ||
3718                 pkgname == "AOD.par")       hasAOD = kTRUE;
3719             if (pkgname == "ANALYSIS" ||
3720                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
3721             if (pkgname == "OADB" ||
3722                 pkgname == "OADB.par")      hasOADB = kTRUE;
3723             if (pkgname == "ANALYSISalice" ||
3724                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
3725             if (pkgname == "CORRFW" ||
3726                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
3727          }
3728          if (hasANALYSISalice) setupPar = "SetupPar";   
3729          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
3730          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
3731          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
3732          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
3733          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
3734          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
3735          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
3736          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
3737          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
3738          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
3739          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
3740          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
3741          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
3742          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
3743          out << "// Compile other par packages" << endl;
3744          next.Reset();
3745          while ((obj=next())) {
3746             pkgname = obj->GetName();
3747             if (pkgname == "STEERBase" ||
3748                 pkgname == "STEERBase.par" ||
3749                 pkgname == "ESD" ||
3750                 pkgname == "ESD.par" ||
3751                 pkgname == "AOD" ||
3752                 pkgname == "AOD.par" ||
3753                 pkgname == "ANALYSIS" ||
3754                 pkgname == "ANALYSIS.par" ||
3755                 pkgname == "OADB" ||
3756                 pkgname == "OADB.par" ||
3757                 pkgname == "ANALYSISalice" ||
3758                 pkgname == "ANALYSISalice.par" ||
3759                 pkgname == "CORRFW" ||
3760                 pkgname == "CORRFW.par") continue;
3761             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
3762          }   
3763       }   
3764       out << "// include path" << endl;
3765       // Get the include path from the interpreter and remove entries pointing to AliRoot
3766       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
3767       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
3768       out << "   TIter nextpath(listpaths);" << endl;
3769       out << "   TObjString *pname;" << endl;
3770       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
3771       out << "      TString current = pname->GetName();" << endl;
3772       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
3773       out << "      gSystem->AddIncludePath(current);" << endl;
3774       out << "   }" << endl;
3775       out << "   if (listpaths) delete listpaths;" << endl;
3776       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
3777       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
3778       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
3779       if (fAdditionalLibs.Length()) {
3780          out << "// Add aditional AliRoot libraries" << endl;
3781          TObjArray *list = fAdditionalLibs.Tokenize(" ");
3782          TIter next(list);
3783          TObjString *str;
3784          while((str=(TObjString*)next())) {
3785             if (str->GetString().Contains(".so"))
3786                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
3787             if (str->GetString().Contains(".par"))
3788                out << "   if (!" << setupPar << "(\"" << str->GetString() << "\")) return;" << endl;
3789          }
3790          if (list) delete list;
3791       }
3792       out << endl;
3793       out << "// analysis source to be compiled at runtime (if any)" << endl;
3794       if (fAnalysisSource.Length()) {
3795          TObjArray *list = fAnalysisSource.Tokenize(" ");
3796          TIter next(list);
3797          TObjString *str;
3798          while((str=(TObjString*)next())) {
3799             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
3800          }   
3801          if (list) delete list;
3802       }
3803       out << endl;
3804 //      out << "   printf(\"Currently load libraries:\\n\");" << endl;
3805 //      out << "   printf(\"%s\\n\", gSystem->GetLibraries());" << endl;
3806       if (fFastReadOption) {
3807          Warning("WriteAnalysisMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid jobs. This may skip some files that could be accessed !!! \
3808                 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
3809          out << "// fast xrootd reading enabled" << endl;
3810          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
3811          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
3812          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
3813          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
3814          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
3815          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
3816       } 
3817       if (!IsLocalTest()) {  
3818          out << "// connect to AliEn and make the chain" << endl;
3819          out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
3820       }   
3821       out << "// read the analysis manager from file" << endl;
3822       TString analysisFile = fExecutable;
3823       analysisFile.ReplaceAll(".sh", ".root");
3824       out << "   AliAnalysisManager *mgr = AliAnalysisAlien::LoadAnalysisManager(\"" 
3825           << analysisFile << "\");" << endl;
3826       out << "   if (!mgr) return;" << endl;
3827       if (IsLocalTest()) {
3828          out << "   AliAnalysisAlien *plugin = new AliAnalysisAlien();" << endl;
3829          out << "   plugin->SetRunMode(\"test\");" << endl;
3830          if (fFileForTestMode.IsNull())
3831             out << "   plugin->SetFileForTestMode(\"data.txt\");" << endl;
3832          else   
3833             out << "   plugin->SetFileForTestMode(\"" << fFileForTestMode << "\");" << endl;
3834          out << "   plugin->SetNtestFiles(" << fNtestFiles << ");" << endl;
3835          out << "   mgr->SetGridHandler(plugin);" << endl;
3836          if (AliAnalysisManager::GetAnalysisManager()) {
3837             out << "   mgr->SetDebugLevel(" << AliAnalysisManager::GetAnalysisManager()->GetDebugLevel() << ");" << endl;
3838             out << "   mgr->SetNSysInfo(" << AliAnalysisManager::GetAnalysisManager()->GetNsysInfo() << ");" << endl;
3839          } else {
3840             out << "   mgr->SetDebugLevel(10);" << endl;
3841             out << "   mgr->SetNSysInfo(100);" << endl;
3842          }
3843       }
3844       out << "   mgr->PrintStatus();" << endl;
3845       if (AliAnalysisManager::GetAnalysisManager()) {
3846          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
3847             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
3848          } else {
3849             if (TestBit(AliAnalysisGrid::kTest))            
3850                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
3851             else
3852                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
3853          }
3854       }   
3855       if (!IsLocalTest()) {
3856          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;   
3857          out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
3858       } else {
3859          out << "   mgr->StartAnalysis(\"localfile\");" << endl;
3860       }   
3861       out << "   timer.Stop();" << endl;
3862       out << "   timer.Print();" << endl;
3863       out << "}" << endl << endl;
3864       if (!IsLocalTest()) {
3865          out <<"//________________________________________________________________________________" << endl;
3866          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
3867          out << "{" << endl;
3868          out << "// Create a chain using url's from xml file" << endl;
3869          out << "   TString filename;" << endl;
3870          out << "   Int_t run = 0;" << endl;
3871          if (IsUseMCchain()) {
3872             out << "   TString treename = \"TE\";" << endl;
3873          } else {   
3874             out << "   TString treename = type;" << endl;
3875             out << "   treename.ToLower();" << endl;
3876             out << "   treename += \"Tree\";" << endl;
3877          }   
3878          out << "   printf(\"***************************************\\n\");" << endl;
3879          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
3880          out << "   printf(\"***************************************\\n\");" << endl;
3881          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
3882          out << "   if (!coll) {" << endl;
3883          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
3884          out << "      return NULL;" << endl;
3885          out << "   }" << endl;
3886          out << "   AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();" << endl;
3887          out << "   TChain *chain = new TChain(treename);" << endl;
3888          if(fFriendChainName!="") {
3889             out << "   TChain *chainFriend = new TChain(treename);" << endl;
3890          }
3891          out << "   coll->Reset();" << endl;
3892          out << "   while (coll->Next()) {" << endl;
3893          out << "      filename = coll->GetTURL("");" << endl;
3894          out << "      if (mgr) {" << endl;
3895          out << "         Int_t nrun = AliAnalysisManager::GetRunFromAlienPath(filename);" << endl;
3896          out << "         if (nrun && nrun != run) {" << endl;
3897          out << "            printf(\"### Run number detected from chain: %d\\n\", nrun);" << endl;
3898          out << "            mgr->SetRunFromPath(nrun);" << endl;
3899          out << "            run = nrun;" << endl;
3900          out << "         }" << endl;
3901          out << "      }" << endl;
3902          out << "      chain->Add(filename);" << endl;
3903          if(fFriendChainName!="") {
3904             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
3905             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3906             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
3907             out << "      chainFriend->Add(fileFriend.Data());" << endl;
3908          }
3909          out << "   }" << endl;
3910          out << "   if (!chain->GetNtrees()) {" << endl;
3911          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
3912          out << "      return NULL;" << endl;
3913          out << "   }" << endl;
3914          if(fFriendChainName!="") {
3915             out << "   chain->AddFriend(chainFriend);" << endl;
3916          }
3917          out << "   return chain;" << endl;
3918          out << "}" << endl << endl;
3919       }   
3920       if (hasANALYSISalice) {
3921          out <<"//________________________________________________________________________________" << endl;
3922          out << "Bool_t SetupPar(const char *package) {" << endl;
3923          out << "// Compile the package and set it up." << endl;
3924          out << "   TString pkgdir = package;" << endl;
3925          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
3926          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
3927          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
3928          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
3929          out << "   // Check for BUILD.sh and execute" << endl;
3930          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
3931          out << "      printf(\"*******************************\\n\");" << endl;
3932          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
3933          out << "      printf(\"*******************************\\n\");" << endl;
3934          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
3935          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
3936          out << "         gSystem->ChangeDirectory(cdir);" << endl;
3937          out << "         return kFALSE;" << endl;
3938          out << "      }" << endl;
3939          out << "   } else {" << endl;
3940          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
3941          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3942          out << "      return kFALSE;" << endl;
3943          out << "   }" << endl;
3944          out << "   // Check for SETUP.C and execute" << endl;
3945          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
3946          out << "      printf(\"*******************************\\n\");" << endl;
3947          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
3948          out << "      printf(\"*******************************\\n\");" << endl;
3949          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
3950          out << "   } else {" << endl;
3951          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
3952          out << "      gSystem->ChangeDirectory(cdir);" << endl;
3953          out << "      return kFALSE;" << endl;
3954          out << "   }" << endl;
3955          out << "   // Restore original workdir" << endl;
3956          out << "   gSystem->ChangeDirectory(cdir);" << endl;
3957          out << "   return kTRUE;" << endl;
3958          out << "}" << endl;
3959       }
3960       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
3961    }   
3962    Bool_t copy = kTRUE;
3963    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3964    if (copy) {
3965       CdWork();
3966       TString workdir = gGrid->GetHomeDirectory();
3967       workdir += fGridWorkingDir;
3968       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
3969       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
3970 //      TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
3971       if (!copyLocal2Alien("WriteAnalysisMacro",fAnalysisMacro.Data(), 
3972            Form("alien://%s/%s", workdir.Data(), 
3973            fAnalysisMacro.Data()))) Fatal("","Terminating");
3974    }
3975 }
3976
3977 //______________________________________________________________________________
3978 void AliAnalysisAlien::WriteMergingMacro()
3979 {
3980 // Write a macro to merge the outputs per master job.
3981    if (!fMergeViaJDL) return;
3982    if (!fOutputFiles.Length()) {
3983       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
3984       return;
3985    }   
3986    TString mergingMacro = fExecutable;
3987    mergingMacro.ReplaceAll(".sh","_merge.C");
3988    if (gGrid && !fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
3989    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3990       ofstream out;
3991       out.open(mergingMacro.Data(), ios::out);
3992       if (!out.good()) {
3993          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
3994          return;
3995       }
3996       Bool_t hasSTEERBase = kFALSE;
3997       Bool_t hasESD = kFALSE;
3998       Bool_t hasAOD = kFALSE;
3999       Bool_t hasANALYSIS = kFALSE;
4000       Bool_t hasOADB = kFALSE;
4001       Bool_t hasANALYSISalice = kFALSE;
4002       Bool_t hasCORRFW = kFALSE;
4003       TString func = mergingMacro;
4004       TString comment;
4005       func.ReplaceAll(".C", "");
4006       out << "void " << func.Data() << "(const char *dir, Int_t stage=0)" << endl;
4007       out << "{" << endl;
4008       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
4009       out << "   TStopwatch timer;" << endl;
4010       out << "   timer.Start();" << endl << endl;
4011       // Reset existing include path
4012       out << "// Reset existing include path and add current directory first in the search" << endl;
4013       out << "   gSystem->SetIncludePath(\"-I.\");" << endl;
4014       if (!fExecutableCommand.Contains("aliroot")) {
4015          out << "// load base root libraries" << endl;
4016          out << "   gSystem->Load(\"libTree\");" << endl;
4017          out << "   gSystem->Load(\"libGeom\");" << endl;
4018          out << "   gSystem->Load(\"libVMC\");" << endl;
4019          out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
4020          out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
4021       }   
4022       if (fAdditionalRootLibs.Length()) {
4023          // in principle libtree /lib geom libvmc etc. can go into this list, too
4024          out << "// Add aditional libraries" << endl;
4025          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
4026          TIter next(list);
4027          TObjString *str;
4028          while((str=(TObjString*)next())) {
4029             if (str->GetString().Contains(".so"))
4030             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
4031          }
4032          if (list) delete list;
4033       }
4034       out << "// Load analysis framework libraries" << endl;
4035       if (!fPackages) {
4036          if (!fExecutableCommand.Contains("aliroot")) {
4037             out << "   gSystem->Load(\"libSTEERBase\");" << endl;
4038             out << "   gSystem->Load(\"libESD\");" << endl;
4039             out << "   gSystem->Load(\"libAOD\");" << endl;
4040          }
4041          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
4042          out << "   gSystem->Load(\"libOADB\");" << endl;
4043          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
4044          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
4045       } else {
4046          TIter next(fPackages);
4047          TObject *obj;
4048          TString pkgname;
4049          TString setupPar = "AliAnalysisAlien::SetupPar";
4050          while ((obj=next())) {
4051             pkgname = obj->GetName();
4052             if (pkgname == "STEERBase" ||
4053                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
4054             if (pkgname == "ESD" ||
4055                 pkgname == "ESD.par")       hasESD = kTRUE;
4056             if (pkgname == "AOD" ||
4057                 pkgname == "AOD.par")       hasAOD = kTRUE;
4058             if (pkgname == "ANALYSIS" ||
4059                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
4060             if (pkgname == "OADB" ||
4061                 pkgname == "OADB.par")      hasOADB = kTRUE;
4062             if (pkgname == "ANALYSISalice" ||
4063                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
4064             if (pkgname == "CORRFW" ||
4065                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
4066          }   
4067          if (hasANALYSISalice) setupPar = "SetupPar";   
4068          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
4069          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
4070          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
4071          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
4072          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
4073          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
4074          out << "   gSystem->Load(\"libOADB\");" << endl;
4075          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
4076          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
4077          if (!hasOADB)  out << "   gSystem->Load(\"libOADB\");" << endl;
4078          else out << "   if (!" << setupPar << "(\"OADB\")) return;" << endl;
4079          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
4080          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
4081          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
4082          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
4083          out << "// Compile other par packages" << endl;
4084          next.Reset();
4085          while ((obj=next())) {
4086             pkgname = obj->GetName();
4087             if (pkgname == "STEERBase" ||
4088                 pkgname == "STEERBase.par" ||
4089                 pkgname == "ESD" ||
4090                 pkgname == "ESD.par" ||
4091                 pkgname == "AOD" ||
4092                 pkgname == "AOD.par" ||
4093                 pkgname == "ANALYSIS" ||
4094                 pkgname == "ANALYSIS.par" ||
4095                 pkgname == "OADB" ||
4096                 pkgname == "OADB.par" ||
4097                 pkgname == "ANALYSISalice" ||
4098                 pkgname == "ANALYSISalice.par" ||
4099                 pkgname == "CORRFW" ||
4100                 pkgname == "CORRFW.par") continue;
4101             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
4102          }   
4103       }   
4104       out << "// include path" << endl;
4105       // Get the include path from the interpreter and remove entries pointing to AliRoot
4106       out << "   TString intPath = gInterpreter->GetIncludePath();" << endl;
4107       out << "   TObjArray *listpaths = intPath.Tokenize(\" \");" << endl;
4108       out << "   TIter nextpath(listpaths);" << endl;
4109       out << "   TObjString *pname;" << endl;
4110       out << "   while ((pname=(TObjString*)nextpath())) {" << endl;
4111       out << "      TString current = pname->GetName();" << endl;
4112       out << "      if (current.Contains(\"AliRoot\") || current.Contains(\"ALICE_ROOT\")) continue;" << endl;
4113       out << "      gSystem->AddIncludePath(current);" << endl;
4114       out << "   }" << endl;
4115       out << "   if (listpaths) delete listpaths;" << endl;
4116       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
4117       out << "   gROOT->ProcessLine(\".include $ALICE_ROOT/include\");" << endl;
4118       out << "   printf(\"Include path: %s\\n\", gSystem->GetIncludePath());" << endl << endl;
4119       if (fAdditionalLibs.Length()) {
4120          out << "// Add aditional AliRoot libraries" << endl;
4121          TObjArray *list = fAdditionalLibs.Tokenize(" ");
4122          TIter next(list);
4123          TObjString *str;
4124          while((str=(TObjString*)next())) {
4125             if (str->GetString().Contains(".so"))
4126                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
4127          }
4128          if (list) delete list;
4129       }
4130       out << endl;
4131       out << "// Analysis source to be compiled at runtime (if any)" << endl;
4132       if (fAnalysisSource.Length()) {
4133          TObjArray *list = fAnalysisSource.Tokenize(" ");
4134          TIter next(list);
4135          TObjString *str;
4136          while((str=(TObjString*)next())) {
4137             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
4138          }   
4139          if (list) delete list;
4140       }
4141       out << endl;      
4142
4143       if (fFastReadOption) {
4144          Warning("WriteMergingMacro", "!!! You requested FastRead option. Using xrootd flags to reduce timeouts in the grid merging jobs. Note that this may skip some files that could be accessed !!!");
4145          out << "// fast xrootd reading enabled" << endl;
4146          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
4147          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",50);" << endl;
4148          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",50);" << endl;
4149          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
4150          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",50);" << endl;
4151          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
4152       }
4153       // Change temp directory to current one
4154       out << "// Set temporary merging directory to current one" << endl;
4155       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
4156       out << "// Set temporary compilation directory to current one" << endl;
4157       out << "   gSystem->SetBuildDir(gSystem->pwd(), kTRUE);" << endl << endl;   
4158       out << "// Connect to AliEn" << endl;
4159       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
4160       out << "   TString outputDir = dir;" << endl;  
4161       out << "   TString outputFiles = \"" << GetListOfFiles("out") << "\";" << endl;
4162       out << "   TString mergeExcludes = \"" << fMergeExcludes << " " << fRegisterExcludes << "\";" << endl;
4163       out << "   TObjArray *list = outputFiles.Tokenize(\",\");" << endl;
4164       out << "   TIter *iter = new TIter(list);" << endl;
4165       out << "   TObjString *str;" << endl;
4166       out << "   TString outputFile;" << endl;
4167       out << "   Bool_t merged = kTRUE;" << endl;
4168       out << "   while((str=(TObjString*)iter->Next())) {" << endl;
4169       out << "      outputFile = str->GetString();" << endl;
4170       out << "      if (outputFile.Contains(\"*\")) continue;" << endl;
4171       out << "      Int_t index = outputFile.Index(\"@\");" << endl;
4172       out << "      if (index > 0) outputFile.Remove(index);" << endl;
4173       out << "      // Skip already merged outputs" << endl;
4174       out << "      if (!gSystem->AccessPathName(outputFile)) {" << endl;
4175       out << "         printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
4176       out << "         continue;" << endl;
4177       out << "      }" << endl;
4178       out << "      if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
4179       out << "      merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ", stage);" << endl;
4180       out << "      if (!merged) {" << endl;
4181       out << "         printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
4182       out << "         return;" << endl;
4183       out << "      }" << endl;
4184       out << "   }" << endl;
4185       out << "   // all outputs merged, validate" << endl;
4186       out << "   ofstream out;" << endl;
4187       out << "   out.open(\"outputs_valid\", ios::out);" << endl;
4188       out << "   out.close();" << endl;
4189       out << "   // read the analysis manager from file" << endl;
4190       TString analysisFile = fExecutable;
4191       analysisFile.ReplaceAll(".sh", ".root");
4192       out << "   if (!outputDir.Contains(\"Stage\")) return;" << endl;
4193       out << "   AliAnalysisManager *mgr = AliAnalysisAlien::LoadAnalysisManager(\"" 
4194           << analysisFile << "\");" << endl;
4195       out << "   if (!mgr) return;" << endl;
4196       out << "   mgr->SetRunFromPath(mgr->GetRunFromAlienPath(dir));" << endl;
4197       out << "   mgr->SetSkipTerminate(kFALSE);" << endl;
4198       out << "   mgr->PrintStatus();" << endl;
4199       if (AliAnalysisManager::GetAnalysisManager()) {
4200          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
4201             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
4202          } else {
4203             if (TestBit(AliAnalysisGrid::kTest))            
4204                out << "   AliLog::SetGlobalLogLevel(AliLog::kWarning);" << endl;
4205             else
4206                out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
4207          }
4208       }   
4209       out << "   TTree *tree = NULL;" << endl;
4210       out << "   mgr->StartAnalysis(\"gridterminate\", tree);" << endl;
4211       out << "}" << endl << endl;
4212       if (hasANALYSISalice) {
4213          out <<"//________________________________________________________________________________" << endl;
4214          out << "Bool_t SetupPar(const char *package) {" << endl;
4215          out << "// Compile the package and set it up." << endl;
4216          out << "   TString pkgdir = package;" << endl;
4217          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
4218          out << "   gSystem->Exec(TString::Format(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
4219          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
4220          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
4221          out << "   // Check for BUILD.sh and execute" << endl;
4222          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
4223          out << "      printf(\"*******************************\\n\");" << endl;
4224          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
4225          out << "      printf(\"*******************************\\n\");" << endl;
4226          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
4227          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
4228          out << "         gSystem->ChangeDirectory(cdir);" << endl;
4229          out << "         return kFALSE;" << endl;
4230          out << "      }" << endl;
4231          out << "   } else {" << endl;
4232          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
4233          out << "      gSystem->ChangeDirectory(cdir);" << endl;
4234          out << "      return kFALSE;" << endl;
4235          out << "   }" << endl;
4236          out << "   // Check for SETUP.C and execute" << endl;
4237          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
4238          out << "      printf(\"*******************************\\n\");" << endl;
4239          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
4240          out << "      printf(\"*******************************\\n\");" << endl;
4241          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
4242          out << "   } else {" << endl;
4243          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
4244          out << "      gSystem->ChangeDirectory(cdir);" << endl;
4245          out << "      return kFALSE;" << endl;
4246          out << "   }" << endl;
4247          out << "   // Restore original workdir" << endl;
4248          out << "   gSystem->ChangeDirectory(cdir);" << endl;
4249          out << "   return kTRUE;" << endl;
4250          out << "}" << endl;
4251       }
4252    }   
4253    Bool_t copy = kTRUE;
4254    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4255    if (copy) {
4256       CdWork();
4257       TString workdir = gGrid->GetHomeDirectory();
4258       workdir += fGridWorkingDir;
4259       if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
4260       Info("WriteMergingMacro", "\n#####   Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
4261 //      TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
4262       if (!copyLocal2Alien("WriteMergeMacro",mergingMacro.Data(), 
4263            Form("%s/%s", workdir.Data(), mergingMacro.Data()))) Fatal("","Terminating");
4264    }
4265 }
4266
4267 //______________________________________________________________________________
4268 Bool_t AliAnalysisAlien::SetupPar(const char *package)
4269 {
4270 // Compile the par file archive pointed by <package>. This must be present in the current directory.
4271 // Note that for loading the compiled library. The current directory should have precedence in
4272 // LD_LIBRARY_PATH
4273    TString pkgdir = package;
4274    pkgdir.ReplaceAll(".par","");
4275    gSystem->Exec(TString::Format("tar xzf %s.par", pkgdir.Data()));
4276    TString cdir = gSystem->WorkingDirectory();
4277    gSystem->ChangeDirectory(pkgdir);
4278    // Check for BUILD.sh and execute
4279    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
4280       printf("**************************************************\n");
4281       printf("*** Building PAR archive %s\n", package);
4282       printf("**************************************************\n");
4283       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
4284          ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
4285          gSystem->ChangeDirectory(cdir);
4286          return kFALSE;
4287       }
4288    } else {
4289       ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
4290       gSystem->ChangeDirectory(cdir);
4291       return kFALSE;
4292    }
4293    // Check for SETUP.C and execute
4294    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
4295       printf("**************************************************\n");
4296       printf("*** Setup PAR archive %s\n", package);
4297       printf("**************************************************\n");
4298       gROOT->Macro("PROOF-INF/SETUP.C");
4299       printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
4300    } else {
4301       ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
4302       gSystem->ChangeDirectory(cdir);
4303       return kFALSE;
4304    }   
4305    // Restore original workdir
4306    gSystem->ChangeDirectory(cdir);
4307    return kTRUE;
4308 }
4309
4310 //______________________________________________________________________________
4311 void AliAnalysisAlien::WriteExecutable()
4312 {
4313 // Generate the alien executable script.
4314    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
4315       ofstream out;
4316       out.open(fExecutable.Data(), ios::out);
4317       if (out.bad()) {
4318          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
4319          return;
4320       }
4321       out << "#!/bin/bash" << endl;
4322       // Make sure we can properly compile par files
4323       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
4324       out << "echo \"=========================================\"" << endl; 
4325       out << "echo \"############## PATH : ##############\"" << endl;
4326       out << "echo $PATH" << endl;
4327       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
4328       out << "echo $LD_LIBRARY_PATH" << endl;
4329       out << "echo \"############## ROOTSYS : ##############\"" << endl;
4330       out << "echo $ROOTSYS" << endl;
4331       out << "echo \"############## which root : ##############\"" << endl;
4332       out << "which root" << endl;
4333       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
4334       out << "echo $ALICE_ROOT" << endl;
4335       out << "echo \"############## which aliroot : ##############\"" << endl;
4336       out << "which aliroot" << endl;
4337       out << "echo \"############## system limits : ##############\"" << endl;
4338       out << "ulimit -a" << endl;
4339       out << "echo \"############## memory : ##############\"" << endl;
4340       out << "free -m" << endl;
4341       out << "echo \"=========================================\"" << endl << endl;
4342       out << fExecutableCommand << " "; 
4343       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
4344       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
4345       out << "echo \"############## memory after: ##############\"" << endl;
4346       out << "free -m" << endl;
4347    }   
4348    Bool_t copy = kTRUE;
4349    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4350    if (copy) {
4351       CdWork();
4352       TString workdir = gGrid->GetHomeDirectory();
4353       TString bindir = Form("%s/bin", workdir.Data());
4354       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
4355       workdir += fGridWorkingDir;
4356       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
4357       if (FileExists(executable)) gGrid->Rm(executable);
4358       Info("WriteExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
4359 //      TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
4360       if (!copyLocal2Alien("WriteExecutable",fExecutable.Data(), 
4361           executable.Data())) Fatal("","Terminating");
4362    } 
4363 }
4364
4365 //______________________________________________________________________________
4366 void AliAnalysisAlien::WriteMergeExecutable()
4367 {
4368 // Generate the alien executable script for the merging job.
4369    if (!fMergeViaJDL) return;
4370    TString mergeExec = fExecutable;
4371    mergeExec.ReplaceAll(".sh", "_merge.sh");
4372    if (!TestBit(AliAnalysisGrid::kSubmit)) {
4373       ofstream out;
4374       out.open(mergeExec.Data(), ios::out);
4375       if (out.bad()) {
4376          Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
4377          return;
4378       }
4379       out << "#!/bin/bash" << endl;
4380       // Make sure we can properly compile par files
4381       out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
4382       out << "echo \"=========================================\"" << endl; 
4383       out << "echo \"############## PATH : ##############\"" << endl;
4384       out << "echo $PATH" << endl;
4385       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
4386       out << "echo $LD_LIBRARY_PATH" << endl;
4387       out << "echo \"############## ROOTSYS : ##############\"" << endl;
4388       out << "echo $ROOTSYS" << endl;
4389       out << "echo \"############## which root : ##############\"" << endl;
4390       out << "which root" << endl;
4391       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
4392       out << "echo $ALICE_ROOT" << endl;
4393       out << "echo \"############## which aliroot : ##############\"" << endl;
4394       out << "which aliroot" << endl;
4395       out << "echo \"############## system limits : ##############\"" << endl;
4396       out << "ulimit -a" << endl;
4397       out << "echo \"############## memory : ##############\"" << endl;
4398       out << "free -m" << endl;
4399       out << "echo \"=========================================\"" << endl << endl;
4400       TString mergeMacro = fExecutable;
4401       mergeMacro.ReplaceAll(".sh", "_merge.C");
4402       if (IsOneStageMerging())
4403          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
4404       else
4405          out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\",$2)\"" << endl;
4406       out << fExecutableCommand << " " << "$ARG" << endl; 
4407       out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
4408       out << "echo \"############## memory after: ##############\"" << endl;
4409       out << "free -m" << endl;
4410    }   
4411    Bool_t copy = kTRUE;
4412    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4413    if (copy) {
4414       CdWork();
4415       TString workdir = gGrid->GetHomeDirectory();
4416       TString bindir = Form("%s/bin", workdir.Data());
4417       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir,"-p");
4418       workdir += fGridWorkingDir;
4419       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
4420       if (FileExists(executable)) gGrid->Rm(executable);
4421       Info("WriteMergeExecutable", "\n#####   Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
4422 //      TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
4423       if (!copyLocal2Alien("WriteMergeExecutable",
4424           mergeExec.Data(), executable.Data())) Fatal("","Terminating");
4425    } 
4426 }
4427
4428 //______________________________________________________________________________
4429 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
4430 {
4431 // Write the production file to be submitted by LPM manager. The format is:
4432 // First line: full_path_to_jdl estimated_no_subjobs_per_master
4433 // Next lines: full_path_to_dataset XXX (XXX is a string)
4434 // To submit, one has to: submit jdl XXX for all lines
4435    ofstream out;
4436    out.open(filename, ios::out);
4437    if (out.bad()) {
4438       Error("WriteProductionFile", "Bad file name: %s", filename);
4439       return;
4440    }
4441    TString workdir;
4442    if (!fProductionMode && !fGridWorkingDir.BeginsWith("/alice"))
4443       workdir = gGrid->GetHomeDirectory();
4444    workdir += fGridWorkingDir;
4445    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
4446    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
4447    out << locjdl << " " << njobspermaster << endl;
4448    Int_t nmasterjobs = fInputFiles->GetEntries();
4449    for (Int_t i=0; i<nmasterjobs; i++) {
4450       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
4451       runOutDir.ReplaceAll(".xml", "");
4452       if (fOutputToRunNo)
4453          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
4454       else
4455          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
4456    }
4457    if (gGrid) {
4458       Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
4459       if (FileExists(filename)) gGrid->Rm(filename);
4460 //      TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));
4461       if (!copyLocal2Alien("WriteProductionFile", filename, 
4462           Form("%s/%s", workdir.Data(),filename))) Fatal("","Terminating");
4463    }   
4464 }
4465
4466 //______________________________________________________________________________
4467 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
4468 {
4469 // Generate the alien validation script.
4470    // Generate the validation script
4471    TObjString *os;
4472    if (fValidationScript.IsNull()) {
4473       fValidationScript = fExecutable;
4474       fValidationScript.ReplaceAll(".sh", "_validation.sh");
4475    }   
4476    TString validationScript = fValidationScript;
4477    if (merge) validationScript.ReplaceAll(".sh", "_merge.sh");
4478    if (!Connect()) {
4479       Error("WriteValidationScript", "Alien connection required");
4480       return;
4481    }
4482    if (!fTerminateFiles.IsNull()) {
4483       fTerminateFiles.Strip();
4484       fTerminateFiles.ReplaceAll(" ",",");
4485    }   
4486    TString outStream = "";
4487    if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
4488    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
4489       ofstream out;
4490       out.open(validationScript, ios::out);
4491       out << "#!/bin/bash" << endl;
4492       out << "##################################################" << endl;
4493       out << "validateout=`dirname $0`" << endl;
4494       out << "validatetime=`date`" << endl;
4495       out << "validated=\"0\";" << endl;
4496       out << "error=0" << endl;
4497       out << "if [ -z $validateout ]" << endl;
4498       out << "then" << endl;
4499       out << "    validateout=\".\"" << endl;
4500       out << "fi" << endl << endl;
4501       out << "cd $validateout;" << endl;
4502       out << "validateworkdir=`pwd`;" << endl << endl;
4503       out << "echo \"*******************************************************\"" << outStream << endl;
4504       out << "echo \"* Automatically generated validation script           *\""  << outStream << endl;
4505       out << "" << endl;
4506       out << "echo \"* Time:    $validatetime \""  << outStream << endl;
4507       out << "echo \"* Dir:     $validateout\""  << outStream << endl;
4508       out << "echo \"* Workdir: $validateworkdir\""  << outStream << endl;
4509       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
4510       out << "ls -la ./"  << outStream << endl;
4511       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl << endl;
4512       out << "##################################################" << endl;
4513       out << "" << endl;
4514
4515       out << "if [ ! -f stderr ] ; then" << endl;
4516       out << "   error=1" << endl;
4517       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << outStream << endl;
4518       out << "   echo \"Error = $error\" " << outStream << endl;
4519       out << "fi" << endl;
4520
4521       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
4522       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
4523       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
4524       out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
4525       out << "" << endl;
4526
4527       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
4528       out << "   error=1" << endl;
4529       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << outStream << endl;
4530       out << "   echo \"$parArch\" " << outStream << endl;
4531       out << "   echo \"Error = $error\" " << outStream << endl;
4532       out << "fi" << endl;
4533
4534       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
4535       out << "   error=1" << endl;
4536       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << outStream << endl;
4537       out << "   echo \"$segViol\" " << outStream << endl;
4538       out << "   echo \"Error = $error\" " << outStream << endl;
4539       out << "fi" << endl;
4540
4541       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
4542       out << "   error=1" << endl;
4543       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << outStream << endl;
4544       out << "   echo \"$segFault\" " << outStream << endl;
4545       out << "   echo \"Error = $error\" " << outStream << endl;
4546       out << "fi" << endl;
4547
4548       out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
4549       out << "   error=1" << endl;
4550       out << "   echo \"* ########## Job not validated - *** glibc detected ***  ###\" " << outStream << endl;
4551       out << "   echo \"$glibcErr\" " << outStream << endl;
4552       out << "   echo \"Error = $error\" " << outStream << endl;
4553       out << "fi" << endl;
4554
4555       // Part dedicated to the specific analyses running into the train
4556
4557       TString outputFiles = fOutputFiles;
4558       if (merge && !fTerminateFiles.IsNull()) {
4559          outputFiles += ",";
4560          outputFiles += fTerminateFiles;
4561       }
4562       TObjArray *arr = outputFiles.Tokenize(",");
4563       TIter next1(arr);
4564       TString outputFile;
4565       while (!merge && (os=(TObjString*)next1())) { 
4566          // No need to validate outputs produced by merging since the merging macro does this
4567          outputFile = os->GetString();
4568          Int_t index = outputFile.Index("@");
4569          if (index > 0) outputFile.Remove(index);
4570          if (fTerminateFiles.Contains(outputFile)) continue;
4571          if (outputFile.Contains("*")) continue;
4572          out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
4573          out << "   error=1" << endl;
4574          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\""  << outStream << endl;
4575          out << "   echo \"Output file " << outputFile << " not found. Job FAILED !\" >> stderr" << endl;
4576          out << "fi" << endl;
4577       }   
4578       delete arr;
4579       out << "if ! [ -f outputs_valid ] ; then" << endl;
4580       out << "   error=1" << endl;
4581       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
4582       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
4583       out << "fi" << endl;
4584       
4585       out << "if [ $error = 0 ] ; then" << endl;
4586       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << outStream << endl;
4587       if (!IsKeepLogs()) {
4588          out << "   echo \"* === Logs std* will be deleted === \"" << endl;
4589          outStream = "";
4590          out << "   rm -f std*" << endl;
4591       }            
4592       out << "fi" << endl;
4593
4594       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
4595       out << "echo \"*******************************************************\""  << outStream << endl;
4596       out << "cd -" << endl;
4597       out << "exit $error" << endl;
4598    }    
4599    Bool_t copy = kTRUE;
4600    if (fProductionMode || TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
4601    if (copy) {
4602       CdWork();
4603       TString workdir = gGrid->GetHomeDirectory();
4604       workdir += fGridWorkingDir;
4605       Info("WriteValidationScript", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
4606       if (FileExists(validationScript)) gGrid->Rm(validationScript);
4607 //      TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
4608       if (!copyLocal2Alien("WriteValidationScript", validationScript.Data(), 
4609           Form("%s/%s",workdir.Data(), validationScript.Data()))) Fatal("","Terminating");
4610    } 
4611 }