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