Fixed format in printouts. Changed temp directory in merging to be current directory
[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 \
1824       analysis manager");
1825    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1826 }
1827       
1828 //______________________________________________________________________________
1829 void AliAnalysisAlien::SetOutputFiles(const char *list)
1830 {
1831 // Manually set the output files list.
1832 // Removes duplicates. Not allowed if default outputs are not disabled.
1833    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1834       Fatal("SetOutputFiles", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set output files.");
1835       return;
1836    }
1837    Info("SetOutputFiles", "Output file list is set manually - you are on your own.");
1838    fOutputFiles = "";
1839    TString slist = list;
1840    if (slist.Contains("@")) Warning("SetOutputFiles","The plugin does not allow explicit SE's. Please use: SetNumberOfReplicas() instead.");
1841    TObjArray *arr = slist.Tokenize(" "); 
1842    TObjString *os;
1843    TIter next(arr);
1844    TString sout;
1845    while ((os=(TObjString*)next())) {
1846       sout = os->GetString();
1847       if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
1848       if (fOutputFiles.Contains(sout)) continue;
1849       if (!fOutputFiles.IsNull()) fOutputFiles += ",";
1850       fOutputFiles += sout;
1851    }
1852    delete arr;   
1853 }      
1854
1855 //______________________________________________________________________________
1856 void AliAnalysisAlien::SetOutputArchive(const char *list)
1857 {
1858 // Manually set the output archive list. Free text - you are on your own...
1859 // Not allowed if default outputs are not disabled.
1860    if (TObject::TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1861       Fatal("SetOutputArchive", "You have to explicitly call SetDefaultOutputs(kFALSE) to manually set the output archives.");
1862       return;
1863    }
1864    Info("SetOutputArchive", "Output archive is set manually - you are on your own.");
1865    fOutputArchive = list;
1866 }
1867
1868 //______________________________________________________________________________
1869 void AliAnalysisAlien::SetPreferedSE(const char */*se*/)
1870 {
1871 // Setting a prefered output SE is not allowed anymore.
1872    Warning("SetPreferedSE", "Setting a preferential SE is not allowed anymore via the plugin. Use SetNumberOfReplicas() and SetDefaultOutputs()");
1873 }
1874
1875 //______________________________________________________________________________
1876 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1877 {
1878 // Start remote grid analysis.
1879    
1880    // Check if output files have to be taken from the analysis manager
1881    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1882       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1883       if (!mgr || !mgr->IsInitialized()) {
1884          Error("StartAnalysis", "You need an initialized analysis manager for this");
1885          return kFALSE;
1886       }
1887       fOutputFiles = "";
1888       TIter next(mgr->GetOutputs());
1889       AliAnalysisDataContainer *output;
1890       while ((output=(AliAnalysisDataContainer*)next())) {
1891          const char *filename = output->GetFileName();
1892          if (!(strcmp(filename, "default"))) {
1893             if (!mgr->GetOutputEventHandler()) continue;
1894             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1895          }
1896          if (fOutputFiles.Contains(filename)) continue;
1897          if (fOutputFiles.Length()) fOutputFiles += ",";
1898          fOutputFiles += filename;
1899       }
1900       // Add extra files registered to the analysis manager
1901       if (mgr->GetExtraFiles().Length()) {
1902          if (fOutputFiles.Length()) fOutputFiles += ",";
1903          TString extra = mgr->GetExtraFiles();
1904          extra.ReplaceAll(" ", ",");
1905          // Protection in case extra files do not exist (will it work?)
1906          extra.ReplaceAll(".root", "*.root");
1907          fOutputFiles += extra;
1908       }
1909       // Compose the output archive.
1910       fOutputArchive = "log_archive.zip:std*@disk=1 ";
1911       fOutputArchive += Form("root_archive.zip:%s@disk=%d",fOutputFiles.Data(),fNreplicas);
1912    }
1913 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1914    if (TestBit(AliAnalysisGrid::kOffline)) {
1915       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1916       \n                         there nor any job run. You can revise the JDL and analysis \
1917       \n                         macro then run the same in \"submit\" mode.");
1918    } else if (TestBit(AliAnalysisGrid::kTest)) {
1919       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1920       \n                         dataset.");
1921    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1922       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1923       \n                         space and job submitted.");
1924    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1925       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1926       if (fMergeViaJDL) CheckInputData();
1927       return kTRUE;
1928    } else {
1929       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1930    }   
1931       
1932    Print();   
1933    if (!Connect()) {
1934       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1935       return kFALSE;
1936    }
1937    if (IsCheckCopy()) CheckFileCopy(gGrid->GetHomeDirectory());
1938    if (!CheckInputData()) {
1939       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1940       return kFALSE;
1941    }   
1942    if (!CreateDataset(fDataPattern)) {
1943       TString serror;
1944       if (!fRunNumbers.Length() && !fRunRange[0]) serror = Form("path to data directory: <%s>", fGridDataDir.Data());
1945       if (fRunNumbers.Length()) serror = "run numbers";
1946       if (fRunRange[0]) serror = Form("run range [%d, %d]", fRunRange[0], fRunRange[1]);
1947       serror += Form("\n   or data pattern <%s>", fDataPattern.Data());
1948       Error("StartAnalysis", "No data to process. Please fix %s in your plugin configuration.", serror.Data());
1949       return kFALSE;
1950    }   
1951    WriteAnalysisFile();   
1952    WriteAnalysisMacro();
1953    WriteExecutable();
1954    WriteValidationScript();
1955    if (fMergeViaJDL) {
1956       WriteMergingMacro();
1957       WriteMergeExecutable();
1958       WriteValidationScript(kTRUE);
1959    }   
1960    if (!CreateJDL()) return kFALSE;
1961    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1962    if (TestBit(AliAnalysisGrid::kTest)) {
1963       // Locally testing the analysis
1964       Info("StartAnalysis", "\n_______________________________________________________________________ \
1965       \n   Running analysis script in a daughter shell as on a worker node \
1966       \n_______________________________________________________________________");
1967       TObjArray *list = fOutputFiles.Tokenize(",");
1968       TIter next(list);
1969       TObjString *str;
1970       TString outputFile;
1971       while((str=(TObjString*)next())) {
1972          outputFile = str->GetString();
1973          Int_t index = outputFile.Index("@");
1974          if (index > 0) outputFile.Remove(index);         
1975          if (!gSystem->AccessPathName(outputFile)) gSystem->Exec(Form("rm %s", outputFile.Data()));
1976       }
1977       delete list;
1978       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1979       TString validationScript = fExecutable;
1980       validationScript.ReplaceAll(".sh", "_validation.sh");
1981       gSystem->Exec(Form("bash %s",validationScript.Data()));
1982 //      gSystem->Exec("cat stdout");
1983       return kFALSE;
1984    }
1985    // Check if submitting is managed by LPM manager
1986    if (fProductionMode) {
1987       TString prodfile = fJDLName;
1988       prodfile.ReplaceAll(".jdl", ".prod");
1989       WriteProductionFile(prodfile);
1990       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1991       return kFALSE;
1992    }   
1993    // Submit AliEn job(s)
1994    gGrid->Cd(fGridOutputDir);
1995    TGridResult *res;
1996    TString jobID = "";
1997    if (!fRunNumbers.Length() && !fRunRange[0]) {
1998       // Submit a given xml or a set of runs
1999       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
2000       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
2001       if (res) {
2002          const char *cjobId = res->GetKey(0,"jobId");
2003          if (!cjobId) {
2004             gGrid->Stdout();
2005             gGrid->Stderr();
2006             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
2007             return kFALSE;
2008          } else {
2009             Info("StartAnalysis", "\n_______________________________________________________________________ \
2010             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2011             \n_______________________________________________________________________",
2012                    fJDLName.Data(), cjobId);
2013             jobID = cjobId;      
2014          }          
2015          delete res;
2016       } else {
2017          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2018          return kFALSE;      
2019       }   
2020    } else {
2021       // Submit for a range of enumeration of runs.
2022       if (!Submit()) return kFALSE;
2023    }   
2024          
2025    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
2026    \n You may exit at any time and terminate the job later using the option <terminate> \
2027    \n ##################################################################################", jobID.Data());
2028    gSystem->Exec("aliensh");
2029    return kTRUE;
2030 }
2031
2032 //______________________________________________________________________________
2033 Bool_t AliAnalysisAlien::Submit()
2034 {
2035 // Submit all master jobs.
2036    Int_t nmasterjobs = fInputFiles->GetEntries();
2037    Long_t tshoot = gSystem->Now();
2038    if (!fNsubmitted && !SubmitNext()) return kFALSE;
2039    while (fNsubmitted < nmasterjobs) {
2040       Long_t now = gSystem->Now();
2041       if ((now-tshoot)>30000) {
2042          tshoot = now;
2043          if (!SubmitNext()) return kFALSE;
2044       }   
2045    }
2046    return kTRUE;
2047 }
2048
2049 //______________________________________________________________________________
2050 Bool_t AliAnalysisAlien::SubmitMerging()
2051 {
2052 // Submit all merging jobs.
2053    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2054    gGrid->Cd(fGridOutputDir);
2055    TString mergeJDLName = fExecutable;
2056    mergeJDLName.ReplaceAll(".sh", "_merge.jdl");
2057    Int_t ntosubmit = fInputFiles->GetEntries();
2058    printf("### Submitting %d merging jobs...\n", ntosubmit);
2059    for (Int_t i=0; i<ntosubmit; i++) {
2060       TString query;
2061       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2062       runOutDir.ReplaceAll(".xml", "");
2063       if (fOutputToRunNo)
2064          query = Form("submit %s %s", mergeJDLName.Data(), runOutDir.Data());
2065       else
2066          query = Form("submit %s %03d", mergeJDLName.Data(), i);
2067       printf("********* %s\n",query.Data());
2068       TGridResult *res = gGrid->Command(query);
2069       if (res) {
2070          const char *cjobId = res->GetKey(0,"jobId");
2071          if (!cjobId) {
2072             gGrid->Stdout();
2073             gGrid->Stderr();
2074             Error("StartAnalysis", "Your JDL %s could not be submitted", mergeJDLName.Data());
2075             return kFALSE;
2076          } else {
2077             Info("StartAnalysis", "\n_______________________________________________________________________ \
2078             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
2079             \n_______________________________________________________________________",
2080                    mergeJDLName.Data(), cjobId);
2081          }
2082          delete res;
2083       } else {     
2084          Error("SubmitMerging", "No grid result after submission !!! Bailing out...");
2085          return kFALSE;
2086       }             
2087    }
2088    if (!ntosubmit) return kTRUE;
2089    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR MERGING JOBS HAVE FINISHED. #### \
2090    \n You may exit at any time and terminate the job later using the option <terminate> but disabling SetMergeViaJDL\
2091    \n ##################################################################################");
2092    gSystem->Exec("aliensh");
2093    return kTRUE;
2094 }
2095
2096 //______________________________________________________________________________
2097 Bool_t AliAnalysisAlien::SubmitNext()
2098 {
2099 // Submit next bunch of master jobs if the queue is free.
2100    static Bool_t iscalled = kFALSE;
2101    static Int_t firstmaster = 0;
2102    static Int_t lastmaster = 0;
2103    static Int_t npermaster  = 0;
2104    if (iscalled) return kTRUE;
2105    iscalled = kTRUE;
2106    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
2107    Int_t ntosubmit = 0;
2108    TGridResult *res;
2109    TString jobID = "";
2110    if (!fNsubmitted) ntosubmit = 1;
2111    else {
2112       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
2113       printf("=== master %d: %s\n", lastmaster, status.Data());
2114       // If last master not split, just return
2115       if (status != "SPLIT") {iscalled = kFALSE; return kTRUE;}
2116       // No more than 100 waiting jobs
2117       if (nwaiting>100) {iscalled = kFALSE; return kTRUE;}
2118       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
2119       if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
2120       if (!ntosubmit) ntosubmit = 1;
2121       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
2122              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
2123    }
2124    Int_t nmasterjobs = fInputFiles->GetEntries();
2125    for (Int_t i=0; i<ntosubmit; i++) {
2126       // Submit for a range of enumeration of runs.
2127       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return kTRUE;}
2128       TString query;
2129       TString runOutDir = gSystem->BaseName(fInputFiles->At(fNsubmitted)->GetName());
2130       runOutDir.ReplaceAll(".xml", "");
2131       if (fOutputToRunNo)
2132          query = Form("submit %s %s %s", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), runOutDir.Data());
2133       else
2134          query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
2135       printf("********* %s\n",query.Data());
2136       res = gGrid->Command(query);
2137       if (res) {
2138          TString cjobId1 = res->GetKey(0,"jobId");
2139          if (!cjobId1.Length()) {
2140             iscalled = kFALSE;
2141             gGrid->Stdout();
2142             gGrid->Stderr();
2143             Error("StartAnalysis", "Your JDL %s could not be submitted. The message was:", fJDLName.Data());
2144             return kFALSE;
2145          } else {
2146             Info("StartAnalysis", "\n_______________________________________________________________________ \
2147             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
2148             \n_______________________________________________________________________",
2149                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
2150             jobID += cjobId1;
2151             jobID += " ";
2152             lastmaster = cjobId1.Atoi();
2153             if (!firstmaster) firstmaster = lastmaster;
2154             fNsubmitted++;
2155          }          
2156          delete res;
2157       } else {
2158          Error("StartAnalysis", "No grid result after submission !!! Bailing out...");
2159          return kFALSE;
2160       }   
2161    }
2162    iscalled = kFALSE;
2163    return kTRUE;
2164 }
2165
2166 //______________________________________________________________________________
2167 void AliAnalysisAlien::WriteAnalysisFile()
2168 {
2169 // Write current analysis manager into the file <analysisFile>
2170    TString analysisFile = fExecutable;
2171    analysisFile.ReplaceAll(".sh", ".root");
2172    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2173       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
2174       if (!mgr || !mgr->IsInitialized()) {
2175          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
2176          return;
2177       }
2178       // Check analysis type
2179       TObject *handler;
2180       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
2181       handler = (TObject*)mgr->GetInputEventHandler();
2182       if (handler) {
2183          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
2184          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
2185       }
2186       TDirectory *cdir = gDirectory;
2187       TFile *file = TFile::Open(analysisFile, "RECREATE");
2188       if (file) {
2189          // Skip task Terminate calls for the grid job (but not in test mode, where we want to check also the terminate mode
2190          if (!TestBit(AliAnalysisGrid::kTest)) mgr->SetSkipTerminate(kTRUE);
2191          // Unless merging makes no sense
2192          if (IsSingleOutput()) mgr->SetSkipTerminate(kFALSE);
2193          mgr->Write();
2194          delete file;
2195          // Enable termination for local jobs
2196          mgr->SetSkipTerminate(kFALSE);
2197       }
2198       if (cdir) cdir->cd();
2199       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
2200    }   
2201    Bool_t copy = kTRUE;
2202    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2203    if (copy) {
2204       CdWork();
2205       TString workdir = gGrid->GetHomeDirectory();
2206       workdir += fGridWorkingDir;
2207       Info("CreateJDL", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
2208       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
2209       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
2210    }   
2211 }
2212
2213 //______________________________________________________________________________
2214 void AliAnalysisAlien::WriteAnalysisMacro()
2215 {
2216 // Write the analysis macro that will steer the analysis in grid mode.
2217    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2218       ofstream out;
2219       out.open(fAnalysisMacro.Data(), ios::out);
2220       if (!out.good()) {
2221          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2222          return;
2223       }
2224       Bool_t hasSTEERBase = kFALSE;
2225       Bool_t hasESD = kFALSE;
2226       Bool_t hasAOD = kFALSE;
2227       Bool_t hasANALYSIS = kFALSE;
2228       Bool_t hasANALYSISalice = kFALSE;
2229       Bool_t hasCORRFW = kFALSE;
2230       TString func = fAnalysisMacro;
2231       TString type = "ESD";
2232       TString comment = "// Analysis using ";
2233       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
2234       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
2235          type = "AOD";
2236          comment += "AOD";
2237       }   
2238       if (type!="AOD" && fFriendChainName!="") {
2239          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
2240          return;
2241       }
2242       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
2243       else comment += " data";
2244       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
2245       func.ReplaceAll(".C", "");
2246       out << "void " << func.Data() << "()" << endl; 
2247       out << "{" << endl;
2248       out << comment.Data() << endl;
2249       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
2250       out << "   TStopwatch timer;" << endl;
2251       out << "   timer.Start();" << endl << endl;
2252       out << "// load base root libraries" << endl;
2253       out << "   gSystem->Load(\"libTree\");" << endl;
2254       out << "   gSystem->Load(\"libGeom\");" << endl;
2255       out << "   gSystem->Load(\"libVMC\");" << endl;
2256       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
2257       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
2258       if (fAdditionalRootLibs.Length()) {
2259          // in principle libtree /lib geom libvmc etc. can go into this list, too
2260          out << "// Add aditional libraries" << endl;
2261          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2262          TIter next(list);
2263          TObjString *str;
2264          while((str=(TObjString*)next())) {
2265             if (str->GetString().Contains(".so"))
2266             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2267          }
2268          if (list) delete list;
2269       }
2270       out << "// include path" << endl;
2271       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2272       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2273       out << "// Load analysis framework libraries" << endl;
2274       if (!fPackages) {
2275          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2276          out << "   gSystem->Load(\"libESD\");" << endl;
2277          out << "   gSystem->Load(\"libAOD\");" << endl;
2278          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2279          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2280          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2281       } else {
2282          TIter next(fPackages);
2283          TObject *obj;
2284          TString pkgname;
2285          TString setupPar = "AliAnalysisAlien::SetupPar";
2286          while ((obj=next())) {
2287             pkgname = obj->GetName();
2288             if (pkgname == "STEERBase" ||
2289                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2290             if (pkgname == "ESD" ||
2291                 pkgname == "ESD.par")       hasESD = kTRUE;
2292             if (pkgname == "AOD" ||
2293                 pkgname == "AOD.par")       hasAOD = kTRUE;
2294             if (pkgname == "ANALYSIS" ||
2295                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
2296             if (pkgname == "ANALYSISalice" ||
2297                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2298             if (pkgname == "CORRFW" ||
2299                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
2300          }
2301          if (hasANALYSISalice) setupPar = "SetupPar";   
2302          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2303          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2304          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
2305          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
2306          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
2307          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
2308          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2309          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2310          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2311          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2312          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2313          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2314          out << "// Compile other par packages" << endl;
2315          next.Reset();
2316          while ((obj=next())) {
2317             pkgname = obj->GetName();
2318             if (pkgname == "STEERBase" ||
2319                 pkgname == "STEERBase.par" ||
2320                 pkgname == "ESD" ||
2321                 pkgname == "ESD.par" ||
2322                 pkgname == "AOD" ||
2323                 pkgname == "AOD.par" ||
2324                 pkgname == "ANALYSIS" ||
2325                 pkgname == "ANALYSIS.par" ||
2326                 pkgname == "ANALYSISalice" ||
2327                 pkgname == "ANALYSISalice.par" ||
2328                 pkgname == "CORRFW" ||
2329                 pkgname == "CORRFW.par") continue;
2330             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2331          }   
2332       }   
2333       if (fAdditionalLibs.Length()) {
2334          out << "// Add aditional AliRoot libraries" << endl;
2335          TObjArray *list = fAdditionalLibs.Tokenize(" ");
2336          TIter next(list);
2337          TObjString *str;
2338          while((str=(TObjString*)next())) {
2339             if (str->GetString().Contains(".so"))
2340                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2341          }
2342          if (list) delete list;
2343       }
2344       out << endl;
2345       out << "// analysis source to be compiled at runtime (if any)" << endl;
2346       if (fAnalysisSource.Length()) {
2347          TObjArray *list = fAnalysisSource.Tokenize(" ");
2348          TIter next(list);
2349          TObjString *str;
2350          while((str=(TObjString*)next())) {
2351             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2352          }   
2353          if (list) delete list;
2354       }
2355       out << endl;
2356       if (fFastReadOption) {
2357          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 !!! \
2358                 \n+++ NOTE: To disable this option, use: plugin->SetFastReadOption(kFALSE)");
2359          out << "// fast xrootd reading enabled" << endl;
2360          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2361          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",10);" << endl;
2362          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",10);" << endl;
2363          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2364          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",10);" << endl;
2365          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2366       }   
2367       // Change temp directory to current one
2368       out << "// Set temporary merging directory to current one" << endl;
2369       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
2370       out << "// connect to AliEn and make the chain" << endl;
2371       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
2372       if (IsUsingTags()) {
2373          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
2374       } else {
2375          if(fFriendChainName!="AliAOD.VertexingHF.root") {
2376             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;    
2377          } else {
2378             out << "   // Check if the macro to create the chain was provided" << endl;
2379             out << "   if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
2380             out << "      ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
2381             out << "      return;" << endl;
2382             out << "   }" << endl;
2383             out << "   gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
2384             out << "   TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
2385          }  
2386       }   
2387       out << "// read the analysis manager from file" << endl;
2388       TString analysisFile = fExecutable;
2389       analysisFile.ReplaceAll(".sh", ".root");
2390       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
2391       out << "   if (!file) return;" << endl; 
2392       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
2393       out << "   AliAnalysisManager *mgr = 0;" << endl;
2394       out << "   TKey *key;" << endl;
2395       out << "   while ((key=(TKey*)nextkey())) {" << endl;
2396       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2397       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2398       out << "   };" << endl;
2399       out << "   if (!mgr) {" << endl;
2400       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2401       out << "      return;" << endl;
2402       out << "   }" << endl << endl;
2403       out << "   mgr->PrintStatus();" << endl;
2404       if (AliAnalysisManager::GetAnalysisManager()) {
2405          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
2406             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2407          } else {
2408             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2409          }
2410       }   
2411       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
2412       out << "   timer.Stop();" << endl;
2413       out << "   timer.Print();" << endl;
2414       out << "}" << endl << endl;
2415       if (IsUsingTags()) {
2416          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
2417          out << "{" << endl;
2418          out << "// Create a chain using tags from the xml file." << endl;
2419          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
2420          out << "   if (!coll) {" << endl;
2421          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2422          out << "      return NULL;" << endl;
2423          out << "   }" << endl;
2424          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
2425          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
2426          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
2427          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
2428          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
2429          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
2430          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
2431          out << "   // Check if the cuts configuration file was provided" << endl;
2432          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
2433          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
2434          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2435          out << "   }" << endl;
2436          if (fFriendChainName=="") {
2437             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
2438          } else {
2439             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
2440             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
2441             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
2442          }
2443          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
2444          out << "   chain->ls();" << endl;
2445          out << "   return chain;" << endl;
2446          out << "}" << endl << endl;
2447          if (gSystem->AccessPathName("ConfigureCuts.C")) {
2448             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
2449             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
2450             msg += "                      AliLHCTagCuts *lhcCuts,\n";
2451             msg += "                      AliDetectorTagCuts *detCuts,\n";
2452             msg += "                      AliEventTagCuts *evCuts)";
2453             Info("WriteAnalysisMacro", msg.Data());
2454          }
2455       } 
2456       if (!IsUsingTags() || fFriendChainName!="") {
2457          out <<"//________________________________________________________________________________" << endl;
2458          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
2459          out << "{" << endl;
2460          out << "// Create a chain using url's from xml file" << endl;
2461          out << "   TString treename = type;" << endl;
2462          out << "   treename.ToLower();" << endl;
2463          out << "   treename += \"Tree\";" << endl;
2464          out << "   printf(\"***************************************\\n\");" << endl;
2465          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
2466          out << "   printf(\"***************************************\\n\");" << endl;
2467          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2468          out << "   if (!coll) {" << endl;
2469          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2470          out << "      return NULL;" << endl;
2471          out << "   }" << endl;
2472          out << "   TChain *chain = new TChain(treename);" << endl;
2473          if(fFriendChainName!="") {
2474             out << "   TChain *chainFriend = new TChain(treename);" << endl;
2475          }
2476          out << "   coll->Reset();" << endl;
2477          out << "   while (coll->Next()) {" << endl;
2478          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
2479          if(fFriendChainName!="") {
2480             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
2481             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2482             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2483             out << "      chainFriend->Add(fileFriend.Data());" << endl;
2484          }
2485          out << "   }" << endl;
2486          out << "   if (!chain->GetNtrees()) {" << endl;
2487          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2488          out << "      return NULL;" << endl;
2489          out << "   }" << endl;
2490          if(fFriendChainName!="") {
2491             out << "   chain->AddFriend(chainFriend);" << endl;
2492          }
2493          out << "   return chain;" << endl;
2494          out << "}" << endl << endl;
2495       }   
2496       if (hasANALYSISalice) {
2497          out <<"//________________________________________________________________________________" << endl;
2498          out << "Bool_t SetupPar(const char *package) {" << endl;
2499          out << "// Compile the package and set it up." << endl;
2500          out << "   TString pkgdir = package;" << endl;
2501          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2502          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2503          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2504          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2505          out << "   // Check for BUILD.sh and execute" << endl;
2506          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2507          out << "      printf(\"*******************************\\n\");" << endl;
2508          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2509          out << "      printf(\"*******************************\\n\");" << endl;
2510          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2511          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2512          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2513          out << "         return kFALSE;" << endl;
2514          out << "      }" << endl;
2515          out << "   } else {" << endl;
2516          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2517          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2518          out << "      return kFALSE;" << endl;
2519          out << "   }" << endl;
2520          out << "   // Check for SETUP.C and execute" << endl;
2521          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2522          out << "      printf(\"*******************************\\n\");" << endl;
2523          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2524          out << "      printf(\"*******************************\\n\");" << endl;
2525          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2526          out << "   } else {" << endl;
2527          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2528          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2529          out << "      return kFALSE;" << endl;
2530          out << "   }" << endl;
2531          out << "   // Restore original workdir" << endl;
2532          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2533          out << "   return kTRUE;" << endl;
2534          out << "}" << endl;
2535       }
2536       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2537    }   
2538    Bool_t copy = kTRUE;
2539    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2540    if (copy) {
2541       CdWork();
2542       TString workdir = gGrid->GetHomeDirectory();
2543       workdir += fGridWorkingDir;
2544       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2545       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2546          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2547          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2548          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2549       }   
2550       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2551       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2552    }
2553 }
2554
2555 //______________________________________________________________________________
2556 void AliAnalysisAlien::WriteMergingMacro()
2557 {
2558 // Write a macro to merge the outputs per master job.
2559    if (!fMergeViaJDL) return;
2560    if (!fOutputFiles.Length()) {
2561       Error("WriteMergingMacro", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
2562       return;
2563    }   
2564    TString mergingMacro = fExecutable;
2565    mergingMacro.ReplaceAll(".sh","_merge.C");
2566    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
2567    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2568       ofstream out;
2569       out.open(mergingMacro.Data(), ios::out);
2570       if (!out.good()) {
2571          Error("WriteMergingMacro", "could not open file %s for writing", fAnalysisMacro.Data());
2572          return;
2573       }
2574       Bool_t hasSTEERBase = kFALSE;
2575       Bool_t hasESD = kFALSE;
2576       Bool_t hasAOD = kFALSE;
2577       Bool_t hasANALYSIS = kFALSE;
2578       Bool_t hasANALYSISalice = kFALSE;
2579       Bool_t hasCORRFW = kFALSE;
2580       TString func = mergingMacro;
2581       TString comment;
2582       func.ReplaceAll(".C", "");
2583       out << "void " << func.Data() << "(const char *dir)" << endl;
2584       out << "{" << endl;
2585       out << "// Automatically generated merging macro executed in grid subjobs" << endl << endl;
2586       out << "   TStopwatch timer;" << endl;
2587       out << "   timer.Start();" << endl << endl;
2588       out << "// load base root libraries" << endl;
2589       out << "   gSystem->Load(\"libTree\");" << endl;
2590       out << "   gSystem->Load(\"libGeom\");" << endl;
2591       out << "   gSystem->Load(\"libVMC\");" << endl;
2592       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
2593       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
2594       if (fAdditionalRootLibs.Length()) {
2595          // in principle libtree /lib geom libvmc etc. can go into this list, too
2596          out << "// Add aditional libraries" << endl;
2597          TObjArray *list = fAdditionalRootLibs.Tokenize(" ");
2598          TIter next(list);
2599          TObjString *str;
2600          while((str=(TObjString*)next())) {
2601             if (str->GetString().Contains(".so"))
2602             out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2603          }
2604          if (list) delete list;
2605       }
2606       out << "// include path" << endl;
2607       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
2608       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
2609       out << "// Load analysis framework libraries" << endl;
2610       if (!fPackages) {
2611          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2612          out << "   gSystem->Load(\"libESD\");" << endl;
2613          out << "   gSystem->Load(\"libAOD\");" << endl;
2614          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2615          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2616          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2617       } else {
2618          TIter next(fPackages);
2619          TObject *obj;
2620          TString pkgname;
2621          TString setupPar = "AliAnalysisAlien::SetupPar";
2622          while ((obj=next())) {
2623             pkgname = obj->GetName();
2624             if (pkgname == "STEERBase" ||
2625                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
2626             if (pkgname == "ESD" ||
2627                 pkgname == "ESD.par")       hasESD = kTRUE;
2628             if (pkgname == "AOD" ||
2629                 pkgname == "AOD.par")       hasAOD = kTRUE;
2630             if (pkgname == "ANALYSIS" ||
2631                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
2632             if (pkgname == "ANALYSISalice" ||
2633                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
2634             if (pkgname == "CORRFW" ||
2635                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
2636          }   
2637          if (hasANALYSISalice) setupPar = "SetupPar";   
2638          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
2639          else out << "   if (!" << setupPar << "(\"STEERBase\")) return;" << endl;
2640          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
2641          else out << "   if (!" << setupPar << "(\"ESD\")) return;" << endl;
2642          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
2643          else out << "   if (!" << setupPar << "(\"AOD\")) return;" << endl;
2644          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
2645          else out << "   if (!" << setupPar << "(\"ANALYSIS\")) return;" << endl;
2646          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
2647          else out << "   if (!" << setupPar << "(\"ANALYSISalice\")) return;" << endl;
2648          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
2649          else out << "   if (!" << setupPar << "(\"CORRFW\")) return;" << endl << endl;
2650          out << "// Compile other par packages" << endl;
2651          next.Reset();
2652          while ((obj=next())) {
2653             pkgname = obj->GetName();
2654             if (pkgname == "STEERBase" ||
2655                 pkgname == "STEERBase.par" ||
2656                 pkgname == "ESD" ||
2657                 pkgname == "ESD.par" ||
2658                 pkgname == "AOD" ||
2659                 pkgname == "AOD.par" ||
2660                 pkgname == "ANALYSIS" ||
2661                 pkgname == "ANALYSIS.par" ||
2662                 pkgname == "ANALYSISalice" ||
2663                 pkgname == "ANALYSISalice.par" ||
2664                 pkgname == "CORRFW" ||
2665                 pkgname == "CORRFW.par") continue;
2666             out << "   if (!" << setupPar << "(\"" << obj->GetName() << "\")) return;" << endl;
2667          }   
2668       }   
2669       if (fAdditionalLibs.Length()) {
2670          out << "// Add aditional AliRoot libraries" << endl;
2671          TObjArray *list = fAdditionalLibs.Tokenize(" ");
2672          TIter next(list);
2673          TObjString *str;
2674          while((str=(TObjString*)next())) {
2675             if (str->GetString().Contains(".so"))
2676                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
2677          }
2678          if (list) delete list;
2679       }
2680       out << endl;
2681       out << "// Analysis source to be compiled at runtime (if any)" << endl;
2682       if (fAnalysisSource.Length()) {
2683          TObjArray *list = fAnalysisSource.Tokenize(" ");
2684          TIter next(list);
2685          TObjString *str;
2686          while((str=(TObjString*)next())) {
2687             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
2688          }   
2689          if (list) delete list;
2690       }
2691       out << endl;      
2692
2693       if (fFastReadOption) {
2694          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 !!!");
2695          out << "// fast xrootd reading enabled" << endl;
2696          out << "   printf(\"!!! You requested FastRead option. Using xrootd flags to reduce timeouts. Note that this may skip some files that could be accessed !!!\");" << endl;
2697          out << "   gEnv->SetValue(\"XNet.ConnectTimeout\",10);" << endl;
2698          out << "   gEnv->SetValue(\"XNet.RequestTimeout\",10);" << endl;
2699          out << "   gEnv->SetValue(\"XNet.MaxRedirectCount\",2);" << endl;
2700          out << "   gEnv->SetValue(\"XNet.ReconnectTimeout\",10);" << endl;
2701          out << "   gEnv->SetValue(\"XNet.FirstConnectMaxCnt\",1);" << endl << endl;
2702       }
2703       // Change temp directory to current one
2704       out << "// Set temporary merging directory to current one" << endl;
2705       out << "   gSystem->Setenv(\"TMPDIR\", gSystem->pwd());" << endl << endl;   
2706       out << "// Connect to AliEn" << endl;
2707       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
2708       out << "   TString outputDir = \"" << fGridOutputDir << "/\";" << endl;  
2709       out << "   outputDir += dir;" << endl;    
2710       out << "   TString outputFiles = \"" << fOutputFiles << "\";" << endl;
2711       out << "   TString mergeExcludes = \"" << fMergeExcludes << "\";" << endl;
2712       out << "   mergeExcludes += \"" << AliAnalysisManager::GetAnalysisManager()->GetExtraFiles() << "\";" << endl;
2713       out << "   TObjArray *list = outputFiles.Tokenize(\" \");" << endl;
2714       out << "   TIter *iter = new TIter(list);" << endl;
2715       out << "   TObjString *str;" << endl;
2716       out << "   TString outputFile;" << endl;
2717       out << "   Bool_t merged = kTRUE;" << endl;
2718       out << "   while((str=(TObjString*)iter->Next())) {" << endl;
2719       out << "      outputFile = str->GetString();" << endl;
2720       out << "      Int_t index = outputFile.Index(\"@\");" << endl;
2721       out << "      if (index > 0) outputFile.Remove(index);" << endl;
2722       out << "      // Skip already merged outputs" << endl;
2723       out << "      if (!gSystem->AccessPathName(outputFile)) {" << endl;
2724       out << "         printf(\"Output file <%s> found. Not merging again.\",outputFile.Data());" << endl;
2725       out << "         continue;" << endl;
2726       out << "      }" << endl;
2727       out << "      if (mergeExcludes.Contains(outputFile.Data())) continue;" << endl;
2728       out << "      merged = AliAnalysisAlien::MergeOutput(outputFile, outputDir, " << fMaxMergeFiles << ");" << endl;
2729       out << "      if (!merged) {" << endl;
2730       out << "         printf(\"ERROR: Cannot merge %s\\n\", outputFile.Data());" << endl;
2731       out << "      }" << endl;
2732       out << "   }" << endl;
2733       out << "// read the analysis manager from file" << endl;
2734       TString analysisFile = fExecutable;
2735       analysisFile.ReplaceAll(".sh", ".root");
2736       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
2737       out << "   if (!file) return;" << endl; 
2738       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
2739       out << "   AliAnalysisManager *mgr = 0;" << endl;
2740       out << "   TKey *key;" << endl;
2741       out << "   while ((key=(TKey*)nextkey())) {" << endl;
2742       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
2743       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
2744       out << "   };" << endl;
2745       out << "   if (!mgr) {" << endl;
2746       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
2747       out << "      return;" << endl;
2748       out << "   }" << endl << endl;
2749       out << "   mgr->SetSkipTerminate(kFALSE);" << endl;
2750       out << "   mgr->PrintStatus();" << endl;
2751       if (AliAnalysisManager::GetAnalysisManager()) {
2752          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>3) {
2753             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
2754          } else {
2755             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
2756          }
2757       }   
2758       out << "   mgr->StartAnalysis(\"gridterminate\");" << endl;
2759       out << "}" << endl << endl;
2760       if (hasANALYSISalice) {
2761          out <<"//________________________________________________________________________________" << endl;
2762          out << "Bool_t SetupPar(const char *package) {" << endl;
2763          out << "// Compile the package and set it up." << endl;
2764          out << "   TString pkgdir = package;" << endl;
2765          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2766          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2767          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2768          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2769          out << "   // Check for BUILD.sh and execute" << endl;
2770          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2771          out << "      printf(\"*******************************\\n\");" << endl;
2772          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2773          out << "      printf(\"*******************************\\n\");" << endl;
2774          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2775          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2776          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2777          out << "         return kFALSE;" << endl;
2778          out << "      }" << endl;
2779          out << "   } else {" << endl;
2780          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2781          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2782          out << "      return kFALSE;" << endl;
2783          out << "   }" << endl;
2784          out << "   // Check for SETUP.C and execute" << endl;
2785          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2786          out << "      printf(\"*******************************\\n\");" << endl;
2787          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2788          out << "      printf(\"*******************************\\n\");" << endl;
2789          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2790          out << "   } else {" << endl;
2791          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2792          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2793          out << "      return kFALSE;" << endl;
2794          out << "   }" << endl;
2795          out << "   // Restore original workdir" << endl;
2796          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2797          out << "   return kTRUE;" << endl;
2798          out << "}" << endl;
2799       }
2800    }   
2801    Bool_t copy = kTRUE;
2802    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2803    if (copy) {
2804       CdWork();
2805       TString workdir = gGrid->GetHomeDirectory();
2806       workdir += fGridWorkingDir;
2807       if (FileExists(mergingMacro)) gGrid->Rm(mergingMacro);
2808       Info("WriteMergingMacro", "\n#####   Copying merging macro: <%s> to your alien workspace", mergingMacro.Data());
2809       TFile::Cp(Form("file:%s",mergingMacro.Data()), Form("alien://%s/%s", workdir.Data(), mergingMacro.Data()));
2810    }
2811 }
2812
2813 //______________________________________________________________________________
2814 Bool_t AliAnalysisAlien::SetupPar(const char *package)
2815 {
2816 // Compile the par file archive pointed by <package>. This must be present in the current durectory.
2817 // Note that for loading the compiled library. The current directory should have precedence in
2818 // LD_LIBRARY_PATH
2819    TString pkgdir = package;
2820    pkgdir.ReplaceAll(".par","");
2821    gSystem->Exec(Form("tar xvzf %s.par", pkgdir.Data()));
2822    TString cdir = gSystem->WorkingDirectory();
2823    gSystem->ChangeDirectory(pkgdir);
2824    // Check for BUILD.sh and execute
2825    if (!gSystem->AccessPathName("PROOF-INF/BUILD.sh")) {
2826       printf("**************************************************\n");
2827       printf("*** Building PAR archive %s\n", package);
2828       printf("**************************************************\n");
2829       if (gSystem->Exec("PROOF-INF/BUILD.sh")) {
2830          ::Error("SetupPar", "Cannot build par archive %s", pkgdir.Data());
2831          gSystem->ChangeDirectory(cdir);
2832          return kFALSE;
2833       }
2834    } else {
2835       ::Error("SetupPar","Cannot access PROOF-INF/BUILD.sh for package %s", pkgdir.Data());
2836       gSystem->ChangeDirectory(cdir);
2837       return kFALSE;
2838    }
2839    // Check for SETUP.C and execute
2840    if (!gSystem->AccessPathName("PROOF-INF/SETUP.C")) {
2841       printf("**************************************************\n");
2842       printf("*** Setup PAR archive %s\n", package);
2843       printf("**************************************************\n");
2844       gROOT->Macro("PROOF-INF/SETUP.C");
2845       printf("*** Loaded library: %s\n", gSystem->GetLibraries(pkgdir,"",kFALSE));
2846    } else {
2847       ::Error("SetupPar","Cannot access PROOF-INF/SETUP.C for package %s", pkgdir.Data());
2848       gSystem->ChangeDirectory(cdir);
2849       return kFALSE;
2850    }   
2851    // Restore original workdir
2852    gSystem->ChangeDirectory(cdir);
2853    return kTRUE;
2854 }
2855
2856 //______________________________________________________________________________
2857 void AliAnalysisAlien::WriteExecutable()
2858 {
2859 // Generate the alien executable script.
2860    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2861       ofstream out;
2862       out.open(fExecutable.Data(), ios::out);
2863       if (out.bad()) {
2864          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2865          return;
2866       }
2867       out << "#!/bin/bash" << endl;
2868       out << "echo \"=========================================\"" << endl; 
2869       out << "echo \"############## PATH : ##############\"" << endl;
2870       out << "echo $PATH" << endl;
2871       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2872       out << "echo $LD_LIBRARY_PATH" << endl;
2873       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2874       out << "echo $ROOTSYS" << endl;
2875       out << "echo \"############## which root : ##############\"" << endl;
2876       out << "which root" << endl;
2877       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2878       out << "echo $ALICE_ROOT" << endl;
2879       out << "echo \"############## which aliroot : ##############\"" << endl;
2880       out << "which aliroot" << endl;
2881       out << "echo \"############## system limits : ##############\"" << endl;
2882       out << "ulimit -a" << endl;
2883       out << "echo \"############## memory : ##############\"" << endl;
2884       out << "free -m" << endl;
2885       out << "echo \"=========================================\"" << endl << endl;
2886       // Make sure we can properly compile par files
2887       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2888       out << fExecutableCommand << " "; 
2889       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2890       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2891       out << "echo \"############## memory after: ##############\"" << endl;
2892       out << "free -m" << endl;
2893    }   
2894    Bool_t copy = kTRUE;
2895    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2896    if (copy) {
2897       CdWork();
2898       TString workdir = gGrid->GetHomeDirectory();
2899       TString bindir = Form("%s/bin", workdir.Data());
2900       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2901       workdir += fGridWorkingDir;
2902       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2903       if (FileExists(executable)) gGrid->Rm(executable);
2904       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2905       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2906    } 
2907 }
2908
2909 //______________________________________________________________________________
2910 void AliAnalysisAlien::WriteMergeExecutable()
2911 {
2912 // Generate the alien executable script for the merging job.
2913    if (!fMergeViaJDL) return;
2914    TString mergeExec = fExecutable;
2915    mergeExec.ReplaceAll(".sh", "_merge.sh");
2916    if (!TestBit(AliAnalysisGrid::kSubmit)) {
2917       ofstream out;
2918       out.open(mergeExec.Data(), ios::out);
2919       if (out.bad()) {
2920          Error("WriteMergingExecutable", "Bad file name for executable: %s", mergeExec.Data());
2921          return;
2922       }
2923       out << "#!/bin/bash" << endl;
2924       out << "echo \"=========================================\"" << endl; 
2925       out << "echo \"############## PATH : ##############\"" << endl;
2926       out << "echo $PATH" << endl;
2927       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2928       out << "echo $LD_LIBRARY_PATH" << endl;
2929       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2930       out << "echo $ROOTSYS" << endl;
2931       out << "echo \"############## which root : ##############\"" << endl;
2932       out << "which root" << endl;
2933       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2934       out << "echo $ALICE_ROOT" << endl;
2935       out << "echo \"############## which aliroot : ##############\"" << endl;
2936       out << "which aliroot" << endl;
2937       out << "echo \"############## system limits : ##############\"" << endl;
2938       out << "ulimit -a" << endl;
2939       out << "echo \"############## memory : ##############\"" << endl;
2940       out << "free -m" << endl;
2941       out << "echo \"=========================================\"" << endl << endl;
2942       // Make sure we can properly compile par files
2943       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2944       TString mergeMacro = fExecutable;
2945       mergeMacro.ReplaceAll(".sh", "_merge.C");
2946       out << "export ARG=\"" << mergeMacro << "(\\\"$1\\\")\"" << endl;
2947       out << fExecutableCommand << " " << "$ARG" << endl; 
2948       out << "echo \"======== " << mergeMacro.Data() << " finished with exit code: $? ========\"" << endl;
2949       out << "echo \"############## memory after: ##############\"" << endl;
2950       out << "free -m" << endl;
2951    }   
2952    Bool_t copy = kTRUE;
2953    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2954    if (copy) {
2955       CdWork();
2956       TString workdir = gGrid->GetHomeDirectory();
2957       TString bindir = Form("%s/bin", workdir.Data());
2958       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2959       workdir += fGridWorkingDir;
2960       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), mergeExec.Data());
2961       if (FileExists(executable)) gGrid->Rm(executable);
2962       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", mergeExec.Data());
2963       TFile::Cp(Form("file:%s",mergeExec.Data()), Form("alien://%s", executable.Data()));
2964    } 
2965 }
2966
2967 //______________________________________________________________________________
2968 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2969 {
2970 // Write the production file to be submitted by LPM manager. The format is:
2971 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2972 // Next lines: full_path_to_dataset XXX (XXX is a string)
2973 // To submit, one has to: submit jdl XXX for all lines
2974    ofstream out;
2975    out.open(filename, ios::out);
2976    if (out.bad()) {
2977       Error("WriteProductionFile", "Bad file name: %s", filename);
2978       return;
2979    }
2980    TString workdir = gGrid->GetHomeDirectory();
2981    workdir += fGridWorkingDir;
2982    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2983    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2984    out << locjdl << " " << njobspermaster << endl;
2985    Int_t nmasterjobs = fInputFiles->GetEntries();
2986    for (Int_t i=0; i<nmasterjobs; i++) {
2987       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2988       runOutDir.ReplaceAll(".xml", "");
2989       if (fOutputToRunNo)
2990          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
2991       else
2992          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2993    }
2994    Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
2995    if (FileExists(filename)) gGrid->Rm(filename);
2996    TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));   
2997 }
2998
2999 //______________________________________________________________________________
3000 void AliAnalysisAlien::WriteValidationScript(Bool_t merge)
3001 {
3002 // Generate the alien validation script.
3003    // Generate the validation script
3004    TObjString *os;
3005    TString validationScript = fExecutable;
3006    if (merge) validationScript.ReplaceAll(".sh", "_mergevalidation.sh");
3007    else       validationScript.ReplaceAll(".sh", "_validation.sh");
3008    if (!Connect()) {
3009       Error("WriteValidationScript", "Alien connection required");
3010       return;
3011    }
3012    TString outStream = "";
3013    if (!TestBit(AliAnalysisGrid::kTest)) outStream = " >> stdout";
3014    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
3015       ofstream out;
3016       out.open(validationScript, ios::out);
3017       out << "#!/bin/bash" << endl;
3018       out << "##################################################" << endl;
3019       out << "validateout=`dirname $0`" << endl;
3020       out << "validatetime=`date`" << endl;
3021       out << "validated=\"0\";" << endl;
3022       out << "error=0" << endl;
3023       out << "if [ -z $validateout ]" << endl;
3024       out << "then" << endl;
3025       out << "    validateout=\".\"" << endl;
3026       out << "fi" << endl << endl;
3027       out << "cd $validateout;" << endl;
3028       out << "validateworkdir=`pwd`;" << endl << endl;
3029       out << "echo \"*******************************************************\"" << outStream << endl;
3030       out << "echo \"* Automatically generated validation script           *\""  << outStream << endl;
3031       out << "" << endl;
3032       out << "echo \"* Time:    $validatetime \""  << outStream << endl;
3033       out << "echo \"* Dir:     $validateout\""  << outStream << endl;
3034       out << "echo \"* Workdir: $validateworkdir\""  << outStream << endl;
3035       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
3036       out << "ls -la ./"  << outStream << endl;
3037       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl << endl;
3038       out << "##################################################" << endl;
3039       out << "" << endl;
3040
3041       out << "if [ ! -f stderr ] ; then" << endl;
3042       out << "   error=1" << endl;
3043       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << outStream << endl;
3044       out << "   echo \"Error = $error\" " << outStream << endl;
3045       out << "fi" << endl;
3046
3047       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
3048       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
3049       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
3050       out << "glibcErr=`grep -Ei \"*** glibc detected ***\" stderr`" << endl;
3051       out << "" << endl;
3052
3053       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
3054       out << "   error=1" << endl;
3055       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << outStream << endl;
3056       out << "   echo \"$parArch\" " << outStream << endl;
3057       out << "   echo \"Error = $error\" " << outStream << endl;
3058       out << "fi" << endl;
3059
3060       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
3061       out << "   error=1" << endl;
3062       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << outStream << endl;
3063       out << "   echo \"$segViol\" " << outStream << endl;
3064       out << "   echo \"Error = $error\" " << outStream << endl;
3065       out << "fi" << endl;
3066
3067       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
3068       out << "   error=1" << endl;
3069       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << outStream << endl;
3070       out << "   echo \"$segFault\" " << outStream << endl;
3071       out << "   echo \"Error = $error\" " << outStream << endl;
3072       out << "fi" << endl;
3073
3074       out << "if [ \"$glibcErr\" != \"\" ] ; then" << endl;
3075       out << "   error=1" << endl;
3076       out << "   echo \"* ########## Job not validated - *** glibc detected ***  ###\" " << outStream << endl;
3077       out << "   echo \"$glibcErr\" " << outStream << endl;
3078       out << "   echo \"Error = $error\" " << outStream << endl;
3079       out << "fi" << endl;
3080
3081       // Part dedicated to the specific analyses running into the train
3082
3083       TObjArray *arr = fOutputFiles.Tokenize(",");
3084       TIter next1(arr);
3085       TString outputFile;
3086       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
3087       TString extra = mgr->GetExtraFiles();
3088       while ((os=(TObjString*)next1())) { 
3089          outputFile = os->GetString();
3090          Int_t index = outputFile.Index("@");
3091          if (index > 0) outputFile.Remove(index);
3092          if (merge && fMergeExcludes.Contains(outputFile)) continue;
3093          if (extra.Contains(outputFile)) continue;
3094          if (outputFile.Contains("*")) continue;
3095          out << "if ! [ -f " << outputFile.Data() << " ] ; then" << endl;
3096          out << "   error=1" << endl;
3097          out << "   echo \"Output file(s) not found. Job FAILED !\""  << outStream << endl;
3098          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
3099          out << "fi" << endl;
3100       }   
3101       delete arr;
3102       if (!merge) {
3103         out << "if ! [ -f outputs_valid ] ; then" << endl;
3104         out << "   error=1" << endl;
3105         out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
3106         out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
3107         out << "fi" << endl;
3108       }  
3109       
3110       out << "if [ $error = 0 ] ; then" << endl;
3111       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << outStream << endl;
3112       if (!IsKeepLogs()) {
3113          out << "   echo \"* === Logs std* will be deleted === \"" << endl;
3114          outStream = "";
3115          out << "   rm -f std*" << endl;
3116       }            
3117       out << "fi" << endl;
3118
3119       out << "echo \"* ----------------------------------------------------*\""  << outStream << endl;
3120       out << "echo \"*******************************************************\""  << outStream << endl;
3121       out << "cd -" << endl;
3122       out << "exit $error" << endl;
3123    }    
3124    Bool_t copy = kTRUE;
3125    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
3126    if (copy) {
3127       CdWork();
3128       TString workdir = gGrid->GetHomeDirectory();
3129       workdir += fGridWorkingDir;
3130       Info("CreateJDL", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
3131       if (FileExists(validationScript)) gGrid->Rm(validationScript);
3132       TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
3133    } 
3134 }