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