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