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