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