]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
Added the possibility to prefix run numbers with a string. Can be used in correlation...
[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 "TGridJobStatusList.h"
34 #include "TGridJobStatus.h"
35 #include "TFileMerger.h"
36 #include "AliAnalysisManager.h"
37 #include "AliVEventHandler.h"
38 #include "AliAnalysisDataContainer.h"
39 #include "AliAnalysisAlien.h"
40
41 ClassImp(AliAnalysisAlien)
42
43 //______________________________________________________________________________
44 AliAnalysisAlien::AliAnalysisAlien()
45                  :AliAnalysisGrid(),
46                   fGridJDL(NULL),
47                   fPrice(0),
48                   fTTL(0),
49                   fSplitMaxInputFileNumber(0),
50                   fMaxInitFailed(0),
51                   fMasterResubmitThreshold(0),
52                   fNtestFiles(0),
53                   fNrunsPerMaster(0),
54                   fMaxMergeFiles(0),
55                   fNsubmitted(0),
56                   fProductionMode(0),
57                   fRunNumbers(),
58                   fExecutable(),
59                   fExecutableCommand(),
60                   fArguments(),
61                   fAnalysisMacro(),
62                   fAnalysisSource(),
63                   fAdditionalLibs(),
64                   fSplitMode(),
65                   fAPIVersion(),
66                   fROOTVersion(),
67                   fAliROOTVersion(),
68                   fExternalPackages(),
69                   fUser(),
70                   fGridWorkingDir(),
71                   fGridDataDir(),
72                   fDataPattern(),
73                   fGridOutputDir(),
74                   fOutputArchive(),
75                   fOutputFiles(),
76                   fInputFormat(),
77                   fDatasetName(),
78                   fJDLName(),
79                             fMergeExcludes(),
80                   fIncludePath(),
81                   fCloseSE(),
82                   fFriendChainName(),
83                   fJobTag(),
84                   fOutputSingle(),
85                   fRunPrefix(),
86                   fInputFiles(0),
87                   fPackages(0)
88 {
89 // Dummy ctor.
90    SetDefaults();
91 }
92
93 //______________________________________________________________________________
94 AliAnalysisAlien::AliAnalysisAlien(const char *name)
95                  :AliAnalysisGrid(name),
96                   fGridJDL(NULL),
97                   fPrice(0),
98                   fTTL(0),
99                   fSplitMaxInputFileNumber(0),
100                   fMaxInitFailed(0),
101                   fMasterResubmitThreshold(0),
102                   fNtestFiles(0),
103                   fNrunsPerMaster(0),
104                   fMaxMergeFiles(0),
105                   fNsubmitted(0),
106                   fProductionMode(0),
107                   fRunNumbers(),
108                   fExecutable(),
109                   fExecutableCommand(),
110                   fArguments(),
111                   fAnalysisMacro(),
112                   fAnalysisSource(),
113                   fAdditionalLibs(),
114                   fSplitMode(),
115                   fAPIVersion(),
116                   fROOTVersion(),
117                   fAliROOTVersion(),
118                   fExternalPackages(),
119                   fUser(),
120                   fGridWorkingDir(),
121                   fGridDataDir(),
122                   fDataPattern(),
123                   fGridOutputDir(),
124                   fOutputArchive(),
125                   fOutputFiles(),
126                   fInputFormat(),
127                   fDatasetName(),
128                   fJDLName(),
129                   fMergeExcludes(),
130                   fIncludePath(),
131                   fCloseSE(),
132                   fFriendChainName(),
133                   fJobTag(),
134                   fOutputSingle(),
135                   fRunPrefix(),
136                   fInputFiles(0),
137                   fPackages(0)
138 {
139 // Default ctor.
140    SetDefaults();
141 }
142
143 //______________________________________________________________________________
144 AliAnalysisAlien::AliAnalysisAlien(const AliAnalysisAlien& other)
145                  :AliAnalysisGrid(other),
146                   fGridJDL(NULL),
147                   fPrice(other.fPrice),
148                   fTTL(other.fTTL),
149                   fSplitMaxInputFileNumber(other.fSplitMaxInputFileNumber),
150                   fMaxInitFailed(other.fMaxInitFailed),
151                   fMasterResubmitThreshold(other.fMasterResubmitThreshold),
152                   fNtestFiles(other.fNtestFiles),
153                   fNrunsPerMaster(other.fNrunsPerMaster),
154                   fMaxMergeFiles(other.fMaxMergeFiles),
155                   fNsubmitted(other.fNsubmitted),
156                   fProductionMode(other.fProductionMode),
157                   fRunNumbers(other.fRunNumbers),
158                   fExecutable(other.fExecutable),
159                   fExecutableCommand(other.fExecutableCommand),
160                   fArguments(other.fArguments),
161                   fAnalysisMacro(other.fAnalysisMacro),
162                   fAnalysisSource(other.fAnalysisSource),
163                   fAdditionalLibs(other.fAdditionalLibs),
164                   fSplitMode(other.fSplitMode),
165                   fAPIVersion(other.fAPIVersion),
166                   fROOTVersion(other.fROOTVersion),
167                   fAliROOTVersion(other.fAliROOTVersion),
168                   fExternalPackages(other.fExternalPackages),
169                   fUser(other.fUser),
170                   fGridWorkingDir(other.fGridWorkingDir),
171                   fGridDataDir(other.fGridDataDir),
172                   fDataPattern(other.fDataPattern),
173                   fGridOutputDir(other.fGridOutputDir),
174                   fOutputArchive(other.fOutputArchive),
175                   fOutputFiles(other.fOutputFiles),
176                   fInputFormat(other.fInputFormat),
177                   fDatasetName(other.fDatasetName),
178                   fJDLName(other.fJDLName),
179                   fMergeExcludes(other.fMergeExcludes),
180                   fIncludePath(other.fIncludePath),
181                   fCloseSE(other.fCloseSE),
182                   fFriendChainName(other.fFriendChainName),
183                   fJobTag(other.fJobTag),
184                   fOutputSingle(other.fOutputSingle),
185                   fRunPrefix(other.fRunPrefix),
186                   fInputFiles(0),
187                   fPackages(0)
188 {
189 // Copy ctor.
190    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
191    fRunRange[0] = other.fRunRange[0];
192    fRunRange[1] = other.fRunRange[1];
193    if (other.fInputFiles) {
194       fInputFiles = new TObjArray();
195       TIter next(other.fInputFiles);
196       TObject *obj;
197       while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
198       fInputFiles->SetOwner();
199    }   
200    if (other.fPackages) {
201       fPackages = new TObjArray();
202       TIter next(other.fPackages);
203       TObject *obj;
204       while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
205       fPackages->SetOwner();
206    }   
207 }
208
209 //______________________________________________________________________________
210 AliAnalysisAlien::~AliAnalysisAlien()
211 {
212 // Destructor.
213    if (fGridJDL) delete fGridJDL;
214    if (fInputFiles) delete fInputFiles;
215    if (fPackages) delete fPackages;
216 }   
217
218 //______________________________________________________________________________
219 AliAnalysisAlien &AliAnalysisAlien::operator=(const AliAnalysisAlien& other)
220 {
221 // Assignment.
222    if (this != &other) {
223       AliAnalysisGrid::operator=(other);
224       fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
225       fPrice                   = other.fPrice;
226       fTTL                     = other.fTTL;
227       fSplitMaxInputFileNumber = other.fSplitMaxInputFileNumber;
228       fMaxInitFailed           = other.fMaxInitFailed;
229       fMasterResubmitThreshold = other.fMasterResubmitThreshold;
230       fNtestFiles              = other.fNtestFiles;
231       fNrunsPerMaster          = other.fNrunsPerMaster;
232       fMaxMergeFiles           = other.fMaxMergeFiles;
233       fNsubmitted              = other.fNsubmitted;
234       fProductionMode          = other.fProductionMode;
235       fRunNumbers              = other.fRunNumbers;
236       fExecutable              = other.fExecutable;
237       fExecutableCommand       = other.fExecutableCommand;
238       fArguments               = other.fArguments;
239       fAnalysisMacro           = other.fAnalysisMacro;
240       fAnalysisSource          = other.fAnalysisSource;
241       fAdditionalLibs          = other.fAdditionalLibs;
242       fSplitMode               = other.fSplitMode;
243       fAPIVersion              = other.fAPIVersion;
244       fROOTVersion             = other.fROOTVersion;
245       fAliROOTVersion          = other.fAliROOTVersion;
246       fExternalPackages        = other.fExternalPackages;
247       fUser                    = other.fUser;
248       fGridWorkingDir          = other.fGridWorkingDir;
249       fGridDataDir             = other.fGridDataDir;
250       fDataPattern             = other.fDataPattern;
251       fGridOutputDir           = other.fGridOutputDir;
252       fOutputArchive           = other.fOutputArchive;
253       fOutputFiles             = other.fOutputFiles;
254       fInputFormat             = other.fInputFormat;
255       fDatasetName             = other.fDatasetName;
256       fJDLName                 = other.fJDLName;
257       fMergeExcludes           = other.fMergeExcludes;
258       fIncludePath             = other.fIncludePath;
259       fCloseSE                 = other.fCloseSE;
260       fFriendChainName         = other.fFriendChainName;
261       fJobTag                  = other.fJobTag;
262       fOutputSingle            = other.fOutputSingle;
263       fRunPrefix               = other.fRunPrefix;
264       if (other.fInputFiles) {
265          fInputFiles = new TObjArray();
266          TIter next(other.fInputFiles);
267          TObject *obj;
268          while ((obj=next())) fInputFiles->Add(new TObjString(obj->GetName()));
269          fInputFiles->SetOwner();
270       }   
271       if (other.fPackages) {
272          fPackages = new TObjArray();
273          TIter next(other.fPackages);
274          TObject *obj;
275          while ((obj=next())) fPackages->Add(new TObjString(obj->GetName()));
276          fPackages->SetOwner();
277       }   
278    }
279    return *this;
280 }
281
282 //______________________________________________________________________________
283 void AliAnalysisAlien::AddIncludePath(const char *path)
284 {
285 // Add include path in the remote analysis macro.
286    TString p(path);
287    if (p.Contains("-I")) fIncludePath += Form("%s ", path);
288    else                  fIncludePath += Form("-I%s ", path);
289 }
290
291 //______________________________________________________________________________
292 void AliAnalysisAlien::AddRunNumber(Int_t run)
293 {
294 // Add a run number to the list of runs to be processed.
295    if (fRunNumbers.Length()) fRunNumbers += " ";
296    fRunNumbers += Form("%s%d", fRunPrefix.Data(), run);
297 }   
298
299 //______________________________________________________________________________
300 void AliAnalysisAlien::AddRunNumber(const char* run)
301 {
302 // Add a run number to the list of runs to be processed.
303    if (fRunNumbers.Length()) fRunNumbers += " ";
304    fRunNumbers += run;
305 }   
306
307 //______________________________________________________________________________
308 void AliAnalysisAlien::AddDataFile(const char *lfn)
309 {
310 // Adds a data file to the input to be analysed. The file should be a valid LFN
311 // or point to an existing file in the alien workdir.
312    if (!fInputFiles) fInputFiles = new TObjArray();
313    fInputFiles->Add(new TObjString(lfn));
314 }
315
316 //______________________________________________________________________________
317 void AliAnalysisAlien::AddExternalPackage(const char *package)
318 {
319 // Adds external packages w.r.t to the default ones (root,aliroot and gapi)
320    if (fExternalPackages) fExternalPackages += " ";
321    fExternalPackages += package;
322 }   
323       
324 //______________________________________________________________________________
325 Bool_t AliAnalysisAlien::Connect()
326 {
327 // Try to connect to AliEn. User needs a valid token and /tmp/gclient_env_$UID sourced.
328    if (gGrid && gGrid->IsConnected()) return kTRUE;
329    if (!gSystem->Getenv("alien_API_USER")) {
330       Error("Connect", "Make sure you:\n 1. Have called: alien-token-init <username> today\n 2. Have sourced /tmp/gclient_env_%s",
331             gSystem->Getenv("UID"));
332       return kFALSE;
333    }         
334    if (!gGrid) {
335       Info("Connect", "Trying to connect to AliEn ...");
336       TGrid::Connect("alien://");
337    }
338    if (!gGrid || !gGrid->IsConnected()) {
339       Error("Connect", "Did not managed to connect to AliEn. Make sure you have a valid token.");
340       return kFALSE;
341    }  
342    fUser = gGrid->GetUser();
343    Info("Connect", "\n#####   Connected to AliEn as user %s. Setting analysis user to <%s>", fUser.Data(), fUser.Data());
344    return kTRUE;
345 }
346
347 //______________________________________________________________________________
348 void AliAnalysisAlien::CdWork()
349 {
350 // Check validity of alien workspace. Create directory if possible.
351    if (!Connect()) {
352       Error("CdWork", "Alien connection required");
353       return;
354    } 
355    TString homedir = gGrid->GetHomeDirectory();
356    TString workdir = homedir + fGridWorkingDir;
357    if (DirectoryExists(workdir)) {
358       gGrid->Cd(workdir);
359       return;
360    }   
361    // Work directory not existing - create it
362    gGrid->Cd(homedir);
363    if (gGrid->Mkdir(workdir)) {
364       gGrid->Cd(fGridWorkingDir);
365       Info("CreateJDL", "\n#####   Created alien working directory %s", fGridWorkingDir.Data());
366    } else {
367       Warning("CreateJDL", "Working directory %s cannot be created.\n Using %s instead.",
368               workdir.Data(), homedir.Data());
369       fGridWorkingDir = "";
370    }          
371 }
372
373 //______________________________________________________________________________
374 Bool_t AliAnalysisAlien::CheckInputData()
375 {
376 // Check validity of input data. If necessary, create xml files.
377    if (!fInputFiles && !fRunNumbers.Length() && !fRunRange[0]) {
378       if (!fGridDataDir.Length()) {
379          Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
380          return kFALSE;
381       }
382       Info("CheckInputData", "Analysis will make a single xml for base data directory %s",fGridDataDir.Data());
383       return kTRUE;
384    }
385    // Process declared files
386    Bool_t is_collection = kFALSE;
387    Bool_t is_xml = kFALSE;
388    Bool_t use_tags = kFALSE;
389    Bool_t checked = kFALSE;
390    CdWork();
391    TString file;
392    TString workdir = gGrid->GetHomeDirectory();
393    workdir += fGridWorkingDir;
394    if (fInputFiles) {
395       TObjString *objstr;
396       TIter next(fInputFiles);
397       while ((objstr=(TObjString*)next())) {
398          file = workdir;
399          file += "/";
400          file += objstr->GetString();
401          // Store full lfn path
402          if (FileExists(file)) objstr->SetString(file);
403          else {
404             file = objstr->GetName();
405             if (!FileExists(objstr->GetName())) {
406                Error("CheckInputData", "Data file %s not found or not in your working dir: %s",
407                      objstr->GetName(), workdir.Data());
408                return kFALSE;
409             }         
410          }
411          Bool_t iscoll, isxml, usetags;
412          CheckDataType(file, iscoll, isxml, usetags);
413          if (!checked) {
414             checked = kTRUE;
415             is_collection = iscoll;
416             is_xml = isxml;
417             use_tags = usetags;
418             TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
419          } else {
420             if ((iscoll != is_collection) || (isxml != is_xml) || (usetags != use_tags)) {
421                Error("CheckInputData", "Some conflict was found in the types of inputs");
422                return kFALSE;
423             } 
424          }
425       }
426    }
427    // Process requested run numbers
428    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
429    // Check validity of alien data directory
430    if (!fGridDataDir.Length()) {
431       Error("CkeckInputData", "AliEn path to base data directory must be set.\n = Use: SetGridDataDir()");
432       return kFALSE;
433    }
434    if (!DirectoryExists(fGridDataDir)) {
435       Error("CheckInputData", "Data directory %s not existing.", fGridDataDir.Data());
436       return kFALSE;
437    }
438    if (is_collection) {
439       Error("CheckInputData", "You are using raw AliEn collections as input. Cannot process run numbers.");
440       return kFALSE;   
441    }
442    
443    if (checked && !is_xml) {
444       Error("CheckInputData", "Cannot mix processing of full runs with non-xml files");
445       return kFALSE;   
446    }
447    // Check validity of run number(s)
448    TObjArray *arr;
449    TObjString *os;
450    Int_t nruns = 0;
451    TString schunk;
452    TString path;
453    if (!checked) {
454       checked = kTRUE;
455       use_tags = fDataPattern.Contains("tag");
456       TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
457    }   
458    if (use_tags != fDataPattern.Contains("tag")) {
459       Error("CheckInputData", "Cannot mix input files using/not using tags");
460       return kFALSE;
461    }
462    if (fRunNumbers.Length()) {
463       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
464       arr = fRunNumbers.Tokenize(" ");
465       TIter next(arr);
466       while ((os=(TObjString*)next())) {
467          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
468          if (!DirectoryExists(path)) {
469             Warning("CheckInputData", "Run number %s not found in path: <%s>", os->GetString().Data(), path.Data());
470             continue;
471          }
472          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
473          TString msg = "\n#####   file: ";
474          msg += path;
475          msg += " type: xml_collection;";
476          if (use_tags) msg += " using_tags: Yes";
477          else          msg += " using_tags: No";
478          Info("CheckDataType", msg.Data());
479          if (fNrunsPerMaster<2) {
480             AddDataFile(Form("%s.xml", os->GetString().Data()));
481          } else {
482             nruns++;
483             if (((nruns-1)%fNrunsPerMaster) == 0) {
484                schunk = os->GetString();
485             }   
486             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) continue;
487             schunk += Form("_%s.xml", os->GetString().Data());
488             AddDataFile(schunk);
489          }   
490       }
491       delete arr;   
492    } else {
493       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
494       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
495          path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
496          if (!DirectoryExists(path)) {
497 //            Warning("CheckInputData", "Run number %d not found in path: <%s>", irun, path.Data());
498             continue;
499          }
500          path = Form("%s/%s%d.xml", workdir.Data(),fRunPrefix.Data(),irun);
501          TString msg = "\n#####   file: ";
502          msg += path;
503          msg += " type: xml_collection;";
504          if (use_tags) msg += " using_tags: Yes";
505          else          msg += " using_tags: No";
506          Info("CheckDataType", msg.Data());
507          if (fNrunsPerMaster<2) {
508             AddDataFile(Form("%s%d.xml",fRunPrefix.Data(),irun));
509          } else {
510             nruns++;
511             if (((nruns-1)%fNrunsPerMaster) == 0) {
512                schunk = Form("%s%d", fRunPrefix.Data(),irun);
513             }
514             if ((nruns%fNrunsPerMaster)!=0 && irun != fRunRange[1]) continue;
515             schunk += Form("_%s%d.xml", fRunPrefix.Data(), irun);
516             AddDataFile(schunk);
517          }   
518       }
519    }
520    return kTRUE;      
521 }   
522
523 //______________________________________________________________________________
524 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
525 {
526 // Create dataset for the grid data directory + run number.
527    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
528    if (!Connect()) {
529       Error("CreateDataset", "Cannot create dataset with no grid connection");
530       return kFALSE;
531    }   
532
533    // Cd workspace
534    CdWork();
535    TString workdir = gGrid->GetHomeDirectory();
536    workdir += fGridWorkingDir;
537
538    // Compose the 'find' command arguments
539    TString command;
540    TString options = "-x collection ";
541    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
542    TString conditions = "";
543    
544    TString file;
545    TString path;
546    Int_t nruns = 0;
547    TString schunk;
548    TGridCollection *cbase=0, *cadd=0;
549    if (!fRunNumbers.Length() && !fRunRange[0]) {
550       if (fInputFiles && fInputFiles->GetEntries()) return kTRUE;
551       // Make a single data collection from data directory.
552       path = fGridDataDir;
553       if (!DirectoryExists(path)) {
554          Error("CreateDataset", "Path to data directory %s not valid",fGridDataDir.Data());
555          return kFALSE;
556       }   
557 //      CdWork();
558       if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
559       else file = Form("%s.xml", gSystem->BaseName(path));
560       if (gSystem->AccessPathName(file) || TestBit(AliAnalysisGrid::kTest)) {
561          command = "find ";
562          command += options;
563          command += path;
564          command += " ";
565          command += pattern;
566          command += conditions;
567          printf("command: %s\n", command.Data());
568          TGridResult *res = gGrid->Command(command);
569          if (res) delete res;
570          // Write standard output to file
571          gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
572       }   
573       if (!TestBit(AliAnalysisGrid::kTest) && !FileExists(file)) {
574          // Copy xml file to alien space
575          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
576          if (!FileExists(file)) {
577             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
578             return kFALSE;
579          }
580          // Update list of files to be processed.
581       }
582       AddDataFile(Form("%s/%s", workdir.Data(), file.Data()));
583       return kTRUE;
584    }   
585    // Several runs
586    if (fRunNumbers.Length()) {
587       TObjArray *arr = fRunNumbers.Tokenize(" ");
588       TObjString *os;
589       TIter next(arr);
590       while ((os=(TObjString*)next())) {
591          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
592          if (!DirectoryExists(path)) continue;
593 //         CdWork();
594          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
595          else file = Form("%s.xml", os->GetString().Data());
596          // If local collection file does not exist, create it via 'find' command.
597          if (gSystem->AccessPathName(file)) {
598             command = "find ";
599             command += options;
600             command += path;
601             command += pattern;
602             command += conditions;
603             TGridResult *res = gGrid->Command(command);
604             if (res) delete res;
605             // Write standard output to file
606             gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
607          }   
608          if (TestBit(AliAnalysisGrid::kTest)) break;
609          // Check if there is one run per master job.
610          if (fNrunsPerMaster<2) {
611             if (FileExists(file)) {
612                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
613                continue;
614             }        
615             // Copy xml file to alien space
616             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
617             if (!FileExists(file)) {
618                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
619                delete arr;
620                return kFALSE;
621             }
622          } else {
623             nruns++;
624             if (((nruns-1)%fNrunsPerMaster) == 0) {
625                schunk = os->GetString();
626                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
627             } else {
628                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
629                printf("   Merging collection <%s> into masterjob input...\n", file.Data());
630                cbase->Add(cadd);
631                delete cadd;
632             }
633             if ((nruns%fNrunsPerMaster)!=0 && os!=arr->Last()) {
634                continue;
635             }   
636             schunk += Form("_%s.xml", os->GetString().Data());
637             if (FileExists(schunk)) {
638                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
639                continue;
640             }        
641             printf("Exporting merged collection <%s> and copying to AliEn\n", schunk.Data());
642             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
643             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
644             if (!FileExists(schunk)) {
645                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
646                delete arr;
647                return kFALSE;
648             }
649          }   
650       }   
651       delete arr;
652    } else {
653       // Process a full run range.
654       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
655          path = Form("%s/%s%d ", fGridDataDir.Data(), fRunPrefix.Data(), irun);
656          if (!DirectoryExists(path)) continue;
657 //         CdWork();
658          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
659          else file = Form("%s%d.xml", fRunPrefix.Data(), irun);
660          if (FileExists(file) && fNrunsPerMaster<2 && !TestBit(AliAnalysisGrid::kTest)) {
661             Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
662 //            gGrid->Rm(file); 
663             continue;
664          }
665          // If local collection file does not exist, create it via 'find' command.
666          if (gSystem->AccessPathName(file)) {
667             command = "find ";
668             command += options;
669             command += path;
670             command += pattern;
671             command += conditions;
672             TGridResult *res = gGrid->Command(command);
673             if (res) delete res;
674             // Write standard output to file
675             gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
676          }   
677          if (TestBit(AliAnalysisGrid::kTest)) break;
678          // Check if there is one run per master job.
679          if (fNrunsPerMaster<2) {
680             if (FileExists(file)) {
681                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
682                continue;
683             }        
684             // Copy xml file to alien space
685             TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
686             if (!FileExists(file)) {
687                Error("CreateDataset", "Command %s did NOT succeed", command.Data());
688                return kFALSE;
689             }
690          } else {
691             nruns++;
692             // Check if the collection for the chunk exist locally.
693             Int_t nchunk = (nruns-1)/fNrunsPerMaster;
694             if (FileExists(fInputFiles->At(nchunk)->GetName())) continue;
695             printf("   Merging collection <%s> into %d runs chunk...\n",file.Data(),fNrunsPerMaster);
696             if (((nruns-1)%fNrunsPerMaster) == 0) {
697                schunk = Form("%d", irun);
698                cbase = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
699             } else {
700                cadd = (TGridCollection*)gROOT->ProcessLine(Form("new TAlienCollection(\"%s\", 1000000);",file.Data()));
701                cbase->Add(cadd);
702                delete cadd;
703             }
704             if ((nruns%fNrunsPerMaster)!=0 && irun!=fRunRange[1]) {
705                continue;
706             }   
707             schunk += Form("_%d.xml", irun);
708             if (FileExists(schunk)) {
709                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", schunk.Data());
710                continue;
711             }        
712             printf("Exporting merged collection <%s> and copying to AliEn.\n", schunk.Data());
713             cbase->ExportXML(Form("file://%s", schunk.Data()),kFALSE,kFALSE, schunk, "Merged runs");
714             if (FileExists(schunk)) {
715                Info("CreateDataset", "\n#####   Dataset %s exist. Skipping copy...", schunk.Data());
716                continue;
717             }   
718             TFile::Cp(Form("file:%s",schunk.Data()), Form("alien://%s/%s",workdir.Data(), schunk.Data()));
719             if (!FileExists(schunk)) {
720                Error("CreateDataset", "Copy command did NOT succeed for %s", schunk.Data());
721                return kFALSE;
722             }
723          }   
724       }
725    }      
726    return kTRUE;
727 }
728
729 //______________________________________________________________________________
730 Bool_t AliAnalysisAlien::CreateJDL()
731 {
732 // Generate a JDL file according to current settings. The name of the file is 
733 // specified by fJDLName.
734    Bool_t error = kFALSE;
735    TObjArray *arr = 0;
736    Bool_t copy = kTRUE;
737    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
738    Bool_t generate = kTRUE;
739    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
740    if (!Connect()) {
741       Error("CreateJDL", "Alien connection required");
742       return kFALSE;
743    }   
744    // Check validity of alien workspace
745    CdWork();
746    TString workdir = gGrid->GetHomeDirectory();
747    workdir += fGridWorkingDir;
748    if (generate) {
749       TObjString *os;
750       if (!fInputFiles) {
751          Error("CreateJDL()", "Define some input files for your analysis.");
752          error = kTRUE;
753       }
754       // Compose list of input files   
755       // Check if output files were defined
756       if (!fOutputFiles.Length()) {
757          Error("CreateJDL", "You must define at least one output file");
758          error = kTRUE;
759       }   
760       // Check if an output directory was defined and valid
761       if (!fGridOutputDir.Length()) {
762          Error("CreateJDL", "You must define AliEn output directory");
763          error = kTRUE;
764       } else {
765          if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("%s/%s", workdir.Data(), fGridOutputDir.Data());
766          if (!DirectoryExists(fGridOutputDir)) {
767             if (gGrid->Mkdir(fGridOutputDir)) {
768                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
769             } else {
770                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
771                // error = kTRUE;
772             }
773          }
774          gGrid->Cd(workdir);
775       }   
776       // Exit if any error up to now
777       if (error) return kFALSE;   
778       // Set JDL fields
779       fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
780       fGridJDL->SetExecutable(fExecutable);
781 //      fGridJDL->SetTTL((UInt_t)fTTL);
782       fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
783       if (fMaxInitFailed > 0) 
784          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
785       if (fSplitMaxInputFileNumber > 0) 
786          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
787       if (fSplitMode.Length()) 
788          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
789 //      fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
790       if (fAliROOTVersion.Length())  
791          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
792       if (fROOTVersion.Length()) 
793          fGridJDL->AddToPackages("ROOT", fROOTVersion);
794       if (fAPIVersion.Length()) 
795          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
796       if (!fExternalPackages.IsNull()) {
797          arr = fExternalPackages.Tokenize(" ");
798          TIter next(arr);
799          while ((os=(TObjString*)next())) {
800             TString pkgname = os->GetString();
801             Int_t index = pkgname.Index("::");
802             TString pkgversion = pkgname(index+2, pkgname.Length());
803             pkgname.Remove(index);
804             fGridJDL->AddToPackages(pkgname, pkgversion);
805          }   
806          delete arr;   
807       }   
808       fGridJDL->SetInputDataListFormat(fInputFormat);
809       fGridJDL->SetInputDataList("wn.xml");
810       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
811       TString analysisFile = fExecutable;
812       analysisFile.ReplaceAll(".sh", ".root");
813       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(),analysisFile.Data()));
814       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
815          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
816       if (fAdditionalLibs.Length()) {
817          arr = fAdditionalLibs.Tokenize(" ");
818          TIter next(arr);
819          while ((os=(TObjString*)next())) {
820             if (os->GetString().Contains(".so")) continue;
821             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
822          }   
823          delete arr;   
824       }
825       if (fPackages) {
826          TIter next(fPackages);
827          TObject *obj;
828          while ((obj=next()))
829             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
830       }
831       if (fOutputArchive.Length()) {
832          arr = fOutputArchive.Tokenize(" ");
833          TIter next(arr);
834          while ((os=(TObjString*)next()))
835          if (!os->GetString().Contains("@") && fCloseSE.Length())
836             fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
837          else
838             fGridJDL->AddToOutputArchive(os->GetString());
839          delete arr;
840       }      
841       arr = fOutputFiles.Tokenize(" ");
842       TIter next(arr);
843       while ((os=(TObjString*)next())) {
844          // Ignore ouputs in jdl that are also in outputarchive
845          TString sout = os->GetString();
846          if (sout.Index("@")>0) sout.Remove(sout.Index("@"));
847          if (fOutputArchive.Contains(sout)) continue;
848          if (!os->GetString().Contains("@") && fCloseSE.Length())
849             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
850          else
851             fGridJDL->AddToOutputSandbox(os->GetString());
852       }   
853       delete arr;
854 //      fGridJDL->SetPrice((UInt_t)fPrice);
855       fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
856       TString validationScript = fExecutable;
857       validationScript.ReplaceAll(".sh", "_validation.sh");
858       fGridJDL->SetValidationCommand(Form("%s/%s", workdir.Data(),validationScript.Data()));
859       if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
860       // Write a jdl with 2 input parameters: collection name and output dir name.
861       WriteJDL(copy);
862    }
863    // Copy jdl to grid workspace   
864    if (copy) {
865       if (TestBit(AliAnalysisGrid::kSubmit)) {
866          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
867          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
868          if (fProductionMode)
869             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
870          if (FileExists(locjdl)) gGrid->Rm(locjdl);
871          TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
872       }
873       if (fAdditionalLibs.Length()) {
874          arr = fAdditionalLibs.Tokenize(" ");
875          TObjString *os;
876          TIter next(arr);
877          while ((os=(TObjString*)next())) {
878             if (os->GetString().Contains(".so")) continue;
879             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
880             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
881             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
882          }   
883          delete arr;   
884       }
885       if (fPackages) {
886          TIter next(fPackages);
887          TObject *obj;
888          while ((obj=next())) {
889             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
890             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
891          }   
892       }      
893    } 
894    return kTRUE;
895 }
896
897 //______________________________________________________________________________
898 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
899 {
900 // Writes one or more JDL's corresponding to findex. If findex is negative,
901 // all run numbers are considered in one go (jdl). For non-negative indices
902 // they correspond to the indices in the array fInputFiles.
903    if (!fInputFiles) return kFALSE;
904    TObjString *os;
905    TString workdir = gGrid->GetHomeDirectory();
906    workdir += fGridWorkingDir;
907    
908    if (!fRunNumbers.Length() && !fRunRange[0]) {
909       // One jdl with no parameters in case input data is specified by name.
910       TIter next(fInputFiles);
911       while ((os=(TObjString*)next()))
912          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
913       if (!fOutputSingle.IsNull())
914          fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
915       else                                    
916          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
917    } else {
918       // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
919       fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
920       if (!fOutputSingle.IsNull())
921          fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
922       fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()));
923    }
924       
925
926    // Generate the JDL as a string
927    TString sjdl = fGridJDL->Generate();
928    Int_t index;
929    index = sjdl.Index("Executable");
930    if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
931    index = sjdl.Index("Split ");
932    if (index >= 0) sjdl.Insert(index, "\n# We split per SE or file\n");
933    index = sjdl.Index("SplitMaxInputFileNumber");
934    if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
935    index = sjdl.Index("InputDataCollection");
936    if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
937    index = sjdl.Index("InputFile");
938    if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
939    index = sjdl.Index("InputDataList ");
940    if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
941    index = sjdl.Index("InputDataListFormat");
942    if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
943    index = sjdl.Index("Price");
944    if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
945    index = sjdl.Index("Requirements");
946    if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
947    index = sjdl.Index("Packages");
948    if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
949    index = sjdl.Index("User =");
950    if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
951    index = sjdl.Index("TTL");
952    if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
953    index = sjdl.Index("OutputFile");
954    if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
955    index = sjdl.Index("OutputDir");
956    if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
957    index = sjdl.Index("OutputArchive");
958    if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
959    index = sjdl.Index("MaxInitFailed");
960    if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
961    index = sjdl.Index("MasterResubmitThreshold");
962    if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
963    sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
964    index = sjdl.Index("Validationcommand");
965    if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
966    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
967    sjdl.ReplaceAll("(member", "\n   (member");
968    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
969    sjdl.ReplaceAll("{", "{\n   ");
970    sjdl.ReplaceAll("};", "\n};");
971    sjdl.ReplaceAll("{\n   \n", "{\n");
972    sjdl.ReplaceAll("\n\n", "\n");
973    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
974    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
975    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
976    index = sjdl.Index("JDLVariables");
977    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
978    // Write jdl to file
979    ofstream out;
980    out.open(fJDLName.Data(), ios::out);
981    if (out.bad()) {
982       Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
983       return kFALSE;
984    }
985    out << sjdl << endl;
986
987    // Copy jdl to grid workspace   
988    if (!copy) {
989       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
990    } else {
991       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
992       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
993       if (fProductionMode)
994          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
995       if (FileExists(locjdl)) gGrid->Rm(locjdl);
996       TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
997    } 
998    return kTRUE;
999 }
1000
1001 //______________________________________________________________________________
1002 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1003 {
1004 // Returns true if file exists.
1005    if (!gGrid) return kFALSE;
1006    TGridResult *res = gGrid->Ls(lfn);
1007    if (!res) return kFALSE;
1008    TMap *map = dynamic_cast<TMap*>(res->At(0));
1009    if (!map) {
1010       delete res;
1011       return kFALSE;
1012    }   
1013    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1014    if (!objs || !objs->GetString().Length()) {
1015       delete res;
1016       return kFALSE;
1017    }
1018    delete res;   
1019    return kTRUE;
1020 }
1021
1022 //______________________________________________________________________________
1023 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1024 {
1025 // Returns true if directory exists. Can be also a path.
1026    if (!gGrid) return kFALSE;
1027    // Check if dirname is a path
1028    TString dirstripped = dirname;
1029    dirstripped = dirstripped.Strip();
1030    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1031    TString dir = gSystem->BaseName(dirstripped);
1032    dir += "/";
1033    TString path = gSystem->DirName(dirstripped);
1034    TGridResult *res = gGrid->Ls(path, "-F");
1035    if (!res) return kFALSE;
1036    TIter next(res);
1037    TMap *map;
1038    TObject *obj;
1039    while ((map=dynamic_cast<TMap*>(next()))) {
1040       obj = map->GetValue("name");
1041       if (!obj) break;
1042       if (dir == obj->GetName()) {
1043          delete res;
1044          return kTRUE;
1045       }
1046    }
1047    delete res;
1048    return kFALSE;
1049 }      
1050
1051 //______________________________________________________________________________
1052 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1053 {
1054 // Check input data type.
1055    is_collection = kFALSE;
1056    is_xml = kFALSE;
1057    use_tags = kFALSE;
1058    if (!gGrid) {
1059       Error("CheckDataType", "No connection to grid");
1060       return;
1061    }
1062    is_collection = IsCollection(lfn);
1063    TString msg = "\n#####   file: ";
1064    msg += lfn;
1065    if (is_collection) {
1066       msg += " type: raw_collection;";
1067    // special treatment for collections
1068       is_xml = kFALSE;
1069       // check for tag files in the collection
1070       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1071       if (!res) {
1072          msg += " using_tags: No (unknown)";
1073          Info("CheckDataType", msg.Data());
1074          return;
1075       }   
1076       const char* typeStr = res->GetKey(0, "origLFN");
1077       if (!typeStr || !strlen(typeStr)) {
1078          msg += " using_tags: No (unknown)";
1079          Info("CheckDataType", msg.Data());
1080          return;
1081       }   
1082       TString file = typeStr;
1083       use_tags = file.Contains(".tag");
1084       if (use_tags) msg += " using_tags: Yes";
1085       else          msg += " using_tags: No";
1086       Info("CheckDataType", msg.Data());
1087       return;
1088    }
1089    TString slfn(lfn);
1090    slfn.ToLower();
1091    is_xml = slfn.Contains(".xml");
1092    if (is_xml) {
1093    // Open xml collection and check if there are tag files inside
1094       msg += " type: xml_collection;";
1095       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1096       if (!coll) {
1097          msg += " using_tags: No (unknown)";
1098          Info("CheckDataType", msg.Data());
1099          return;
1100       }   
1101       TMap *map = coll->Next();
1102       if (!map) {
1103          msg += " using_tags: No (unknown)";
1104          Info("CheckDataType", msg.Data());
1105          return;
1106       }   
1107       map = (TMap*)map->GetValue("");
1108       TString file;
1109       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1110       use_tags = file.Contains(".tag");
1111       delete coll;
1112       if (use_tags) msg += " using_tags: Yes";
1113       else          msg += " using_tags: No";
1114       Info("CheckDataType", msg.Data());
1115       return;
1116    }
1117    use_tags = slfn.Contains(".tag");
1118    if (slfn.Contains(".root")) msg += " type: root file;";
1119    else                        msg += " type: unhnown file;";
1120    if (use_tags) msg += " using_tags: Yes";
1121    else          msg += " using_tags: No";
1122    Info("CheckDataType", msg.Data());
1123 }
1124
1125 //______________________________________________________________________________
1126 void AliAnalysisAlien::EnablePackage(const char *package)
1127 {
1128 // Enables a par file supposed to exist in the current directory.
1129    TString pkg(package);
1130    pkg.ReplaceAll(".par", "");
1131    pkg += ".par";
1132    if (gSystem->AccessPathName(pkg)) {
1133       Error("EnablePackage", "Package %s not found", pkg.Data());
1134       return;
1135    }
1136    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1137       Info("EnablePackage", "AliEn plugin will use .par packages");
1138    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1139    if (!fPackages) {
1140       fPackages = new TObjArray();
1141       fPackages->SetOwner();
1142    }
1143    fPackages->Add(new TObjString(pkg));
1144 }      
1145
1146 //______________________________________________________________________________
1147 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1148 {
1149 // Get job status for all jobs with jobid>jobidstart.
1150    static char mstatus[20];
1151    mstatus[0] = '\0';
1152    nrunning = 0;
1153    nwaiting = 0;
1154    nerror   = 0;
1155    ndone    = 0;
1156    TGridJobStatusList *list = gGrid->Ps("");
1157    if (!list) return mstatus;
1158    Int_t nentries = list->GetSize();
1159    TGridJobStatus *status;
1160    Int_t pid;
1161    for (Int_t ijob=0; ijob<nentries; ijob++) {
1162       status = (TGridJobStatus *)list->At(ijob);
1163       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1164       if (pid<jobidstart) continue;
1165       if (pid == lastid) {
1166          gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1167       }   
1168       switch (status->GetStatus()) {
1169          case TGridJobStatus::kWAITING:
1170             nwaiting++; break;
1171          case TGridJobStatus::kRUNNING:
1172             nrunning++; break;
1173          case TGridJobStatus::kABORTED:
1174          case TGridJobStatus::kFAIL:
1175          case TGridJobStatus::kUNKNOWN:
1176             nerror++; break;
1177          case TGridJobStatus::kDONE:
1178             ndone++;
1179       }
1180    }
1181    list->Delete();
1182    delete list;
1183    return mstatus;
1184 }
1185
1186 //______________________________________________________________________________
1187 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1188 {
1189 // Returns true if file is a collection. Functionality duplicated from
1190 // TAlien::Type() because we don't want to directly depend on TAlien.
1191    if (!gGrid) {
1192       Error("IsCollection", "No connection to grid");
1193       return kFALSE;
1194    }
1195    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1196    if (!res) return kFALSE;
1197    const char* typeStr = res->GetKey(0, "type");
1198    if (!typeStr || !strlen(typeStr)) return kFALSE;
1199    if (!strcmp(typeStr, "collection")) return kTRUE;
1200    delete res;
1201    return kFALSE;
1202 }   
1203
1204 //______________________________________________________________________________
1205 void AliAnalysisAlien::Print(Option_t *) const
1206 {
1207 // Print current plugin settings.
1208    printf("### AliEn analysis plugin current settings ###\n");
1209    printf("=   Production mode:______________________________ %d\n", fProductionMode);
1210    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1211    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1212    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1213    if (fUser.Length()) 
1214    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
1215    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1216    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1217    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1218    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
1219    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
1220    if (fRunNumbers.Length()) 
1221    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1222    if (fRunRange[0])
1223    printf("=   Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1224    if (!fRunRange[0] && !fRunNumbers.Length()) {
1225       TIter next(fInputFiles);
1226       TObject *obj;
1227       TString list;
1228       while ((obj=next())) list += obj->GetName();
1229       printf("=   Input files to be processed: _________________ %s\n", list.Data());
1230    }
1231    if (TestBit(AliAnalysisGrid::kTest))
1232    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
1233    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1234    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1235    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1236    printf("=====================================================================\n");
1237    printf("=   Job price: ___________________________________ %d\n", fPrice);
1238    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
1239    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1240    if (fMaxInitFailed>0) 
1241    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1242    if (fMasterResubmitThreshold>0) 
1243    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1244    if (fNrunsPerMaster>0)
1245    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1246    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1247    printf("=   Name of the generated execution script: ______ %s\n",fExecutable.Data());
1248    if (fArguments.Length()) 
1249    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
1250    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1251    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1252    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1253    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1254    if (fDatasetName)
1255    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1256    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1257    if (fIncludePath.Data())
1258    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1259    if (fCloseSE.Length())
1260    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1261    if (fFriendChainName.Length())
1262    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1263    if (fPackages) {
1264       TIter next(fPackages);
1265       TObject *obj;
1266       TString list;
1267       while ((obj=next())) list += obj->GetName();
1268       printf("=   Par files to be used: ________________________ %s\n", list.Data());
1269    }   
1270 }
1271
1272 //______________________________________________________________________________
1273 void AliAnalysisAlien::SetDefaults()
1274 {
1275 // Set default values for everything. What cannot be filled will be left empty.
1276    if (fGridJDL) delete fGridJDL;
1277    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1278    fPrice                      = 1;
1279    fTTL                        = 30000;
1280    fSplitMaxInputFileNumber    = 100;
1281    fMaxInitFailed              = 0;
1282    fMasterResubmitThreshold    = 0;
1283    fNtestFiles                 = 10;
1284    fRunRange[0]                = 0;
1285    fRunRange[1]                = 0;
1286    fNrunsPerMaster             = 1;
1287    fMaxMergeFiles              = 100;
1288    fRunNumbers                 = "";
1289    fExecutable                 = "analysis.sh";
1290    fExecutableCommand          = "root -b -q";
1291    fArguments                  = "";
1292    fAnalysisMacro              = "myAnalysis.C";
1293    fAnalysisSource             = "";
1294    fAdditionalLibs             = "";
1295    fSplitMode                  = "se";
1296    fAPIVersion                 = "";
1297    fROOTVersion                = "";
1298    fAliROOTVersion             = "";
1299    fUser                       = "";  // Your alien user name
1300    fGridWorkingDir             = "";
1301    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
1302    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1303    fFriendChainName            = "";
1304    fGridOutputDir              = "output";
1305    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1306    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
1307    fInputFormat                = "xml-single";
1308    fJDLName                    = "analysis.jdl";
1309    fJobTag                     = "Automatically generated analysis JDL";
1310    fMergeExcludes              = "";
1311 }   
1312
1313 //______________________________________________________________________________
1314 Bool_t AliAnalysisAlien::MergeOutputs()
1315 {
1316 // Merge analysis outputs existing in the AliEn space.
1317    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1318    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1319    if (!Connect()) {
1320       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1321       return kFALSE;
1322    }   
1323    // Get the output path
1324    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1325    if (!DirectoryExists(fGridOutputDir)) {
1326       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1327       return kFALSE;
1328    }
1329    if (!fOutputFiles.Length()) {
1330       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1331       return kFALSE;
1332    }   
1333    TObjArray *list = fOutputFiles.Tokenize(" ");
1334    TIter next(list);
1335    TObjString *str;
1336    TString command;
1337    TString output_file;
1338    TString output_chunk;
1339    TString previous_chunk;
1340    Int_t count_chunk = 0;
1341    Int_t count_zero = fMaxMergeFiles;
1342    Bool_t merged = kTRUE;
1343    while((str=(TObjString*)next())) {
1344       output_file = str->GetString();
1345       Int_t index = output_file.Index("@");
1346       if (index > 0) output_file.Remove(index);
1347       // Skip already merged outputs
1348       if (!gSystem->AccessPathName(output_file)) {
1349          Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1350          continue;
1351       }   
1352       if (fMergeExcludes.Length() &&
1353           fMergeExcludes.Contains(output_file.Data())) continue;
1354       // Perform a 'find' command in the output directory, looking for registered outputs    
1355       command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1356       printf("command: %s\n", command.Data());
1357       TGridResult *res = gGrid->Command(command);
1358       if (!res) continue;
1359       TFileMerger *fm = 0;
1360       TIter nextmap(res);
1361       TMap *map = 0;
1362       previous_chunk = "";
1363       count_chunk = 0;
1364       // Check if there is a merge operation to resume
1365       output_chunk = output_file;
1366       output_chunk.ReplaceAll(".root", "_*.root");
1367       if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1368          while (1) {
1369             for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1370             if (!map) {
1371                Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1372                delete res;
1373                return kFALSE;
1374             }
1375             output_chunk = output_file;
1376             output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1377             printf("%s\n", output_chunk.Data());
1378             count_chunk++;
1379             if (gSystem->AccessPathName(output_chunk)) continue;
1380             // Merged file with chunks up to <count_chunk> found
1381             printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1382             previous_chunk = output_chunk;
1383             break;
1384          }
1385       }
1386       count_zero = fMaxMergeFiles;
1387       while ((map=(TMap*)nextmap())) {
1388       // Loop 'find' results and get next LFN
1389          if (count_zero == fMaxMergeFiles) {
1390             // First file in chunk - create file merger and add previous chunk if any.
1391             fm = new TFileMerger(kFALSE);
1392             fm->SetFastMethod(kTRUE);
1393             if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1394             output_chunk = output_file;
1395             output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1396          }
1397          // If last file found, put merged results in the output file
1398          if (map == res->Last()) output_chunk = output_file;
1399          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1400          if (!objs || !objs->GetString().Length()) {
1401             // Nothing found - skip this output
1402             delete res;
1403             delete fm;
1404             break;
1405          } 
1406          // Add file to be merged and decrement chunk counter.
1407          fm->AddFile(objs->GetString());
1408          count_zero--;
1409          if (count_zero==0 || map == res->Last()) {            
1410             fm->OutputFile(output_chunk);
1411             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1412             // Nothing found - skip this output
1413                Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1414                delete res;
1415                delete fm;
1416                break;
1417             }
1418             // Merge the outputs, then go to next chunk      
1419             if (!fm->Merge()) {
1420                Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1421                delete res;
1422                delete fm;
1423                merged = kFALSE;
1424                break;
1425             } else {
1426                Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1427                gSystem->Unlink(previous_chunk);
1428             }
1429             if (map == res->Last()) {
1430                delete res;
1431                delete fm;
1432                break;
1433             }      
1434             count_chunk++;
1435             count_zero = fMaxMergeFiles;
1436             previous_chunk = output_chunk;
1437          }
1438       }
1439    } 
1440    if (!merged) {
1441       Error("MergeOutputs", "Terminate() will  NOT be executed");
1442    }  
1443    return merged;
1444 }   
1445
1446 //______________________________________________________________________________
1447 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1448 {
1449 // Use the output files connected to output containers from the analysis manager
1450 // rather than the files defined by SetOutputFiles
1451    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1452       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1453       analysis manager");
1454    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1455 }
1456       
1457 //______________________________________________________________________________
1458 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1459 {
1460 // Start remote grid analysis.
1461    
1462    // Check if output files have to be taken from the analysis manager
1463    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1464       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1465       if (!mgr || !mgr->IsInitialized()) {
1466          Error("StartAnalysis", "You need an initialized analysis manager for this");
1467          return kFALSE;
1468       }
1469       fOutputFiles = "";
1470       TIter next(mgr->GetOutputs());
1471       AliAnalysisDataContainer *output;
1472       while ((output=(AliAnalysisDataContainer*)next())) {
1473          const char *filename = output->GetFileName();
1474          if (!(strcmp(filename, "default"))) {
1475             if (!mgr->GetOutputEventHandler()) continue;
1476             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1477          }
1478          if (fOutputFiles.Contains(filename)) continue;
1479          if (fOutputFiles.Length()) fOutputFiles += " ";
1480          fOutputFiles += filename;
1481       }
1482       // Add extra files registered to the analysis manager
1483       if (mgr->GetExtraFiles().Length()) {
1484          if (fOutputFiles.Length()) fOutputFiles += " ";
1485          fOutputFiles += mgr->GetExtraFiles();
1486       }
1487    }
1488 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1489    if (TestBit(AliAnalysisGrid::kOffline)) {
1490       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1491       \n                         there nor any job run. You can revise the JDL and analysis \
1492       \n                         macro then run the same in \"submit\" mode.");
1493    } else if (TestBit(AliAnalysisGrid::kTest)) {
1494       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1495       \n                         dataset.");
1496    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1497       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1498       \n                         space and job submitted.");
1499    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1500       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1501       return kTRUE;
1502    } else {
1503       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1504    }   
1505       
1506    if (!Connect()) {
1507       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1508       return kFALSE;
1509    }
1510    Print();   
1511    if (!CheckInputData()) {
1512       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1513       return kFALSE;
1514    }   
1515    CreateDataset(fDataPattern);
1516    WriteAnalysisFile();   
1517    WriteAnalysisMacro();
1518    WriteExecutable();
1519    WriteValidationScript();
1520    if (!CreateJDL()) return kFALSE;
1521    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1522    if (TestBit(AliAnalysisGrid::kTest)) {
1523       // Locally testing the analysis
1524       Info("StartAnalysis", "\n_______________________________________________________________________ \
1525       \n   Running analysis script in a daughter shell as on a worker node \
1526       \n_______________________________________________________________________");
1527       TObjArray *list = fOutputFiles.Tokenize(" ");
1528       TIter next(list);
1529       TObjString *str;
1530       TString output_file;
1531       while((str=(TObjString*)next())) {
1532          output_file = str->GetString();
1533          Int_t index = output_file.Index("@");
1534          if (index > 0) output_file.Remove(index);         
1535          if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1536       }
1537       delete list;
1538       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1539       TString validationScript = fExecutable;
1540       validationScript.ReplaceAll(".sh", "_validation.sh");
1541       gSystem->Exec(Form("bash %s",validationScript.Data()));
1542 //      gSystem->Exec("cat stdout");
1543       return kFALSE;
1544    }
1545    // Check if submitting is managed by LPM manager
1546    if (fProductionMode) {
1547       TString prodfile = fJDLName;
1548       prodfile.ReplaceAll(".jdl", ".prod");
1549       WriteProductionFile(prodfile);
1550       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1551       return kFALSE;
1552    }   
1553    // Submit AliEn job(s)
1554    gGrid->Cd(fGridOutputDir);
1555    TGridResult *res;
1556    TString jobID = "";
1557    if (!fRunNumbers.Length() && !fRunRange[0]) {
1558       // Submit a given xml or a set of runs
1559       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1560       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1561       if (res) {
1562          const char *cjobId = res->GetKey(0,"jobId");
1563          if (!cjobId) {
1564             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1565             return kFALSE;
1566          } else {
1567             Info("StartAnalysis", "\n_______________________________________________________________________ \
1568             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1569             \n_______________________________________________________________________",
1570                    fJDLName.Data(), cjobId);
1571             jobID = cjobId;      
1572          }          
1573          delete res;
1574       }   
1575    } else {
1576       // Submit for a range of enumeration of runs.
1577       Submit();
1578    }   
1579          
1580    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1581    \n You may exit at any time and terminate the job later using the option <terminate> \
1582    \n ##################################################################################", jobID.Data());
1583    gSystem->Exec("aliensh");
1584    return kTRUE;
1585 }
1586
1587 //______________________________________________________________________________
1588 void AliAnalysisAlien::Submit()
1589 {
1590 // Submit all master jobs.
1591    Int_t nmasterjobs = fInputFiles->GetEntries();
1592    Long_t tshoot = gSystem->Now();
1593    if (!fNsubmitted) SubmitNext();
1594    while (fNsubmitted < nmasterjobs) {
1595       Long_t now = gSystem->Now();
1596       if ((now-tshoot)>30000) {
1597          tshoot = now;
1598          SubmitNext();
1599       }   
1600    }
1601 }
1602
1603 //______________________________________________________________________________
1604 void AliAnalysisAlien::SubmitNext()
1605 {
1606 // Submit next bunch of master jobs if the queue is free.
1607    static Bool_t iscalled = kFALSE;
1608    static Int_t firstmaster = 0;
1609    static Int_t lastmaster = 0;
1610    static Int_t npermaster  = 0;
1611    if (iscalled) return;
1612    iscalled = kTRUE;
1613    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1614    Int_t ntosubmit = 0;
1615    TGridResult *res;
1616    TString jobID = "";
1617    if (!fNsubmitted) ntosubmit = 1;
1618    else {
1619       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1620       printf("=== master %d: %s\n", lastmaster, status.Data());
1621       // If last master not split, just return
1622       if (status != "SPLIT") {iscalled = kFALSE; return;}
1623       // No more than 100 waiting jobs
1624       if (nwaiting>100) {iscalled = kFALSE; return;}
1625       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
1626       if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1627       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
1628              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1629    }
1630    Int_t nmasterjobs = fInputFiles->GetEntries();
1631    for (Int_t i=0; i<ntosubmit; i++) {
1632       // Submit for a range of enumeration of runs.
1633       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1634       TString query;
1635       query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1636       printf("********* %s\n",query.Data());
1637       res = gGrid->Command(query);
1638       if (res) {
1639          TString cjobId1 = res->GetKey(0,"jobId");
1640          if (!cjobId1.Length()) {
1641             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1642             iscalled = kFALSE;
1643             return;
1644          } else {
1645             Info("StartAnalysis", "\n_______________________________________________________________________ \
1646             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1647             \n_______________________________________________________________________",
1648                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1649             jobID += cjobId1;
1650             jobID += " ";
1651             lastmaster = cjobId1.Atoi();
1652             if (!firstmaster) firstmaster = lastmaster;
1653             fNsubmitted++;
1654          }          
1655          delete res;
1656       }   
1657    }
1658    iscalled = kFALSE;
1659 }
1660
1661 //______________________________________________________________________________
1662 void AliAnalysisAlien::WriteAnalysisFile()
1663 {
1664 // Write current analysis manager into the file <analysisFile>
1665    TString analysisFile = fExecutable;
1666    analysisFile.ReplaceAll(".sh", ".root");
1667    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1668       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1669       if (!mgr || !mgr->IsInitialized()) {
1670          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1671          return;
1672       }
1673       // Check analysis type
1674       TObject *handler;
1675       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1676       handler = (TObject*)mgr->GetInputEventHandler();
1677       if (handler) {
1678          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1679          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1680       }
1681       TDirectory *cdir = gDirectory;
1682       TFile *file = TFile::Open(analysisFile, "RECREATE");
1683       if (file) {
1684          mgr->Write();
1685          delete file;
1686       }
1687       if (cdir) cdir->cd();
1688       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1689    }   
1690    Bool_t copy = kTRUE;
1691    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1692    if (copy) {
1693       CdWork();
1694       TString workdir = gGrid->GetHomeDirectory();
1695       workdir += fGridWorkingDir;
1696       Info("CreateJDL", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1697       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1698       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1699    }   
1700 }
1701
1702 //______________________________________________________________________________
1703 void AliAnalysisAlien::WriteAnalysisMacro()
1704 {
1705 // Write the analysis macro that will steer the analysis in grid mode.
1706    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1707       ofstream out;
1708       out.open(fAnalysisMacro.Data(), ios::out);
1709       if (!out.good()) {
1710          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1711          return;
1712       }
1713       TString func = fAnalysisMacro;
1714       TString type = "ESD";
1715       TString comment = "// Analysis using ";
1716       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1717       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1718          type = "AOD";
1719          comment += "AOD";
1720       }   
1721       if (type!="AOD" && fFriendChainName!="") {
1722          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1723          return;
1724       }
1725       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1726       else comment += " data";
1727       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1728       func.ReplaceAll(".C", "");
1729       out << "void " << func.Data() << "()" << endl; 
1730       out << "{" << endl;
1731       out << comment.Data() << endl;
1732       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1733       out << "   TStopwatch timer;" << endl;
1734       out << "   timer.Start();" << endl << endl;
1735       out << "// load base root libraries" << endl;
1736       out << "   gSystem->Load(\"libTree\");" << endl;
1737       out << "   gSystem->Load(\"libGeom\");" << endl;
1738       out << "   gSystem->Load(\"libVMC\");" << endl;
1739       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
1740       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
1741       out << "// Load analysis framework libraries" << endl;
1742       if (!fPackages) {
1743          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1744          out << "   gSystem->Load(\"libESD\");" << endl;
1745          out << "   gSystem->Load(\"libAOD\");" << endl;
1746          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1747          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1748          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1749       } else {
1750          TIter next(fPackages);
1751          TObject *obj;
1752          TString pkgname;
1753          Bool_t hasSTEERBase = kFALSE;
1754          Bool_t hasESD = kFALSE;
1755          Bool_t hasAOD = kFALSE;
1756          Bool_t hasANALYSIS = kFALSE;
1757          Bool_t hasANALYSISalice = kFALSE;
1758          Bool_t hasCORRFW = kFALSE;
1759          while ((obj=next())) {
1760             pkgname = obj->GetName();
1761             if (pkgname == "STEERBase" ||
1762                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1763             if (pkgname == "ESD" ||
1764                 pkgname == "ESD.par")       hasESD = kTRUE;
1765             if (pkgname == "AOD" ||
1766                 pkgname == "AOD.par")       hasAOD = kTRUE;
1767             if (pkgname == "ANALYSIS" ||
1768                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
1769             if (pkgname == "ANALYSISalice" ||
1770                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1771             if (pkgname == "CORRFW" ||
1772                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
1773          }   
1774          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1775          else out << "   if (!SetupPar(\"STEERBase\")) return;" << endl;
1776          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
1777          else out << "   if (!SetupPar(\"ESD\")) return;" << endl;
1778          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
1779          else out << "   if (!SetupPar(\"AOD\")) return;" << endl;
1780          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1781          else out << "   if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1782          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1783          else out << "   if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1784          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1785          else out << "   if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1786          out << "// Compile other par packages" << endl;
1787          next.Reset();
1788          while ((obj=next())) {
1789             pkgname = obj->GetName();
1790             if (pkgname == "STEERBase" ||
1791                 pkgname == "STEERBase.par" ||
1792                 pkgname == "ESD" ||
1793                 pkgname == "ESD.par" ||
1794                 pkgname == "AOD" ||
1795                 pkgname == "AOD.par" ||
1796                 pkgname == "ANALYSIS" ||
1797                 pkgname == "ANALYSIS.par" ||
1798                 pkgname == "ANALYSISalice" ||
1799                 pkgname == "ANALYSISalice.par" ||
1800                 pkgname == "CORRFW" ||
1801                 pkgname == "CORRFW.par") continue;
1802             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1803          }   
1804       }   
1805       out << "// include path" << endl;
1806       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1807       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1808       if (fAdditionalLibs.Length()) {
1809          out << "// Add aditional AliRoot libraries" << endl;
1810          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1811          TIter next(list);
1812          TObjString *str;
1813          while((str=(TObjString*)next())) {
1814             if (str->GetString().Contains(".so"))
1815                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1816          }
1817          if (list) delete list;
1818       }
1819       out << endl;
1820       out << "// analysis source to be compiled at runtime (if any)" << endl;
1821       if (fAnalysisSource.Length()) {
1822          TObjArray *list = fAnalysisSource.Tokenize(" ");
1823          TIter next(list);
1824          TObjString *str;
1825          while((str=(TObjString*)next())) {
1826             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1827          }   
1828          if (list) delete list;
1829       }
1830       out << endl;
1831       out << "// connect to AliEn and make the chain" << endl;
1832       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1833       if (IsUsingTags()) {
1834          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1835       } else {
1836          if(fFriendChainName!="AliAOD.VertexingHF.root") {
1837             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;    
1838          } else {
1839             out << "   // Check if the macro to create the chain was provided" << endl;
1840             out << "   if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1841             out << "      ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1842             out << "      return;" << endl;
1843             out << "   }" << endl;
1844             out << "   gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1845             out << "   TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1846          }  
1847       }   
1848       out << "// read the analysis manager from file" << endl;
1849       TString analysisFile = fExecutable;
1850       analysisFile.ReplaceAll(".sh", ".root");
1851       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1852       out << "   if (!file) return;" << endl; 
1853       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1854       out << "   AliAnalysisManager *mgr = 0;" << endl;
1855       out << "   TKey *key;" << endl;
1856       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1857       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1858       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1859       out << "   };" << endl;
1860       out << "   if (!mgr) {" << endl;
1861       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1862       out << "      return;" << endl;
1863       out << "   }" << endl << endl;
1864       out << "   mgr->PrintStatus();" << endl;
1865       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1866       out << "   timer.Stop();" << endl;
1867       out << "   timer.Print();" << endl;
1868       out << "}" << endl << endl;
1869       if (IsUsingTags()) {
1870          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1871          out << "{" << endl;
1872          out << "// Create a chain using tags from the xml file." << endl;
1873          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1874          out << "   if (!coll) {" << endl;
1875          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1876          out << "      return NULL;" << endl;
1877          out << "   }" << endl;
1878          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1879          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1880          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1881          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1882          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1883          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1884          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1885          out << "   // Check if the cuts configuration file was provided" << endl;
1886          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1887          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1888          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1889          out << "   }" << endl;
1890          if (fFriendChainName=="") {
1891             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1892          } else {
1893             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
1894             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1895             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1896          }
1897          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1898          out << "   chain->ls();" << endl;
1899          out << "   return chain;" << endl;
1900          out << "}" << endl << endl;
1901          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1902             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1903             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1904             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1905             msg += "                      AliDetectorTagCuts *detCuts,\n";
1906             msg += "                      AliEventTagCuts *evCuts)";
1907             Info("WriteAnalysisMacro", msg.Data());
1908          }
1909       } 
1910       if (!IsUsingTags() || fFriendChainName!="") {
1911          out <<"//________________________________________________________________________________" << endl;
1912          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1913          out << "{" << endl;
1914          out << "// Create a chain using url's from xml file" << endl;
1915          out << "   TString treename = type;" << endl;
1916          out << "   treename.ToLower();" << endl;
1917          out << "   treename += \"Tree\";" << endl;
1918          out << "   printf(\"***************************************\\n\");" << endl;
1919          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
1920          out << "   printf(\"***************************************\\n\");" << endl;
1921          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1922          out << "   if (!coll) {" << endl;
1923          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1924          out << "      return NULL;" << endl;
1925          out << "   }" << endl;
1926          out << "   TChain *chain = new TChain(treename);" << endl;
1927          if(fFriendChainName!="") {
1928             out << "   TChain *chainFriend = new TChain(treename);" << endl;
1929          }
1930          out << "   coll->Reset();" << endl;
1931          out << "   while (coll->Next()) {" << endl;
1932          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
1933          if(fFriendChainName!="") {
1934             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
1935             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1936             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1937             out << "      chainFriend->Add(fileFriend.Data());" << endl;
1938          }
1939          out << "   }" << endl;
1940          out << "   if (!chain->GetNtrees()) {" << endl;
1941          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1942          out << "      return NULL;" << endl;
1943          out << "   }" << endl;
1944          if(fFriendChainName!="") {
1945             out << "   chain->AddFriend(chainFriend);" << endl;
1946          }
1947          out << "   return chain;" << endl;
1948          out << "}" << endl << endl;
1949       }   
1950       if (fPackages) {
1951          out <<"//________________________________________________________________________________" << endl;
1952          out << "Bool_t SetupPar(const char *package) {" << endl;
1953          out << "// Compile the package and set it up." << endl;
1954          out << "   TString pkgdir = package;" << endl;
1955          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1956          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1957          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
1958          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
1959          out << "   // Check for BUILD.sh and execute" << endl;
1960          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1961          out << "      printf(\"*******************************\\n\");" << endl;
1962          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
1963          out << "      printf(\"*******************************\\n\");" << endl;
1964          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1965          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1966          out << "         gSystem->ChangeDirectory(cdir);" << endl;
1967          out << "         return kFALSE;" << endl;
1968          out << "      }" << endl;
1969          out << "   } else {" << endl;
1970          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1971          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1972          out << "      return kFALSE;" << endl;
1973          out << "   }" << endl;
1974          out << "   // Check for SETUP.C and execute" << endl;
1975          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1976          out << "      printf(\"*******************************\\n\");" << endl;
1977          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
1978          out << "      printf(\"*******************************\\n\");" << endl;
1979          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1980          out << "   } else {" << endl;
1981          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1982          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1983          out << "      return kFALSE;" << endl;
1984          out << "   }" << endl;
1985          out << "   // Restore original workdir" << endl;
1986          out << "   gSystem->ChangeDirectory(cdir);" << endl;
1987          out << "   return kTRUE;" << endl;
1988          out << "}" << endl;
1989       }
1990       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1991    }   
1992    Bool_t copy = kTRUE;
1993    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1994    if (copy) {
1995       CdWork();
1996       TString workdir = gGrid->GetHomeDirectory();
1997       workdir += fGridWorkingDir;
1998       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1999       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2000          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2001          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2002          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2003       }   
2004       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2005       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2006    }
2007 }
2008
2009 //______________________________________________________________________________
2010 void AliAnalysisAlien::WriteExecutable()
2011 {
2012 // Generate the alien executable script.
2013    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2014       ofstream out;
2015       out.open(fExecutable.Data(), ios::out);
2016       if (out.bad()) {
2017          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2018          return;
2019       }
2020       out << "#!/bin/bash" << endl;
2021       out << "echo \"=========================================\"" << endl; 
2022       out << "echo \"############## PATH : ##############\"" << endl;
2023       out << "echo $PATH" << endl;
2024       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2025       out << "echo $LD_LIBRARY_PATH" << endl;
2026       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2027       out << "echo $ROOTSYS" << endl;
2028       out << "echo \"############## which root : ##############\"" << endl;
2029       out << "which root" << endl;
2030       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2031       out << "echo $ALICE_ROOT" << endl;
2032       out << "echo \"############## which aliroot : ##############\"" << endl;
2033       out << "which aliroot" << endl;
2034       out << "echo \"=========================================\"" << endl << endl;
2035       // Make sure we can properly compile par files
2036       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2037       out << fExecutableCommand << " "; 
2038       out << fAnalysisMacro.Data() << endl << endl;
2039       out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
2040    }   
2041    Bool_t copy = kTRUE;
2042    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2043    if (copy) {
2044       CdWork();
2045       TString workdir = gGrid->GetHomeDirectory();
2046       TString bindir = Form("%s/bin", workdir.Data());
2047       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2048       workdir += fGridWorkingDir;
2049       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2050       if (FileExists(executable)) gGrid->Rm(executable);
2051       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2052       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2053    } 
2054 }
2055
2056 //______________________________________________________________________________
2057 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2058 {
2059 // Write the production file to be submitted by LPM manager. The format is:
2060 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2061 // Next lines: full_path_to_dataset XXX (XXX is a string)
2062 // To submit, one has to: submit jdl XXX for all lines
2063    ofstream out;
2064    out.open(filename, ios::out);
2065    if (out.bad()) {
2066       Error("WriteProductionFile", "Bad file name: %s", filename);
2067       return;
2068    }
2069    TString workdir = gGrid->GetHomeDirectory();
2070    workdir += fGridWorkingDir;
2071    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2072    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2073    out << locjdl << " " << njobspermaster << endl;
2074    Int_t nmasterjobs = fInputFiles->GetEntries();
2075    for (Int_t i=0; i<nmasterjobs; i++) {
2076       out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2077    }
2078    Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
2079    TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));   
2080 }
2081
2082 //______________________________________________________________________________
2083 void AliAnalysisAlien::WriteValidationScript()
2084 {
2085 // Generate the alien validation script.
2086    // Generate the validation script
2087    TObjString *os;
2088    TString validationScript = fExecutable;
2089    validationScript.ReplaceAll(".sh", "_validation.sh");
2090    if (!Connect()) {
2091       Error("WriteValidationScript", "Alien connection required");
2092       return;
2093    }
2094    TString out_stream = "";
2095    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2096    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2097       ofstream out;
2098       out.open(validationScript, ios::out);
2099       out << "#!/bin/bash" << endl;
2100       out << "##################################################" << endl;
2101       out << "validateout=`dirname $0`" << endl;
2102       out << "validatetime=`date`" << endl;
2103       out << "validated=\"0\";" << endl;
2104       out << "error=0" << endl;
2105       out << "if [ -z $validateout ]" << endl;
2106       out << "then" << endl;
2107       out << "    validateout=\".\"" << endl;
2108       out << "fi" << endl << endl;
2109       out << "cd $validateout;" << endl;
2110       out << "validateworkdir=`pwd`;" << endl << endl;
2111       out << "echo \"*******************************************************\"" << out_stream << endl;
2112       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
2113       out << "" << endl;
2114       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
2115       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
2116       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
2117       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2118       out << "ls -la ./"  << out_stream << endl;
2119       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
2120       out << "##################################################" << endl;
2121
2122       out << "" << endl;
2123       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2124       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2125       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2126       out << "" << endl;
2127
2128       out << "if [ ! -f stderr ] ; then" << endl;
2129       out << "   error=1" << endl;
2130       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
2131       out << "   echo \"Error = $error\" " << out_stream << endl;
2132       out << "fi" << endl;
2133
2134       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2135       out << "   error=1" << endl;
2136       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
2137       out << "   echo \"$parArch\" " << out_stream << endl;
2138       out << "   echo \"Error = $error\" " << out_stream << endl;
2139       out << "fi" << endl;
2140
2141       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2142       out << "   error=1" << endl;
2143       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
2144       out << "   echo \"$segViol\" " << out_stream << endl;
2145       out << "   echo \"Error = $error\" " << out_stream << endl;
2146       out << "fi" << endl;
2147
2148       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2149       out << "   error=1" << endl;
2150       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
2151       out << "   echo \"$segFault\" " << out_stream << endl;
2152       out << "   echo \"Error = $error\" " << out_stream << endl;
2153       out << "fi" << endl;
2154
2155       // Part dedicated to the specific analyses running into the train
2156
2157       TObjArray *arr = fOutputFiles.Tokenize(" ");
2158       TIter next1(arr);
2159       TString output_file;
2160       while ((os=(TObjString*)next1())) { 
2161          output_file = os->GetString();
2162          Int_t index = output_file.Index("@");
2163          if (index > 0) output_file.Remove(index);
2164          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2165          out << "   error=1" << endl;
2166          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
2167          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2168          out << "fi" << endl;
2169       }   
2170       delete arr;
2171       out << "if ! [ -f outputs_valid ] ; then" << endl;
2172       out << "   error=1" << endl;
2173       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2174       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2175       out << "fi" << endl;
2176       
2177       out << "if [ $error = 0 ] ; then" << endl;
2178       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
2179       out << "fi" << endl;
2180
2181       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2182       out << "echo \"*******************************************************\""  << out_stream << endl;
2183       out << "cd -" << endl;
2184       out << "exit $error" << endl;
2185    }    
2186    Bool_t copy = kTRUE;
2187    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2188    if (copy) {
2189       CdWork();
2190       TString workdir = gGrid->GetHomeDirectory();
2191       workdir += fGridWorkingDir;
2192       Info("CreateJDL", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
2193       if (FileExists(validationScript)) gGrid->Rm(validationScript);
2194       TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
2195    } 
2196 }