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