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