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