]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
Extra files do not have to be mandatory produced anymore in grid jobs
[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->SetTTL((UInt_t)fTTL);
853       fMergingJDL->SetTTL((UInt_t)fTTL);
854       if (fMaxInitFailed > 0) {
855          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
856          fGridJDL->SetDescription("MaxInitFailed", "Maximum number of first failing jobs to abort the master job");
857       }   
858       if (fSplitMaxInputFileNumber > 0) {
859          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
860          fGridJDL->SetDescription("SplitMaxInputFileNumber", "Maximum number of input files to be processed per subjob");
861       }   
862       if (fSplitMode.Length()) {
863          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
864          fGridJDL->SetDescription("Split", "We split per SE or file");
865       }   
866       if (!fAliROOTVersion.IsNull()) {
867          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion,"VO_ALICE", "List of requested packages");
868          fMergingJDL->AddToPackages("AliRoot", fAliROOTVersion, "VO_ALICE", "List of requested packages");
869       }   
870       if (!fROOTVersion.IsNull()) {
871          fGridJDL->AddToPackages("ROOT", fROOTVersion);
872          fMergingJDL->AddToPackages("ROOT", fROOTVersion);
873       }   
874       if (!fAPIVersion.IsNull()) {
875          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
876          fMergingJDL->AddToPackages("APISCONFIG", fAPIVersion);
877       }   
878       if (!fExternalPackages.IsNull()) {
879          arr = fExternalPackages.Tokenize(" ");
880          TIter next(arr);
881          while ((os=(TObjString*)next())) {
882             TString pkgname = os->GetString();
883             Int_t index = pkgname.Index("::");
884             TString pkgversion = pkgname(index+2, pkgname.Length());
885             pkgname.Remove(index);
886             fGridJDL->AddToPackages(pkgname, pkgversion);
887             fMergingJDL->AddToPackages(pkgname, pkgversion);
888          }   
889          delete arr;   
890       }   
891       fGridJDL->SetInputDataListFormat(fInputFormat, "Format of input data");
892       fGridJDL->SetInputDataList("wn.xml", "Collection name to be processed on each worker node");
893       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()), "List of input files to be uploaded to workers");
894       TString analysisFile = fExecutable;
895       analysisFile.ReplaceAll(".sh", ".root");
896       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
897       fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
898       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
899          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
900       if (fAdditionalLibs.Length()) {
901          arr = fAdditionalLibs.Tokenize(" ");
902          TIter next(arr);
903          while ((os=(TObjString*)next())) {
904             if (os->GetString().Contains(".so")) continue;
905             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
906             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
907          }   
908          delete arr;   
909       }
910       if (fPackages) {
911          TIter next(fPackages);
912          TObject *obj;
913          while ((obj=next())) {
914             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
915             fMergingJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
916          }
917       }
918       if (fOutputArchive.Length()) {
919          arr = fOutputArchive.Tokenize(" ");
920          TIter next(arr);
921          Bool_t first = kTRUE;
922          const char *comment = "Files to be archived";
923          const char *comment1 = comment;
924          while ((os=(TObjString*)next())) {
925             if (!first) comment = NULL;
926             if (!os->GetString().Contains("@") && fCloseSE.Length())
927                fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
928             else
929                fGridJDL->AddToOutputArchive(os->GetString(), comment);
930             first = kFALSE;   
931          }      
932          delete arr;
933          TString outputArchive = fOutputArchive;
934          if (!fMergeExcludes.IsNull()) {
935             arr = fMergeExcludes.Tokenize(" ");
936             TIter next1(arr);
937             while ((os=(TObjString*)next1())) {
938                outputArchive.ReplaceAll(Form("%s,",os->GetString().Data()),"");
939                outputArchive.ReplaceAll(os->GetString(),"");
940             }
941             delete arr;
942          }
943          arr = outputArchive.Tokenize(" ");
944          TIter next2(arr);
945          comment = comment1;
946          first = kTRUE;
947          while ((os=(TObjString*)next2())) {
948             if (!first) comment = NULL;
949             if (!os->GetString().Contains("@") && fCloseSE.Length())
950                fMergingJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
951             else
952                fMergingJDL->AddToOutputArchive(os->GetString(), comment);
953             first = kFALSE;   
954          }      
955          delete arr;         
956       }      
957       arr = fOutputFiles.Tokenize(" ");
958       TIter next(arr);
959       Bool_t first = kTRUE;
960       const char *comment = "Files to be archived";
961       const char *comment1 = comment;
962       while ((os=(TObjString*)next())) {
963          // Ignore ouputs in jdl that are also in outputarchive
964          TString sout = os->GetString();
965          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
966          if (fOutputArchive.Contains(sout)) continue;
967          if (!first) comment = NULL;
968          if (!os->GetString().Contains("@") && fCloseSE.Length())
969             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
970          else
971             fGridJDL->AddToOutputSandbox(os->GetString(), comment);
972          first = kFALSE;   
973       }   
974       delete arr;
975       if (fOutputFiles.Length()) {
976          TString outputFiles = fOutputFiles;
977          if (!fMergeExcludes.IsNull()) {
978             arr = fMergeExcludes.Tokenize(" ");
979             TIter next1(arr);
980             while ((os=(TObjString*)next1())) {
981                outputFiles.ReplaceAll(Form("%s,",os->GetString().Data()),"");
982                outputFiles.ReplaceAll(os->GetString(),"");
983             }
984             delete arr;
985          }
986          arr = outputFiles.Tokenize(" ");
987          TIter next2(arr);
988          comment = comment1;
989          first = kTRUE;
990          while ((os=(TObjString*)next2())) {
991             // Ignore ouputs in jdl that are also in outputarchive
992             TString sout = os->GetString();
993             if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
994             if (fOutputArchive.Contains(sout)) continue;
995             if (!first) comment = NULL;
996             if (!os->GetString().Contains("@") && fCloseSE.Length())
997                fMergingJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data()), comment); 
998             else
999                fMergingJDL->AddToOutputSandbox(os->GetString(), comment);
1000          }   
1001          delete arr;
1002       }
1003       fGridJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1004       fMergingJDL->SetPrice((UInt_t)fPrice, "AliEn price for this job");
1005       TString validationScript = fExecutable;
1006       validationScript.ReplaceAll(".sh", "_validation.sh");
1007       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1008       validationScript = fExecutable;
1009       validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
1010       fMergingJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()), "Validation script to be run for each subjob");
1011       if (fMasterResubmitThreshold) {
1012          fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
1013          fGridJDL->SetDescription("MasterResubmitThreshold", "Resubmit failed jobs until DONE rate reaches this percentage");
1014       }   
1015       // Write a jdl with 2 input parameters: collection name and output dir name.
1016       WriteJDL(copy);
1017    }
1018    // Copy jdl to grid workspace   
1019    if (copy) {
1020       // Check if an output directory was defined and valid
1021       if (!fGridOutputDir.Length()) {
1022          Error("CreateJDL", "You must define AliEn output directory");
1023          return kFALSE;
1024       } else {
1025          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
1026          if (!fProductionMode && !DirectoryExists(fGridOutputDir)) {
1027             if (gGrid->Mkdir(fGridOutputDir)) {
1028                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
1029             } else {
1030                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
1031                return kFALSE;
1032             }
1033          }
1034          gGrid->Cd(workdir);
1035       }   
1036       if (TestBit(AliAnalysisGrid::kSubmit)) {
1037          TString mergeJDLName = fExecutable;
1038          mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1039          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1040          TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1041          if (fProductionMode) {
1042             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1043             locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1044          }   
1045          if (FileExists(locjdl)) gGrid->Rm(locjdl);
1046          if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1047          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1048          TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1049          if (fMergeViaJDL) {
1050             Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1051             TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1052          }   
1053       }
1054       if (fAdditionalLibs.Length()) {
1055          arr = fAdditionalLibs.Tokenize(" ");
1056          TObjString *os;
1057          TIter next(arr);
1058          while ((os=(TObjString*)next())) {
1059             if (os->GetString().Contains(".so")) continue;
1060             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
1061             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
1062             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
1063          }   
1064          delete arr;   
1065       }
1066       if (fPackages) {
1067          TIter next(fPackages);
1068          TObject *obj;
1069          while ((obj=next())) {
1070             if (FileExists(obj->GetName())) gGrid->Rm(obj->GetName());
1071             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
1072             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
1073          }   
1074       }      
1075    } 
1076    return kTRUE;
1077 }
1078
1079 //______________________________________________________________________________
1080 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
1081 {
1082 // Writes one or more JDL's corresponding to findex. If findex is negative,
1083 // all run numbers are considered in one go (jdl). For non-negative indices
1084 // they correspond to the indices in the array fInputFiles.
1085    if (!fInputFiles) return kFALSE;
1086    TObjString *os;
1087    TString workdir = gGrid->GetHomeDirectory();
1088    workdir += fGridWorkingDir;
1089    
1090    if (!fRunNumbers.Length() && !fRunRange[0]) {
1091       // One jdl with no parameters in case input data is specified by name.
1092       TIter next(fInputFiles);
1093       while ((os=(TObjString*)next()))
1094          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()), "Input xml collections");
1095       if (!fOutputSingle.IsNull())
1096          fGridJDL->SetOutputDirectory(Form("#alienfulldir#/../%s",fOutputSingle.Data()), "Output directory");
1097       else {
1098          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1099          fMergingJDL->SetOutputDirectory(fGridOutputDir);         
1100       }   
1101    } else {
1102       // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
1103       fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()), "Input xml collections");
1104       if (!fOutputSingle.IsNull()) {
1105          if (!fOutputToRunNo) fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()), "Output directory");
1106          else fGridJDL->SetOutputDirectory(Form("%s/$2",fGridOutputDir.Data()), "Output directory");
1107       } else {   
1108          fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()), "Output directory");
1109          fMergingJDL->SetOutputDirectory(Form("%s/$1", fGridOutputDir.Data()), "Output directory");
1110       }   
1111    }
1112       
1113
1114    // Generate the JDL as a string
1115    TString sjdl = fGridJDL->Generate();
1116    TString sjdl1 = fMergingJDL->Generate();
1117    Int_t index;
1118    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
1119    sjdl.ReplaceAll("(member", "\n   (member");
1120    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1121    sjdl.ReplaceAll("{", "{\n   ");
1122    sjdl.ReplaceAll("};", "\n};");
1123    sjdl.ReplaceAll("{\n   \n", "{\n");
1124    sjdl.ReplaceAll("\n\n", "\n");
1125    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
1126    sjdl1.ReplaceAll("\"LF:", "\n   \"LF:");
1127    sjdl1.ReplaceAll("(member", "\n   (member");
1128    sjdl1.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
1129    sjdl1.ReplaceAll("{", "{\n   ");
1130    sjdl1.ReplaceAll("};", "\n};");
1131    sjdl1.ReplaceAll("{\n   \n", "{\n");
1132    sjdl1.ReplaceAll("\n\n", "\n");
1133    sjdl1.ReplaceAll("OutputDirectory", "OutputDir");
1134    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1135    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
1136    index = sjdl.Index("JDLVariables");
1137    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
1138    sjdl1 += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
1139    sjdl1.Prepend(Form("Jobtag = {\n   \"comment:Merging_%s\"\n};\n", fJobTag.Data()));
1140    index = sjdl1.Index("JDLVariables");
1141    if (index >= 0) sjdl1.Insert(index, "\n# JDL variables\n");
1142    // Write jdl to file
1143    ofstream out;
1144    out.open(fJDLName.Data(), ios::out);
1145    if (out.bad()) {
1146       Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
1147       return kFALSE;
1148    }
1149    out << sjdl << endl;
1150    TString mergeJDLName = fExecutable;
1151    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1152    if (fMergeViaJDL) {
1153       ofstream out1;
1154       out1.open(mergeJDLName.Data(), ios::out);
1155       if (out.bad()) {
1156          Error("CreateJDL", "Bad file name: %s", mergeJDLName.Data());
1157          return kFALSE;
1158       }
1159       out1 << sjdl1 << endl;
1160    }   
1161
1162    // Copy jdl to grid workspace   
1163    if (!copy) {
1164       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
1165    } else {
1166       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
1167       TString locjdl1 = Form("%s/%s", fGridOutputDir.Data(),mergeJDLName.Data());
1168       if (fProductionMode) {
1169          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1170          locjdl1 = Form("%s/%s", workdir.Data(),mergeJDLName.Data());
1171       }   
1172       if (FileExists(locjdl)) gGrid->Rm(locjdl);
1173       if (FileExists(locjdl1)) gGrid->Rm(locjdl1);
1174       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
1175       TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1176       if (fMergeViaJDL) {
1177          Info("CreateJDL", "\n#####   Copying merging JDL file <%s> to your AliEn output directory", mergeJDLName.Data());
1178          TFile::Cp(Form("file:%s",mergeJDLName.Data()), Form("alien://%s", locjdl1.Data()));
1179       }   
1180    } 
1181    return kTRUE;
1182 }
1183
1184 //______________________________________________________________________________
1185 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1186 {
1187 // Returns true if file exists.
1188    if (!gGrid) return kFALSE;
1189    TGridResult *res = gGrid->Ls(lfn);
1190    if (!res) return kFALSE;
1191    TMap *map = dynamic_cast<TMap*>(res->At(0));
1192    if (!map) {
1193       delete res;
1194       return kFALSE;
1195    }   
1196    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1197    if (!objs || !objs->GetString().Length()) {
1198       delete res;
1199       return kFALSE;
1200    }
1201    delete res;   
1202    return kTRUE;
1203 }
1204
1205 //______________________________________________________________________________
1206 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1207 {
1208 // Returns true if directory exists. Can be also a path.
1209    if (!gGrid) return kFALSE;
1210    // Check if dirname is a path
1211    TString dirstripped = dirname;
1212    dirstripped = dirstripped.Strip();
1213    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1214    TString dir = gSystem->BaseName(dirstripped);
1215    dir += "/";
1216    TString path = gSystem->DirName(dirstripped);
1217    TGridResult *res = gGrid->Ls(path, "-F");
1218    if (!res) return kFALSE;
1219    TIter next(res);
1220    TMap *map;
1221    TObject *obj;
1222    while ((map=dynamic_cast<TMap*>(next()))) {
1223       obj = map->GetValue("name");
1224       if (!obj) break;
1225       if (dir == obj->GetName()) {
1226          delete res;
1227          return kTRUE;
1228       }
1229    }
1230    delete res;
1231    return kFALSE;
1232 }      
1233
1234 //______________________________________________________________________________
1235 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1236 {
1237 // Check input data type.
1238    is_collection = kFALSE;
1239    is_xml = kFALSE;
1240    use_tags = kFALSE;
1241    if (!gGrid) {
1242       Error("CheckDataType", "No connection to grid");
1243       return;
1244    }
1245    is_collection = IsCollection(lfn);
1246    TString msg = "\n#####   file: ";
1247    msg += lfn;
1248    if (is_collection) {
1249       msg += " type: raw_collection;";
1250    // special treatment for collections
1251       is_xml = kFALSE;
1252       // check for tag files in the collection
1253       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1254       if (!res) {
1255          msg += " using_tags: No (unknown)";
1256          Info("CheckDataType", msg.Data());
1257          return;
1258       }   
1259       const char* typeStr = res->GetKey(0, "origLFN");
1260       if (!typeStr || !strlen(typeStr)) {
1261          msg += " using_tags: No (unknown)";
1262          Info("CheckDataType", msg.Data());
1263          return;
1264       }   
1265       TString file = typeStr;
1266       use_tags = file.Contains(".tag");
1267       if (use_tags) msg += " using_tags: Yes";
1268       else          msg += " using_tags: No";
1269       Info("CheckDataType", msg.Data());
1270       return;
1271    }
1272    TString slfn(lfn);
1273    slfn.ToLower();
1274    is_xml = slfn.Contains(".xml");
1275    if (is_xml) {
1276    // Open xml collection and check if there are tag files inside
1277       msg += " type: xml_collection;";
1278       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1279       if (!coll) {
1280          msg += " using_tags: No (unknown)";
1281          Info("CheckDataType", msg.Data());
1282          return;
1283       }   
1284       TMap *map = coll->Next();
1285       if (!map) {
1286          msg += " using_tags: No (unknown)";
1287          Info("CheckDataType", msg.Data());
1288          return;
1289       }   
1290       map = (TMap*)map->GetValue("");
1291       TString file;
1292       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1293       use_tags = file.Contains(".tag");
1294       delete coll;
1295       if (use_tags) msg += " using_tags: Yes";
1296       else          msg += " using_tags: No";
1297       Info("CheckDataType", msg.Data());
1298       return;
1299    }
1300    use_tags = slfn.Contains(".tag");
1301    if (slfn.Contains(".root")) msg += " type: root file;";
1302    else                        msg += " type: unknown file;";
1303    if (use_tags) msg += " using_tags: Yes";
1304    else          msg += " using_tags: No";
1305    Info("CheckDataType", msg.Data());
1306 }
1307
1308 //______________________________________________________________________________
1309 void AliAnalysisAlien::EnablePackage(const char *package)
1310 {
1311 // Enables a par file supposed to exist in the current directory.
1312    TString pkg(package);
1313    pkg.ReplaceAll(".par", "");
1314    pkg += ".par";
1315    if (gSystem->AccessPathName(pkg)) {
1316       Fatal("EnablePackage", "Package %s not found", pkg.Data());
1317       return;
1318    }
1319    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1320       Info("EnablePackage", "AliEn plugin will use .par packages");
1321    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1322    if (!fPackages) {
1323       fPackages = new TObjArray();
1324       fPackages->SetOwner();
1325    }
1326    fPackages->Add(new TObjString(pkg));
1327 }      
1328
1329 //______________________________________________________________________________
1330 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1331 {
1332 // Get job status for all jobs with jobid>jobidstart.
1333    static char mstatus[20];
1334    mstatus[0] = '\0';
1335    nrunning = 0;
1336    nwaiting = 0;
1337    nerror   = 0;
1338    ndone    = 0;
1339    TGridJobStatusList *list = gGrid->Ps("");
1340    if (!list) return mstatus;
1341    Int_t nentries = list->GetSize();
1342    TGridJobStatus *status;
1343    Int_t pid;
1344    for (Int_t ijob=0; ijob<nentries; ijob++) {
1345       status = (TGridJobStatus *)list->At(ijob);
1346       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1347       if (pid<jobidstart) continue;
1348       if (pid == lastid) {
1349          gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1350       }   
1351       switch (status->GetStatus()) {
1352          case TGridJobStatus::kWAITING:
1353             nwaiting++; break;
1354          case TGridJobStatus::kRUNNING:
1355             nrunning++; break;
1356          case TGridJobStatus::kABORTED:
1357          case TGridJobStatus::kFAIL:
1358          case TGridJobStatus::kUNKNOWN:
1359             nerror++; break;
1360          case TGridJobStatus::kDONE:
1361             ndone++;
1362       }
1363    }
1364    list->Delete();
1365    delete list;
1366    return mstatus;
1367 }
1368
1369 //______________________________________________________________________________
1370 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1371 {
1372 // Returns true if file is a collection. Functionality duplicated from
1373 // TAlien::Type() because we don't want to directly depend on TAlien.
1374    if (!gGrid) {
1375       Error("IsCollection", "No connection to grid");
1376       return kFALSE;
1377    }
1378    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1379    if (!res) return kFALSE;
1380    const char* typeStr = res->GetKey(0, "type");
1381    if (!typeStr || !strlen(typeStr)) return kFALSE;
1382    if (!strcmp(typeStr, "collection")) return kTRUE;
1383    delete res;
1384    return kFALSE;
1385 }   
1386
1387 //______________________________________________________________________________
1388 Bool_t AliAnalysisAlien::IsSingleOutput() const
1389 {
1390 // Check if single-ouput option is on.
1391    return (!fOutputSingle.IsNull());
1392 }
1393    
1394 //______________________________________________________________________________
1395 void AliAnalysisAlien::Print(Option_t *) const
1396 {
1397 // Print current plugin settings.
1398    printf("### AliEn analysis plugin current settings ###\n");
1399    printf("=   Production mode:______________________________ %d\n", fProductionMode);
1400    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1401    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1402    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1403    if (fUser.Length()) 
1404    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
1405    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1406    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1407    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1408    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
1409    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
1410    if (fRunNumbers.Length()) 
1411    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1412    if (fRunRange[0])
1413    printf("=   Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1414    if (!fRunRange[0] && !fRunNumbers.Length()) {
1415       TIter next(fInputFiles);
1416       TObject *obj;
1417       TString list;
1418       while ((obj=next())) list += obj->GetName();
1419       printf("=   Input files to be processed: _________________ %s\n", list.Data());
1420    }
1421    if (TestBit(AliAnalysisGrid::kTest))
1422    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
1423    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1424    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1425    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1426    printf("=====================================================================\n");
1427    printf("=   Job price: ___________________________________ %d\n", fPrice);
1428    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
1429    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1430    if (fMaxInitFailed>0) 
1431    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1432    if (fMasterResubmitThreshold>0) 
1433    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1434    if (fNrunsPerMaster>0)
1435    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1436    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1437    printf("=   Name of the generated execution script: ______ %s\n", fExecutable.Data());
1438    printf("=   Executable command: __________________________ %s\n", fExecutableCommand.Data());
1439    if (fArguments.Length()) 
1440    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
1441    if (fExecutableArgs.Length()) 
1442    printf("=   Arguments after macro name in executable______ %s\n",fExecutableArgs.Data());
1443    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1444    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1445    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1446    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1447    if (fDatasetName)
1448    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1449    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1450    if (fIncludePath.Data())
1451    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1452    if (fCloseSE.Length())
1453    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1454    if (fFriendChainName.Length())
1455    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1456    if (fPackages) {
1457       TIter next(fPackages);
1458       TObject *obj;
1459       TString list;
1460       while ((obj=next())) list += obj->GetName();
1461       printf("=   Par files to be used: ________________________ %s\n", list.Data());
1462    }   
1463 }
1464
1465 //______________________________________________________________________________
1466 void AliAnalysisAlien::SetDefaults()
1467 {
1468 // Set default values for everything. What cannot be filled will be left empty.
1469    if (fGridJDL) delete fGridJDL;
1470    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1471    fMergingJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1472    fPrice                      = 1;
1473    fTTL                        = 30000;
1474    fSplitMaxInputFileNumber    = 100;
1475    fMaxInitFailed              = 0;
1476    fMasterResubmitThreshold    = 0;
1477    fNtestFiles                 = 10;
1478    fRunRange[0]                = 0;
1479    fRunRange[1]                = 0;
1480    fNrunsPerMaster             = 1;
1481    fMaxMergeFiles              = 100;
1482    fRunNumbers                 = "";
1483    fExecutable                 = "analysis.sh";
1484    fExecutableCommand          = "root -b -q";
1485    fArguments                  = "";
1486    fExecutableArgs             = "";
1487    fAnalysisMacro              = "myAnalysis.C";
1488    fAnalysisSource             = "";
1489    fAdditionalLibs             = "";
1490    fSplitMode                  = "se";
1491    fAPIVersion                 = "";
1492    fROOTVersion                = "";
1493    fAliROOTVersion             = "";
1494    fUser                       = "";  // Your alien user name
1495    fGridWorkingDir             = "";
1496    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
1497    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1498    fFriendChainName            = "";
1499    fGridOutputDir              = "output";
1500    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1501    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
1502    fInputFormat                = "xml-single";
1503    fJDLName                    = "analysis.jdl";
1504    fJobTag                     = "Automatically generated analysis JDL";
1505    fMergeExcludes              = "";
1506    fMergeViaJDL                = 0;
1507 }   
1508
1509 //______________________________________________________________________________
1510 Bool_t AliAnalysisAlien::MergeOutput(const char *output, const char *basedir, Int_t nmaxmerge)
1511 {
1512 // Merge all registered outputs from basedir.
1513    TString output_file = output;
1514    TString command;
1515    TString output_chunk;
1516    TString previous_chunk = "";
1517    Int_t count_chunk = 0;
1518    Int_t count_zero = nmaxmerge;
1519    Bool_t merged = kTRUE;
1520    Int_t index = output_file.Index("@");
1521    if (index > 0) output_file.Remove(index);
1522    command = Form("find %s/ *%s", basedir, output_file.Data());
1523    printf("command: %s\n", command.Data());
1524    TGridResult *res = gGrid->Command(command);
1525    if (!res) {
1526       printf("Error: No result for the find command\n");
1527       return kFALSE;
1528    }     
1529
1530    TFileMerger *fm = 0;
1531    TIter nextmap(res);
1532    TMap *map = 0;
1533    // Check if there is a merge operation to resume
1534    output_chunk = output_file;
1535    output_chunk.ReplaceAll(".root", "_*.root");
1536    // Check for existent temporary merge files
1537    if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1538       while (1) {
1539          // Skip as many input files as in a chunk
1540          for (Int_t counter=0; counter<nmaxmerge; counter++) map = (TMap*)nextmap();
1541          if (!map) {
1542             ::Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1543             delete res;
1544             return kFALSE;
1545          }
1546          output_chunk = output_file;
1547          output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1548          count_chunk++;
1549          if (gSystem->AccessPathName(output_chunk)) continue;
1550          // Merged file with chunks up to <count_chunk> found
1551          printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1552          previous_chunk = output_chunk;
1553          break;
1554       }
1555    }   
1556    count_zero = nmaxmerge;
1557    
1558    while ((map=(TMap*)nextmap())) {
1559    // Loop 'find' results and get next LFN
1560       if (count_zero == nmaxmerge) {
1561          // First file in chunk - create file merger and add previous chunk if any.
1562          fm = new TFileMerger(kFALSE);
1563          fm->SetFastMethod(kTRUE);
1564          if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1565          output_chunk = output_file;
1566          output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1567       }
1568       // If last file found, put merged results in the output file
1569       if (map == res->Last()) output_chunk = output_file;
1570       TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1571       if (!objs || !objs->GetString().Length()) {
1572          // Nothing found - skip this output
1573          delete res;
1574          delete fm;
1575          return kFALSE;
1576       } 
1577       // Add file to be merged and decrement chunk counter.
1578       fm->AddFile(objs->GetString());
1579       count_zero--;
1580       if (count_zero==0 || map == res->Last()) {            
1581          fm->OutputFile(output_chunk);
1582          if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1583          // Nothing found - skip this output
1584             ::Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1585             delete res;
1586             delete fm;
1587             return kFALSE;
1588          }
1589          // Merge the outputs, then go to next chunk      
1590          if (!fm->Merge()) {
1591             ::Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1592             delete res;
1593             delete fm;
1594             merged = kFALSE;
1595             return kFALSE;
1596          } else {
1597             ::Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1598             gSystem->Unlink(previous_chunk);
1599          }
1600          if (map == res->Last()) {
1601             delete res;
1602             delete fm;
1603             break;
1604          }      
1605          count_chunk++;
1606          count_zero = nmaxmerge;
1607          previous_chunk = output_chunk;
1608       }
1609    }
1610    return merged;
1611
1612
1613 //______________________________________________________________________________
1614 Bool_t AliAnalysisAlien::MergeOutputs()
1615 {
1616 // Merge analysis outputs existing in the AliEn space.
1617    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1618    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1619    if (!Connect()) {
1620       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1621       return kFALSE;
1622    }
1623    if (fMergeViaJDL) {
1624       if (!TestBit(AliAnalysisGrid::kMerge)) {
1625          Info("MergeOutputs", "### Re-run with <MergeViaJDL> option in terminate mode of the plugin to submit merging jobs ###");
1626          return kFALSE; 
1627       }     
1628       if (fProductionMode) {
1629          Info("MergeOutputs", "### Merging will be submitted by LPM manager... ###");
1630          return kFALSE;
1631       }
1632       Info("MergeOutputs", "Submitting merging JDL");
1633       SubmitMerging();
1634       Info("MergeOutputs", "### Re-run with <MergeViaJDL> off to collect results after merging jobs are done ###");
1635       Info("MergeOutputs", "### The Terminate() method is executed by the merging jobs");
1636       return kFALSE;
1637    }   
1638    // Get the output path
1639    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1640    if (!DirectoryExists(fGridOutputDir)) {
1641       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1642       return kFALSE;
1643    }
1644    if (!fOutputFiles.Length()) {
1645       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1646       return kFALSE;
1647    }
1648    // Check if fast read option was requested
1649    if (fFastReadOption) {
1650       Warning("MergeOutputs", "You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !");
1651       gEnv->SetValue("XNet.ConnectTimeout",5);
1652       gEnv->SetValue("XNet.RequestTimeout",5);
1653       gEnv->SetValue("XNet.MaxRedirectCount",2);
1654       gEnv->SetValue("XNet.ReconnectTimeout",5);
1655       gEnv->SetValue("XNet.FirstConnectMaxCnt",1);
1656    }   
1657    TObjArray *list = fOutputFiles.Tokenize(" ");
1658    TIter next(list);
1659    TObjString *str;
1660    TString output_file;
1661    Bool_t merged = kTRUE;
1662    while((str=(TObjString*)next())) {
1663       output_file = str->GetString();
1664       Int_t index = output_file.Index("@");
1665       if (index > 0) output_file.Remove(index);
1666       // Skip already merged outputs
1667       if (!gSystem->AccessPathName(output_file)) {
1668          Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1669          continue;
1670       }   
1671       if (fMergeExcludes.Length() &&
1672           fMergeExcludes.Contains(output_file.Data())) continue;
1673       // Perform a 'find' command in the output directory, looking for registered outputs    
1674       merged = MergeOutput(output_file, fGridOutputDir, fMaxMergeFiles);
1675       if (!merged) {
1676          Error("MergeOutputs", "Terminate() will  NOT be executed");
1677          return kFALSE;
1678       }   
1679    } 
1680    return kTRUE;
1681 }   
1682
1683 //______________________________________________________________________________
1684 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1685 {
1686 // Use the output files connected to output containers from the analysis manager
1687 // rather than the files defined by SetOutputFiles
1688    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1689       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1690       analysis manager");
1691    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1692 }
1693       
1694 //______________________________________________________________________________
1695 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1696 {
1697 // Start remote grid analysis.
1698    
1699    // Check if output files have to be taken from the analysis manager
1700    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1701       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1702       if (!mgr || !mgr->IsInitialized()) {
1703          Error("StartAnalysis", "You need an initialized analysis manager for this");
1704          return kFALSE;
1705       }
1706       fOutputFiles = "";
1707       TIter next(mgr->GetOutputs());
1708       AliAnalysisDataContainer *output;
1709       while ((output=(AliAnalysisDataContainer*)next())) {
1710          const char *filename = output->GetFileName();
1711          if (!(strcmp(filename, "default"))) {
1712             if (!mgr->GetOutputEventHandler()) continue;
1713             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1714          }
1715          if (fOutputFiles.Contains(filename)) continue;
1716          if (fOutputFiles.Length()) fOutputFiles += " ";
1717          fOutputFiles += filename;
1718       }
1719       // Add extra files registered to the analysis manager
1720       if (mgr->GetExtraFiles().Length()) {
1721          if (fOutputFiles.Length()) fOutputFiles += " ";
1722          fOutputFiles += mgr->GetExtraFiles();
1723       }
1724    }
1725 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1726    if (TestBit(AliAnalysisGrid::kOffline)) {
1727       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1728       \n                         there nor any job run. You can revise the JDL and analysis \
1729       \n                         macro then run the same in \"submit\" mode.");
1730    } else if (TestBit(AliAnalysisGrid::kTest)) {
1731       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1732       \n                         dataset.");
1733    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1734       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1735       \n                         space and job submitted.");
1736    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1737       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1738       if (fMergeViaJDL) CheckInputData();
1739       return kTRUE;
1740    } else {
1741       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1742    }   
1743       
1744    if (!Connect()) {
1745       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1746       return kFALSE;
1747    }
1748    Print();   
1749    if (!CheckInputData()) {
1750       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1751       return kFALSE;
1752    }   
1753    CreateDataset(fDataPattern);
1754    WriteAnalysisFile();   
1755    WriteAnalysisMacro();
1756    WriteExecutable();
1757    WriteValidationScript();
1758    if (fMergeViaJDL) {
1759       WriteMergingMacro();
1760       WriteMergeExecutable();
1761       WriteValidationScript(kTRUE);
1762    }   
1763    if (!CreateJDL()) return kFALSE;
1764    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1765    if (TestBit(AliAnalysisGrid::kTest)) {
1766       // Locally testing the analysis
1767       Info("StartAnalysis", "\n_______________________________________________________________________ \
1768       \n   Running analysis script in a daughter shell as on a worker node \
1769       \n_______________________________________________________________________");
1770       TObjArray *list = fOutputFiles.Tokenize(" ");
1771       TIter next(list);
1772       TObjString *str;
1773       TString output_file;
1774       while((str=(TObjString*)next())) {
1775          output_file = str->GetString();
1776          Int_t index = output_file.Index("@");
1777          if (index > 0) output_file.Remove(index);         
1778          if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1779       }
1780       delete list;
1781       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1782       TString validationScript = fExecutable;
1783       validationScript.ReplaceAll(".sh", "_validation.sh");
1784       gSystem->Exec(Form("bash %s",validationScript.Data()));
1785 //      gSystem->Exec("cat stdout");
1786       return kFALSE;
1787    }
1788    // Check if submitting is managed by LPM manager
1789    if (fProductionMode) {
1790       TString prodfile = fJDLName;
1791       prodfile.ReplaceAll(".jdl", ".prod");
1792       WriteProductionFile(prodfile);
1793       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1794       return kFALSE;
1795    }   
1796    // Submit AliEn job(s)
1797    gGrid->Cd(fGridOutputDir);
1798    TGridResult *res;
1799    TString jobID = "";
1800    if (!fRunNumbers.Length() && !fRunRange[0]) {
1801       // Submit a given xml or a set of runs
1802       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1803       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1804       if (res) {
1805          const char *cjobId = res->GetKey(0,"jobId");
1806          if (!cjobId) {
1807             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1808             return kFALSE;
1809          } else {
1810             Info("StartAnalysis", "\n_______________________________________________________________________ \
1811             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1812             \n_______________________________________________________________________",
1813                    fJDLName.Data(), cjobId);
1814             jobID = cjobId;      
1815          }          
1816          delete res;
1817       }   
1818    } else {
1819       // Submit for a range of enumeration of runs.
1820       Submit();
1821    }   
1822          
1823    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1824    \n You may exit at any time and terminate the job later using the option <terminate> \
1825    \n ##################################################################################", jobID.Data());
1826    gSystem->Exec("aliensh");
1827    return kTRUE;
1828 }
1829
1830 //______________________________________________________________________________
1831 void AliAnalysisAlien::Submit()
1832 {
1833 // Submit all master jobs.
1834    Int_t nmasterjobs = fInputFiles->GetEntries();
1835    Long_t tshoot = gSystem->Now();
1836    if (!fNsubmitted) SubmitNext();
1837    while (fNsubmitted < nmasterjobs) {
1838       Long_t now = gSystem->Now();
1839       if ((now-tshoot)>30000) {
1840          tshoot = now;
1841          SubmitNext();
1842       }   
1843    }
1844 }
1845
1846 //______________________________________________________________________________
1847 void AliAnalysisAlien::SubmitMerging()
1848 {
1849 // Submit all merging jobs.
1850    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1851    gGrid->Cd(fGridOutputDir);
1852    TString mergeJDLName = fExecutable;
1853    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
1854    Int_t ntosubmit = fInputFiles->GetEntries();
1855    printf("### Submitting %d merging jobs...\n", ntosubmit);
1856    for (Int_t i=0; i<ntosubmit; i++) {
1857       TString query;
1858       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
1859       runOutDir.ReplaceAll(".xml", "");
1860       if (fOutputToRunNo)
1861          query = Form("submit %s %s", mergeJDLName.Data(), runOutDir.Data());
1862       else
1863          query = Form("submit %s %03d", mergeJDLName.Data(), i);
1864       printf("********* %s\n",query.Data());
1865       TGridResult *res = gGrid->Command(query);
1866       if (res) {
1867          const char *cjobId = res->GetKey(0,"jobId");
1868          if (!cjobId) {
1869             Error("StartAnalysis", "Your JDL %s could not be submitted", mergeJDLName.Data());
1870             return;
1871          } else {
1872             Info("StartAnalysis", "\n_______________________________________________________________________ \
1873             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1874             \n_______________________________________________________________________",
1875                    mergeJDLName.Data(), cjobId);
1876          }
1877          delete res;
1878       }             
1879    }
1880    if (!ntosubmit) return;
1881    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
1882    \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
1883    \n ##################################################################################");
1884    gSystem->Exec("aliensh");
1885 }
1886
1887 //______________________________________________________________________________
1888 void AliAnalysisAlien::SubmitNext()
1889 {
1890 // Submit next bunch of master jobs if the queue is free.
1891    static Bool_t iscalled = kFALSE;
1892    static Int_t firstmaster = 0;
1893    static Int_t lastmaster = 0;
1894    static Int_t npermaster  = 0;
1895    if (iscalled) return;
1896    iscalled = kTRUE;
1897    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1898    Int_t ntosubmit = 0;
1899    TGridResult *res;
1900    TString jobID = "";
1901    if (!fNsubmitted) ntosubmit = 1;
1902    else {
1903       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1904       printf("=== master %d: %s\n", lastmaster, status.Data());
1905       // If last master not split, just return
1906       if (status != "SPLIT") {iscalled = kFALSE; return;}
1907       // No more than 100 waiting jobs
1908       if (nwaiting>100) {iscalled = kFALSE; return;}
1909       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
1910       if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1911       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
1912              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1913    }
1914    Int_t nmasterjobs = fInputFiles->GetEntries();
1915    for (Int_t i=0; i<ntosubmit; i++) {
1916       // Submit for a range of enumeration of runs.
1917       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1918       TString query;
1919       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
1920       runOutDir.ReplaceAll(".xml", "");
1921       if (fOutputToRunNo)
1922          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
1923       else
1924          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1925       printf("********* %s\n",query.Data());
1926       res = gGrid->Command(query);
1927       if (res) {
1928          TString cjobId1 = res->GetKey(0,"jobId");
1929          if (!cjobId1.Length()) {
1930             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1931             iscalled = kFALSE;
1932             return;
1933          } else {
1934             Info("StartAnalysis", "\n_______________________________________________________________________ \
1935             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1936             \n_______________________________________________________________________",
1937                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1938             jobID += cjobId1;
1939             jobID += " ";
1940             lastmaster = cjobId1.Atoi();
1941             if (!firstmaster) firstmaster = lastmaster;
1942             fNsubmitted++;
1943          }          
1944          delete res;
1945       }   
1946    }
1947    iscalled = kFALSE;
1948 }
1949
1950 //______________________________________________________________________________
1951 void AliAnalysisAlien::WriteAnalysisFile()
1952 {
1953 // Write current analysis manager into the file <analysisFile>
1954    TString analysisFile = fExecutable;
1955    analysisFile.ReplaceAll(".sh", ".root");
1956    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1957       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1958       if (!mgr || !mgr->IsInitialized()) {
1959          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1960          return;
1961       }
1962       // Check analysis type
1963       TObject *handler;
1964       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1965       handler = (TObject*)mgr->GetInputEventHandler();
1966       if (handler) {
1967          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1968          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1969       }
1970       TDirectory *cdir = gDirectory;
1971       TFile *file = TFile::Open(analysisFile, "RECREATE");
1972       if (file) {
1973          // Skip task Terminate calls for the grid job
1974          mgr->SetSkipTerminate(kTRUE);
1975          // Unless merging makes no sense
1976          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
1977          mgr->Write();
1978          delete file;
1979          // Enable termination for local jobs
1980          mgr->SetSkipTerminate(kFALSE);
1981       }
1982       if (cdir) cdir->cd();
1983       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1984    }   
1985    Bool_t copy = kTRUE;
1986    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1987    if (copy) {
1988       CdWork();
1989       TString workdir = gGrid->GetHomeDirectory();
1990       workdir += fGridWorkingDir;
1991       Info("CreateJDL", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1992       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1993       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1994    }   
1995 }
1996
1997 //______________________________________________________________________________
1998 void AliAnalysisAlien::WriteAnalysisMacro()
1999 {
2000 // Write the analysis macro that will steer the analysis in grid mode.
2001    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2002       ofstream out;
2003       out.open(fAnalysisMacro.Data(), ios::out);
2004       if (!out.good()) {
2005          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2006          return;
2007       }
2008       Bool_t hasSTEERBase = kFALSE;
2009       Bool_t hasESD = kFALSE;
2010       Bool_t hasAOD = kFALSE;
2011       Bool_t hasANALYSIS = kFALSE;
2012       Bool_t hasANALYSISalice = kFALSE;
2013       Bool_t hasCORRFW = kFALSE;
2014       TString func = fAnalysisMacro;
2015       TString type = "ESD";
2016       TString comment = "// Analysis using ";
2017       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2018       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2019          type = "AOD";
2020          comment += "AOD";
2021       }   
2022       if (type!="AOD" && fFriendChainName!="") {
2023          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2024          return;
2025       }
2026       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2027       else comment += " data";
2028       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2029       func.ReplaceAll(".C", "");
2030       out << "void " << func.Data() << "()" << endl; 
2031       out << "{" << endl;
2032       out << comment.Data() << endl;
2033       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
2034       out << "   TStopwatch timer;" << endl;
2035       out << "   timer.Start();" << endl << endl;
2036       out << "// load base root libraries" << endl;
2037       out << "   gSystem->Load(\"libTree\");" << endl;
2038       out << "   gSystem->Load(\"libGeom\");" << endl;
2039       out << "   gSystem->Load(\"libVMC\");" << endl;
2040       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
2041       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
2042       if (fAdditionalRootLibs.Length()) {
2043          // in principle libtree /lib geom libvmc etc. can go into this list, too
2044          out << "// Add aditional libraries" << endl;
2045          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2046          TIter next(list);
2047          TObjString *str;
2048          while((str=(TObjString*)next())) {
2049             if (str->GetString().Contains(".so"))
2050             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2051          }
2052          if (list) delete list;
2053       }
2054       out << "// include path" << endl;
2055       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2056       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2057       out << "// Load analysis framework libraries" << endl;
2058       if (!fPackages) {
2059          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2060          out << "   gSystem->Load(\"libESD\");" << endl;
2061          out << "   gSystem->Load(\"libAOD\");" << endl;
2062          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2063          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2064          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2065       } else {
2066          TIter next(fPackages);
2067          TObject *obj;
2068          TString pkgname;
2069          TString setupPar = "AliAnalysisAlien::SetupPar";
2070          while ((obj=next())) {
2071             pkgname = obj->GetName();
2072             if (pkgname == "STEERBase" ||
2073                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2074             if (pkgname == "ESD" ||
2075                 pkgname == "ESD.par")       hasESD = kTRUE;
2076             if (pkgname == "AOD" ||
2077                 pkgname == "AOD.par")       hasAOD = kTRUE;
2078             if (pkgname == "ANALYSIS" ||
2079                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
2080             if (pkgname == "ANALYSISalice" ||
2081                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2082             if (pkgname == "CORRFW" ||
2083                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
2084          }
2085          if (hasANALYSISalice) setupPar = "SetupPar";   
2086          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2087          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2088          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
2089          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
2090          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
2091          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
2092          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2093          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2094          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2095          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2096          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2097          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2098          out << "// Compile other par packages" << endl;
2099          next.Reset();
2100          while ((obj=next())) {
2101             pkgname = obj->GetName();
2102             if (pkgname == "STEERBase" ||
2103                 pkgname == "STEERBase.par" ||
2104                 pkgname == "ESD" ||
2105                 pkgname == "ESD.par" ||
2106                 pkgname == "AOD" ||
2107                 pkgname == "AOD.par" ||
2108                 pkgname == "ANALYSIS" ||
2109                 pkgname == "ANALYSIS.par" ||
2110                 pkgname == "ANALYSISalice" ||
2111                 pkgname == "ANALYSISalice.par" ||
2112                 pkgname == "CORRFW" ||
2113                 pkgname == "CORRFW.par") continue;
2114             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2115          }   
2116       }   
2117       if (fAdditionalLibs.Length()) {
2118          out << "// Add aditional AliRoot libraries" << endl;
2119          TObjArray *list = fAdditionalLibs.Tokenize(" ");
2120          TIter next(list);
2121          TObjString *str;
2122          while((str=(TObjString*)next())) {
2123             if (str->GetString().Contains(".so"))
2124                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2125          }
2126          if (list) delete list;
2127       }
2128       out << endl;
2129       out << "// analysis source to be compiled at runtime (if any)" << endl;
2130       if (fAnalysisSource.Length()) {
2131          TObjArray *list = fAnalysisSource.Tokenize(" ");
2132          TIter next(list);
2133          TObjString *str;
2134          while((str=(TObjString*)next())) {
2135             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2136          }   
2137          if (list) delete list;
2138       }
2139       out << endl;
2140       if (fFastReadOption) {
2141          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 !!!");
2142          out << "// fast xrootd reading enabled" << endl;
2143          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2144          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",5);" << endl;
2145          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",5);" << endl;
2146          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2147          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",5);" << endl;
2148          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2149       }   
2150       out << "// connect to AliEn and make the chain" << endl;
2151       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
2152       if (IsUsingTags()) {
2153          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
2154       } else {
2155          if(fFriendChainName!="AliAOD.VertexingHF.root") {
2156             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;    
2157          } else {
2158             out << "   // Check if the macro to create the chain was provided" << endl;
2159             out << "   if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
2160             out << "      ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
2161             out << "      return;" << endl;
2162             out << "   }" << endl;
2163             out << "   gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
2164             out << "   TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
2165          }  
2166       }   
2167       out << "// read the analysis manager from file" << endl;
2168       TString analysisFile = fExecutable;
2169       analysisFile.ReplaceAll(".sh", ".root");
2170       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
2171       out << "   if (!file) return;" << endl; 
2172       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
2173       out << "   AliAnalysisManager *mgr = 0;" << endl;
2174       out << "   TKey *key;" << endl;
2175       out << "   while ((key=(TKey*)nextkey())) {" << endl;
2176       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2177       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2178       out << "   };" << endl;
2179       out << "   if (!mgr) {" << endl;
2180       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2181       out << "      return;" << endl;
2182       out << "   }" << endl << endl;
2183       out << "   mgr->PrintStatus();" << endl;
2184       if (AliAnalysisManager::GetAnalysisManager()) {
2185          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
2186             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2187          } else {
2188             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2189          }
2190       }   
2191       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
2192       out << "   timer.Stop();" << endl;
2193       out << "   timer.Print();" << endl;
2194       out << "}" << endl << endl;
2195       if (IsUsingTags()) {
2196          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
2197          out << "{" << endl;
2198          out << "// Create a chain using tags from the xml file." << endl;
2199          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
2200          out << "   if (!coll) {" << endl;
2201          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2202          out << "      return NULL;" << endl;
2203          out << "   }" << endl;
2204          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
2205          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
2206          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
2207          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
2208          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
2209          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
2210          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
2211          out << "   // Check if the cuts configuration file was provided" << endl;
2212          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
2213          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
2214          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2215          out << "   }" << endl;
2216          if (fFriendChainName=="") {
2217             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2218          } else {
2219             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
2220             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
2221             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
2222          }
2223          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
2224          out << "   chain->ls();" << endl;
2225          out << "   return chain;" << endl;
2226          out << "}" << endl << endl;
2227          if (gSystem->AccessPathName("ConfigureCuts.C")) {
2228             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
2229             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
2230             msg += "                      AliLHCTagCuts *lhcCuts,\n";
2231             msg += "                      AliDetectorTagCuts *detCuts,\n";
2232             msg += "                      AliEventTagCuts *evCuts)";
2233             Info("WriteAnalysisMacro", msg.Data());
2234          }
2235       } 
2236       if (!IsUsingTags() || fFriendChainName!="") {
2237          out <<"//________________________________________________________________________________" << endl;
2238          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
2239          out << "{" << endl;
2240          out << "// Create a chain using url's from xml file" << endl;
2241          out << "   TString treename = type;" << endl;
2242          out << "   treename.ToLower();" << endl;
2243          out << "   treename += \"Tree\";" << endl;
2244          out << "   printf(\"***************************************\\n\");" << endl;
2245          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
2246          out << "   printf(\"***************************************\\n\");" << endl;
2247          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2248          out << "   if (!coll) {" << endl;
2249          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2250          out << "      return NULL;" << endl;
2251          out << "   }" << endl;
2252          out << "   TChain *chain = new TChain(treename);" << endl;
2253          if(fFriendChainName!="") {
2254             out << "   TChain *chainFriend = new TChain(treename);" << endl;
2255          }
2256          out << "   coll->Reset();" << endl;
2257          out << "   while (coll->Next()) {" << endl;
2258          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
2259          if(fFriendChainName!="") {
2260             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
2261             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2262             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2263             out << "      chainFriend->Add(fileFriend.Data());" << endl;
2264          }
2265          out << "   }" << endl;
2266          out << "   if (!chain->GetNtrees()) {" << endl;
2267          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2268          out << "      return NULL;" << endl;
2269          out << "   }" << endl;
2270          if(fFriendChainName!="") {
2271             out << "   chain->AddFriend(chainFriend);" << endl;
2272          }
2273          out << "   return chain;" << endl;
2274          out << "}" << endl << endl;
2275       }   
2276       if (hasANALYSISalice) {
2277          out <<"//________________________________________________________________________________" << endl;
2278          out << "Bool_t SetupPar(const char *package) {" << endl;
2279          out << "// Compile the package and set it up." << endl;
2280          out << "   TString pkgdir = package;" << endl;
2281          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2282          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2283          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2284          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2285          out << "   // Check for BUILD.sh and execute" << endl;
2286          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2287          out << "      printf(\"*******************************\\n\");" << endl;
2288          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2289          out << "      printf(\"*******************************\\n\");" << endl;
2290          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2291          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2292          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2293          out << "         return kFALSE;" << endl;
2294          out << "      }" << endl;
2295          out << "   } else {" << endl;
2296          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2297          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2298          out << "      return kFALSE;" << endl;
2299          out << "   }" << endl;
2300          out << "   // Check for SETUP.C and execute" << endl;
2301          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2302          out << "      printf(\"*******************************\\n\");" << endl;
2303          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2304          out << "      printf(\"*******************************\\n\");" << endl;
2305          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2306          out << "   } else {" << endl;
2307          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2308          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2309          out << "      return kFALSE;" << endl;
2310          out << "   }" << endl;
2311          out << "   // Restore original workdir" << endl;
2312          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2313          out << "   return kTRUE;" << endl;
2314          out << "}" << endl;
2315       }
2316       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2317    }   
2318    Bool_t copy = kTRUE;
2319    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2320    if (copy) {
2321       CdWork();
2322       TString workdir = gGrid->GetHomeDirectory();
2323       workdir += fGridWorkingDir;
2324       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2325       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2326          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2327          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2328          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2329       }   
2330       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2331       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2332    }
2333 }
2334
2335 //______________________________________________________________________________
2336 void AliAnalysisAlien::WriteMergingMacro()
2337 {
2338 // Write a macro to merge the outputs per master job.
2339    if (!fMergeViaJDL) return;
2340    if (!fOutputFiles.Length()) {
2341       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2342       return;
2343    }   
2344    TString mergingMacro = fExecutable;
2345    mergingMacro.ReplaceAll(".sh","_merge.C");
2346    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2347    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2348       ofstream out;
2349       out.open(mergingMacro.Data(), ios::out);
2350       if (!out.good()) {
2351          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2352          return;
2353       }
2354       Bool_t hasSTEERBase = kFALSE;
2355       Bool_t hasESD = kFALSE;
2356       Bool_t hasAOD = kFALSE;
2357       Bool_t hasANALYSIS = kFALSE;
2358       Bool_t hasANALYSISalice = kFALSE;
2359       Bool_t hasCORRFW = kFALSE;
2360       TString func = mergingMacro;
2361       TString comment;
2362       func.ReplaceAll(".C", "");
2363       out << "void " << func.Data() << "(const char *dir)" << endl;
2364       out << "{" << endl;
2365       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
2366       out << "   TStopwatch timer;" << endl;
2367       out << "   timer.Start();" << endl << endl;
2368       out << "// load base root libraries" << endl;
2369       out << "   gSystem->Load(\"libTree\");" << endl;
2370       out << "   gSystem->Load(\"libGeom\");" << endl;
2371       out << "   gSystem->Load(\"libVMC\");" << endl;
2372       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
2373       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
2374       if (fAdditionalRootLibs.Length()) {
2375          // in principle libtree /lib geom libvmc etc. can go into this list, too
2376          out << "// Add aditional libraries" << endl;
2377          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2378          TIter next(list);
2379          TObjString *str;
2380          while((str=(TObjString*)next())) {
2381             if (str->GetString().Contains(".so"))
2382             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2383          }
2384          if (list) delete list;
2385       }
2386       out << "// include path" << endl;
2387       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2388       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2389       out << "// Load analysis framework libraries" << endl;
2390       if (!fPackages) {
2391          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2392          out << "   gSystem->Load(\"libESD\");" << endl;
2393          out << "   gSystem->Load(\"libAOD\");" << endl;
2394          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2395          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2396          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2397       } else {
2398          TIter next(fPackages);
2399          TObject *obj;
2400          TString pkgname;
2401          TString setupPar = "AliAnalysisAlien::SetupPar";
2402          while ((obj=next())) {
2403             pkgname = obj->GetName();
2404             if (pkgname == "STEERBase" ||
2405                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2406             if (pkgname == "ESD" ||
2407                 pkgname == "ESD.par")       hasESD = kTRUE;
2408             if (pkgname == "AOD" ||
2409                 pkgname == "AOD.par")       hasAOD = kTRUE;
2410             if (pkgname == "ANALYSIS" ||
2411                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
2412             if (pkgname == "ANALYSISalice" ||
2413                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2414             if (pkgname == "CORRFW" ||
2415                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
2416          }   
2417          if (hasANALYSISalice) setupPar = "SetupPar";   
2418          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2419          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2420          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
2421          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
2422          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
2423          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
2424          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2425          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2426          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2427          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2428          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2429          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2430          out << "// Compile other par packages" << endl;
2431          next.Reset();
2432          while ((obj=next())) {
2433             pkgname = obj->GetName();
2434             if (pkgname == "STEERBase" ||
2435                 pkgname == "STEERBase.par" ||
2436                 pkgname == "ESD" ||
2437                 pkgname == "ESD.par" ||
2438                 pkgname == "AOD" ||
2439                 pkgname == "AOD.par" ||
2440                 pkgname == "ANALYSIS" ||
2441                 pkgname == "ANALYSIS.par" ||
2442                 pkgname == "ANALYSISalice" ||
2443                 pkgname == "ANALYSISalice.par" ||
2444                 pkgname == "CORRFW" ||
2445                 pkgname == "CORRFW.par") continue;
2446             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2447          }   
2448       }   
2449       if (fAdditionalLibs.Length()) {
2450          out << "// Add aditional AliRoot libraries" << endl;
2451          TObjArray *list = fAdditionalLibs.Tokenize(" ");
2452          TIter next(list);
2453          TObjString *str;
2454          while((str=(TObjString*)next())) {
2455             if (str->GetString().Contains(".so"))
2456                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2457          }
2458          if (list) delete list;
2459       }
2460       out << endl;
2461       out << "// Analysis source to be compiled at runtime (if any)" << endl;
2462       if (fAnalysisSource.Length()) {
2463          TObjArray *list = fAnalysisSource.Tokenize(" ");
2464          TIter next(list);
2465          TObjString *str;
2466          while((str=(TObjString*)next())) {
2467             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2468          }   
2469          if (list) delete list;
2470       }
2471       out << endl;
2472       if (fFastReadOption) {
2473          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 !!!");
2474          out << "// fast xrootd reading enabled" << endl;
2475          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2476          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",5);" << endl;
2477          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",5);" << endl;
2478          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2479          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",5);" << endl;
2480          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2481       }   
2482       out << "// Connect to AliEn" << endl;
2483       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
2484       out << "   TString outputDir = \"" << fGridOutputDir << "/\";" << endl;  
2485       out << "   outputDir += dir;" << endl;    
2486       out << "   TString outputFiles = \"" << fOutputFiles << "\";" << endl;
2487       out << "   TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
2488       out << "   TObjArray *list = outputFiles.Tokenize(\" \");" << endl;
2489       out << "   TIter *iter = new TIter(list);" << endl;
2490       out << "   TObjString *str;" << endl;
2491       out << "   TString output_file;" << endl;
2492       out << "   Bool_t merged = kTRUE;" << endl;
2493       out << "   while((str=(TObjString*)iter->Next())) {" << endl;
2494       out << "      output_file = str->GetString();" << endl;
2495       out << "      Int_t index = output_file.Index(\"@\");" << endl;
2496       out << "      if (index > 0) output_file.Remove(index);" << endl;
2497       out << "      // Skip already merged outputs" << endl;
2498       out << "      if (!gSystem->AccessPathName(output_file)) {" << endl;
2499       out << "         printf(\"Output file <%s> found. Not merging again.\",output_file.Data());" << endl;
2500       out << "         continue;" << endl;
2501       out << "      }" << endl;
2502       out << "      if (mergeExcludes.Contains(output_file.Data())) continue;" << endl;
2503       out << "      merged = AliAnalysisAlien::MergeOutput(output_file, outputDir, " << fMaxMergeFiles << ");" << endl;
2504       out << "      if (!merged) {" << endl;
2505       out << "         printf(\"ERROR: Cannot merge %s\\n\", output_file.Data());" << endl;
2506       out << "         return;" << endl;
2507       out << "      }" << endl;
2508       out << "   }" << endl;
2509       out << "// read the analysis manager from file" << endl;
2510       TString analysisFile = fExecutable;
2511       analysisFile.ReplaceAll(".sh", ".root");
2512       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
2513       out << "   if (!file) return;" << endl; 
2514       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
2515       out << "   AliAnalysisManager *mgr = 0;" << endl;
2516       out << "   TKey *key;" << endl;
2517       out << "   while ((key=(TKey*)nextkey())) {" << endl;
2518       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2519       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2520       out << "   };" << endl;
2521       out << "   if (!mgr) {" << endl;
2522       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2523       out << "      return;" << endl;
2524       out << "   }" << endl << endl;
2525       out << "   mgr->SetSkipTerminate(kFALSE);" << endl;
2526       out << "   mgr->PrintStatus();" << endl;
2527       if (AliAnalysisManager::GetAnalysisManager()) {
2528          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
2529             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2530          } else {
2531             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2532          }
2533       }   
2534       out << "   mgr->StartAnalysis(\"gridterminate\");" << endl;
2535       out << "}" << endl << endl;
2536       if (hasANALYSISalice) {
2537          out <<"//________________________________________________________________________________" << endl;
2538          out << "Bool_t SetupPar(const char *package) {" << endl;
2539          out << "// Compile the package and set it up." << endl;
2540          out << "   TString pkgdir = package;" << endl;
2541          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2542          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2543          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2544          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2545          out << "   // Check for BUILD.sh and execute" << endl;
2546          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2547          out << "      printf(\"*******************************\\n\");" << endl;
2548          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2549          out << "      printf(\"*******************************\\n\");" << endl;
2550          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2551          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2552          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2553          out << "         return kFALSE;" << endl;
2554          out << "      }" << endl;
2555          out << "   } else {" << endl;
2556          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2557          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2558          out << "      return kFALSE;" << endl;
2559          out << "   }" << endl;
2560          out << "   // Check for SETUP.C and execute" << endl;
2561          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2562          out << "      printf(\"*******************************\\n\");" << endl;
2563          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2564          out << "      printf(\"*******************************\\n\");" << endl;
2565          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2566          out << "   } else {" << endl;
2567          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2568          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2569          out << "      return kFALSE;" << endl;
2570          out << "   }" << endl;
2571          out << "   // Restore original workdir" << endl;
2572          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2573          out << "   return kTRUE;" << endl;
2574          out << "}" << endl;
2575       }
2576    }   
2577    Bool_t copy = kTRUE;
2578    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2579    if (copy) {
2580       CdWork();
2581       TString workdir = gGrid->GetHomeDirectory();
2582       workdir += fGridWorkingDir;
2583       if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
2584       Info("WriteMergingMacro", "\n#####   Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
2585       TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
2586    }
2587 }
2588
2589 //______________________________________________________________________________
2590 Bool_t AliAnalysisAlien::SetupPar(const char *package)
2591 {
2592 // Compile the par file archive pointed by <package>. This must be present in the current durectory.
2593 // Note that for loading the compiled library. The current directory should have precedence in
2594 // LD_LIBRARY_PATH
2595    TString pkgdir = package;
2596    pkgdir.ReplaceAll(".par","");
2597    gSystem->Exec(Form("tar xvzf %s.par", pkgdir.Data()));
2598    TString cdir = gSystem->WorkingDirectory();
2599    gSystem->ChangeDirectory(pkgdir);
2600    // Check for BUILD.sh and execute
2601    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
2602       printf("**************************************************\n");
2603       printf("*** Building PAR archive %s\n", package);
2604       printf("**************************************************\n");
2605       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
2606          ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
2607          gSystem->ChangeDirectory(cdir);
2608          return kFALSE;
2609       }
2610    } else {
2611       ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
2612       gSystem->ChangeDirectory(cdir);
2613       return kFALSE;
2614    }
2615    // Check for SETUP.C and execute
2616    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
2617       printf("**************************************************\n");
2618       printf("*** Setup PAR archive %s\n", package);
2619       printf("**************************************************\n");
2620       gROOT->Macro("PROOF-INF/SETUP.C");
2621       printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
2622    } else {
2623       ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
2624       gSystem->ChangeDirectory(cdir);
2625       return kFALSE;
2626    }   
2627    // Restore original workdir
2628    gSystem->ChangeDirectory(cdir);
2629    return kTRUE;
2630 }
2631
2632 //______________________________________________________________________________
2633 void AliAnalysisAlien::WriteExecutable()
2634 {
2635 // Generate the alien executable script.
2636    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2637       ofstream out;
2638       out.open(fExecutable.Data(), ios::out);
2639       if (out.bad()) {
2640          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2641          return;
2642       }
2643       out << "#!/bin/bash" << endl;
2644       out << "echo \"=========================================\"" << endl; 
2645       out << "echo \"############## PATH : ##############\"" << endl;
2646       out << "echo $PATH" << endl;
2647       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2648       out << "echo $LD_LIBRARY_PATH" << endl;
2649       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2650       out << "echo $ROOTSYS" << endl;
2651       out << "echo \"############## which root : ##############\"" << endl;
2652       out << "which root" << endl;
2653       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2654       out << "echo $ALICE_ROOT" << endl;
2655       out << "echo \"############## which aliroot : ##############\"" << endl;
2656       out << "which aliroot" << endl;
2657       out << "echo \"############## system limits : ##############\"" << endl;
2658       out << "ulimit -a" << endl;
2659       out << "echo \"############## memory : ##############\"" << endl;
2660       out << "free -m" << endl;
2661       out << "echo \"=========================================\"" << endl << endl;
2662       // Make sure we can properly compile par files
2663       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2664       out << fExecutableCommand << " "; 
2665       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2666       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2667       out << "echo \"############## memory after: ##############\"" << endl;
2668       out << "free -m" << endl;
2669       out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2670       out << "dmesg | tail -n 10" << endl;
2671    }   
2672    Bool_t copy = kTRUE;
2673    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2674    if (copy) {
2675       CdWork();
2676       TString workdir = gGrid->GetHomeDirectory();
2677       TString bindir = Form("%s/bin", workdir.Data());
2678       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2679       workdir += fGridWorkingDir;
2680       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2681       if (FileExists(executable)) gGrid->Rm(executable);
2682       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2683       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2684    } 
2685 }
2686
2687 //______________________________________________________________________________
2688 void AliAnalysisAlien::WriteMergeExecutable()
2689 {
2690 // Generate the alien executable script for the merging job.
2691    if (!fMergeViaJDL) return;
2692    TString mergeExec = fExecutable;
2693    mergeExec.ReplaceAll(".sh", "_merge.sh");
2694    if (!TestBit(AliAnalysisGrid::kSubmit)) {
2695       ofstream out;
2696       out.open(mergeExec.Data(), ios::out);
2697       if (out.bad()) {
2698          Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
2699          return;
2700       }
2701       out << "#!/bin/bash" << endl;
2702       out << "echo \"=========================================\"" << endl; 
2703       out << "echo \"############## PATH : ##############\"" << endl;
2704       out << "echo $PATH" << endl;
2705       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2706       out << "echo $LD_LIBRARY_PATH" << endl;
2707       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2708       out << "echo $ROOTSYS" << endl;
2709       out << "echo \"############## which root : ##############\"" << endl;
2710       out << "which root" << endl;
2711       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2712       out << "echo $ALICE_ROOT" << endl;
2713       out << "echo \"############## which aliroot : ##############\"" << endl;
2714       out << "which aliroot" << endl;
2715       out << "echo \"############## system limits : ##############\"" << endl;
2716       out << "ulimit -a" << endl;
2717       out << "echo \"############## memory : ##############\"" << endl;
2718       out << "free -m" << endl;
2719       out << "echo \"=========================================\"" << endl << endl;
2720       // Make sure we can properly compile par files
2721       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2722       TString mergeMacro = fExecutable;
2723       mergeMacro.ReplaceAll(".sh", "_merge.C");
2724       out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
2725       out << fExecutableCommand << " " << "$ARG" << endl; 
2726       out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
2727       out << "echo \"############## memory after: ##############\"" << endl;
2728       out << "free -m" << endl;
2729       out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2730       out << "dmesg | tail -n 10" << endl;
2731    }   
2732    Bool_t copy = kTRUE;
2733    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2734    if (copy) {
2735       CdWork();
2736       TString workdir = gGrid->GetHomeDirectory();
2737       TString bindir = Form("%s/bin", workdir.Data());
2738       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2739       workdir += fGridWorkingDir;
2740       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
2741       if (FileExists(executable)) gGrid->Rm(executable);
2742       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
2743       TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
2744    } 
2745 }
2746
2747 //______________________________________________________________________________
2748 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2749 {
2750 // Write the production file to be submitted by LPM manager. The format is:
2751 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2752 // Next lines: full_path_to_dataset XXX (XXX is a string)
2753 // To submit, one has to: submit jdl XXX for all lines
2754    ofstream out;
2755    out.open(filename, ios::out);
2756    if (out.bad()) {
2757       Error("WriteProductionFile", "Bad file name: %s", filename);
2758       return;
2759    }
2760    TString workdir = gGrid->GetHomeDirectory();
2761    workdir += fGridWorkingDir;
2762    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2763    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2764    out << locjdl << " " << njobspermaster << endl;
2765    Int_t nmasterjobs = fInputFiles->GetEntries();
2766    for (Int_t i=0; i<nmasterjobs; i++) {
2767       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2768       runOutDir.ReplaceAll(".xml", "");
2769       if (fOutputToRunNo)
2770          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
2771       else
2772          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2773    }
2774    Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
2775    if (FileExists(filename)) gGrid->Rm(filename);
2776    TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));   
2777 }
2778
2779 //______________________________________________________________________________
2780 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
2781 {
2782 // Generate the alien validation script.
2783    // Generate the validation script
2784    TObjString *os;
2785    TString validationScript = fExecutable;
2786    if (merge) validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
2787    else       validationScript.ReplaceAll(".sh", "_validation.sh");
2788    if (!Connect()) {
2789       Error("WriteValidationScript", "Alien connection required");
2790       return;
2791    }
2792    TString out_stream = "";
2793    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2794    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2795       ofstream out;
2796       out.open(validationScript, ios::out);
2797       out << "#!/bin/bash" << endl;
2798       out << "##################################################" << endl;
2799       out << "validateout=`dirname $0`" << endl;
2800       out << "validatetime=`date`" << endl;
2801       out << "validated=\"0\";" << endl;
2802       out << "error=0" << endl;
2803       out << "if [ -z $validateout ]" << endl;
2804       out << "then" << endl;
2805       out << "    validateout=\".\"" << endl;
2806       out << "fi" << endl << endl;
2807       out << "cd $validateout;" << endl;
2808       out << "validateworkdir=`pwd`;" << endl << endl;
2809       out << "echo \"*******************************************************\"" << out_stream << endl;
2810       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
2811       out << "" << endl;
2812       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
2813       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
2814       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
2815       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2816       out << "ls -la ./"  << out_stream << endl;
2817       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
2818       out << "##################################################" << endl;
2819
2820       out << "" << endl;
2821       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2822       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2823       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2824       out << "" << endl;
2825
2826       out << "if [ ! -f stderr ] ; then" << endl;
2827       out << "   error=1" << endl;
2828       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
2829       out << "   echo \"Error = $error\" " << out_stream << endl;
2830       out << "fi" << endl;
2831
2832       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2833       out << "   error=1" << endl;
2834       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
2835       out << "   echo \"$parArch\" " << out_stream << endl;
2836       out << "   echo \"Error = $error\" " << out_stream << endl;
2837       out << "fi" << endl;
2838
2839       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2840       out << "   error=1" << endl;
2841       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
2842       out << "   echo \"$segViol\" " << out_stream << endl;
2843       out << "   echo \"Error = $error\" " << out_stream << endl;
2844       out << "fi" << endl;
2845
2846       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2847       out << "   error=1" << endl;
2848       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
2849       out << "   echo \"$segFault\" " << out_stream << endl;
2850       out << "   echo \"Error = $error\" " << out_stream << endl;
2851       out << "fi" << endl;
2852
2853       // Part dedicated to the specific analyses running into the train
2854
2855       TObjArray *arr = fOutputFiles.Tokenize(" ");
2856       TIter next1(arr);
2857       TString output_file;
2858       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2859       TString extra = mgr->GetExtraFiles();
2860       while ((os=(TObjString*)next1())) { 
2861          output_file = os->GetString();
2862          Int_t index = output_file.Index("@");
2863          if (index > 0) output_file.Remove(index);
2864          if (merge && fMergeExcludes.Contains(output_file)) continue;
2865          if (extra.Contains(output_file)) continue;
2866          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2867          out << "   error=1" << endl;
2868          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
2869          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2870          out << "fi" << endl;
2871       }   
2872       delete arr;
2873       if (!merge) {
2874         out << "if ! [ -f outputs_valid ] ; then" << endl;
2875         out << "   error=1" << endl;
2876         out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2877         out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2878         out << "fi" << endl;
2879       }  
2880       
2881       out << "if [ $error = 0 ] ; then" << endl;
2882       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
2883       out << "fi" << endl;
2884
2885       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2886       out << "echo \"*******************************************************\""  << out_stream << endl;
2887       out << "cd -" << endl;
2888       out << "exit $error" << endl;
2889    }    
2890    Bool_t copy = kTRUE;
2891    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2892    if (copy) {
2893       CdWork();
2894       TString workdir = gGrid->GetHomeDirectory();
2895       workdir += fGridWorkingDir;
2896       Info("CreateJDL", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
2897       if (FileExists(validationScript)) gGrid->Rm(validationScript);
2898       TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
2899    } 
2900 }