]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
Run ranges now supported: plugin->SetRunRange(min,max). If run numbers are given...
[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             WriteJDL(irun-fRunRange[0],copy);
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    CdWork();
689    if (findex < 0) {
690       TIter next(fInputFiles);
691       while ((os=(TObjString*)next()))
692          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
693       fGridJDL->SetOutputDirectory(Form("%s/%s/#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data()));
694    } else {
695       os = (TObjString*)fInputFiles->At(findex);
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 (fRunNumbers.Length()) {
1131       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1132       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1133       if (res) {
1134          const char *cjobId = res->GetKey(0,"jobId");
1135          if (!cjobId) {
1136             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1137             return;
1138          } else {
1139             Info("StartAnalysis", "\n_______________________________________________________________________ \
1140             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1141             \n_______________________________________________________________________",
1142                    fJDLName.Data(), cjobId);
1143             jobID = cjobId;      
1144          }          
1145          delete res;
1146       }   
1147    } else {
1148       if (!fRunRange[0]) {
1149          Error("StartAnalysis", "No runs defined. Exiting.");
1150          return;
1151       }
1152       TString sjdl;
1153       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1154          sjdl = fJDLName;
1155          sjdl.ReplaceAll(".jdl", Form("_%03d.jdl", irun-fRunRange[0]));
1156          res = gGrid->Command(Form("submit %s", sjdl.Data()));
1157          printf("*************************** %s\n",Form("submit %s", sjdl.Data()));
1158          if (res) {
1159             const char *cjobId1 = res->GetKey(0,"jobId");
1160             if (!cjobId1) {
1161                Error("StartAnalysis", "Your JDL %s could not be submitted", sjdl.Data());
1162                return;
1163             } else {
1164                Info("StartAnalysis", "\n_______________________________________________________________________ \
1165                \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1166                \n_______________________________________________________________________",
1167                    sjdl.Data(), cjobId1);
1168                jobID += cjobId1;
1169                jobID += " ";
1170             }          
1171             delete res;
1172          }   
1173       }
1174    }   
1175          
1176    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1177    \n You may exit at any time and terminate the job later using the option <terminate> \
1178    \n ##################################################################################", jobID.Data());
1179    //gGrid->Shell();
1180    gSystem->Exec("aliensh");
1181 }
1182
1183 //______________________________________________________________________________
1184 void AliAnalysisAlien::WriteAnalysisFile()
1185 {
1186 // Write current analysis manager into the file analysis.root
1187    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1188       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1189       if (!mgr || !mgr->IsInitialized()) {
1190          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1191          return;
1192       }
1193       // Check analysis type
1194       TObject *handler;
1195       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1196       handler = (TObject*)mgr->GetInputEventHandler();
1197       if (handler) {
1198          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1199          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1200       }
1201       TDirectory *cdir = gDirectory;
1202       TFile *file = TFile::Open("analysis.root", "RECREATE");
1203       if (file) {
1204          mgr->Write();
1205          delete file;
1206       }
1207       if (cdir) cdir->cd();
1208       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
1209    }   
1210    Bool_t copy = kTRUE;
1211    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1212    if (copy) {
1213       CdWork();
1214       TString workdir = gGrid->GetHomeDirectory();
1215       workdir += fGridWorkingDir;
1216       Info("CreateJDL", "\n#####   Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
1217       if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
1218       TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
1219    }   
1220 }
1221
1222 //______________________________________________________________________________
1223 void AliAnalysisAlien::WriteAnalysisMacro()
1224 {
1225 // Write the analysis macro that will steer the analysis in grid mode.
1226    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1227       ofstream out;
1228       out.open(fAnalysisMacro.Data(), ios::out);
1229       if (!out.good()) {
1230          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1231          return;
1232       }
1233       TString func = fAnalysisMacro;
1234       TString type = "ESD";
1235       TString comment = "// Analysis using ";
1236       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1237       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1238          type = "AOD";
1239          comment += "AOD";
1240       }   
1241       if (type!="AOD" && fFriendChainName!="") {
1242          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1243          return;
1244       }
1245       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1246       else comment += " data";
1247       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1248       func.ReplaceAll(".C", "");
1249       out << "void " << func.Data() << "()" << endl; 
1250       out << "{" << endl;
1251       out << comment.Data() << endl;
1252       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1253       out << "   TStopwatch timer;" << endl;
1254       out << "   timer.Start();" << endl << endl;
1255       out << "// load base root libraries" << endl;
1256       out << "   gSystem->Load(\"libTree\");" << endl;
1257       out << "   gSystem->Load(\"libGeom\");" << endl;
1258       out << "   gSystem->Load(\"libVMC\");" << endl;
1259       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
1260       out << "// Load analysis framework libraries" << endl;
1261       if (!fPackages) {
1262          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1263          out << "   gSystem->Load(\"libESD\");" << endl;
1264          out << "   gSystem->Load(\"libAOD\");" << endl;
1265          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1266          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1267          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1268       } else {
1269          TIter next(fPackages);
1270          TObject *obj;
1271          TString pkgname;
1272          Bool_t hasSTEERBase = kFALSE;
1273          Bool_t hasESD = kFALSE;
1274          Bool_t hasAOD = kFALSE;
1275          Bool_t hasANALYSIS = kFALSE;
1276          Bool_t hasANALYSISalice = kFALSE;
1277          Bool_t hasCORRFW = kFALSE;
1278          while ((obj=next())) {
1279             pkgname = obj->GetName();
1280             if (pkgname == "STEERBase" ||
1281                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1282             if (pkgname == "ESD" ||
1283                 pkgname == "ESD.par")       hasESD = kTRUE;
1284             if (pkgname == "AOD" ||
1285                 pkgname == "AOD.par")       hasAOD = kTRUE;
1286             if (pkgname == "ANALYSIS" ||
1287                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
1288             if (pkgname == "ANALYSISalice" ||
1289                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1290             if (pkgname == "CORRFW" ||
1291                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
1292          }   
1293          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1294          else out << "   if (!SetupPar(\"STEERBase\")) return;" << endl;
1295          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
1296          else out << "   if (!SetupPar(\"ESD\")) return;" << endl;
1297          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
1298          else out << "   if (!SetupPar(\"AOD\")) return;" << endl;
1299          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1300          else out << "   if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1301          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1302          else out << "   if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1303          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1304          else out << "   if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1305          out << "// Compile other par packages" << endl;
1306          next.Reset();
1307          while ((obj=next())) {
1308             pkgname = obj->GetName();
1309             if (pkgname == "STEERBase" ||
1310                 pkgname == "STEERBase.par" ||
1311                 pkgname == "ESD" ||
1312                 pkgname == "ESD.par" ||
1313                 pkgname == "AOD" ||
1314                 pkgname == "AOD.par" ||
1315                 pkgname == "ANALYSIS" ||
1316                 pkgname == "ANALYSIS.par" ||
1317                 pkgname == "ANALYSISalice" ||
1318                 pkgname == "ANALYSISalice.par" ||
1319                 pkgname == "CORRFW" ||
1320                 pkgname == "CORRFW.par") continue;
1321             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1322          }   
1323       }   
1324       out << "// include path" << endl;
1325       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1326       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1327       if (fAdditionalLibs.Length()) {
1328          out << "// Add aditional AliRoot libraries" << endl;
1329          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1330          TIter next(list);
1331          TObjString *str;
1332          while((str=(TObjString*)next())) {
1333             if (str->GetString().Contains(".so"))
1334                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1335          }
1336          if (list) delete list;
1337       }
1338       out << endl;
1339       out << "// analysis source to be compiled at runtime (if any)" << endl;
1340       if (fAnalysisSource.Length()) {
1341          TObjArray *list = fAnalysisSource.Tokenize(" ");
1342          TIter next(list);
1343          TObjString *str;
1344          while((str=(TObjString*)next())) {
1345             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1346          }   
1347          if (list) delete list;
1348       }
1349       out << endl;
1350       out << "// connect to AliEn and make the chain" << endl;
1351       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1352       if (IsUsingTags()) {
1353          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1354       } else {
1355          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;      
1356       }   
1357       out << "// read the analysis manager from file" << endl;
1358       out << "   TFile *file = TFile::Open(\"analysis.root\");" << endl;
1359       out << "   if (!file) return;" << endl; 
1360       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1361       out << "   AliAnalysisManager *mgr = 0;" << endl;
1362       out << "   TKey *key;" << endl;
1363       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1364       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1365       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1366       out << "   };" << endl;
1367       out << "   if (!mgr) {" << endl;
1368       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1369       out << "      return;" << endl;
1370       out << "   }" << endl << endl;
1371       out << "   mgr->PrintStatus();" << endl;
1372       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1373       out << "   timer.Stop();" << endl;
1374       out << "   timer.Print();" << endl;
1375       out << "}" << endl << endl;
1376       if (IsUsingTags()) {
1377          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1378          out << "{" << endl;
1379          out << "// Create a chain using tags from the xml file." << endl;
1380          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1381          out << "   if (!coll) {" << endl;
1382          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1383          out << "      return NULL;" << endl;
1384          out << "   }" << endl;
1385          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1386          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1387          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1388          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1389          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1390          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1391          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1392          out << "   // Check if the cuts configuration file was provided" << endl;
1393          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1394          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1395          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1396          out << "   }" << endl;
1397          if (fFriendChainName=="") {
1398             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1399          } else {
1400             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
1401             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1402             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1403          }
1404          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1405          out << "   chain->ls();" << endl;
1406          out << "   return chain;" << endl;
1407          out << "}" << endl << endl;
1408          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1409             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1410             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1411             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1412             msg += "                      AliDetectorTagCuts *detCuts,\n";
1413             msg += "                      AliEventTagCuts *evCuts)";
1414             Info("WriteAnalysisMacro", msg.Data());
1415          }
1416       } 
1417       if (!IsUsingTags() || fFriendChainName!="") {
1418          out <<"//________________________________________________________________________________" << endl;
1419          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1420          out << "{" << endl;
1421          out << "// Create a chain using url's from xml file" << endl;
1422          out << "   TString treename = type;" << endl;
1423          out << "   treename.ToLower();" << endl;
1424          out << "   treename += \"Tree\";" << endl;
1425          out << "   printf(\"***************************************\\n\");" << endl;
1426          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
1427          out << "   printf(\"***************************************\\n\");" << endl;
1428          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1429          out << "   if (!coll) {" << endl;
1430          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1431          out << "      return NULL;" << endl;
1432          out << "   }" << endl;
1433          out << "   TChain *chain = new TChain(treename);" << endl;
1434          if(fFriendChainName!="") {
1435             out << "   TChain *chainFriend = new TChain(treename);" << endl;
1436          }
1437          out << "   coll->Reset();" << endl;
1438          out << "   while (coll->Next()) {" << endl;
1439          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
1440          if(fFriendChainName!="") {
1441             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
1442             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1443             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1444             out << "      chainFriend->Add(fileFriend.Data());" << endl;
1445          }
1446          out << "   }" << endl;
1447          out << "   if (!chain->GetNtrees()) {" << endl;
1448          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1449          out << "      return NULL;" << endl;
1450          out << "   }" << endl;
1451          if(fFriendChainName!="") {
1452             out << "   chain->AddFriend(chainFriend);" << endl;
1453          }
1454          out << "   return chain;" << endl;
1455          out << "}" << endl << endl;
1456       }   
1457       if (fPackages) {
1458          out <<"//________________________________________________________________________________" << endl;
1459          out << "Bool_t SetupPar(const char *package) {" << endl;
1460          out << "// Compile the package and set it up." << endl;
1461          out << "   TString pkgdir = package;" << endl;
1462          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1463          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1464          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
1465          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
1466          out << "   // Check for BUILD.sh and execute" << endl;
1467          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1468          out << "      printf(\"*******************************\\n\");" << endl;
1469          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
1470          out << "      printf(\"*******************************\\n\");" << endl;
1471          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1472          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1473          out << "         gSystem->ChangeDirectory(cdir);" << endl;
1474          out << "         return kFALSE;" << endl;
1475          out << "      }" << endl;
1476          out << "   } else {" << endl;
1477          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1478          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1479          out << "      return kFALSE;" << endl;
1480          out << "   }" << endl;
1481          out << "   // Check for SETUP.C and execute" << endl;
1482          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1483          out << "      printf(\"*******************************\\n\");" << endl;
1484          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
1485          out << "      printf(\"*******************************\\n\");" << endl;
1486          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1487          out << "   } else {" << endl;
1488          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1489          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1490          out << "      return kFALSE;" << endl;
1491          out << "   }" << endl;
1492          out << "   // Restore original workdir" << endl;
1493          out << "   gSystem->ChangeDirectory(cdir);" << endl;
1494          out << "   return kTRUE;" << endl;
1495          out << "}" << endl;
1496       }
1497       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1498    }   
1499    Bool_t copy = kTRUE;
1500    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1501    if (copy) {
1502       CdWork();
1503       TString workdir = gGrid->GetHomeDirectory();
1504       workdir += fGridWorkingDir;
1505       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1506       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1507          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1508          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1509          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1510       }   
1511       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1512       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1513    }
1514 }
1515
1516 //______________________________________________________________________________
1517 void AliAnalysisAlien::WriteExecutable()
1518 {
1519 // Generate the alien executable script.
1520    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1521       ofstream out;
1522       out.open(fExecutable.Data(), ios::out);
1523       if (out.bad()) {
1524          Error("CreateJDL", "Bad file name for executable: %s", fExecutable.Data());
1525          return;
1526       }
1527       out << "#!/bin/bash" << endl;
1528       out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1529       out << "echo \"=========================================\"" << endl; 
1530       out << "echo \"############## PATH : ##############\"" << endl;
1531       out << "echo $PATH" << endl;
1532       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1533       out << "echo $LD_LIBRARY_PATH" << endl;
1534       out << "echo \"############## ROOTSYS : ##############\"" << endl;
1535       out << "echo $ROOTSYS" << endl;
1536       out << "echo \"############## which root : ##############\"" << endl;
1537       out << "which root" << endl;
1538       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1539       out << "echo $ALICE_ROOT" << endl;
1540       out << "echo \"############## which aliroot : ##############\"" << endl;
1541       out << "which aliroot" << endl;
1542       out << "echo \"=========================================\"" << endl << endl;
1543 //      if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1544       out << "root -b -q "; 
1545       out << fAnalysisMacro.Data() << endl << endl;
1546       out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1547    }   
1548    Bool_t copy = kTRUE;
1549    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1550    if (copy) {
1551       CdWork();
1552       TString workdir = gGrid->GetHomeDirectory();
1553       workdir += fGridWorkingDir;
1554       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1555       if (FileExists(executable)) gGrid->Rm(executable);
1556       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1557       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1558    } 
1559 }
1560
1561 //______________________________________________________________________________
1562 void AliAnalysisAlien::WriteValidationScript()
1563 {
1564 // Generate the alien validation script.
1565    // Generate the validation script
1566    TObjString *os;
1567    if (!Connect()) {
1568       Error("WriteValidationScript", "Alien connection required");
1569       return;
1570    }
1571    TString out_stream = "";
1572    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1573    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1574       ofstream out;
1575       out.open("validate.sh", ios::out);
1576       out << "#!/bin/bash" << endl;
1577       out << "##################################################" << endl;
1578       out << "validateout=`dirname $0`" << endl;
1579       out << "validatetime=`date`" << endl;
1580       out << "validated=\"0\";" << endl;
1581       out << "error=0" << endl;
1582       out << "if [ -z $validateout ]" << endl;
1583       out << "then" << endl;
1584       out << "    validateout=\".\"" << endl;
1585       out << "fi" << endl << endl;
1586       out << "cd $validateout;" << endl;
1587       out << "validateworkdir=`pwd`;" << endl << endl;
1588       out << "echo \"*******************************************************\"" << out_stream << endl;
1589       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
1590       out << "" << endl;
1591       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
1592       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
1593       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
1594       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1595       out << "ls -la ./"  << out_stream << endl;
1596       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
1597       out << "##################################################" << endl;
1598
1599       out << "" << endl;
1600       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
1601       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
1602       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
1603       out << "" << endl;
1604
1605       out << "if [ ! -f stderr ] ; then" << endl;
1606       out << "   error=1" << endl;
1607       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
1608       out << "   echo \"Error = $error\" " << out_stream << endl;
1609       out << "fi" << endl;
1610
1611       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
1612       out << "   error=1" << endl;
1613       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
1614       out << "   echo \"$parArch\" " << out_stream << endl;
1615       out << "   echo \"Error = $error\" " << out_stream << endl;
1616       out << "fi" << endl;
1617
1618       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
1619       out << "   error=1" << endl;
1620       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
1621       out << "   echo \"$segViol\" " << out_stream << endl;
1622       out << "   echo \"Error = $error\" " << out_stream << endl;
1623       out << "fi" << endl;
1624
1625       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
1626       out << "   error=1" << endl;
1627       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
1628       out << "   echo \"$segFault\" " << out_stream << endl;
1629       out << "   echo \"Error = $error\" " << out_stream << endl;
1630       out << "fi" << endl;
1631
1632       // Part dedicated to the specific analyses running into the train
1633
1634       TObjArray *arr = fOutputFiles.Tokenize(" ");
1635       TIter next1(arr);
1636       TString output_file;
1637       while ((os=(TObjString*)next1())) { 
1638          output_file = os->GetString();
1639          Int_t index = output_file.Index("@");
1640          if (index > 0) output_file.Remove(index);
1641          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
1642          out << "   error=1" << endl;
1643          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
1644          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
1645          out << "fi" << endl;
1646       }   
1647       delete arr;
1648       out << "if [ $error = 0 ] ; then" << endl;
1649       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
1650       out << "fi" << endl;
1651
1652       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1653       out << "echo \"*******************************************************\""  << out_stream << endl;
1654       out << "cd -" << endl;
1655       out << "exit $error" << endl;
1656    }    
1657    Bool_t copy = kTRUE;
1658    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1659    if (copy) {
1660       CdWork();
1661       TString workdir = gGrid->GetHomeDirectory();
1662       workdir += fGridWorkingDir;
1663       Info("CreateJDL", "\n#####   Copying validation script <validate.sh> to your AliEn working space");
1664       if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
1665       TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));
1666    } 
1667 }