]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
20be1b91faae6e4ed5032195b2d597dacfbe06e2
[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       if (TestBit(AliAnalysisGrid::kSubmit)) {
872          Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
873          TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
874          if (fProductionMode)
875             locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
876          if (FileExists(locjdl)) gGrid->Rm(locjdl);
877          TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
878       }
879       if (fAdditionalLibs.Length()) {
880          arr = fAdditionalLibs.Tokenize(" ");
881          TObjString *os;
882          TIter next(arr);
883          while ((os=(TObjString*)next())) {
884             if (os->GetString().Contains(".so")) continue;
885             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
886             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
887             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
888          }   
889          delete arr;   
890       }
891       if (fPackages) {
892          TIter next(fPackages);
893          TObject *obj;
894          while ((obj=next())) {
895             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
896             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
897          }   
898       }      
899    } 
900    return kTRUE;
901 }
902
903 //______________________________________________________________________________
904 Bool_t AliAnalysisAlien::WriteJDL(Bool_t copy)
905 {
906 // Writes one or more JDL's corresponding to findex. If findex is negative,
907 // all run numbers are considered in one go (jdl). For non-negative indices
908 // they correspond to the indices in the array fInputFiles.
909    if (!fInputFiles) return kFALSE;
910    TObjString *os;
911    TString workdir = gGrid->GetHomeDirectory();
912    workdir += fGridWorkingDir;
913    
914    if (!fRunNumbers.Length() && !fRunRange[0]) {
915       // One jdl with no parameters in case input data is specified by name.
916       TIter next(fInputFiles);
917       while ((os=(TObjString*)next()))
918          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
919       if (!fOutputSingle.IsNull())
920          fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
921       else                                    
922          fGridJDL->SetOutputDirectory(Form("%s/#alien_counter_03i#", fGridOutputDir.Data()));
923    } else {
924       // One jdl to be submitted with 2 input parameters: data collection name and output dir prefix
925       fGridJDL->AddToInputDataCollection(Form("LF:%s/$1,nodownload", workdir.Data()));
926       if (!fOutputSingle.IsNull())
927          fGridJDL->SetOutputDirectory(Form("#alienfulldir#/%s",fOutputSingle.Data()));
928       fGridJDL->SetOutputDirectory(Form("%s/$2/#alien_counter_03i#", fGridOutputDir.Data()));
929    }
930       
931
932    // Generate the JDL as a string
933    TString sjdl = fGridJDL->Generate();
934    Int_t index;
935    index = sjdl.Index("Executable");
936    if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
937    index = sjdl.Index("Split ");
938    if (index >= 0) sjdl.Insert(index, "\n# We split per SE or file\n");
939    index = sjdl.Index("SplitMaxInputFileNumber");
940    if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
941    index = sjdl.Index("InputDataCollection");
942    if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
943    index = sjdl.Index("InputFile");
944    if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
945    index = sjdl.Index("InputDataList ");
946    if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
947    index = sjdl.Index("InputDataListFormat");
948    if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
949    index = sjdl.Index("Price");
950    if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
951    index = sjdl.Index("Requirements");
952    if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
953    index = sjdl.Index("Packages");
954    if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
955    index = sjdl.Index("User =");
956    if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
957    index = sjdl.Index("TTL");
958    if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
959    index = sjdl.Index("OutputFile");
960    if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
961    index = sjdl.Index("OutputDir");
962    if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
963    index = sjdl.Index("OutputArchive");
964    if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
965    index = sjdl.Index("MaxInitFailed");
966    if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
967    index = sjdl.Index("MasterResubmitThreshold");
968    if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
969    sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
970    index = sjdl.Index("Validationcommand");
971    if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
972    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
973    sjdl.ReplaceAll("(member", "\n   (member");
974    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
975    sjdl.ReplaceAll("{", "{\n   ");
976    sjdl.ReplaceAll("};", "\n};");
977    sjdl.ReplaceAll("{\n   \n", "{\n");
978    sjdl.ReplaceAll("\n\n", "\n");
979    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
980    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
981    sjdl.Prepend(Form("Jobtag = {\n   \"comment:%s\"\n};\n", fJobTag.Data()));
982    index = sjdl.Index("JDLVariables");
983    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
984    // Write jdl to file
985    ofstream out;
986    out.open(fJDLName.Data(), ios::out);
987    if (out.bad()) {
988       Error("CreateJDL", "Bad file name: %s", fJDLName.Data());
989       return kFALSE;
990    }
991    out << sjdl << endl;
992
993    // Copy jdl to grid workspace   
994    if (!copy) {
995       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
996    } else {
997       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn output directory", fJDLName.Data());
998       TString locjdl = Form("%s/%s", fGridOutputDir.Data(),fJDLName.Data());
999       if (fProductionMode)
1000          locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
1001       if (FileExists(locjdl)) gGrid->Rm(locjdl);
1002       TFile::Cp(Form("file:%s",fJDLName.Data()), Form("alien://%s", locjdl.Data()));
1003    } 
1004    return kTRUE;
1005 }
1006
1007 //______________________________________________________________________________
1008 Bool_t AliAnalysisAlien::FileExists(const char *lfn)
1009 {
1010 // Returns true if file exists.
1011    if (!gGrid) return kFALSE;
1012    TGridResult *res = gGrid->Ls(lfn);
1013    if (!res) return kFALSE;
1014    TMap *map = dynamic_cast<TMap*>(res->At(0));
1015    if (!map) {
1016       delete res;
1017       return kFALSE;
1018    }   
1019    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
1020    if (!objs || !objs->GetString().Length()) {
1021       delete res;
1022       return kFALSE;
1023    }
1024    delete res;   
1025    return kTRUE;
1026 }
1027
1028 //______________________________________________________________________________
1029 Bool_t AliAnalysisAlien::DirectoryExists(const char *dirname)
1030 {
1031 // Returns true if directory exists. Can be also a path.
1032    if (!gGrid) return kFALSE;
1033    // Check if dirname is a path
1034    TString dirstripped = dirname;
1035    dirstripped = dirstripped.Strip();
1036    dirstripped = dirstripped.Strip(TString::kTrailing, '/');
1037    TString dir = gSystem->BaseName(dirstripped);
1038    dir += "/";
1039    TString path = gSystem->DirName(dirstripped);
1040    TGridResult *res = gGrid->Ls(path, "-F");
1041    if (!res) return kFALSE;
1042    TIter next(res);
1043    TMap *map;
1044    TObject *obj;
1045    while ((map=dynamic_cast<TMap*>(next()))) {
1046       obj = map->GetValue("name");
1047       if (!obj) break;
1048       if (dir == obj->GetName()) {
1049          delete res;
1050          return kTRUE;
1051       }
1052    }
1053    delete res;
1054    return kFALSE;
1055 }      
1056
1057 //______________________________________________________________________________
1058 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
1059 {
1060 // Check input data type.
1061    is_collection = kFALSE;
1062    is_xml = kFALSE;
1063    use_tags = kFALSE;
1064    if (!gGrid) {
1065       Error("CheckDataType", "No connection to grid");
1066       return;
1067    }
1068    is_collection = IsCollection(lfn);
1069    TString msg = "\n#####   file: ";
1070    msg += lfn;
1071    if (is_collection) {
1072       msg += " type: raw_collection;";
1073    // special treatment for collections
1074       is_xml = kFALSE;
1075       // check for tag files in the collection
1076       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
1077       if (!res) {
1078          msg += " using_tags: No (unknown)";
1079          Info("CheckDataType", msg.Data());
1080          return;
1081       }   
1082       const char* typeStr = res->GetKey(0, "origLFN");
1083       if (!typeStr || !strlen(typeStr)) {
1084          msg += " using_tags: No (unknown)";
1085          Info("CheckDataType", msg.Data());
1086          return;
1087       }   
1088       TString file = typeStr;
1089       use_tags = file.Contains(".tag");
1090       if (use_tags) msg += " using_tags: Yes";
1091       else          msg += " using_tags: No";
1092       Info("CheckDataType", msg.Data());
1093       return;
1094    }
1095    TString slfn(lfn);
1096    slfn.ToLower();
1097    is_xml = slfn.Contains(".xml");
1098    if (is_xml) {
1099    // Open xml collection and check if there are tag files inside
1100       msg += " type: xml_collection;";
1101       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
1102       if (!coll) {
1103          msg += " using_tags: No (unknown)";
1104          Info("CheckDataType", msg.Data());
1105          return;
1106       }   
1107       TMap *map = coll->Next();
1108       if (!map) {
1109          msg += " using_tags: No (unknown)";
1110          Info("CheckDataType", msg.Data());
1111          return;
1112       }   
1113       map = (TMap*)map->GetValue("");
1114       TString file;
1115       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
1116       use_tags = file.Contains(".tag");
1117       delete coll;
1118       if (use_tags) msg += " using_tags: Yes";
1119       else          msg += " using_tags: No";
1120       Info("CheckDataType", msg.Data());
1121       return;
1122    }
1123    use_tags = slfn.Contains(".tag");
1124    if (slfn.Contains(".root")) msg += " type: root file;";
1125    else                        msg += " type: unhnown file;";
1126    if (use_tags) msg += " using_tags: Yes";
1127    else          msg += " using_tags: No";
1128    Info("CheckDataType", msg.Data());
1129 }
1130
1131 //______________________________________________________________________________
1132 void AliAnalysisAlien::EnablePackage(const char *package)
1133 {
1134 // Enables a par file supposed to exist in the current directory.
1135    TString pkg(package);
1136    pkg.ReplaceAll(".par", "");
1137    pkg += ".par";
1138    if (gSystem->AccessPathName(pkg)) {
1139       Error("EnablePackage", "Package %s not found", pkg.Data());
1140       return;
1141    }
1142    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
1143       Info("EnablePackage", "AliEn plugin will use .par packages");
1144    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
1145    if (!fPackages) {
1146       fPackages = new TObjArray();
1147       fPackages->SetOwner();
1148    }
1149    fPackages->Add(new TObjString(pkg));
1150 }      
1151
1152 //______________________________________________________________________________
1153 const char *AliAnalysisAlien::GetJobStatus(Int_t jobidstart, Int_t lastid, Int_t &nrunning, Int_t &nwaiting, Int_t &nerror, Int_t &ndone)
1154 {
1155 // Get job status for all jobs with jobid>jobidstart.
1156    static char mstatus[20];
1157    mstatus[0] = '\0';
1158    nrunning = 0;
1159    nwaiting = 0;
1160    nerror   = 0;
1161    ndone    = 0;
1162    TGridJobStatusList *list = gGrid->Ps("");
1163    if (!list) return mstatus;
1164    Int_t nentries = list->GetSize();
1165    TGridJobStatus *status;
1166    Int_t pid;
1167    for (Int_t ijob=0; ijob<nentries; ijob++) {
1168       status = (TGridJobStatus *)list->At(ijob);
1169       pid = gROOT->ProcessLine(Form("atoi(((TAlienJobStatus*)0x%lx)->GetKey(\"queueId\"));", (ULong_t)status));
1170       if (pid<jobidstart) continue;
1171       if (pid == lastid) {
1172          gROOT->ProcessLine(Form("sprintf((char*)0x%lx,((TAlienJobStatus*)0x%lx)->GetKey(\"status\"));",(ULong_t)mstatus, (ULong_t)status));
1173       }   
1174       switch (status->GetStatus()) {
1175          case TGridJobStatus::kWAITING:
1176             nwaiting++; break;
1177          case TGridJobStatus::kRUNNING:
1178             nrunning++; break;
1179          case TGridJobStatus::kABORTED:
1180          case TGridJobStatus::kFAIL:
1181          case TGridJobStatus::kUNKNOWN:
1182             nerror++; break;
1183          case TGridJobStatus::kDONE:
1184             ndone++;
1185       }
1186    }
1187    list->Delete();
1188    delete list;
1189    return mstatus;
1190 }
1191
1192 //______________________________________________________________________________
1193 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
1194 {
1195 // Returns true if file is a collection. Functionality duplicated from
1196 // TAlien::Type() because we don't want to directly depend on TAlien.
1197    if (!gGrid) {
1198       Error("IsCollection", "No connection to grid");
1199       return kFALSE;
1200    }
1201    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
1202    if (!res) return kFALSE;
1203    const char* typeStr = res->GetKey(0, "type");
1204    if (!typeStr || !strlen(typeStr)) return kFALSE;
1205    if (!strcmp(typeStr, "collection")) return kTRUE;
1206    delete res;
1207    return kFALSE;
1208 }   
1209
1210 //______________________________________________________________________________
1211 void AliAnalysisAlien::Print(Option_t *) const
1212 {
1213 // Print current plugin settings.
1214    printf("### AliEn analysis plugin current settings ###\n");
1215    printf("=   Production mode:______________________________ %d\n", fProductionMode);
1216    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
1217    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
1218    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
1219    if (fUser.Length()) 
1220    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
1221    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
1222    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
1223    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
1224    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
1225    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
1226    if (fRunNumbers.Length()) 
1227    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
1228    if (fRunRange[0])
1229    printf("=   Run range to be processed: ___________________ %s%d-%s%d\n", fRunPrefix.Data(), fRunRange[0], fRunPrefix.Data(), fRunRange[1]);
1230    if (!fRunRange[0] && !fRunNumbers.Length()) {
1231       TIter next(fInputFiles);
1232       TObject *obj;
1233       TString list;
1234       while ((obj=next())) list += obj->GetName();
1235       printf("=   Input files to be processed: _________________ %s\n", list.Data());
1236    }
1237    if (TestBit(AliAnalysisGrid::kTest))
1238    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
1239    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
1240    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
1241    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
1242    printf("=====================================================================\n");
1243    printf("=   Job price: ___________________________________ %d\n", fPrice);
1244    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
1245    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
1246    if (fMaxInitFailed>0) 
1247    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
1248    if (fMasterResubmitThreshold>0) 
1249    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
1250    if (fNrunsPerMaster>0)
1251    printf("=   Number of runs per master job: _______________ %d\n", fNrunsPerMaster);
1252    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
1253    printf("=   Name of the generated execution script: ______ %s\n",fExecutable.Data());
1254    if (fArguments.Length()) 
1255    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
1256    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
1257    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
1258    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
1259    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
1260    if (fDatasetName)
1261    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
1262    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
1263    if (fIncludePath.Data())
1264    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
1265    if (fCloseSE.Length())
1266    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
1267    if (fFriendChainName.Length())
1268    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
1269    if (fPackages) {
1270       TIter next(fPackages);
1271       TObject *obj;
1272       TString list;
1273       while ((obj=next())) list += obj->GetName();
1274       printf("=   Par files to be used: ________________________ %s\n", list.Data());
1275    }   
1276 }
1277
1278 //______________________________________________________________________________
1279 void AliAnalysisAlien::SetDefaults()
1280 {
1281 // Set default values for everything. What cannot be filled will be left empty.
1282    if (fGridJDL) delete fGridJDL;
1283    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
1284    fPrice                      = 1;
1285    fTTL                        = 30000;
1286    fSplitMaxInputFileNumber    = 100;
1287    fMaxInitFailed              = 0;
1288    fMasterResubmitThreshold    = 0;
1289    fNtestFiles                 = 10;
1290    fRunRange[0]                = 0;
1291    fRunRange[1]                = 0;
1292    fNrunsPerMaster             = 1;
1293    fMaxMergeFiles              = 100;
1294    fRunNumbers                 = "";
1295    fExecutable                 = "analysis.sh";
1296    fExecutableCommand          = "root -b -q";
1297    fArguments                  = "";
1298    fAnalysisMacro              = "myAnalysis.C";
1299    fAnalysisSource             = "";
1300    fAdditionalLibs             = "";
1301    fSplitMode                  = "se";
1302    fAPIVersion                 = "";
1303    fROOTVersion                = "";
1304    fAliROOTVersion             = "";
1305    fUser                       = "";  // Your alien user name
1306    fGridWorkingDir             = "";
1307    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
1308    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1309    fFriendChainName            = "";
1310    fGridOutputDir              = "output";
1311    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1312    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
1313    fInputFormat                = "xml-single";
1314    fJDLName                    = "analysis.jdl";
1315    fJobTag                     = "Automatically generated analysis JDL";
1316    fMergeExcludes              = "";
1317 }   
1318
1319 //______________________________________________________________________________
1320 Bool_t AliAnalysisAlien::MergeOutputs()
1321 {
1322 // Merge analysis outputs existing in the AliEn space.
1323    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1324    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1325    if (!Connect()) {
1326       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1327       return kFALSE;
1328    }   
1329    // Get the output path
1330    if (!fGridOutputDir.Contains("/")) fGridOutputDir = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1331    if (!DirectoryExists(fGridOutputDir)) {
1332       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1333       return kFALSE;
1334    }
1335    if (!fOutputFiles.Length()) {
1336       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1337       return kFALSE;
1338    }   
1339    TObjArray *list = fOutputFiles.Tokenize(" ");
1340    TIter next(list);
1341    TObjString *str;
1342    TString command;
1343    TString output_file;
1344    TString output_chunk;
1345    TString previous_chunk;
1346    Int_t count_chunk = 0;
1347    Int_t count_zero = fMaxMergeFiles;
1348    Bool_t merged = kTRUE;
1349    while((str=(TObjString*)next())) {
1350       output_file = str->GetString();
1351       Int_t index = output_file.Index("@");
1352       if (index > 0) output_file.Remove(index);
1353       // Skip already merged outputs
1354       if (!gSystem->AccessPathName(output_file)) {
1355          Info("MergeOutputs", "Output file <%s> found. Not merging again.", output_file.Data());
1356          continue;
1357       }   
1358       if (fMergeExcludes.Length() &&
1359           fMergeExcludes.Contains(output_file.Data())) continue;
1360       // Perform a 'find' command in the output directory, looking for registered outputs    
1361       command = Form("find %s/ *%s", fGridOutputDir.Data(), output_file.Data());
1362       printf("command: %s\n", command.Data());
1363       TGridResult *res = gGrid->Command(command);
1364       if (!res) continue;
1365       TFileMerger *fm = 0;
1366       TIter nextmap(res);
1367       TMap *map = 0;
1368       previous_chunk = "";
1369       count_chunk = 0;
1370       // Check if there is a merge operation to resume
1371       output_chunk = output_file;
1372       output_chunk.ReplaceAll(".root", "_*.root");
1373       if (!gSystem->Exec(Form("ls %s", output_chunk.Data()))) {
1374          while (1) {
1375             for (Int_t counter=0; counter<fMaxMergeFiles; counter++) map = (TMap*)nextmap();
1376             if (!map) {
1377                Error("MergeOutputs", "Cannot resume merging for <%s>, nentries=%d", output_file.Data(), res->GetSize());
1378                delete res;
1379                return kFALSE;
1380             }
1381             output_chunk = output_file;
1382             output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1383             printf("%s\n", output_chunk.Data());
1384             count_chunk++;
1385             if (gSystem->AccessPathName(output_chunk)) continue;
1386             // Merged file with chunks up to <count_chunk> found
1387             printf("Resume merging of <%s> from <%s>\n", output_file.Data(), output_chunk.Data());
1388             previous_chunk = output_chunk;
1389             break;
1390          }
1391       }
1392       count_zero = fMaxMergeFiles;
1393       while ((map=(TMap*)nextmap())) {
1394       // Loop 'find' results and get next LFN
1395          if (count_zero == fMaxMergeFiles) {
1396             // First file in chunk - create file merger and add previous chunk if any.
1397             fm = new TFileMerger(kFALSE);
1398             fm->SetFastMethod(kTRUE);
1399             if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1400             output_chunk = output_file;
1401             output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1402          }
1403          // If last file found, put merged results in the output file
1404          if (map == res->Last()) output_chunk = output_file;
1405          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1406          if (!objs || !objs->GetString().Length()) {
1407             // Nothing found - skip this output
1408             delete res;
1409             delete fm;
1410             break;
1411          } 
1412          // Add file to be merged and decrement chunk counter.
1413          fm->AddFile(objs->GetString());
1414          count_zero--;
1415          if (count_zero==0 || map == res->Last()) {            
1416             fm->OutputFile(output_chunk);
1417             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1418             // Nothing found - skip this output
1419                Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1420                delete res;
1421                delete fm;
1422                break;
1423             }
1424             // Merge the outputs, then go to next chunk      
1425             if (!fm->Merge()) {
1426                Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1427                delete res;
1428                delete fm;
1429                merged = kFALSE;
1430                break;
1431             } else {
1432                Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1433                gSystem->Unlink(previous_chunk);
1434             }
1435             if (map == res->Last()) {
1436                delete res;
1437                delete fm;
1438                break;
1439             }      
1440             count_chunk++;
1441             count_zero = fMaxMergeFiles;
1442             previous_chunk = output_chunk;
1443          }
1444       }
1445    } 
1446    if (!merged) {
1447       Error("MergeOutputs", "Terminate() will  NOT be executed");
1448    }  
1449    return merged;
1450 }   
1451
1452 //______________________________________________________________________________
1453 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1454 {
1455 // Use the output files connected to output containers from the analysis manager
1456 // rather than the files defined by SetOutputFiles
1457    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1458       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1459       analysis manager");
1460    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1461 }
1462       
1463 //______________________________________________________________________________
1464 Bool_t AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1465 {
1466 // Start remote grid analysis.
1467    
1468    // Check if output files have to be taken from the analysis manager
1469    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1470       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1471       if (!mgr || !mgr->IsInitialized()) {
1472          Error("StartAnalysis", "You need an initialized analysis manager for this");
1473          return kFALSE;
1474       }
1475       fOutputFiles = "";
1476       TIter next(mgr->GetOutputs());
1477       AliAnalysisDataContainer *output;
1478       while ((output=(AliAnalysisDataContainer*)next())) {
1479          const char *filename = output->GetFileName();
1480          if (!(strcmp(filename, "default"))) {
1481             if (!mgr->GetOutputEventHandler()) continue;
1482             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1483          }
1484          if (fOutputFiles.Contains(filename)) continue;
1485          if (fOutputFiles.Length()) fOutputFiles += " ";
1486          fOutputFiles += filename;
1487       }
1488       // Add extra files registered to the analysis manager
1489       if (mgr->GetExtraFiles().Length()) {
1490          if (fOutputFiles.Length()) fOutputFiles += " ";
1491          fOutputFiles += mgr->GetExtraFiles();
1492       }
1493    }
1494 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1495    if (TestBit(AliAnalysisGrid::kOffline)) {
1496       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1497       \n                         there nor any job run. You can revise the JDL and analysis \
1498       \n                         macro then run the same in \"submit\" mode.");
1499    } else if (TestBit(AliAnalysisGrid::kTest)) {
1500       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1501       \n                         dataset.");
1502    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1503       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1504       \n                         space and job submitted.");
1505    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1506       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1507       return kTRUE;
1508    } else {
1509       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1510    }   
1511       
1512    if (!Connect()) {
1513       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1514       return kFALSE;
1515    }
1516    Print();   
1517    if (!CheckInputData()) {
1518       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1519       return kFALSE;
1520    }   
1521    CreateDataset(fDataPattern);
1522    WriteAnalysisFile();   
1523    WriteAnalysisMacro();
1524    WriteExecutable();
1525    WriteValidationScript();
1526    if (!CreateJDL()) return kFALSE;
1527    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1528    if (TestBit(AliAnalysisGrid::kTest)) {
1529       // Locally testing the analysis
1530       Info("StartAnalysis", "\n_______________________________________________________________________ \
1531       \n   Running analysis script in a daughter shell as on a worker node \
1532       \n_______________________________________________________________________");
1533       TObjArray *list = fOutputFiles.Tokenize(" ");
1534       TIter next(list);
1535       TObjString *str;
1536       TString output_file;
1537       while((str=(TObjString*)next())) {
1538          output_file = str->GetString();
1539          Int_t index = output_file.Index("@");
1540          if (index > 0) output_file.Remove(index);         
1541          if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1542       }
1543       delete list;
1544       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1545       TString validationScript = fExecutable;
1546       validationScript.ReplaceAll(".sh", "_validation.sh");
1547       gSystem->Exec(Form("bash %s",validationScript.Data()));
1548 //      gSystem->Exec("cat stdout");
1549       return kFALSE;
1550    }
1551    // Check if submitting is managed by LPM manager
1552    if (fProductionMode) {
1553       TString prodfile = fJDLName;
1554       prodfile.ReplaceAll(".jdl", ".prod");
1555       WriteProductionFile(prodfile);
1556       Info("StartAnalysis", "Job submitting is managed by LPM. Rerun in terminate mode after jobs finished.");
1557       return kFALSE;
1558    }   
1559    // Submit AliEn job(s)
1560    gGrid->Cd(fGridOutputDir);
1561    TGridResult *res;
1562    TString jobID = "";
1563    if (!fRunNumbers.Length() && !fRunRange[0]) {
1564       // Submit a given xml or a set of runs
1565       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1566       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1567       if (res) {
1568          const char *cjobId = res->GetKey(0,"jobId");
1569          if (!cjobId) {
1570             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1571             return kFALSE;
1572          } else {
1573             Info("StartAnalysis", "\n_______________________________________________________________________ \
1574             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1575             \n_______________________________________________________________________",
1576                    fJDLName.Data(), cjobId);
1577             jobID = cjobId;      
1578          }          
1579          delete res;
1580       }   
1581    } else {
1582       // Submit for a range of enumeration of runs.
1583       Submit();
1584    }   
1585          
1586    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1587    \n You may exit at any time and terminate the job later using the option <terminate> \
1588    \n ##################################################################################", jobID.Data());
1589    gSystem->Exec("aliensh");
1590    return kTRUE;
1591 }
1592
1593 //______________________________________________________________________________
1594 void AliAnalysisAlien::Submit()
1595 {
1596 // Submit all master jobs.
1597    Int_t nmasterjobs = fInputFiles->GetEntries();
1598    Long_t tshoot = gSystem->Now();
1599    if (!fNsubmitted) SubmitNext();
1600    while (fNsubmitted < nmasterjobs) {
1601       Long_t now = gSystem->Now();
1602       if ((now-tshoot)>30000) {
1603          tshoot = now;
1604          SubmitNext();
1605       }   
1606    }
1607 }
1608
1609 //______________________________________________________________________________
1610 void AliAnalysisAlien::SubmitNext()
1611 {
1612 // Submit next bunch of master jobs if the queue is free.
1613    static Bool_t iscalled = kFALSE;
1614    static Int_t firstmaster = 0;
1615    static Int_t lastmaster = 0;
1616    static Int_t npermaster  = 0;
1617    if (iscalled) return;
1618    iscalled = kTRUE;
1619    Int_t nrunning=0, nwaiting=0, nerror=0, ndone=0;
1620    Int_t ntosubmit = 0;
1621    TGridResult *res;
1622    TString jobID = "";
1623    if (!fNsubmitted) ntosubmit = 1;
1624    else {
1625       TString status = GetJobStatus(firstmaster, lastmaster, nrunning, nwaiting, nerror, ndone);
1626       printf("=== master %d: %s\n", lastmaster, status.Data());
1627       // If last master not split, just return
1628       if (status != "SPLIT") {iscalled = kFALSE; return;}
1629       // No more than 100 waiting jobs
1630       if (nwaiting>100) {iscalled = kFALSE; return;}
1631       npermaster = (nrunning+nwaiting+nerror+ndone)/fNsubmitted;      
1632       if (npermaster) ntosubmit = (100-nwaiting)/npermaster;
1633       printf("=== WAITING(%d) RUNNING(%d) DONE(%d) OTHER(%d) NperMaster=%d => to submit %d jobs\n", 
1634              nwaiting, nrunning, ndone, nerror, npermaster, ntosubmit);
1635    }
1636    Int_t nmasterjobs = fInputFiles->GetEntries();
1637    for (Int_t i=0; i<ntosubmit; i++) {
1638       // Submit for a range of enumeration of runs.
1639       if (fNsubmitted>=nmasterjobs) {iscalled = kFALSE; return;}
1640       TString query;
1641       query = Form("submit %s %s %03d", fJDLName.Data(), fInputFiles->At(fNsubmitted)->GetName(), fNsubmitted);
1642       printf("********* %s\n",query.Data());
1643       res = gGrid->Command(query);
1644       if (res) {
1645          TString cjobId1 = res->GetKey(0,"jobId");
1646          if (!cjobId1.Length()) {
1647             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1648             iscalled = kFALSE;
1649             return;
1650          } else {
1651             Info("StartAnalysis", "\n_______________________________________________________________________ \
1652             \n#####   Your JDL %s submitted (%d to go). \nTHE JOB ID IS: %s \
1653             \n_______________________________________________________________________",
1654                 fJDLName.Data(), nmasterjobs-fNsubmitted-1, cjobId1.Data());
1655             jobID += cjobId1;
1656             jobID += " ";
1657             lastmaster = cjobId1.Atoi();
1658             if (!firstmaster) firstmaster = lastmaster;
1659             fNsubmitted++;
1660          }          
1661          delete res;
1662       }   
1663    }
1664    iscalled = kFALSE;
1665 }
1666
1667 //______________________________________________________________________________
1668 void AliAnalysisAlien::WriteAnalysisFile()
1669 {
1670 // Write current analysis manager into the file <analysisFile>
1671    TString analysisFile = fExecutable;
1672    analysisFile.ReplaceAll(".sh", ".root");
1673    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1674       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1675       if (!mgr || !mgr->IsInitialized()) {
1676          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1677          return;
1678       }
1679       // Check analysis type
1680       TObject *handler;
1681       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1682       handler = (TObject*)mgr->GetInputEventHandler();
1683       if (handler) {
1684          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1685          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1686       }
1687       TDirectory *cdir = gDirectory;
1688       TFile *file = TFile::Open(analysisFile, "RECREATE");
1689       if (file) {
1690          mgr->Write();
1691          delete file;
1692       }
1693       if (cdir) cdir->cd();
1694       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <%s>\n", mgr->GetName(),analysisFile.Data());
1695    }   
1696    Bool_t copy = kTRUE;
1697    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1698    if (copy) {
1699       CdWork();
1700       TString workdir = gGrid->GetHomeDirectory();
1701       workdir += fGridWorkingDir;
1702       Info("CreateJDL", "\n#####   Copying file <%s> containing your initialized analysis manager to your alien workspace", analysisFile.Data());
1703       if (FileExists(analysisFile)) gGrid->Rm(analysisFile);
1704       TFile::Cp(Form("file:%s",analysisFile.Data()), Form("alien://%s/%s", workdir.Data(),analysisFile.Data()));
1705    }   
1706 }
1707
1708 //______________________________________________________________________________
1709 void AliAnalysisAlien::WriteAnalysisMacro()
1710 {
1711 // Write the analysis macro that will steer the analysis in grid mode.
1712    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1713       ofstream out;
1714       out.open(fAnalysisMacro.Data(), ios::out);
1715       if (!out.good()) {
1716          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1717          return;
1718       }
1719       TString func = fAnalysisMacro;
1720       TString type = "ESD";
1721       TString comment = "// Analysis using ";
1722       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1723       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1724          type = "AOD";
1725          comment += "AOD";
1726       }   
1727       if (type!="AOD" && fFriendChainName!="") {
1728          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1729          return;
1730       }
1731       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1732       else comment += " data";
1733       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1734       func.ReplaceAll(".C", "");
1735       out << "void " << func.Data() << "()" << endl; 
1736       out << "{" << endl;
1737       out << comment.Data() << endl;
1738       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1739       out << "   TStopwatch timer;" << endl;
1740       out << "   timer.Start();" << endl << endl;
1741       out << "// load base root libraries" << endl;
1742       out << "   gSystem->Load(\"libTree\");" << endl;
1743       out << "   gSystem->Load(\"libGeom\");" << endl;
1744       out << "   gSystem->Load(\"libVMC\");" << endl;
1745       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
1746       out << "   gSystem->Load(\"libMinuit\");" << endl << endl;
1747       out << "// Load analysis framework libraries" << endl;
1748       if (!fPackages) {
1749          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1750          out << "   gSystem->Load(\"libESD\");" << endl;
1751          out << "   gSystem->Load(\"libAOD\");" << endl;
1752          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1753          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1754          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1755       } else {
1756          TIter next(fPackages);
1757          TObject *obj;
1758          TString pkgname;
1759          Bool_t hasSTEERBase = kFALSE;
1760          Bool_t hasESD = kFALSE;
1761          Bool_t hasAOD = kFALSE;
1762          Bool_t hasANALYSIS = kFALSE;
1763          Bool_t hasANALYSISalice = kFALSE;
1764          Bool_t hasCORRFW = kFALSE;
1765          while ((obj=next())) {
1766             pkgname = obj->GetName();
1767             if (pkgname == "STEERBase" ||
1768                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1769             if (pkgname == "ESD" ||
1770                 pkgname == "ESD.par")       hasESD = kTRUE;
1771             if (pkgname == "AOD" ||
1772                 pkgname == "AOD.par")       hasAOD = kTRUE;
1773             if (pkgname == "ANALYSIS" ||
1774                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
1775             if (pkgname == "ANALYSISalice" ||
1776                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1777             if (pkgname == "CORRFW" ||
1778                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
1779          }   
1780          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1781          else out << "   if (!SetupPar(\"STEERBase\")) return;" << endl;
1782          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
1783          else out << "   if (!SetupPar(\"ESD\")) return;" << endl;
1784          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
1785          else out << "   if (!SetupPar(\"AOD\")) return;" << endl;
1786          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1787          else out << "   if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1788          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1789          else out << "   if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1790          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1791          else out << "   if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1792          out << "// Compile other par packages" << endl;
1793          next.Reset();
1794          while ((obj=next())) {
1795             pkgname = obj->GetName();
1796             if (pkgname == "STEERBase" ||
1797                 pkgname == "STEERBase.par" ||
1798                 pkgname == "ESD" ||
1799                 pkgname == "ESD.par" ||
1800                 pkgname == "AOD" ||
1801                 pkgname == "AOD.par" ||
1802                 pkgname == "ANALYSIS" ||
1803                 pkgname == "ANALYSIS.par" ||
1804                 pkgname == "ANALYSISalice" ||
1805                 pkgname == "ANALYSISalice.par" ||
1806                 pkgname == "CORRFW" ||
1807                 pkgname == "CORRFW.par") continue;
1808             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1809          }   
1810       }   
1811       out << "// include path" << endl;
1812       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1813       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1814       if (fAdditionalLibs.Length()) {
1815          out << "// Add aditional AliRoot libraries" << endl;
1816          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1817          TIter next(list);
1818          TObjString *str;
1819          while((str=(TObjString*)next())) {
1820             if (str->GetString().Contains(".so"))
1821                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1822          }
1823          if (list) delete list;
1824       }
1825       out << endl;
1826       out << "// analysis source to be compiled at runtime (if any)" << endl;
1827       if (fAnalysisSource.Length()) {
1828          TObjArray *list = fAnalysisSource.Tokenize(" ");
1829          TIter next(list);
1830          TObjString *str;
1831          while((str=(TObjString*)next())) {
1832             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1833          }   
1834          if (list) delete list;
1835       }
1836       out << endl;
1837       out << "// connect to AliEn and make the chain" << endl;
1838       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1839       if (IsUsingTags()) {
1840          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1841       } else {
1842          if(fFriendChainName!="AliAOD.VertexingHF.root") {
1843             out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;    
1844          } else {
1845             out << "   // Check if the macro to create the chain was provided" << endl;
1846             out << "   if (gSystem->AccessPathName(\"MakeAODInputChain.C\")) {" << endl;
1847             out << "      ::Error(\"" << func.Data() << "\", \"File MakeAODInputChain.C not provided. Aborting.\");" << endl;
1848             out << "      return;" << endl;
1849             out << "   }" << endl;
1850             out << "   gROOT->LoadMacro(\"MakeAODInputChain.C\");" << endl;
1851             out << "   TChain *chain = MakeAODInputChain(\"wn.xml\",\"none\");" << endl << endl;
1852          }  
1853       }   
1854       out << "// read the analysis manager from file" << endl;
1855       TString analysisFile = fExecutable;
1856       analysisFile.ReplaceAll(".sh", ".root");
1857       out << "   TFile *file = TFile::Open(\"" << analysisFile << "\");" << endl;
1858       out << "   if (!file) return;" << endl; 
1859       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1860       out << "   AliAnalysisManager *mgr = 0;" << endl;
1861       out << "   TKey *key;" << endl;
1862       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1863       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1864       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1865       out << "   };" << endl;
1866       out << "   if (!mgr) {" << endl;
1867       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file" << analysisFile <<"\");" << endl;
1868       out << "      return;" << endl;
1869       out << "   }" << endl << endl;
1870       out << "   mgr->PrintStatus();" << endl;
1871       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1872       out << "   timer.Stop();" << endl;
1873       out << "   timer.Print();" << endl;
1874       out << "}" << endl << endl;
1875       if (IsUsingTags()) {
1876          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1877          out << "{" << endl;
1878          out << "// Create a chain using tags from the xml file." << endl;
1879          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1880          out << "   if (!coll) {" << endl;
1881          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1882          out << "      return NULL;" << endl;
1883          out << "   }" << endl;
1884          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1885          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1886          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1887          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1888          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1889          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1890          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1891          out << "   // Check if the cuts configuration file was provided" << endl;
1892          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1893          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1894          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1895          out << "   }" << endl;
1896          if (fFriendChainName=="") {
1897             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1898          } else {
1899             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
1900             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1901             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1902          }
1903          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1904          out << "   chain->ls();" << endl;
1905          out << "   return chain;" << endl;
1906          out << "}" << endl << endl;
1907          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1908             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1909             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1910             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1911             msg += "                      AliDetectorTagCuts *detCuts,\n";
1912             msg += "                      AliEventTagCuts *evCuts)";
1913             Info("WriteAnalysisMacro", msg.Data());
1914          }
1915       } 
1916       if (!IsUsingTags() || fFriendChainName!="") {
1917          out <<"//________________________________________________________________________________" << endl;
1918          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1919          out << "{" << endl;
1920          out << "// Create a chain using url's from xml file" << endl;
1921          out << "   TString treename = type;" << endl;
1922          out << "   treename.ToLower();" << endl;
1923          out << "   treename += \"Tree\";" << endl;
1924          out << "   printf(\"***************************************\\n\");" << endl;
1925          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
1926          out << "   printf(\"***************************************\\n\");" << endl;
1927          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1928          out << "   if (!coll) {" << endl;
1929          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1930          out << "      return NULL;" << endl;
1931          out << "   }" << endl;
1932          out << "   TChain *chain = new TChain(treename);" << endl;
1933          if(fFriendChainName!="") {
1934             out << "   TChain *chainFriend = new TChain(treename);" << endl;
1935          }
1936          out << "   coll->Reset();" << endl;
1937          out << "   while (coll->Next()) {" << endl;
1938          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
1939          if(fFriendChainName!="") {
1940             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
1941             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1942             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1943             out << "      chainFriend->Add(fileFriend.Data());" << endl;
1944          }
1945          out << "   }" << endl;
1946          out << "   if (!chain->GetNtrees()) {" << endl;
1947          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1948          out << "      return NULL;" << endl;
1949          out << "   }" << endl;
1950          if(fFriendChainName!="") {
1951             out << "   chain->AddFriend(chainFriend);" << endl;
1952          }
1953          out << "   return chain;" << endl;
1954          out << "}" << endl << endl;
1955       }   
1956       if (fPackages) {
1957          out <<"//________________________________________________________________________________" << endl;
1958          out << "Bool_t SetupPar(const char *package) {" << endl;
1959          out << "// Compile the package and set it up." << endl;
1960          out << "   TString pkgdir = package;" << endl;
1961          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1962          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1963          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
1964          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
1965          out << "   // Check for BUILD.sh and execute" << endl;
1966          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1967          out << "      printf(\"*******************************\\n\");" << endl;
1968          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
1969          out << "      printf(\"*******************************\\n\");" << endl;
1970          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1971          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1972          out << "         gSystem->ChangeDirectory(cdir);" << endl;
1973          out << "         return kFALSE;" << endl;
1974          out << "      }" << endl;
1975          out << "   } else {" << endl;
1976          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1977          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1978          out << "      return kFALSE;" << endl;
1979          out << "   }" << endl;
1980          out << "   // Check for SETUP.C and execute" << endl;
1981          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1982          out << "      printf(\"*******************************\\n\");" << endl;
1983          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
1984          out << "      printf(\"*******************************\\n\");" << endl;
1985          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1986          out << "   } else {" << endl;
1987          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1988          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1989          out << "      return kFALSE;" << endl;
1990          out << "   }" << endl;
1991          out << "   // Restore original workdir" << endl;
1992          out << "   gSystem->ChangeDirectory(cdir);" << endl;
1993          out << "   return kTRUE;" << endl;
1994          out << "}" << endl;
1995       }
1996       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1997    }   
1998    Bool_t copy = kTRUE;
1999    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2000    if (copy) {
2001       CdWork();
2002       TString workdir = gGrid->GetHomeDirectory();
2003       workdir += fGridWorkingDir;
2004       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
2005       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
2006          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
2007          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
2008          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
2009       }   
2010       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
2011       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
2012    }
2013 }
2014
2015 //______________________________________________________________________________
2016 void AliAnalysisAlien::WriteExecutable()
2017 {
2018 // Generate the alien executable script.
2019    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2020       ofstream out;
2021       out.open(fExecutable.Data(), ios::out);
2022       if (out.bad()) {
2023          Error("WriteExecutable", "Bad file name for executable: %s", fExecutable.Data());
2024          return;
2025       }
2026       out << "#!/bin/bash" << endl;
2027       out << "echo \"=========================================\"" << endl; 
2028       out << "echo \"############## PATH : ##############\"" << endl;
2029       out << "echo $PATH" << endl;
2030       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
2031       out << "echo $LD_LIBRARY_PATH" << endl;
2032       out << "echo \"############## ROOTSYS : ##############\"" << endl;
2033       out << "echo $ROOTSYS" << endl;
2034       out << "echo \"############## which root : ##############\"" << endl;
2035       out << "which root" << endl;
2036       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
2037       out << "echo $ALICE_ROOT" << endl;
2038       out << "echo \"############## which aliroot : ##############\"" << endl;
2039       out << "which aliroot" << endl;
2040       out << "echo \"=========================================\"" << endl << endl;
2041       // Make sure we can properly compile par files
2042       if (TObject::TestBit(AliAnalysisGrid::kUsePars)) out << "export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH" << endl;
2043       out << fExecutableCommand << " "; 
2044       out << fAnalysisMacro.Data() << endl << endl;
2045       out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
2046    }   
2047    Bool_t copy = kTRUE;
2048    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2049    if (copy) {
2050       CdWork();
2051       TString workdir = gGrid->GetHomeDirectory();
2052       TString bindir = Form("%s/bin", workdir.Data());
2053       if (!DirectoryExists(bindir)) gGrid->Mkdir(bindir);
2054       workdir += fGridWorkingDir;
2055       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
2056       if (FileExists(executable)) gGrid->Rm(executable);
2057       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
2058       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
2059    } 
2060 }
2061
2062 //______________________________________________________________________________
2063 void AliAnalysisAlien::WriteProductionFile(const char *filename) const
2064 {
2065 // Write the production file to be submitted by LPM manager. The format is:
2066 // First line: full_path_to_jdl estimated_no_subjobs_per_master
2067 // Next lines: full_path_to_dataset XXX (XXX is a string)
2068 // To submit, one has to: submit jdl XXX for all lines
2069    ofstream out;
2070    out.open(filename, ios::out);
2071    if (out.bad()) {
2072       Error("WriteProductionFile", "Bad file name: %s", filename);
2073       return;
2074    }
2075    TString workdir = gGrid->GetHomeDirectory();
2076    workdir += fGridWorkingDir;
2077    Int_t njobspermaster = 1000*fNrunsPerMaster/fSplitMaxInputFileNumber;
2078    TString locjdl = Form("%s/%s", workdir.Data(),fJDLName.Data());
2079    out << locjdl << " " << njobspermaster << endl;
2080    Int_t nmasterjobs = fInputFiles->GetEntries();
2081    for (Int_t i=0; i<nmasterjobs; i++) {
2082       out << Form("%s", fInputFiles->At(i)->GetName()) << " " << Form("%03d", i) << endl;
2083    }
2084    Info("WriteProductionFile", "\n#####   Copying production file <%s> to your work directory", filename);
2085    TFile::Cp(Form("file:%s",filename), Form("alien://%s/%s", workdir.Data(),filename));   
2086 }
2087
2088 //______________________________________________________________________________
2089 void AliAnalysisAlien::WriteValidationScript()
2090 {
2091 // Generate the alien validation script.
2092    // Generate the validation script
2093    TObjString *os;
2094    TString validationScript = fExecutable;
2095    validationScript.ReplaceAll(".sh", "_validation.sh");
2096    if (!Connect()) {
2097       Error("WriteValidationScript", "Alien connection required");
2098       return;
2099    }
2100    TString out_stream = "";
2101    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
2102    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
2103       ofstream out;
2104       out.open(validationScript, ios::out);
2105       out << "#!/bin/bash" << endl;
2106       out << "##################################################" << endl;
2107       out << "validateout=`dirname $0`" << endl;
2108       out << "validatetime=`date`" << endl;
2109       out << "validated=\"0\";" << endl;
2110       out << "error=0" << endl;
2111       out << "if [ -z $validateout ]" << endl;
2112       out << "then" << endl;
2113       out << "    validateout=\".\"" << endl;
2114       out << "fi" << endl << endl;
2115       out << "cd $validateout;" << endl;
2116       out << "validateworkdir=`pwd`;" << endl << endl;
2117       out << "echo \"*******************************************************\"" << out_stream << endl;
2118       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
2119       out << "" << endl;
2120       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
2121       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
2122       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
2123       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2124       out << "ls -la ./"  << out_stream << endl;
2125       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
2126       out << "##################################################" << endl;
2127
2128       out << "" << endl;
2129       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
2130       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
2131       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
2132       out << "" << endl;
2133
2134       out << "if [ ! -f stderr ] ; then" << endl;
2135       out << "   error=1" << endl;
2136       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
2137       out << "   echo \"Error = $error\" " << out_stream << endl;
2138       out << "fi" << endl;
2139
2140       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
2141       out << "   error=1" << endl;
2142       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
2143       out << "   echo \"$parArch\" " << out_stream << endl;
2144       out << "   echo \"Error = $error\" " << out_stream << endl;
2145       out << "fi" << endl;
2146
2147       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
2148       out << "   error=1" << endl;
2149       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
2150       out << "   echo \"$segViol\" " << out_stream << endl;
2151       out << "   echo \"Error = $error\" " << out_stream << endl;
2152       out << "fi" << endl;
2153
2154       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
2155       out << "   error=1" << endl;
2156       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
2157       out << "   echo \"$segFault\" " << out_stream << endl;
2158       out << "   echo \"Error = $error\" " << out_stream << endl;
2159       out << "fi" << endl;
2160
2161       // Part dedicated to the specific analyses running into the train
2162
2163       TObjArray *arr = fOutputFiles.Tokenize(" ");
2164       TIter next1(arr);
2165       TString output_file;
2166       while ((os=(TObjString*)next1())) { 
2167          output_file = os->GetString();
2168          Int_t index = output_file.Index("@");
2169          if (index > 0) output_file.Remove(index);
2170          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
2171          out << "   error=1" << endl;
2172          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
2173          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
2174          out << "fi" << endl;
2175       }   
2176       delete arr;
2177       out << "if ! [ -f outputs_valid ] ; then" << endl;
2178       out << "   error=1" << endl;
2179       out << "   echo \"Output files were not validated by the analysis manager\" >> stdout" << endl;
2180       out << "   echo \"Output files were not validated by the analysis manager\" >> stderr" << endl;
2181       out << "fi" << endl;
2182       
2183       out << "if [ $error = 0 ] ; then" << endl;
2184       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
2185       out << "fi" << endl;
2186
2187       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
2188       out << "echo \"*******************************************************\""  << out_stream << endl;
2189       out << "cd -" << endl;
2190       out << "exit $error" << endl;
2191    }    
2192    Bool_t copy = kTRUE;
2193    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
2194    if (copy) {
2195       CdWork();
2196       TString workdir = gGrid->GetHomeDirectory();
2197       workdir += fGridWorkingDir;
2198       Info("CreateJDL", "\n#####   Copying validation script <%s> to your AliEn working space", validationScript.Data());
2199       if (FileExists(validationScript)) gGrid->Rm(validationScript);
2200       TFile::Cp(Form("file:%s",validationScript.Data()), Form("alien://%s/%s", workdir.Data(),validationScript.Data()));
2201    } 
2202 }