]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
Fix for processing single xml files introduced together with run ranges.
[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 "TROOT.h"
25 #include "TSystem.h"
26 #include "TFile.h"
27 #include "TObjString.h"
28 #include "TObjArray.h"
29 #include "TGrid.h"
30 #include "TGridResult.h"
31 #include "TGridCollection.h"
32 #include "TGridJDL.h"
33 #include "TFileMerger.h"
34 #include "AliAnalysisManager.h"
35 #include "AliVEventHandler.h"
36 #include "AliAnalysisDataContainer.h"
37 #include "AliAnalysisAlien.h"
38
39 ClassImp(AliAnalysisAlien)
40
41 //______________________________________________________________________________
42 AliAnalysisAlien::AliAnalysisAlien()
43                  :AliAnalysisGrid(),
44                   fGridJDL(NULL),
45                   fPrice(0),
46                   fTTL(0),
47                   fSplitMaxInputFileNumber(0),
48                   fMaxInitFailed(0),
49                   fMasterResubmitThreshold(0),
50                   fNtestFiles(0),
51                   fNMasterJobs(0),
52                   fRunNumbers(),
53                   fExecutable(),
54                   fArguments(),
55                   fAnalysisMacro(),
56                   fAnalysisSource(),
57                   fAdditionalLibs(),
58                   fSplitMode(),
59                   fAPIVersion(),
60                   fROOTVersion(),
61                   fAliROOTVersion(),
62                   fUser(),
63                   fGridWorkingDir(),
64                   fGridDataDir(),
65                   fDataPattern(),
66                   fGridOutputDir(),
67                   fOutputArchive(),
68                   fOutputFiles(),
69                   fInputFormat(),
70                   fDatasetName(),
71                   fJDLName(),
72                             fMergeExcludes(),
73                   fIncludePath(),
74                   fCloseSE(),
75                   fFriendChainName(),
76                   fInputFiles(0),
77                   fPackages(0)
78 {
79 // Dummy ctor.
80    SetDefaults();
81 }
82
83 //______________________________________________________________________________
84 AliAnalysisAlien::AliAnalysisAlien(const char *name)
85                  :AliAnalysisGrid(name),
86                   fGridJDL(NULL),
87                   fPrice(0),
88                   fTTL(0),
89                   fSplitMaxInputFileNumber(0),
90                   fMaxInitFailed(0),
91                   fMasterResubmitThreshold(0),
92                   fNtestFiles(0),
93                   fNMasterJobs(0),
94                   fRunNumbers(),
95                   fExecutable(),
96                   fArguments(),
97                   fAnalysisMacro(),
98                   fAnalysisSource(),
99                   fAdditionalLibs(),
100                   fSplitMode(),
101                   fAPIVersion(),
102                   fROOTVersion(),
103                   fAliROOTVersion(),
104                   fUser(),
105                   fGridWorkingDir(),
106                   fGridDataDir(),
107                   fDataPattern(),
108                   fGridOutputDir(),
109                   fOutputArchive(),
110                   fOutputFiles(),
111                   fInputFormat(),
112                   fDatasetName(),
113                   fJDLName(),
114                   fMergeExcludes(),
115                   fIncludePath(),
116                   fCloseSE(),
117                   fFriendChainName(),
118                   fInputFiles(0),
119                   fPackages(0)
120 {
121 // Default ctor.
122    SetDefaults();
123 }
124
125 //______________________________________________________________________________
126 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
127                  :AliAnalysisGrid(other),
128                   fGridJDL(NULL),
129                   fPrice(other.fPrice),
130                   fTTL(other.fTTL),
131                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
132                   fMaxInitFailed(other.fMaxInitFailed),
133                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
134                   fNtestFiles(other.fNtestFiles),
135                   fNMasterJobs(other.fNMasterJobs),
136                   fRunNumbers(other.fRunNumbers),
137                   fExecutable(other.fExecutable),
138                   fArguments(other.fArguments),
139                   fAnalysisMacro(other.fAnalysisMacro),
140                   fAnalysisSource(other.fAnalysisSource),
141                   fAdditionalLibs(other.fAdditionalLibs),
142                   fSplitMode(other.fSplitMode),
143                   fAPIVersion(other.fAPIVersion),
144                   fROOTVersion(other.fROOTVersion),
145                   fAliROOTVersion(other.fAliROOTVersion),
146                   fUser(other.fUser),
147                   fGridWorkingDir(other.fGridWorkingDir),
148                   fGridDataDir(other.fGridDataDir),
149                   fDataPattern(other.fDataPattern),
150                   fGridOutputDir(other.fGridOutputDir),
151                   fOutputArchive(other.fOutputArchive),
152                   fOutputFiles(other.fOutputFiles),
153                   fInputFormat(other.fInputFormat),
154                   fDatasetName(other.fDatasetName),
155                   fJDLName(other.fJDLName),
156                   fMergeExcludes(other.fMergeExcludes),
157                   fIncludePath(other.fIncludePath),
158                   fCloseSE(other.fCloseSE),
159                   fFriendChainName(other.fFriendChainName),
160                   fInputFiles(0),
161                   fPackages(0)
162 {
163 // Copy ctor.
164    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
165    fRunRange[0] = other.fRunRange[0];
166    fRunRange[1] = other.fRunRange[1];
167    if (other.fInputFiles) {
168       fInputFiles = new TObjArray();
169       TIter next(other.fInputFiles);
170       TObject *obj;
171       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
172       fInputFiles->SetOwner();
173    }   
174    if (other.fPackages) {
175       fPackages = new TObjArray();
176       TIter next(other.fPackages);
177       TObject *obj;
178       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
179       fPackages->SetOwner();
180    }   
181 }
182
183 //______________________________________________________________________________
184 AliAnalysisAlien::~AliAnalysisAlien()
185 {
186 // Destructor.
187    if (fGridJDL) delete fGridJDL;
188    if (fInputFiles) delete fInputFiles;
189    if (fPackages) delete fPackages;
190 }   
191
192 //______________________________________________________________________________
193 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
194 {
195 // Assignment.
196    if (this != &other) {
197       AliAnalysisGrid::operator=(other);
198       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
199       fPrice                   = other.fPrice;
200       fTTL                     = other.fTTL;
201       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
202       fMaxInitFailed           = other.fMaxInitFailed;
203       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
204       fNtestFiles              = other.fNtestFiles;
205       fRunNumbers              = other.fRunNumbers;
206       fExecutable              = other.fExecutable;
207       fArguments               = other.fArguments;
208       fAnalysisMacro           = other.fAnalysisMacro;
209       fAnalysisSource          = other.fAnalysisSource;
210       fAdditionalLibs          = other.fAdditionalLibs;
211       fSplitMode               = other.fSplitMode;
212       fAPIVersion              = other.fAPIVersion;
213       fROOTVersion             = other.fROOTVersion;
214       fAliROOTVersion          = other.fAliROOTVersion;
215       fUser                    = other.fUser;
216       fGridWorkingDir          = other.fGridWorkingDir;
217       fGridDataDir             = other.fGridDataDir;
218       fDataPattern             = other.fDataPattern;
219       fGridOutputDir           = other.fGridOutputDir;
220       fOutputArchive           = other.fOutputArchive;
221       fOutputFiles             = other.fOutputFiles;
222       fInputFormat             = other.fInputFormat;
223       fDatasetName             = other.fDatasetName;
224       fJDLName                 = other.fJDLName;
225       fMergeExcludes           = other.fMergeExcludes;
226       fIncludePath             = other.fIncludePath;
227       fCloseSE                 = other.fCloseSE;
228       fFriendChainName         = other.fFriendChainName;
229       if (other.fInputFiles) {
230          fInputFiles = new TObjArray();
231          TIter next(other.fInputFiles);
232          TObject *obj;
233          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
234          fInputFiles->SetOwner();
235       }   
236       if (other.fPackages) {
237          fPackages = new TObjArray();
238          TIter next(other.fPackages);
239          TObject *obj;
240          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
241          fPackages->SetOwner();
242       }   
243    }
244    return *this;
245 }
246
247 //______________________________________________________________________________
248 void AliAnalysisAlien::AddIncludePath(const char *path)
249 {
250 // Add include path in the remote analysis macro.
251    TString p(path);
252    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
253    else                  fIncludePath += Form("-I%s ", path);
254 }
255
256 //______________________________________________________________________________
257 void AliAnalysisAlien::AddRunNumber(Int_t run)
258 {
259 // Add a run number to the list of runs to be processed.
260    if (fRunNumbers.Length()) fRunNumbers += " ";
261    fRunNumbers += Form("%d", run);
262 }   
263
264 //______________________________________________________________________________
265 void AliAnalysisAlien::AddDataFile(const char *lfn)
266 {
267 // Adds a data file to the input to be analysed. The file should be a valid LFN
268 // or point to an existing file in the alien workdir.
269    if (!fInputFiles) fInputFiles = new TObjArray();
270    fInputFiles->Add(new TObjString(lfn));
271 }
272    
273 //______________________________________________________________________________
274 Bool_t AliAnalysisAlien::Connect()
275 {
276 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
277    if (gGrid && gGrid->IsConnected()) return kTRUE;
278    if (!gSystem->Getenv("alien_API_USER")) {
279       Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
280             gSystem->Getenv("UID"));
281       return kFALSE;
282    }         
283    if (!gGrid) {
284       Info("Connect", "Trying to connect to AliEn ...");
285       TGrid::Connect("alien://");
286    }
287    if (!gGrid || !gGrid->IsConnected()) {
288       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
289       return kFALSE;
290    }  
291    fUser = gGrid->GetUser();
292    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
293    return kTRUE;
294 }
295
296 //______________________________________________________________________________
297 void AliAnalysisAlien::CdWork()
298 {
299 // Check validity of alien workspace. Create directory if possible.
300    if (!Connect()) {
301       Error("CdWork", "Alien connection required");
302       return;
303    } 
304    TString homedir = gGrid->GetHomeDirectory();
305    TString workdir = homedir + fGridWorkingDir;
306    if (!gGrid->Cd(workdir)) {
307       gGrid->Cd(homedir);
308       if (gGrid->Mkdir(workdir)) {
309          gGrid->Cd(fGridWorkingDir);
310          Info("CreateJDL", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
311       } else {
312          Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
313                  workdir.Data(), homedir.Data());
314          fGridWorkingDir = "";
315       }          
316    }      
317 }
318
319 //______________________________________________________________________________
320 Bool_t AliAnalysisAlien::CheckInputData()
321 {
322 // Check validity of input data. If necessary, create xml files.
323    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
324        Error("CheckInputData", "You have to specify either a set of run numbers or some existing grid files. Use AddRunNumber()/AddDataFile()/SetRunRange().");
325       return kFALSE;
326    }
327    // Process declared files
328    Bool_t is_collection = kFALSE;
329    Bool_t is_xml = kFALSE;
330    Bool_t use_tags = kFALSE;
331    Bool_t checked = kFALSE;
332    CdWork();
333    TString file;
334    TString workdir = gGrid->GetHomeDirectory();
335    workdir += fGridWorkingDir;
336    if (fInputFiles) {
337       TObjString *objstr;
338       TIter next(fInputFiles);
339       while ((objstr=(TObjString*)next())) {
340          file = workdir;
341          file += "/";
342          file += objstr->GetString();
343          // Store full lfn path
344          if (FileExists(file)) objstr->SetString(file);
345          else {
346             file = objstr->GetName();
347             if (!FileExists(objstr->GetName())) {
348                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
349                      objstr->GetName(), workdir.Data());
350                return kFALSE;
351             }         
352          }
353          Bool_t iscoll, isxml, usetags;
354          CheckDataType(file, iscoll, isxml, usetags);
355          if (!checked) {
356             checked = kTRUE;
357             is_collection = iscoll;
358             is_xml = isxml;
359             use_tags = usetags;
360             TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
361          } else {
362             if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
363                Error("CheckInputData", "Some conflict was found in the types of inputs");
364                return kFALSE;
365             } 
366          }
367       }
368    }
369    // Process requested run numbers
370    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
371    // Check validity of alien data directory
372    if (!fGridDataDir.Length()) {
373       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
374       return kFALSE;
375    }
376    if (!gGrid->Cd(fGridDataDir)) {
377       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
378       return kFALSE;
379    }
380    if (is_collection) {
381       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
382       return kFALSE;   
383    }
384    
385    if (checked && !is_xml) {
386       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
387       return kFALSE;   
388    }
389    // Check validity of run number(s)
390    TObjArray *arr;
391    TObjString *os;
392    TString path;
393    if (!checked) {
394       checked = kTRUE;
395       use_tags = fDataPattern.Contains("tag");
396       TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
397    }   
398    if (use_tags != fDataPattern.Contains("tag")) {
399       Error("CheckInputData", "Cannot mix input files using/not using tags");
400       return kFALSE;
401    }
402    if (fRunNumbers.Length()) {
403       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
404       arr = fRunNumbers.Tokenize(" ");
405       TIter next(arr);
406       while ((os=(TObjString*)next())) {
407          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
408          if (!gGrid->Cd(path)) {
409             Warning("CheckInputData", "Run number %s not found in path: %s", os->GetString().Data(), path.Data());
410             continue;
411          }
412          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
413          TString msg = "\n#####   file: ";
414          msg += path;
415          msg += " type: xml_collection;";
416          if (use_tags) msg += " using_tags: Yes";
417          else          msg += " using_tags: No";
418          Info("CheckDataType", msg.Data());
419          AddDataFile(path);
420       }
421       delete arr;   
422    } else {
423       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
424       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
425          path = Form("%s/%d ", fGridDataDir.Data(), irun);
426          if (!gGrid->Cd(path)) {
427             Warning("CheckInputData", "Run number %d not found in path: %s", irun, path.Data());
428             continue;
429          }
430          path = Form("%s/%d.xml", workdir.Data(),irun);
431          TString msg = "\n#####   file: ";
432          msg += path;
433          msg += " type: xml_collection;";
434          if (use_tags) msg += " using_tags: Yes";
435          else          msg += " using_tags: No";
436          Info("CheckDataType", msg.Data());
437          AddDataFile(path);
438       }
439    }
440    return kTRUE;      
441 }   
442
443 //______________________________________________________________________________
444 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
445 {
446 // Create dataset for the grid data directory + run number.
447    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
448    if (!Connect()) {
449       Error("CreateDataset", "Cannot create dataset with no grid connection");
450       return kFALSE;
451    }   
452
453    // Cd workspace
454    CdWork();
455    TString workdir = gGrid->GetHomeDirectory();
456    workdir += fGridWorkingDir;
457
458    // Compose the 'find' command arguments
459    TString command;
460    TString options = "-x collection ";
461    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
462    TString conditions = "";
463    
464    TString file;
465    TString path;
466    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
467    // Several runs
468    if (fRunNumbers.Length()) {
469       TObjArray *arr = fRunNumbers.Tokenize(" ");
470       TObjString *os;
471       TIter next(arr);
472       while ((os=(TObjString*)next())) {
473          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
474          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
475          else file = Form("%s.xml", os->GetString().Data());
476          if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
477             Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
478 //            gGrid->Rm(file); 
479             continue;
480          }
481          command = "find ";
482          command += options;
483          command += path;
484          command += pattern;
485 //         conditions = Form(" > %s", file.Data());
486          command += conditions;
487          TGridResult *res = gGrid->Command(command);
488          if (res) delete res;
489          // Write standard output to file
490          gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
491          if (TestBit(AliAnalysisGrid::kTest)) break;
492          // Copy xml file to alien space
493          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
494          if (!FileExists(file)) {
495             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
496             delete arr;
497             return kFALSE;
498          }
499       }   
500       delete arr;
501    } else {
502       // Process a full run range.
503       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
504          path = Form("%s/%d ", fGridDataDir.Data(), irun);
505          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
506          else file = Form("%d.xml", irun);
507          if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
508             Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
509 //            gGrid->Rm(file); 
510             continue;
511          }
512          command = "find ";
513          command += options;
514          command += path;
515          command += pattern;
516 //         conditions = Form(" > %s", file.Data());
517          command += conditions;
518          TGridResult *res = gGrid->Command(command);
519          if (res) delete res;
520          // Write standard output to file
521          gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
522          if (TestBit(AliAnalysisGrid::kTest)) break;
523          // Copy xml file to alien space
524          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
525          if (!FileExists(file)) {
526             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
527             return kFALSE;
528          }
529       }
530    }      
531    return kTRUE;
532 }
533
534 //______________________________________________________________________________
535 Bool_t AliAnalysisAlien::CreateJDL()
536 {
537 // Generate a JDL file according to current settings. The name of the file is 
538 // specified by fJDLName.
539    Bool_t error = kFALSE;
540    TObjArray *arr = 0;
541    Bool_t copy = kTRUE;
542    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
543    Bool_t generate = kTRUE;
544    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
545    if (!Connect()) {
546       Error("CreateJDL", "Alien connection required");
547       return kFALSE;
548    }   
549    // Check validity of alien workspace
550    CdWork();
551    TString workdir = gGrid->GetHomeDirectory();
552    workdir += fGridWorkingDir;
553    if (generate) {
554       TObjString *os;
555       if (!fInputFiles) {
556          Error("CreateJDL()", "Define some input files for your analysis.");
557          error = kTRUE;
558       }
559       // Compose list of input files   
560       // Check if output files were defined
561       if (!fOutputFiles.Length()) {
562          Error("CreateJDL", "You must define at least one output file");
563          error = kTRUE;
564       }   
565       // Check if an output directory was defined and valid
566       if (!fGridOutputDir.Length()) {
567          Error("CreateJDL", "You must define AliEn output directory");
568          error = kTRUE;
569       } else {
570          if (!gGrid->Cd(fGridOutputDir)) {
571             if (gGrid->Mkdir(fGridOutputDir)) {
572                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
573             } else {
574                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
575                error = kTRUE;
576             }
577          }
578          gGrid->Cd(workdir);
579       }   
580       // Exit if any error up to now
581       if (error) return kFALSE;   
582       // Set JDL fields
583       fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
584       fGridJDL->SetExecutable(fExecutable);
585 //      fGridJDL->SetTTL((UInt_t)fTTL);
586       fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
587       if (fMaxInitFailed > 0) 
588          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
589       if (fSplitMaxInputFileNumber > 0) 
590          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
591       if (fSplitMode.Length()) 
592          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
593 //      fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
594       if (fAliROOTVersion.Length())  
595          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
596       if (fROOTVersion.Length()) 
597          fGridJDL->AddToPackages("ROOT", fROOTVersion);
598       if (fAPIVersion.Length()) 
599          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
600       fGridJDL->SetInputDataListFormat(fInputFormat);
601       fGridJDL->SetInputDataList("wn.xml");
602       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
603       fGridJDL->AddToInputSandbox(Form("LF:%s/analysis.root", workdir.Data()));
604       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
605          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
606       if (fAdditionalLibs.Length()) {
607          arr = fAdditionalLibs.Tokenize(" ");
608          TIter next(arr);
609          while ((os=(TObjString*)next())) {
610             if (os->GetString().Contains(".so")) continue;
611             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
612          }   
613          delete arr;   
614       }
615       if (fPackages) {
616          TIter next(fPackages);
617          TObject *obj;
618          while ((obj=next()))
619             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
620       }
621       if (fOutputArchive.Length()) {
622          arr = fOutputArchive.Tokenize(" ");
623          TIter next(arr);
624          while ((os=(TObjString*)next()))
625          if (!os->GetString().Contains("@") && fCloseSE.Length())
626             fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
627          else
628             fGridJDL->AddToOutputArchive(os->GetString());
629          delete arr;
630       }      
631       arr = fOutputFiles.Tokenize(" ");
632       TIter next(arr);
633       while ((os=(TObjString*)next())) {
634          if (!os->GetString().Contains("@") && fCloseSE.Length())
635             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
636          else
637             fGridJDL->AddToOutputSandbox(os->GetString());
638       }   
639       delete arr;
640 //      fGridJDL->SetPrice((UInt_t)fPrice);
641       fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
642       fGridJDL->SetValidationCommand(Form("%s/validate.sh", workdir.Data()));
643       if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
644       // Depending if going through a run range or not, generate one or mode jdl's
645       if (!fRunRange[0]) WriteJDL(-1,copy);
646       else {
647          for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++)
648             if (!WriteJDL(irun-fRunRange[0],copy)) break;
649       }
650    }
651    // Copy jdl to grid workspace   
652    if (copy) {
653       if (fAdditionalLibs.Length()) {
654          arr = fAdditionalLibs.Tokenize(" ");
655          TObjString *os;
656          TIter next(arr);
657          while ((os=(TObjString*)next())) {
658             if (os->GetString().Contains(".so")) continue;
659             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
660             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
661             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
662          }   
663          delete arr;   
664       }
665       if (fPackages) {
666          TIter next(fPackages);
667          TObject *obj;
668          while ((obj=next())) {
669             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
670             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
671          }   
672       }      
673    } 
674    return kTRUE;
675 }
676
677 //______________________________________________________________________________
678 Bool_t AliAnalysisAlien::WriteJDL(Int_t findex, Bool_t copy)
679 {
680 // Writes one or more JDL's corresponding to findex. If findex is negative,
681 // all run numbers are considered in one go (jdl). For non-negative indices
682 // they correspond to the indices in the array fInputFiles.
683    if (!fInputFiles) return kFALSE;
684    TObjString *os;
685    TString line;
686    TString workdir = gGrid->GetHomeDirectory();
687    workdir += fGridWorkingDir;
688    if (findex < 0) {
689       TIter next(fInputFiles);
690       while ((os=(TObjString*)next()))
691          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
692       fGridJDL->SetOutputDirectory(Form("%s/%s/#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data()));
693    } else {
694       os = (TObjString*)fInputFiles->At(findex);
695       if (!os) return kFALSE;
696       line = "#Input xml collection\n";
697       line += "InputDataCollection = {";
698       line += Form("   \"LF:%s,nodownload\"", os->GetString().Data());
699       line += "\n};\n";
700       fGridJDL->SetOutputDirectory(Form("%s/%s/%03d#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data(),findex));
701    }
702       
703
704    // Generate the JDL as a string
705    TString sjdl = fGridJDL->Generate();
706    Int_t index;
707    index = sjdl.Index("Executable");
708    if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
709    index = sjdl.Index("Split ");
710    if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
711    index = sjdl.Index("SplitMaxInputFileNumber");
712    if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
713    index = sjdl.Index("InputDataCollection");
714    if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
715    else {
716       index = sjdl.Index("OutputDir");
717       sjdl.Insert(index, line.Data());
718    }   
719    index = sjdl.Index("InputFile");
720    if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
721    index = sjdl.Index("InputDataList ");
722    if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
723    index = sjdl.Index("InputDataListFormat");
724    if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
725    index = sjdl.Index("Price");
726    if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
727    index = sjdl.Index("Requirements");
728    if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
729    index = sjdl.Index("Packages");
730    if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
731    index = sjdl.Index("User =");
732    if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
733    index = sjdl.Index("TTL");
734    if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
735    index = sjdl.Index("OutputFile");
736    if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
737    index = sjdl.Index("OutputDir");
738    if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
739    index = sjdl.Index("OutputArchive");
740    if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
741    index = sjdl.Index("MaxInitFailed");
742    if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
743    index = sjdl.Index("MasterResubmitThreshold");
744    if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
745    sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
746    index = sjdl.Index("Validationcommand");
747    if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
748    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
749    sjdl.ReplaceAll("(member", "\n   (member");
750    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
751    sjdl.ReplaceAll("{", "{\n   ");
752    sjdl.ReplaceAll("};", "\n};");
753    sjdl.ReplaceAll("{\n   \n", "{\n");
754    sjdl.ReplaceAll("\n\n", "\n");
755    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
756    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
757    sjdl.Prepend("JobTag = \"Automatically generated analysis JDL\";\n");
758    index = sjdl.Index("JDLVariables");
759    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
760    // Write jdl to file
761    TString snjdl = fJDLName;
762    if (findex >=0) snjdl.ReplaceAll(".jdl", Form("_%03d.jdl", findex));
763    ofstream out;
764    out.open(snjdl.Data(), ios::out);
765    if (out.bad()) {
766       Error("CreateJDL", "Bad file name: %s", snjdl.Data());
767       return kFALSE;
768    }
769    out << sjdl << endl;
770
771    // Copy jdl to grid workspace   
772    if (!copy) {
773       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
774    } else {
775       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn working space", snjdl.Data());
776       if (FileExists(snjdl)) gGrid->Rm(snjdl);
777       TFile::Cp(Form("file:%s",snjdl.Data()), Form("alien://%s/%s", workdir.Data(), snjdl.Data()));
778    } 
779    return kTRUE;
780 }
781
782 //______________________________________________________________________________
783 Bool_t AliAnalysisAlien::FileExists(const char *lfn) const
784 {
785 // Returns true if file exists.
786    if (!gGrid) {
787       Error("FileExists", "No connection to grid");
788       return kFALSE;
789    }
790    TGridResult *res = gGrid->Ls(lfn);
791    if (!res) return kFALSE;
792    TMap *map = dynamic_cast<TMap*>(res->At(0));
793    if (!map) {
794       delete res;
795       return kFALSE;
796    }   
797    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
798    if (!objs || !objs->GetString().Length()) {
799       delete res;
800       return kFALSE;
801    }
802    delete res;   
803    return kTRUE;
804 }
805
806 //______________________________________________________________________________
807 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
808 {
809 // Check input data type.
810    is_collection = kFALSE;
811    is_xml = kFALSE;
812    use_tags = kFALSE;
813    if (!gGrid) {
814       Error("CheckDataType", "No connection to grid");
815       return;
816    }
817    is_collection = IsCollection(lfn);
818    TString msg = "\n#####   file: ";
819    msg += lfn;
820    if (is_collection) {
821       msg += " type: raw_collection;";
822    // special treatment for collections
823       is_xml = kFALSE;
824       // check for tag files in the collection
825       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
826       if (!res) {
827          msg += " using_tags: No (unknown)";
828          Info("CheckDataType", msg.Data());
829          return;
830       }   
831       const char* typeStr = res->GetKey(0, "origLFN");
832       if (!typeStr || !strlen(typeStr)) {
833          msg += " using_tags: No (unknown)";
834          Info("CheckDataType", msg.Data());
835          return;
836       }   
837       TString file = typeStr;
838       use_tags = file.Contains(".tag");
839       if (use_tags) msg += " using_tags: Yes";
840       else          msg += " using_tags: No";
841       Info("CheckDataType", msg.Data());
842       return;
843    }
844    TString slfn(lfn);
845    slfn.ToLower();
846    is_xml = slfn.Contains(".xml");
847    if (is_xml) {
848    // Open xml collection and check if there are tag files inside
849       msg += " type: xml_collection;";
850       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
851       if (!coll) {
852          msg += " using_tags: No (unknown)";
853          Info("CheckDataType", msg.Data());
854          return;
855       }   
856       TMap *map = coll->Next();
857       if (!map) {
858          msg += " using_tags: No (unknown)";
859          Info("CheckDataType", msg.Data());
860          return;
861       }   
862       map = (TMap*)map->GetValue("");
863       TString file;
864       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
865       use_tags = file.Contains(".tag");
866       delete coll;
867       if (use_tags) msg += " using_tags: Yes";
868       else          msg += " using_tags: No";
869       Info("CheckDataType", msg.Data());
870       return;
871    }
872    use_tags = slfn.Contains(".tag");
873    if (slfn.Contains(".root")) msg += " type: root file;";
874    else                        msg += " type: unhnown file;";
875    if (use_tags) msg += " using_tags: Yes";
876    else          msg += " using_tags: No";
877    Info("CheckDataType", msg.Data());
878 }
879
880 //______________________________________________________________________________
881 void AliAnalysisAlien::EnablePackage(const char *package)
882 {
883 // Enables a par file supposed to exist in the current directory.
884    TString pkg(package);
885    pkg.ReplaceAll(".par", "");
886    pkg += ".par";
887    if (gSystem->AccessPathName(pkg)) {
888       Error("EnablePackage", "Package %s not found", pkg.Data());
889       return;
890    }
891    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
892       Info("EnablePackage", "AliEn plugin will use .par packages");
893    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
894    if (!fPackages) {
895       fPackages = new TObjArray();
896       fPackages->SetOwner();
897    }
898    fPackages->Add(new TObjString(pkg));
899 }      
900
901 //______________________________________________________________________________
902 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
903 {
904 // Returns true if file is a collection. Functionality duplicated from
905 // TAlien::Type() because we don't want to directly depend on TAlien.
906    if (!gGrid) {
907       Error("IsCollection", "No connection to grid");
908       return kFALSE;
909    }
910    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
911    if (!res) return kFALSE;
912    const char* typeStr = res->GetKey(0, "type");
913    if (!typeStr || !strlen(typeStr)) return kFALSE;
914    if (!strcmp(typeStr, "collection")) return kTRUE;
915    delete res;
916    return kFALSE;
917 }   
918
919 //______________________________________________________________________________
920 void AliAnalysisAlien::SetDefaults()
921 {
922 // Set default values for everything. What cannot be filled will be left empty.
923    if (fGridJDL) delete fGridJDL;
924    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
925    fPrice                      = 1;
926    fTTL                        = 30000;
927    fSplitMaxInputFileNumber    = 100;
928    fMaxInitFailed              = 0;
929    fMasterResubmitThreshold    = 0;
930    fNtestFiles                 = 10;
931    fRunRange[0]                = 0;
932    fRunRange[1]                = 0;
933    fNMasterJobs                = 0;
934    fRunNumbers                 = "";
935    fExecutable                 = "analysis.sh";
936    fArguments                  = "";
937    fAnalysisMacro              = "myAnalysis.C";
938    fAnalysisSource             = "";
939    fAdditionalLibs             = "";
940    fSplitMode                  = "se";
941    fAPIVersion                 = "";
942    fROOTVersion                = "";
943    fAliROOTVersion             = "";
944    fUser                       = "";  // Your alien user name
945    fGridWorkingDir             = "";
946    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
947    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
948    fFriendChainName            = "";
949    fGridOutputDir              = "output";
950    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
951    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
952    fInputFormat                = "xml-single";
953    fJDLName                    = "analysis.jdl";
954    fMergeExcludes              = "";
955 }   
956
957 //______________________________________________________________________________
958 Bool_t AliAnalysisAlien::MergeOutputs()
959 {
960 // Merge analysis outputs existing in the AliEn space.
961    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
962    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
963    if (!Connect()) {
964       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
965       return kFALSE;
966    }   
967    // Get the output path
968    TString output = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
969    if (!gGrid->Cd(output)) output = Form("/%s/%s", gGrid->GetHomeDirectory(), fGridOutputDir.Data());
970    if (!gGrid->Cd(output)) {
971       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
972       return kFALSE;
973    }
974    if (!fOutputFiles.Length()) {
975       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
976       return kFALSE;
977    }   
978    TObjArray *list = fOutputFiles.Tokenize(" ");
979    TIter next(list);
980    TObjString *str;
981    TString command;
982    TString output_file;
983    Bool_t merged = kTRUE;
984    while((str=(TObjString*)next())) {
985       output_file = str->GetString();
986       Int_t index = output_file.Index("@");
987       if (index > 0) output_file.Remove(index);
988       if (fMergeExcludes.Length() &&
989           fMergeExcludes.Contains(output_file.Data())) continue;
990       command = Form("find %s/ *%s", output.Data(), output_file.Data());
991       printf("command: %s\n", command.Data());
992       TGridResult *res = gGrid->Command(command);
993       if (!res) continue;
994       TFileMerger *fm = 0;
995       TIter nextmap(res);
996       TMap *map;
997       while ((map=(TMap*)nextmap())) {
998          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
999          if (!objs || !objs->GetString().Length()) {
1000             delete res;
1001             continue;
1002          }   
1003          if (!fm) {
1004             fm = new TFileMerger(kFALSE);
1005             fm->SetFastMethod(kTRUE);
1006             fm->OutputFile(output_file);
1007          }
1008          fm->AddFile(objs->GetString());   
1009       }
1010       if (!fm || !fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1011          Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1012          merged = kFALSE;
1013          delete res;
1014          continue;
1015       }
1016       if (!fm->Merge()) {
1017          Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1018          merged = kFALSE;
1019       } else {
1020          Info("MergeOutputs", "\n#####   Merged %d output files <%s>", fm->GetMergeList()->GetSize(), output_file.Data());
1021       }   
1022       delete fm;
1023       delete res;
1024    } 
1025    if (!merged) {
1026       Error("MergeOutputs", "Terminate() will  NOT be executed");
1027    }  
1028    return merged;
1029 }   
1030
1031 //______________________________________________________________________________
1032 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1033 {
1034 // Use the output files connected to output containers from the analysis manager
1035 // rather than the files defined by SetOutputFiles
1036    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1037       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1038       analysis manager");
1039    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1040 }
1041       
1042 //______________________________________________________________________________
1043 void AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1044 {
1045 // Start remote grid analysis.
1046    
1047    // Check if output files have to be taken from the analysis manager
1048    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1049       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1050       if (!mgr || !mgr->IsInitialized()) {
1051          Error("StartAnalysis", "You need an initialized analysis manager for this");
1052          return;
1053       }
1054       fOutputFiles = "";
1055       TIter next(mgr->GetOutputs());
1056       AliAnalysisDataContainer *output;
1057       while ((output=(AliAnalysisDataContainer*)next())) {
1058          const char *filename = output->GetFileName();
1059          if (!(strcmp(filename, "default"))) {
1060             if (!mgr->GetOutputEventHandler()) continue;
1061             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1062          }
1063          if (fOutputFiles.Length()) fOutputFiles += " ";
1064          fOutputFiles += filename;
1065       }
1066       // Add extra files registered to the analysis manager
1067       if (mgr->GetExtraFiles().Length()) {
1068          if (fOutputFiles.Length()) fOutputFiles += " ";
1069          fOutputFiles += mgr->GetExtraFiles();
1070       }   
1071    }
1072 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1073    if (TestBit(AliAnalysisGrid::kOffline)) {
1074       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1075       \n                         there nor any job run. You can revise the JDL and analysis \
1076       \n                         macro then run the same in \"submit\" mode.");
1077    } else if (TestBit(AliAnalysisGrid::kTest)) {
1078       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1079       \n                         dataset.");
1080    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1081       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1082       \n                         space and job submitted.");
1083    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1084       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1085       return;
1086    } else {
1087       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1088    }   
1089       
1090    if (!Connect()) {
1091       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1092       return;
1093    }   
1094    if (!CheckInputData()) {
1095       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1096       return;
1097    }   
1098    CreateDataset(fDataPattern);
1099    WriteAnalysisFile();   
1100    WriteAnalysisMacro();
1101    WriteExecutable();
1102    WriteValidationScript();
1103    if (!CreateJDL()) return;
1104    if (TestBit(AliAnalysisGrid::kOffline)) return;
1105    if (TestBit(AliAnalysisGrid::kTest)) {
1106       // Locally testing the analysis
1107       Info("StartAnalysis", "\n_______________________________________________________________________ \
1108       \n   Running analysis script in a daughter shell as on a worker node \
1109       \n_______________________________________________________________________");
1110       TObjArray *list = fOutputFiles.Tokenize(" ");
1111       TIter next(list);
1112       TObjString *str;
1113       TString output_file;
1114       while((str=(TObjString*)next())) {
1115          output_file = str->GetString();
1116          Int_t index = output_file.Index("@");
1117          if (index > 0) output_file.Remove(index);         
1118          if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1119       }
1120       delete list;
1121       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1122       gSystem->Exec("bash validate.sh");
1123 //      gSystem->Exec("cat stdout");
1124       return;
1125    }
1126    // Submit AliEn job(s)
1127    CdWork();
1128    TGridResult *res;
1129    TString jobID = "";
1130    if (!fRunRange[0]) {
1131       // Submit a given xml or a set of runs
1132       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1133       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1134       if (res) {
1135          const char *cjobId = res->GetKey(0,"jobId");
1136          if (!cjobId) {
1137             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1138             return;
1139          } else {
1140             Info("StartAnalysis", "\n_______________________________________________________________________ \
1141             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1142             \n_______________________________________________________________________",
1143                    fJDLName.Data(), cjobId);
1144             jobID = cjobId;      
1145          }          
1146          delete res;
1147       }   
1148    } else {
1149       // Submit for a range of runs.
1150       TString sjdl;
1151       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1152          if (!fInputFiles->At(irun-fRunRange[0])) break;
1153          sjdl = fJDLName;
1154          sjdl.ReplaceAll(".jdl", Form("_%03d.jdl", irun-fRunRange[0]));
1155          res = gGrid->Command(Form("submit %s", sjdl.Data()));
1156          printf("*************************** %s\n",Form("submit %s", sjdl.Data()));
1157          if (res) {
1158             const char *cjobId1 = res->GetKey(0,"jobId");
1159             if (!cjobId1) {
1160                Error("StartAnalysis", "Your JDL %s could not be submitted", sjdl.Data());
1161                return;
1162             } else {
1163                Info("StartAnalysis", "\n_______________________________________________________________________ \
1164                \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1165                \n_______________________________________________________________________",
1166                    sjdl.Data(), cjobId1);
1167                jobID += cjobId1;
1168                jobID += " ";
1169             }          
1170             delete res;
1171          }   
1172       }
1173    }   
1174          
1175    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1176    \n You may exit at any time and terminate the job later using the option <terminate> \
1177    \n ##################################################################################", jobID.Data());
1178    gSystem->Exec("aliensh");
1179 }
1180
1181 //______________________________________________________________________________
1182 void AliAnalysisAlien::WriteAnalysisFile()
1183 {
1184 // Write current analysis manager into the file analysis.root
1185    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1186       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1187       if (!mgr || !mgr->IsInitialized()) {
1188          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1189          return;
1190       }
1191       // Check analysis type
1192       TObject *handler;
1193       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1194       handler = (TObject*)mgr->GetInputEventHandler();
1195       if (handler) {
1196          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1197          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1198       }
1199       TDirectory *cdir = gDirectory;
1200       TFile *file = TFile::Open("analysis.root", "RECREATE");
1201       if (file) {
1202          mgr->Write();
1203          delete file;
1204       }
1205       if (cdir) cdir->cd();
1206       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
1207    }   
1208    Bool_t copy = kTRUE;
1209    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1210    if (copy) {
1211       CdWork();
1212       TString workdir = gGrid->GetHomeDirectory();
1213       workdir += fGridWorkingDir;
1214       Info("CreateJDL", "\n#####   Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
1215       if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
1216       TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
1217    }   
1218 }
1219
1220 //______________________________________________________________________________
1221 void AliAnalysisAlien::WriteAnalysisMacro()
1222 {
1223 // Write the analysis macro that will steer the analysis in grid mode.
1224    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1225       ofstream out;
1226       out.open(fAnalysisMacro.Data(), ios::out);
1227       if (!out.good()) {
1228          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1229          return;
1230       }
1231       TString func = fAnalysisMacro;
1232       TString type = "ESD";
1233       TString comment = "// Analysis using ";
1234       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1235       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1236          type = "AOD";
1237          comment += "AOD";
1238       }   
1239       if (type!="AOD" && fFriendChainName!="") {
1240          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1241          return;
1242       }
1243       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1244       else comment += " data";
1245       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1246       func.ReplaceAll(".C", "");
1247       out << "void " << func.Data() << "()" << endl; 
1248       out << "{" << endl;
1249       out << comment.Data() << endl;
1250       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1251       out << "   TStopwatch timer;" << endl;
1252       out << "   timer.Start();" << endl << endl;
1253       out << "// load base root libraries" << endl;
1254       out << "   gSystem->Load(\"libTree\");" << endl;
1255       out << "   gSystem->Load(\"libGeom\");" << endl;
1256       out << "   gSystem->Load(\"libVMC\");" << endl;
1257       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
1258       out << "// Load analysis framework libraries" << endl;
1259       if (!fPackages) {
1260          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1261          out << "   gSystem->Load(\"libESD\");" << endl;
1262          out << "   gSystem->Load(\"libAOD\");" << endl;
1263          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1264          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1265          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1266       } else {
1267          TIter next(fPackages);
1268          TObject *obj;
1269          TString pkgname;
1270          Bool_t hasSTEERBase = kFALSE;
1271          Bool_t hasESD = kFALSE;
1272          Bool_t hasAOD = kFALSE;
1273          Bool_t hasANALYSIS = kFALSE;
1274          Bool_t hasANALYSISalice = kFALSE;
1275          Bool_t hasCORRFW = kFALSE;
1276          while ((obj=next())) {
1277             pkgname = obj->GetName();
1278             if (pkgname == "STEERBase" ||
1279                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1280             if (pkgname == "ESD" ||
1281                 pkgname == "ESD.par")       hasESD = kTRUE;
1282             if (pkgname == "AOD" ||
1283                 pkgname == "AOD.par")       hasAOD = kTRUE;
1284             if (pkgname == "ANALYSIS" ||
1285                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
1286             if (pkgname == "ANALYSISalice" ||
1287                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1288             if (pkgname == "CORRFW" ||
1289                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
1290          }   
1291          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1292          else out << "   if (!SetupPar(\"STEERBase\")) return;" << endl;
1293          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
1294          else out << "   if (!SetupPar(\"ESD\")) return;" << endl;
1295          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
1296          else out << "   if (!SetupPar(\"AOD\")) return;" << endl;
1297          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1298          else out << "   if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1299          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1300          else out << "   if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1301          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1302          else out << "   if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1303          out << "// Compile other par packages" << endl;
1304          next.Reset();
1305          while ((obj=next())) {
1306             pkgname = obj->GetName();
1307             if (pkgname == "STEERBase" ||
1308                 pkgname == "STEERBase.par" ||
1309                 pkgname == "ESD" ||
1310                 pkgname == "ESD.par" ||
1311                 pkgname == "AOD" ||
1312                 pkgname == "AOD.par" ||
1313                 pkgname == "ANALYSIS" ||
1314                 pkgname == "ANALYSIS.par" ||
1315                 pkgname == "ANALYSISalice" ||
1316                 pkgname == "ANALYSISalice.par" ||
1317                 pkgname == "CORRFW" ||
1318                 pkgname == "CORRFW.par") continue;
1319             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1320          }   
1321       }   
1322       out << "// include path" << endl;
1323       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1324       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1325       if (fAdditionalLibs.Length()) {
1326          out << "// Add aditional AliRoot libraries" << endl;
1327          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1328          TIter next(list);
1329          TObjString *str;
1330          while((str=(TObjString*)next())) {
1331             if (str->GetString().Contains(".so"))
1332                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1333          }
1334          if (list) delete list;
1335       }
1336       out << endl;
1337       out << "// analysis source to be compiled at runtime (if any)" << endl;
1338       if (fAnalysisSource.Length()) {
1339          TObjArray *list = fAnalysisSource.Tokenize(" ");
1340          TIter next(list);
1341          TObjString *str;
1342          while((str=(TObjString*)next())) {
1343             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1344          }   
1345          if (list) delete list;
1346       }
1347       out << endl;
1348       out << "// connect to AliEn and make the chain" << endl;
1349       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1350       if (IsUsingTags()) {
1351          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1352       } else {
1353          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;      
1354       }   
1355       out << "// read the analysis manager from file" << endl;
1356       out << "   TFile *file = TFile::Open(\"analysis.root\");" << endl;
1357       out << "   if (!file) return;" << endl; 
1358       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1359       out << "   AliAnalysisManager *mgr = 0;" << endl;
1360       out << "   TKey *key;" << endl;
1361       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1362       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1363       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1364       out << "   };" << endl;
1365       out << "   if (!mgr) {" << endl;
1366       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1367       out << "      return;" << endl;
1368       out << "   }" << endl << endl;
1369       out << "   mgr->PrintStatus();" << endl;
1370       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1371       out << "   timer.Stop();" << endl;
1372       out << "   timer.Print();" << endl;
1373       out << "}" << endl << endl;
1374       if (IsUsingTags()) {
1375          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1376          out << "{" << endl;
1377          out << "// Create a chain using tags from the xml file." << endl;
1378          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1379          out << "   if (!coll) {" << endl;
1380          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1381          out << "      return NULL;" << endl;
1382          out << "   }" << endl;
1383          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1384          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1385          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1386          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1387          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1388          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1389          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1390          out << "   // Check if the cuts configuration file was provided" << endl;
1391          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1392          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1393          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1394          out << "   }" << endl;
1395          if (fFriendChainName=="") {
1396             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1397          } else {
1398             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
1399             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1400             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1401          }
1402          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1403          out << "   chain->ls();" << endl;
1404          out << "   return chain;" << endl;
1405          out << "}" << endl << endl;
1406          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1407             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1408             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1409             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1410             msg += "                      AliDetectorTagCuts *detCuts,\n";
1411             msg += "                      AliEventTagCuts *evCuts)";
1412             Info("WriteAnalysisMacro", msg.Data());
1413          }
1414       } 
1415       if (!IsUsingTags() || fFriendChainName!="") {
1416          out <<"//________________________________________________________________________________" << endl;
1417          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1418          out << "{" << endl;
1419          out << "// Create a chain using url's from xml file" << endl;
1420          out << "   TString treename = type;" << endl;
1421          out << "   treename.ToLower();" << endl;
1422          out << "   treename += \"Tree\";" << endl;
1423          out << "   printf(\"***************************************\\n\");" << endl;
1424          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
1425          out << "   printf(\"***************************************\\n\");" << endl;
1426          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1427          out << "   if (!coll) {" << endl;
1428          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1429          out << "      return NULL;" << endl;
1430          out << "   }" << endl;
1431          out << "   TChain *chain = new TChain(treename);" << endl;
1432          if(fFriendChainName!="") {
1433             out << "   TChain *chainFriend = new TChain(treename);" << endl;
1434          }
1435          out << "   coll->Reset();" << endl;
1436          out << "   while (coll->Next()) {" << endl;
1437          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
1438          if(fFriendChainName!="") {
1439             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
1440             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1441             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1442             out << "      chainFriend->Add(fileFriend.Data());" << endl;
1443          }
1444          out << "   }" << endl;
1445          out << "   if (!chain->GetNtrees()) {" << endl;
1446          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1447          out << "      return NULL;" << endl;
1448          out << "   }" << endl;
1449          if(fFriendChainName!="") {
1450             out << "   chain->AddFriend(chainFriend);" << endl;
1451          }
1452          out << "   return chain;" << endl;
1453          out << "}" << endl << endl;
1454       }   
1455       if (fPackages) {
1456          out <<"//________________________________________________________________________________" << endl;
1457          out << "Bool_t SetupPar(const char *package) {" << endl;
1458          out << "// Compile the package and set it up." << endl;
1459          out << "   TString pkgdir = package;" << endl;
1460          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1461          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1462          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
1463          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
1464          out << "   // Check for BUILD.sh and execute" << endl;
1465          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1466          out << "      printf(\"*******************************\\n\");" << endl;
1467          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
1468          out << "      printf(\"*******************************\\n\");" << endl;
1469          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1470          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1471          out << "         gSystem->ChangeDirectory(cdir);" << endl;
1472          out << "         return kFALSE;" << endl;
1473          out << "      }" << endl;
1474          out << "   } else {" << endl;
1475          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1476          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1477          out << "      return kFALSE;" << endl;
1478          out << "   }" << endl;
1479          out << "   // Check for SETUP.C and execute" << endl;
1480          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1481          out << "      printf(\"*******************************\\n\");" << endl;
1482          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
1483          out << "      printf(\"*******************************\\n\");" << endl;
1484          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1485          out << "   } else {" << endl;
1486          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1487          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1488          out << "      return kFALSE;" << endl;
1489          out << "   }" << endl;
1490          out << "   // Restore original workdir" << endl;
1491          out << "   gSystem->ChangeDirectory(cdir);" << endl;
1492          out << "   return kTRUE;" << endl;
1493          out << "}" << endl;
1494       }
1495       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1496    }   
1497    Bool_t copy = kTRUE;
1498    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1499    if (copy) {
1500       CdWork();
1501       TString workdir = gGrid->GetHomeDirectory();
1502       workdir += fGridWorkingDir;
1503       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1504       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1505          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1506          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1507          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1508       }   
1509       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1510       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1511    }
1512 }
1513
1514 //______________________________________________________________________________
1515 void AliAnalysisAlien::WriteExecutable()
1516 {
1517 // Generate the alien executable script.
1518    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1519       ofstream out;
1520       out.open(fExecutable.Data(), ios::out);
1521       if (out.bad()) {
1522          Error("CreateJDL", "Bad file name for executable: %s", fExecutable.Data());
1523          return;
1524       }
1525       out << "#!/bin/bash" << endl;
1526       out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1527       out << "echo \"=========================================\"" << endl; 
1528       out << "echo \"############## PATH : ##############\"" << endl;
1529       out << "echo $PATH" << endl;
1530       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1531       out << "echo $LD_LIBRARY_PATH" << endl;
1532       out << "echo \"############## ROOTSYS : ##############\"" << endl;
1533       out << "echo $ROOTSYS" << endl;
1534       out << "echo \"############## which root : ##############\"" << endl;
1535       out << "which root" << endl;
1536       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1537       out << "echo $ALICE_ROOT" << endl;
1538       out << "echo \"############## which aliroot : ##############\"" << endl;
1539       out << "which aliroot" << endl;
1540       out << "echo \"=========================================\"" << endl << endl;
1541 //      if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1542       out << "root -b -q "; 
1543       out << fAnalysisMacro.Data() << endl << endl;
1544       out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1545    }   
1546    Bool_t copy = kTRUE;
1547    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1548    if (copy) {
1549       CdWork();
1550       TString workdir = gGrid->GetHomeDirectory();
1551       workdir += fGridWorkingDir;
1552       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1553       if (FileExists(executable)) gGrid->Rm(executable);
1554       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1555       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1556    } 
1557 }
1558
1559 //______________________________________________________________________________
1560 void AliAnalysisAlien::WriteValidationScript()
1561 {
1562 // Generate the alien validation script.
1563    // Generate the validation script
1564    TObjString *os;
1565    if (!Connect()) {
1566       Error("WriteValidationScript", "Alien connection required");
1567       return;
1568    }
1569    TString out_stream = "";
1570    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1571    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1572       ofstream out;
1573       out.open("validate.sh", ios::out);
1574       out << "#!/bin/bash" << endl;
1575       out << "##################################################" << endl;
1576       out << "validateout=`dirname $0`" << endl;
1577       out << "validatetime=`date`" << endl;
1578       out << "validated=\"0\";" << endl;
1579       out << "error=0" << endl;
1580       out << "if [ -z $validateout ]" << endl;
1581       out << "then" << endl;
1582       out << "    validateout=\".\"" << endl;
1583       out << "fi" << endl << endl;
1584       out << "cd $validateout;" << endl;
1585       out << "validateworkdir=`pwd`;" << endl << endl;
1586       out << "echo \"*******************************************************\"" << out_stream << endl;
1587       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
1588       out << "" << endl;
1589       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
1590       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
1591       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
1592       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1593       out << "ls -la ./"  << out_stream << endl;
1594       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
1595       out << "##################################################" << endl;
1596
1597       out << "" << endl;
1598       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
1599       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
1600       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
1601       out << "" << endl;
1602
1603       out << "if [ ! -f stderr ] ; then" << endl;
1604       out << "   error=1" << endl;
1605       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
1606       out << "   echo \"Error = $error\" " << out_stream << endl;
1607       out << "fi" << endl;
1608
1609       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
1610       out << "   error=1" << endl;
1611       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
1612       out << "   echo \"$parArch\" " << out_stream << endl;
1613       out << "   echo \"Error = $error\" " << out_stream << endl;
1614       out << "fi" << endl;
1615
1616       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
1617       out << "   error=1" << endl;
1618       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
1619       out << "   echo \"$segViol\" " << out_stream << endl;
1620       out << "   echo \"Error = $error\" " << out_stream << endl;
1621       out << "fi" << endl;
1622
1623       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
1624       out << "   error=1" << endl;
1625       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
1626       out << "   echo \"$segFault\" " << out_stream << endl;
1627       out << "   echo \"Error = $error\" " << out_stream << endl;
1628       out << "fi" << endl;
1629
1630       // Part dedicated to the specific analyses running into the train
1631
1632       TObjArray *arr = fOutputFiles.Tokenize(" ");
1633       TIter next1(arr);
1634       TString output_file;
1635       while ((os=(TObjString*)next1())) { 
1636          output_file = os->GetString();
1637          Int_t index = output_file.Index("@");
1638          if (index > 0) output_file.Remove(index);
1639          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
1640          out << "   error=1" << endl;
1641          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
1642          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
1643          out << "fi" << endl;
1644       }   
1645       delete arr;
1646       out << "if [ $error = 0 ] ; then" << endl;
1647       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
1648       out << "fi" << endl;
1649
1650       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1651       out << "echo \"*******************************************************\""  << out_stream << endl;
1652       out << "cd -" << endl;
1653       out << "exit $error" << endl;
1654    }    
1655    Bool_t copy = kTRUE;
1656    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1657    if (copy) {
1658       CdWork();
1659       TString workdir = gGrid->GetHomeDirectory();
1660       workdir += fGridWorkingDir;
1661       Info("CreateJDL", "\n#####   Copying validation script <validate.sh> to your AliEn working space");
1662       if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
1663       TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));
1664    } 
1665 }