Set include path to AliRoot/include before compiling par files.
[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 << "// include path" << endl;
1816       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1817       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1818       out << "// Load analysis framework libraries" << endl;
1819       if (!fPackages) {
1820          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1821          out << "   gSystem->Load(\"libESD\");" << endl;
1822          out << "   gSystem->Load(\"libAOD\");" << endl;
1823          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1824          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1825          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1826       } else {
1827          TIter next(fPackages);
1828          TObject *obj;
1829          TString pkgname;
1830          Bool_t hasSTEERBase = kFALSE;
1831          Bool_t hasESD = kFALSE;
1832          Bool_t hasAOD = kFALSE;
1833          Bool_t hasANALYSIS = kFALSE;
1834          Bool_t hasANALYSISalice = kFALSE;
1835          Bool_t hasCORRFW = kFALSE;
1836          while ((obj=next())) {
1837             pkgname = obj->GetName();
1838             if (pkgname == "STEERBase" ||
1839                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1840             if (pkgname == "ESD" ||
1841                 pkgname == "ESD.par")       hasESD = kTRUE;
1842             if (pkgname == "AOD" ||
1843                 pkgname == "AOD.par")       hasAOD = kTRUE;
1844             if (pkgname == "ANALYSIS" ||
1845                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
1846             if (pkgname == "ANALYSISalice" ||
1847                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1848             if (pkgname == "CORRFW" ||
1849                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
1850          }   
1851          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1852          else out << "   if (!SetupPar(\"STEERBase\")) return;" << endl;
1853          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
1854          else out << "   if (!SetupPar(\"ESD\")) return;" << endl;
1855          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
1856          else out << "   if (!SetupPar(\"AOD\")) return;" << endl;
1857          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1858          else out << "   if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1859          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1860          else out << "   if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1861          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1862          else out << "   if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1863          out << "// Compile other par packages" << endl;
1864          next.Reset();
1865          while ((obj=next())) {
1866             pkgname = obj->GetName();
1867             if (pkgname == "STEERBase" ||
1868                 pkgname == "STEERBase.par" ||
1869                 pkgname == "ESD" ||
1870                 pkgname == "ESD.par" ||
1871                 pkgname == "AOD" ||
1872                 pkgname == "AOD.par" ||
1873                 pkgname == "ANALYSIS" ||
1874                 pkgname == "ANALYSIS.par" ||
1875                 pkgname == "ANALYSISalice" ||
1876                 pkgname == "ANALYSISalice.par" ||
1877                 pkgname == "CORRFW" ||
1878                 pkgname == "CORRFW.par") continue;
1879             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1880          }   
1881       }   
1882       if (fAdditionalLibs.Length()) {
1883          out << "// Add aditional AliRoot libraries" << endl;
1884          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1885          TIter next(list);
1886          TObjString *str;
1887          while((str=(TObjString*)next())) {
1888             if (str->GetString().Contains(".so"))
1889                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1890          }
1891          if (list) delete list;
1892       }
1893       out << endl;
1894       out << "// analysis source to be compiled at runtime (if any)" << endl;
1895       if (fAnalysisSource.Length()) {
1896          TObjArray *list = fAnalysisSource.Tokenize(" ");
1897          TIter next(list);
1898          TObjString *str;
1899          while((str=(TObjString*)next())) {
1900             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1901          }   
1902          if (list) delete list;
1903       }
1904       out << endl;
1905       out << "// connect to AliEn and make the chain" << endl;
1906       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1907       if (IsUsingTags()) {
1908          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1909       } else {
1910          if(fFriendChainName!="AliAOD.VertexingHF.root") {
1911             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;    
1912          } else {
1913             out << "   // Check if the macro to create the chain was provided" << endl;
1914             out << "   if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1915             out << "      ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1916             out << "      return;" << endl;
1917             out << "   }" << endl;
1918             out << "   gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1919             out << "   TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1920          }  
1921       }   
1922       out << "// read the analysis manager from file" << endl;
1923       TString analysisFile = fExecutable;
1924       analysisFile.ReplaceAll(".sh", ".root");
1925       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1926       out << "   if (!file) return;" << endl; 
1927       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1928       out << "   AliAnalysisManager *mgr = 0;" << endl;
1929       out << "   TKey *key;" << endl;
1930       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1931       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1932       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1933       out << "   };" << endl;
1934       out << "   if (!mgr) {" << endl;
1935       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1936       out << "      return;" << endl;
1937       out << "   }" << endl << endl;
1938       out << "   mgr->PrintStatus();" << endl;
1939       if (AliAnalysisManager::GetAnalysisManager()) {
1940          if (AliAnalysisManager::GetAnalysisManager()->GetDebugLevel()>2) {
1941             out << "   gEnv->SetValue(\"XNet.Debug\", \"1\");" << endl;
1942          } else {
1943             out << "   AliLog::SetGlobalLogLevel(AliLog::kError);" << endl;
1944          }
1945       }   
1946       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1947       out << "   timer.Stop();" << endl;
1948       out << "   timer.Print();" << endl;
1949       out << "}" << endl << endl;
1950       if (IsUsingTags()) {
1951          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1952          out << "{" << endl;
1953          out << "// Create a chain using tags from the xml file." << endl;
1954          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1955          out << "   if (!coll) {" << endl;
1956          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1957          out << "      return NULL;" << endl;
1958          out << "   }" << endl;
1959          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1960          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1961          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1962          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1963          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1964          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1965          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1966          out << "   // Check if the cuts configuration file was provided" << endl;
1967          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1968          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1969          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1970          out << "   }" << endl;
1971          if (fFriendChainName=="") {
1972             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1973          } else {
1974             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
1975             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1976             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1977          }
1978          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1979          out << "   chain->ls();" << endl;
1980          out << "   return chain;" << endl;
1981          out << "}" << endl << endl;
1982          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1983             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1984             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1985             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1986             msg += "                      AliDetectorTagCuts *detCuts,\n";
1987             msg += "                      AliEventTagCuts *evCuts)";
1988             Info("WriteAnalysisMacro", msg.Data());
1989          }
1990       } 
1991       if (!IsUsingTags() || fFriendChainName!="") {
1992          out <<"//________________________________________________________________________________" << endl;
1993          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1994          out << "{" << endl;
1995          out << "// Create a chain using url's from xml file" << endl;
1996          out << "   TString treename = type;" << endl;
1997          out << "   treename.ToLower();" << endl;
1998          out << "   treename += \"Tree\";" << endl;
1999          out << "   printf(\"***************************************\\n\");" << endl;
2000          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
2001          out << "   printf(\"***************************************\\n\");" << endl;
2002          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
2003          out << "   if (!coll) {" << endl;
2004          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
2005          out << "      return NULL;" << endl;
2006          out << "   }" << endl;
2007          out << "   TChain *chain = new TChain(treename);" << endl;
2008          if(fFriendChainName!="") {
2009             out << "   TChain *chainFriend = new TChain(treename);" << endl;
2010          }
2011          out << "   coll->Reset();" << endl;
2012          out << "   while (coll->Next()) {" << endl;
2013          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
2014          if(fFriendChainName!="") {
2015             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
2016             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2017             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
2018             out << "      chainFriend->Add(fileFriend.Data());" << endl;
2019          }
2020          out << "   }" << endl;
2021          out << "   if (!chain->GetNtrees()) {" << endl;
2022          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
2023          out << "      return NULL;" << endl;
2024          out << "   }" << endl;
2025          if(fFriendChainName!="") {
2026             out << "   chain->AddFriend(chainFriend);" << endl;
2027          }
2028          out << "   return chain;" << endl;
2029          out << "}" << endl << endl;
2030       }   
2031       if (fPackages) {
2032          out <<"//________________________________________________________________________________" << endl;
2033          out << "Bool_t SetupPar(const char *package) {" << endl;
2034          out << "// Compile the package and set it up." << endl;
2035          out << "   TString pkgdir = package;" << endl;
2036          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
2037          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
2038          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
2039          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
2040          out << "   // Check for BUILD.sh and execute" << endl;
2041          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
2042          out << "      printf(\"*******************************\\n\");" << endl;
2043          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
2044          out << "      printf(\"*******************************\\n\");" << endl;
2045          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
2046          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
2047          out << "         gSystem->ChangeDirectory(cdir);" << endl;
2048          out << "         return kFALSE;" << endl;
2049          out << "      }" << endl;
2050          out << "   } else {" << endl;
2051          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
2052          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2053          out << "      return kFALSE;" << endl;
2054          out << "   }" << endl;
2055          out << "   // Check for SETUP.C and execute" << endl;
2056          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
2057          out << "      printf(\"*******************************\\n\");" << endl;
2058          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
2059          out << "      printf(\"*******************************\\n\");" << endl;
2060          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
2061          out << "   } else {" << endl;
2062          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
2063          out << "      gSystem->ChangeDirectory(cdir);" << endl;
2064          out << "      return kFALSE;" << endl;
2065          out << "   }" << endl;
2066          out << "   // Restore original workdir" << endl;
2067          out << "   gSystem->ChangeDirectory(cdir);" << endl;
2068          out << "   return kTRUE;" << endl;
2069          out << "}" << endl;
2070       }
2071       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
2072    }   
2073    Bool_t copy = kTRUE;
2074    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2075    if (copy) {
2076       CdWork();
2077       TString workdir = gGrid->GetHomeDirectory();
2078       workdir += fGridWorkingDir;
2079       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2080       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2081          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2082          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2083          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2084       }   
2085       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2086       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2087    }
2088 }
2089
2090 //______________________________________________________________________________
2091 void AliAnalysisAlien::WriteExecutable()
2092 {
2093 // Generate the alien executable script.
2094    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2095       ofstream out;
2096       out.open(fExecutable.Data(), ios::out);
2097       if (out.bad()) {
2098          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2099          return;
2100       }
2101       out << "#!/bin/bash" << endl;
2102       out << "echo \"=========================================\"" << endl; 
2103       out << "echo \"############## PATH : ##############\"" << endl;
2104       out << "echo $PATH" << endl;
2105       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2106       out << "echo $LD_LIBRARY_PATH" << endl;
2107       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2108       out << "echo $ROOTSYS" << endl;
2109       out << "echo \"############## which root : ##############\"" << endl;
2110       out << "which root" << endl;
2111       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2112       out << "echo $ALICE_ROOT" << endl;
2113       out << "echo \"############## which aliroot : ##############\"" << endl;
2114       out << "which aliroot" << endl;
2115       out << "echo \"############## system limits : ##############\"" << endl;
2116       out << "ulimit -a" << endl;
2117       out << "echo \"############## memory : ##############\"" << endl;
2118       out << "free -m" << endl;
2119       out << "echo \"=========================================\"" << endl << endl;
2120       // Make sure we can properly compile par files
2121       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2122       out << fExecutableCommand << " "; 
2123       out << fAnalysisMacro.Data() << " " << fExecutableArgs.Data() << endl << endl;
2124       out << "echo \"======== " << fAnalysisMacro.Data() << " finished with exit code: $? ========\"" << endl;
2125       out << "echo \"############## memory after: ##############\"" << endl;
2126       out << "free -m" << endl;
2127       out << "echo \"############## Last 10 lines from dmesg : ##############\"" << endl;
2128       out << "dmesg | tail -n 10" << endl;
2129    }   
2130    Bool_t copy = kTRUE;
2131    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2132    if (copy) {
2133       CdWork();
2134       TString workdir = gGrid->GetHomeDirectory();
2135       TString bindir = Form("%s/bin", workdir.Data());
2136       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2137       workdir += fGridWorkingDir;
2138       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2139       if (FileExists(executable)) gGrid->Rm(executable);
2140       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2141       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2142    } 
2143 }
2144
2145 //______________________________________________________________________________
2146 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2147 {
2148 // Write the production file to be submitted by LPM manager. The format is:
2149 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2150 // Next lines: full_path_to_dataset XXX (XXX is a string)
2151 // To submit, one has to: submit jdl XXX for all lines
2152    ofstream out;
2153    out.open(filename, ios::out);
2154    if (out.bad()) {
2155       Error("WriteProductionFile", "Bad file name: %s", filename);
2156       return;
2157    }
2158    TString workdir = gGrid->GetHomeDirectory();
2159    workdir += fGridWorkingDir;
2160    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2161    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2162    out << locjdl << " " << njobspermaster << endl;
2163    Int_t nmasterjobs = fInputFiles->GetEntries();
2164    for (Int_t i=0; i<nmasterjobs; i++) {
2165       TString runOutDir = gSystem->BaseName(fInputFiles->At(i)->GetName());
2166       runOutDir.ReplaceAll(".xml", "");
2167       if (fOutputToRunNo)
2168          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << runOutDir << endl;
2169       else
2170          out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2171    }
2172    Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
2173    if (FileExists(filename)) gGrid->Rm(filename);
2174    TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));   
2175 }
2176
2177 //______________________________________________________________________________
2178 void AliAnalysisAlien::WriteValidationScript()
2179 {
2180 // Generate the alien validation script.
2181    // Generate the validation script
2182    TObjString *os;
2183    TString validationScript = fExecutable;
2184    validationScript.ReplaceAll(".sh", "_validation.sh");
2185    if (!Connect()) {
2186       Error("WriteValidationScript", "Alien connection required");
2187       return;
2188    }
2189    TString out_stream = "";
2190    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2191    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2192       ofstream out;
2193       out.open(validationScript, ios::out);
2194       out << "#!/bin/bash" << endl;
2195       out << "##################################################" << endl;
2196       out << "validateout=`dirname $0`" << endl;
2197       out << "validatetime=`date`" << endl;
2198       out << "validated=\"0\";" << endl;
2199       out << "error=0" << endl;
2200       out << "if [ -z $validateout ]" << endl;
2201       out << "then" << endl;
2202       out << "    validateout=\".\"" << endl;
2203       out << "fi" << endl << endl;
2204       out << "cd $validateout;" << endl;
2205       out << "validateworkdir=`pwd`;" << endl << endl;
2206       out << "echo \"*******************************************************\"" << out_stream << endl;
2207       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
2208       out << "" << endl;
2209       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
2210       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
2211       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
2212       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2213       out << "ls -la ./"  << out_stream << endl;
2214       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
2215       out << "##################################################" << endl;
2216
2217       out << "" << endl;
2218       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2219       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2220       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2221       out << "" << endl;
2222
2223       out << "if [ ! -f stderr ] ; then" << endl;
2224       out << "   error=1" << endl;
2225       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
2226       out << "   echo \"Error = $error\" " << out_stream << endl;
2227       out << "fi" << endl;
2228
2229       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2230       out << "   error=1" << endl;
2231       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
2232       out << "   echo \"$parArch\" " << out_stream << endl;
2233       out << "   echo \"Error = $error\" " << out_stream << endl;
2234       out << "fi" << endl;
2235
2236       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2237       out << "   error=1" << endl;
2238       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
2239       out << "   echo \"$segViol\" " << out_stream << endl;
2240       out << "   echo \"Error = $error\" " << out_stream << endl;
2241       out << "fi" << endl;
2242
2243       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2244       out << "   error=1" << endl;
2245       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
2246       out << "   echo \"$segFault\" " << out_stream << endl;
2247       out << "   echo \"Error = $error\" " << out_stream << endl;
2248       out << "fi" << endl;
2249
2250       // Part dedicated to the specific analyses running into the train
2251
2252       TObjArray *arr = fOutputFiles.Tokenize(" ");
2253       TIter next1(arr);
2254       TString output_file;
2255       while ((os=(TObjString*)next1())) { 
2256          output_file = os->GetString();
2257          Int_t index = output_file.Index("@");
2258          if (index > 0) output_file.Remove(index);
2259          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2260          out << "   error=1" << endl;
2261          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
2262          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2263          out << "fi" << endl;
2264       }   
2265       delete arr;
2266       out << "if ! [ -f outputs_valid ] ; then" << endl;
2267       out << "   error=1" << endl;
2268       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2269       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2270       out << "fi" << endl;
2271       
2272       out << "if [ $error = 0 ] ; then" << endl;
2273       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
2274       out << "fi" << endl;
2275
2276       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2277       out << "echo \"*******************************************************\""  << out_stream << endl;
2278       out << "cd -" << endl;
2279       out << "exit $error" << endl;
2280    }    
2281    Bool_t copy = kTRUE;
2282    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2283    if (copy) {
2284       CdWork();
2285       TString workdir = gGrid->GetHomeDirectory();
2286       workdir += fGridWorkingDir;
2287       Info("CreateJDL", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
2288       if (FileExists(validationScript)) gGrid->Rm(validationScript);
2289       TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
2290    } 
2291 }