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