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