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