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