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