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