]> git.uio.no Git - u/mrichter/AliRoot.git/blob - ANALYSIS/AliAnalysisAlien.cxx
a74484b2d676bab414851cc3eb2f90537155e055
[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                   fNMasterJobs(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                   fNMasterJobs(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                   fNMasterJobs(other.fNMasterJobs),
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    TString path;
396    if (!checked) {
397       checked = kTRUE;
398       use_tags = fDataPattern.Contains("tag");
399       TObject::SetBit(AliAnalysisGrid::kUseTags, use_tags);
400    }   
401    if (use_tags != fDataPattern.Contains("tag")) {
402       Error("CheckInputData", "Cannot mix input files using/not using tags");
403       return kFALSE;
404    }
405    if (fRunNumbers.Length()) {
406       Info("CheckDataType", "Using supplied run numbers (run ranges are ignored)");
407       arr = fRunNumbers.Tokenize(" ");
408       TIter next(arr);
409       while ((os=(TObjString*)next())) {
410          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
411          if (!gGrid->Cd(path)) {
412             Warning("CheckInputData", "Run number %s not found in path: %s", os->GetString().Data(), path.Data());
413             continue;
414          }
415          path = Form("%s/%s.xml", workdir.Data(),os->GetString().Data());
416          TString msg = "\n#####   file: ";
417          msg += path;
418          msg += " type: xml_collection;";
419          if (use_tags) msg += " using_tags: Yes";
420          else          msg += " using_tags: No";
421          Info("CheckDataType", msg.Data());
422          AddDataFile(path);
423       }
424       delete arr;   
425    } else {
426       Info("CheckDataType", "Using run range [%d, %d]", fRunRange[0], fRunRange[1]);
427       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
428          path = Form("%s/%d ", fGridDataDir.Data(), irun);
429          if (!gGrid->Cd(path)) {
430             Warning("CheckInputData", "Run number %d not found in path: %s", irun, path.Data());
431             continue;
432          }
433          path = Form("%s/%d.xml", workdir.Data(),irun);
434          TString msg = "\n#####   file: ";
435          msg += path;
436          msg += " type: xml_collection;";
437          if (use_tags) msg += " using_tags: Yes";
438          else          msg += " using_tags: No";
439          Info("CheckDataType", msg.Data());
440          AddDataFile(path);
441       }
442    }
443    return kTRUE;      
444 }   
445
446 //______________________________________________________________________________
447 Bool_t AliAnalysisAlien::CreateDataset(const char *pattern)
448 {
449 // Create dataset for the grid data directory + run number.
450    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
451    if (!Connect()) {
452       Error("CreateDataset", "Cannot create dataset with no grid connection");
453       return kFALSE;
454    }   
455
456    // Cd workspace
457    CdWork();
458    TString workdir = gGrid->GetHomeDirectory();
459    workdir += fGridWorkingDir;
460
461    // Compose the 'find' command arguments
462    TString command;
463    TString options = "-x collection ";
464    if (TestBit(AliAnalysisGrid::kTest)) options += Form("-l %d ", fNtestFiles);
465    TString conditions = "";
466    
467    TString file;
468    TString path;
469    if (!fRunNumbers.Length() && !fRunRange[0]) return kTRUE;
470    // Several runs
471    if (fRunNumbers.Length()) {
472       TObjArray *arr = fRunNumbers.Tokenize(" ");
473       TObjString *os;
474       TIter next(arr);
475       while ((os=(TObjString*)next())) {
476          path = Form("%s/%s ", fGridDataDir.Data(), os->GetString().Data());
477          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
478          else file = Form("%s.xml", os->GetString().Data());
479          if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
480             Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
481 //            gGrid->Rm(file); 
482             continue;
483          }
484          command = "find ";
485          command += options;
486          command += path;
487          command += pattern;
488 //         conditions = Form(" > %s", file.Data());
489          command += conditions;
490          TGridResult *res = gGrid->Command(command);
491          if (res) delete res;
492          // Write standard output to file
493          gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
494          if (TestBit(AliAnalysisGrid::kTest)) break;
495          // Copy xml file to alien space
496          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
497          if (!FileExists(file)) {
498             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
499             delete arr;
500             return kFALSE;
501          }
502       }   
503       delete arr;
504    } else {
505       // Process a full run range.
506       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
507          path = Form("%s/%d ", fGridDataDir.Data(), irun);
508          if (TestBit(AliAnalysisGrid::kTest)) file = "wn.xml";
509          else file = Form("%d.xml", irun);
510          if (FileExists(file) && !TestBit(AliAnalysisGrid::kTest)) {
511             Info("CreateDataset", "\n#####   Dataset %s exist. Skipping creation...", file.Data());
512 //            gGrid->Rm(file); 
513             continue;
514          }
515          command = "find ";
516          command += options;
517          command += path;
518          command += pattern;
519 //         conditions = Form(" > %s", file.Data());
520          command += conditions;
521          TGridResult *res = gGrid->Command(command);
522          if (res) delete res;
523          // Write standard output to file
524          gROOT->ProcessLine(Form("gGrid->Stdout(); > %s", file.Data()));
525          if (TestBit(AliAnalysisGrid::kTest)) break;
526          // Copy xml file to alien space
527          TFile::Cp(Form("file:%s",file.Data()), Form("alien://%s/%s",workdir.Data(), file.Data()));
528          if (!FileExists(file)) {
529             Error("CreateDataset", "Command %s did NOT succeed", command.Data());
530             return kFALSE;
531          }
532       }
533    }      
534    return kTRUE;
535 }
536
537 //______________________________________________________________________________
538 Bool_t AliAnalysisAlien::CreateJDL()
539 {
540 // Generate a JDL file according to current settings. The name of the file is 
541 // specified by fJDLName.
542    Bool_t error = kFALSE;
543    TObjArray *arr = 0;
544    Bool_t copy = kTRUE;
545    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
546    Bool_t generate = kTRUE;
547    if (TestBit(AliAnalysisGrid::kTest) || TestBit(AliAnalysisGrid::kSubmit)) generate = kFALSE;
548    if (!Connect()) {
549       Error("CreateJDL", "Alien connection required");
550       return kFALSE;
551    }   
552    // Check validity of alien workspace
553    CdWork();
554    TString workdir = gGrid->GetHomeDirectory();
555    workdir += fGridWorkingDir;
556    if (generate) {
557       TObjString *os;
558       if (!fInputFiles) {
559          Error("CreateJDL()", "Define some input files for your analysis.");
560          error = kTRUE;
561       }
562       // Compose list of input files   
563       // Check if output files were defined
564       if (!fOutputFiles.Length()) {
565          Error("CreateJDL", "You must define at least one output file");
566          error = kTRUE;
567       }   
568       // Check if an output directory was defined and valid
569       if (!fGridOutputDir.Length()) {
570          Error("CreateJDL", "You must define AliEn output directory");
571          error = kTRUE;
572       } else {
573          if (!gGrid->Cd(fGridOutputDir)) {
574             if (gGrid->Mkdir(fGridOutputDir)) {
575                Info("CreateJDL", "\n#####   Created alien output directory %s", fGridOutputDir.Data());
576             } else {
577                Error("CreateJDL", "Could not create alien output directory %s", fGridOutputDir.Data());
578                error = kTRUE;
579             }
580          }
581          gGrid->Cd(workdir);
582       }   
583       // Exit if any error up to now
584       if (error) return kFALSE;   
585       // Set JDL fields
586       fGridJDL->SetValue("User", Form("\"%s\"", fUser.Data()));
587       fGridJDL->SetExecutable(fExecutable);
588 //      fGridJDL->SetTTL((UInt_t)fTTL);
589       fGridJDL->SetValue("TTL", Form("\"%d\"", fTTL));
590       if (fMaxInitFailed > 0) 
591          fGridJDL->SetValue("MaxInitFailed", Form("\"%d\"",fMaxInitFailed));
592       if (fSplitMaxInputFileNumber > 0) 
593          fGridJDL->SetValue("SplitMaxInputFileNumber", Form("\"%d\"", fSplitMaxInputFileNumber));
594       if (fSplitMode.Length()) 
595          fGridJDL->SetValue("Split", Form("\"%s\"", fSplitMode.Data()));
596 //      fGridJDL->SetSplitMode(fSplitMode, (UInt_t)fSplitMaxInputFileNumber);
597       if (fAliROOTVersion.Length())  
598          fGridJDL->AddToPackages("AliRoot", fAliROOTVersion);
599       if (fROOTVersion.Length()) 
600          fGridJDL->AddToPackages("ROOT", fROOTVersion);
601       if (fAPIVersion.Length()) 
602          fGridJDL->AddToPackages("APISCONFIG", fAPIVersion);
603       fGridJDL->SetInputDataListFormat(fInputFormat);
604       fGridJDL->SetInputDataList("wn.xml");
605       fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), fAnalysisMacro.Data()));
606       fGridJDL->AddToInputSandbox(Form("LF:%s/analysis.root", workdir.Data()));
607       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C"))
608          fGridJDL->AddToInputSandbox(Form("LF:%s/ConfigureCuts.C", workdir.Data()));
609       if (fAdditionalLibs.Length()) {
610          arr = fAdditionalLibs.Tokenize(" ");
611          TIter next(arr);
612          while ((os=(TObjString*)next())) {
613             if (os->GetString().Contains(".so")) continue;
614             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), os->GetString().Data()));
615          }   
616          delete arr;   
617       }
618       if (fPackages) {
619          TIter next(fPackages);
620          TObject *obj;
621          while ((obj=next()))
622             fGridJDL->AddToInputSandbox(Form("LF:%s/%s", workdir.Data(), obj->GetName()));
623       }
624       if (fOutputArchive.Length()) {
625          arr = fOutputArchive.Tokenize(" ");
626          TIter next(arr);
627          while ((os=(TObjString*)next()))
628          if (!os->GetString().Contains("@") && fCloseSE.Length())
629             fGridJDL->AddToOutputArchive(Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
630          else
631             fGridJDL->AddToOutputArchive(os->GetString());
632          delete arr;
633       }      
634       arr = fOutputFiles.Tokenize(" ");
635       TIter next(arr);
636       while ((os=(TObjString*)next())) {
637          if (!os->GetString().Contains("@") && fCloseSE.Length())
638             fGridJDL->AddToOutputSandbox(Form("%s@%s",os->GetString().Data(), fCloseSE.Data())); 
639          else
640             fGridJDL->AddToOutputSandbox(os->GetString());
641       }   
642       delete arr;
643 //      fGridJDL->SetPrice((UInt_t)fPrice);
644       fGridJDL->SetValue("Price", Form("\"%d\"", fPrice));
645       fGridJDL->SetValidationCommand(Form("%s/validate.sh", workdir.Data()));
646       if (fMasterResubmitThreshold) fGridJDL->SetValue("MasterResubmitThreshold", Form("\"%d%%\"", fMasterResubmitThreshold));
647       // Depending if going through a run range or not, generate one or mode jdl's
648       if (!fRunRange[0]) WriteJDL(-1,copy);
649       else {
650          for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++)
651             if (!WriteJDL(irun-fRunRange[0],copy)) break;
652       }
653    }
654    // Copy jdl to grid workspace   
655    if (copy) {
656       if (fAdditionalLibs.Length()) {
657          arr = fAdditionalLibs.Tokenize(" ");
658          TObjString *os;
659          TIter next(arr);
660          while ((os=(TObjString*)next())) {
661             if (os->GetString().Contains(".so")) continue;
662             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", os->GetString().Data());
663             if (FileExists(os->GetString())) gGrid->Rm(os->GetString());
664             TFile::Cp(Form("file:%s",os->GetString().Data()), Form("alien://%s/%s", workdir.Data(), os->GetString().Data()));
665          }   
666          delete arr;   
667       }
668       if (fPackages) {
669          TIter next(fPackages);
670          TObject *obj;
671          while ((obj=next())) {
672             Info("CreateJDL", "\n#####   Copying dependency: <%s> to your alien workspace", obj->GetName());
673             TFile::Cp(Form("file:%s",obj->GetName()), Form("alien://%s/%s", workdir.Data(), obj->GetName()));
674          }   
675       }      
676    } 
677    return kTRUE;
678 }
679
680 //______________________________________________________________________________
681 Bool_t AliAnalysisAlien::WriteJDL(Int_t findex, Bool_t copy)
682 {
683 // Writes one or more JDL's corresponding to findex. If findex is negative,
684 // all run numbers are considered in one go (jdl). For non-negative indices
685 // they correspond to the indices in the array fInputFiles.
686    if (!fInputFiles) return kFALSE;
687    TObjString *os;
688    TString line;
689    TString workdir = gGrid->GetHomeDirectory();
690    workdir += fGridWorkingDir;
691    if (findex < 0) {
692       TIter next(fInputFiles);
693       while ((os=(TObjString*)next()))
694          fGridJDL->AddToInputDataCollection(Form("LF:%s,nodownload", os->GetString().Data()));
695       fGridJDL->SetOutputDirectory(Form("%s/%s/#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data()));
696    } else {
697       os = (TObjString*)fInputFiles->At(findex);
698       if (!os) return kFALSE;
699       line = "#Input xml collection\n";
700       line += "InputDataCollection = {";
701       line += Form("   \"LF:%s,nodownload\"", os->GetString().Data());
702       line += "\n};\n";
703       fGridJDL->SetOutputDirectory(Form("%s/%s/%03d#alien_counter_03i#", workdir.Data(), fGridOutputDir.Data(),findex));
704    }
705       
706
707    // Generate the JDL as a string
708    TString sjdl = fGridJDL->Generate();
709    Int_t index;
710    index = sjdl.Index("Executable");
711    if (index >= 0) sjdl.Insert(index, "\n# This is the startup script\n");
712    index = sjdl.Index("Split ");
713    if (index >= 0) sjdl.Insert(index, "\n# We split per storage element\n");
714    index = sjdl.Index("SplitMaxInputFileNumber");
715    if (index >= 0) sjdl.Insert(index, "\n# We want each subjob to get maximum this number of input files\n");
716    index = sjdl.Index("InputDataCollection");
717    if (index >= 0) sjdl.Insert(index, "# Input xml collections\n");
718    else {
719       index = sjdl.Index("OutputDir");
720       sjdl.Insert(index, line.Data());
721    }   
722    index = sjdl.Index("InputFile");
723    if (index >= 0) sjdl.Insert(index, "\n# List of input files to be uploaded to wn's\n");
724    index = sjdl.Index("InputDataList ");
725    if (index >= 0) sjdl.Insert(index, "\n# Collection to be processed on wn\n");
726    index = sjdl.Index("InputDataListFormat");
727    if (index >= 0) sjdl.Insert(index, "\n# Format of input data\n");
728    index = sjdl.Index("Price");
729    if (index >= 0) sjdl.Insert(index, "\n# AliEn price for this job\n");
730    index = sjdl.Index("Requirements");
731    if (index >= 0) sjdl.Insert(index, "\n# Additional requirements for the computing element\n");
732    index = sjdl.Index("Packages");
733    if (index >= 0) sjdl.Insert(index, "\n# Packages to be used\n");
734    index = sjdl.Index("User =");
735    if (index >= 0) sjdl.Insert(index, "\n# AliEn user\n");
736    index = sjdl.Index("TTL");
737    if (index >= 0) sjdl.Insert(index, "\n# Time to live for the job\n");
738    index = sjdl.Index("OutputFile");
739    if (index >= 0) sjdl.Insert(index, "\n# List of output files to be registered\n");
740    index = sjdl.Index("OutputDir");
741    if (index >= 0) sjdl.Insert(index, "\n# Output directory\n");
742    index = sjdl.Index("OutputArchive");
743    if (index >= 0) sjdl.Insert(index, "\n# Files to be archived\n");
744    index = sjdl.Index("MaxInitFailed");
745    if (index >= 0) sjdl.Insert(index, "\n# Maximum number of first failing jobs to abort the master job\n");
746    index = sjdl.Index("MasterResubmitThreshold");
747    if (index >= 0) sjdl.Insert(index, "\n# Resubmit failed jobs until DONE rate reaches this percentage\n");
748    sjdl.ReplaceAll("ValidationCommand", "Validationcommand");
749    index = sjdl.Index("Validationcommand");
750    if (index >= 0) sjdl.Insert(index, "\n# Validation script to be run for each subjob\n");
751    sjdl.ReplaceAll("\"LF:", "\n   \"LF:");
752    sjdl.ReplaceAll("(member", "\n   (member");
753    sjdl.ReplaceAll("\",\"VO_", "\",\n   \"VO_");
754    sjdl.ReplaceAll("{", "{\n   ");
755    sjdl.ReplaceAll("};", "\n};");
756    sjdl.ReplaceAll("{\n   \n", "{\n");
757    sjdl.ReplaceAll("\n\n", "\n");
758    sjdl.ReplaceAll("OutputDirectory", "OutputDir");
759    sjdl += "JDLVariables = \n{\n   \"Packages\",\n   \"OutputDir\"\n};\n";
760    sjdl.Prepend("JobTag = \"Automatically generated analysis JDL\";\n");
761    index = sjdl.Index("JDLVariables");
762    if (index >= 0) sjdl.Insert(index, "\n# JDL variables\n");
763    // Write jdl to file
764    TString snjdl = fJDLName;
765    if (findex >=0) snjdl.ReplaceAll(".jdl", Form("_%03d.jdl", findex));
766    ofstream out;
767    out.open(snjdl.Data(), ios::out);
768    if (out.bad()) {
769       Error("CreateJDL", "Bad file name: %s", snjdl.Data());
770       return kFALSE;
771    }
772    out << sjdl << endl;
773
774    // Copy jdl to grid workspace   
775    if (!copy) {
776       Info("CreateJDL", "\n#####   You may want to review jdl:%s and analysis macro:%s before running in <submit> mode", fJDLName.Data(), fAnalysisMacro.Data());
777    } else {
778       Info("CreateJDL", "\n#####   Copying JDL file <%s> to your AliEn working space", snjdl.Data());
779       if (FileExists(snjdl)) gGrid->Rm(snjdl);
780       TFile::Cp(Form("file:%s",snjdl.Data()), Form("alien://%s/%s", workdir.Data(), snjdl.Data()));
781    } 
782    return kTRUE;
783 }
784
785 //______________________________________________________________________________
786 Bool_t AliAnalysisAlien::FileExists(const char *lfn) const
787 {
788 // Returns true if file exists.
789    if (!gGrid) {
790       Error("FileExists", "No connection to grid");
791       return kFALSE;
792    }
793    TGridResult *res = gGrid->Ls(lfn);
794    if (!res) return kFALSE;
795    TMap *map = dynamic_cast<TMap*>(res->At(0));
796    if (!map) {
797       delete res;
798       return kFALSE;
799    }   
800    TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("name"));
801    if (!objs || !objs->GetString().Length()) {
802       delete res;
803       return kFALSE;
804    }
805    delete res;   
806    return kTRUE;
807 }
808
809 //______________________________________________________________________________
810 void AliAnalysisAlien::CheckDataType(const char *lfn, Bool_t &is_collection, Bool_t &is_xml, Bool_t &use_tags)
811 {
812 // Check input data type.
813    is_collection = kFALSE;
814    is_xml = kFALSE;
815    use_tags = kFALSE;
816    if (!gGrid) {
817       Error("CheckDataType", "No connection to grid");
818       return;
819    }
820    is_collection = IsCollection(lfn);
821    TString msg = "\n#####   file: ";
822    msg += lfn;
823    if (is_collection) {
824       msg += " type: raw_collection;";
825    // special treatment for collections
826       is_xml = kFALSE;
827       // check for tag files in the collection
828       TGridResult *res = gGrid->Command(Form("listFilesFromCollection -z -v %s",lfn), kFALSE);
829       if (!res) {
830          msg += " using_tags: No (unknown)";
831          Info("CheckDataType", msg.Data());
832          return;
833       }   
834       const char* typeStr = res->GetKey(0, "origLFN");
835       if (!typeStr || !strlen(typeStr)) {
836          msg += " using_tags: No (unknown)";
837          Info("CheckDataType", msg.Data());
838          return;
839       }   
840       TString file = typeStr;
841       use_tags = file.Contains(".tag");
842       if (use_tags) msg += " using_tags: Yes";
843       else          msg += " using_tags: No";
844       Info("CheckDataType", msg.Data());
845       return;
846    }
847    TString slfn(lfn);
848    slfn.ToLower();
849    is_xml = slfn.Contains(".xml");
850    if (is_xml) {
851    // Open xml collection and check if there are tag files inside
852       msg += " type: xml_collection;";
853       TGridCollection *coll = (TGridCollection*)gROOT->ProcessLine(Form("TAlienCollection::Open(\"alien://%s\",1);",lfn));
854       if (!coll) {
855          msg += " using_tags: No (unknown)";
856          Info("CheckDataType", msg.Data());
857          return;
858       }   
859       TMap *map = coll->Next();
860       if (!map) {
861          msg += " using_tags: No (unknown)";
862          Info("CheckDataType", msg.Data());
863          return;
864       }   
865       map = (TMap*)map->GetValue("");
866       TString file;
867       if (map && map->GetValue("name")) file = map->GetValue("name")->GetName();
868       use_tags = file.Contains(".tag");
869       delete coll;
870       if (use_tags) msg += " using_tags: Yes";
871       else          msg += " using_tags: No";
872       Info("CheckDataType", msg.Data());
873       return;
874    }
875    use_tags = slfn.Contains(".tag");
876    if (slfn.Contains(".root")) msg += " type: root file;";
877    else                        msg += " type: unhnown file;";
878    if (use_tags) msg += " using_tags: Yes";
879    else          msg += " using_tags: No";
880    Info("CheckDataType", msg.Data());
881 }
882
883 //______________________________________________________________________________
884 void AliAnalysisAlien::EnablePackage(const char *package)
885 {
886 // Enables a par file supposed to exist in the current directory.
887    TString pkg(package);
888    pkg.ReplaceAll(".par", "");
889    pkg += ".par";
890    if (gSystem->AccessPathName(pkg)) {
891       Error("EnablePackage", "Package %s not found", pkg.Data());
892       return;
893    }
894    if (!TObject::TestBit(AliAnalysisGrid::kUsePars))
895       Info("EnablePackage", "AliEn plugin will use .par packages");
896    TObject::SetBit(AliAnalysisGrid::kUsePars, kTRUE);
897    if (!fPackages) {
898       fPackages = new TObjArray();
899       fPackages->SetOwner();
900    }
901    fPackages->Add(new TObjString(pkg));
902 }      
903
904 //______________________________________________________________________________
905 Bool_t AliAnalysisAlien::IsCollection(const char *lfn) const
906 {
907 // Returns true if file is a collection. Functionality duplicated from
908 // TAlien::Type() because we don't want to directly depend on TAlien.
909    if (!gGrid) {
910       Error("IsCollection", "No connection to grid");
911       return kFALSE;
912    }
913    TGridResult *res = gGrid->Command(Form("type -z %s",lfn),kFALSE);
914    if (!res) return kFALSE;
915    const char* typeStr = res->GetKey(0, "type");
916    if (!typeStr || !strlen(typeStr)) return kFALSE;
917    if (!strcmp(typeStr, "collection")) return kTRUE;
918    delete res;
919    return kFALSE;
920 }   
921
922 //______________________________________________________________________________
923 void AliAnalysisAlien::Print(Option_t *) const
924 {
925 // Print current plugin settings.
926    printf("### AliEn analysis plugin current settings ###\n");
927    printf("=   Version of API requested: ____________________ %s\n", fAPIVersion.Data());
928    printf("=   Version of ROOT requested: ___________________ %s\n", fROOTVersion.Data());
929    printf("=   Version of AliRoot requested: ________________ %s\n", fAliROOTVersion.Data());
930    if (fUser.Length()) 
931    printf("=   User running the plugin: _____________________ %s\n", fUser.Data());
932    printf("=   Grid workdir relative to user $HOME: _________ %s\n", fGridWorkingDir.Data());
933    printf("=   Grid output directory relative to workdir: ___ %s\n", fGridOutputDir.Data());
934    printf("=   Data base directory path requested: __________ %s\n", fGridDataDir.Data());
935    printf("=   Data search pattern: _________________________ %s\n", fDataPattern.Data());
936    printf("=   Input data format: ___________________________ %s\n", fInputFormat.Data());
937    if (fRunNumbers.Length()) 
938    printf("=   Run numbers to be processed: _________________ %s\n", fRunNumbers.Data());
939    if (fRunRange[0])
940    printf("=   Run range to be processed: ___________________ %d-%d\n", fRunRange[0], fRunRange[1]);
941    if (!fRunRange[0] && !fRunNumbers.Length()) {
942       TIter next(fInputFiles);
943       TObject *obj;
944       TString list;
945       while ((obj=next())) list += obj->GetName();
946       printf("=   Input files to be processed: _________________ %s\n", list.Data());
947    }
948    if (TestBit(AliAnalysisGrid::kTest))
949    printf("=   Number of input files used in test mode: _____ %d\n", fNtestFiles);
950    printf("=   List of output files to be registered: _______ %s\n", fOutputFiles.Data());
951    printf("=   List of outputs going to be archived: ________ %s\n", fOutputArchive.Data());
952    printf("=   List of outputs that should not be merged: ___ %s\n", fMergeExcludes.Data());
953    printf("=====================================================================\n");
954    printf("=   Job price: ___________________________________ %d\n", fPrice);
955    printf("=   Time to live (TTL): __________________________ %d\n", fTTL);
956    printf("=   Max files per subjob: ________________________ %d\n", fSplitMaxInputFileNumber);
957    if (fMaxInitFailed>0) 
958    printf("=   Max number of subjob fails to kill: __________ %d\n", fMaxInitFailed);
959    if (fMasterResubmitThreshold>0) 
960    printf("=   Resubmit master job if failed subjobs >_______ %d\n", fMasterResubmitThreshold);
961    if (fNMasterJobs>0)
962    printf("=   Number of master jobs to be launched: ________ not used yet\n");
963    printf("=   Number of files in one chunk to be merged: ___ %d\n", fMaxMergeFiles);
964    printf("=   Name of the generated execution script: ______ %s\n",fExecutable.Data());
965    if (fArguments.Length()) 
966    printf("=   Arguments for the execution script: __________ %s\n",fArguments.Data());
967    printf("=   Name of the generated analysis macro: ________ %s\n",fAnalysisMacro.Data());
968    printf("=   User analysis files to be deployed: __________ %s\n",fAnalysisSource.Data());
969    printf("=   Additional libs to be loaded or souces to be compiled runtime: <%s>\n",fAdditionalLibs.Data());
970    printf("=   Master jobs split mode: ______________________ %s\n",fSplitMode.Data());
971    if (fDatasetName)
972    printf("=   Custom name for the dataset to be created: ___ %s\n", fDatasetName.Data());
973    printf("=   Name of the generated JDL: ___________________ %s\n", fJDLName.Data());
974    if (fIncludePath.Data())
975    printf("=   Include path for runtime task compilation: ___ %s\n", fIncludePath.Data());
976    if (fCloseSE.Length())
977    printf("=   Force job outputs to storage element: ________ %s\n", fCloseSE.Data());
978    if (fFriendChainName.Length())
979    printf("=   Open friend chain file on worker: ____________ %s\n", fFriendChainName.Data());
980    if (fPackages) {
981       TIter next(fPackages);
982       TObject *obj;
983       TString list;
984       while ((obj=next())) list += obj->GetName();
985       printf("=   Par files to be used: ________________________ %s\n", list.Data());
986    }   
987 }
988
989 //______________________________________________________________________________
990 void AliAnalysisAlien::SetDefaults()
991 {
992 // Set default values for everything. What cannot be filled will be left empty.
993    if (fGridJDL) delete fGridJDL;
994    fGridJDL = (TGridJDL*)gROOT->ProcessLine("new TAlienJDL()");
995    fPrice                      = 1;
996    fTTL                        = 30000;
997    fSplitMaxInputFileNumber    = 100;
998    fMaxInitFailed              = 0;
999    fMasterResubmitThreshold    = 0;
1000    fNtestFiles                 = 10;
1001    fRunRange[0]                = 0;
1002    fRunRange[1]                = 0;
1003    fNMasterJobs                = 0;
1004    fMaxMergeFiles              = 100;
1005    fRunNumbers                 = "";
1006    fExecutable                 = "analysis.sh";
1007    fArguments                  = "";
1008    fAnalysisMacro              = "myAnalysis.C";
1009    fAnalysisSource             = "";
1010    fAdditionalLibs             = "";
1011    fSplitMode                  = "se";
1012    fAPIVersion                 = "";
1013    fROOTVersion                = "";
1014    fAliROOTVersion             = "";
1015    fUser                       = "";  // Your alien user name
1016    fGridWorkingDir             = "";
1017    fGridDataDir                = "";  // Can be like: /alice/sim/PDC_08a/LHC08c9/
1018    fDataPattern                = "*AliESDs.root";  // Can be like: *AliESDs.root, */pass1/*AliESDs.root, ...
1019    fFriendChainName            = "";
1020    fGridOutputDir              = "output";
1021    fOutputArchive              = "log_archive.zip:stdout,stderr root_archive.zip:*.root";
1022    fOutputFiles                = "";  // Like "AliAODs.root histos.root"
1023    fInputFormat                = "xml-single";
1024    fJDLName                    = "analysis.jdl";
1025    fMergeExcludes              = "";
1026 }   
1027
1028 //______________________________________________________________________________
1029 Bool_t AliAnalysisAlien::MergeOutputs()
1030 {
1031 // Merge analysis outputs existing in the AliEn space.
1032    if (TestBit(AliAnalysisGrid::kTest)) return kTRUE;
1033    if (TestBit(AliAnalysisGrid::kOffline)) return kFALSE;
1034    if (!Connect()) {
1035       Error("MergeOutputs", "Cannot merge outputs without grid connection. Terminate will NOT be executed");
1036       return kFALSE;
1037    }   
1038    // Get the output path
1039    TString output = Form("/%s/%s/%s", gGrid->GetHomeDirectory(), fGridWorkingDir.Data(), fGridOutputDir.Data());
1040    if (!gGrid->Cd(output)) output = Form("/%s/%s", gGrid->GetHomeDirectory(), fGridOutputDir.Data());
1041    if (!gGrid->Cd(output)) {
1042       Error("MergeOutputs", "Grid output directory %s not found. Terminate() will NOT be executed", fGridOutputDir.Data());
1043       return kFALSE;
1044    }
1045    if (!fOutputFiles.Length()) {
1046       Error("MergeOutputs", "No output file names defined. Are you running the right AliAnalysisAlien configuration ?");
1047       return kFALSE;
1048    }   
1049    TObjArray *list = fOutputFiles.Tokenize(" ");
1050    TIter next(list);
1051    TObjString *str;
1052    TString command;
1053    TString output_file;
1054    TString output_chunk;
1055    TString previous_chunk;
1056    Int_t count_chunk = 0;
1057    Int_t count_zero = fMaxMergeFiles;
1058    Bool_t merged = kTRUE;
1059    while((str=(TObjString*)next())) {
1060       output_file = str->GetString();
1061       Int_t index = output_file.Index("@");
1062       if (index > 0) output_file.Remove(index);
1063       if (fMergeExcludes.Length() &&
1064           fMergeExcludes.Contains(output_file.Data())) continue;
1065       // Perform a 'find' command in the output directory, looking for registered outputs    
1066       command = Form("find %s/ *%s", output.Data(), output_file.Data());
1067       printf("command: %s\n", command.Data());
1068       TGridResult *res = gGrid->Command(command);
1069       if (!res) continue;
1070       TFileMerger *fm = 0;
1071       TIter nextmap(res);
1072       TMap *map;
1073       previous_chunk = "";
1074       count_chunk = 0;
1075       count_zero = fMaxMergeFiles;
1076       while ((map=(TMap*)nextmap())) {
1077       // Loop 'find' results and get next LFN
1078          if (count_zero == fMaxMergeFiles) {
1079             // First file in chunk - create file merger and add previous chunk if any.
1080             fm = new TFileMerger(kFALSE);
1081             fm->SetFastMethod(kTRUE);
1082             if (previous_chunk.Length()) fm->AddFile(previous_chunk.Data());
1083             output_chunk = output_file;
1084             output_chunk.ReplaceAll(".root", Form("_%04d.root", count_chunk));
1085          }
1086          // If last file found, put merged results in the output file
1087          if (map == res->Last()) output_chunk = output_file;
1088          TObjString *objs = dynamic_cast<TObjString*>(map->GetValue("turl"));
1089          if (!objs || !objs->GetString().Length()) {
1090             // Nothing found - skip this output
1091             delete res;
1092             delete fm;
1093             break;
1094          } 
1095          // Add file to be merged and decrement chunk counter.
1096          fm->AddFile(objs->GetString());
1097          count_zero--;
1098          if (count_zero==0 || map == res->Last()) {            
1099             fm->OutputFile(output_chunk);
1100             if (!fm->GetMergeList() || !fm->GetMergeList()->GetSize()) {
1101             // Nothing found - skip this output
1102                Warning("MergeOutputs", "No <%s> files found.", output_file.Data());
1103                delete res;
1104                delete fm;
1105                break;
1106             }
1107             // Merge the outputs, then go to next chunk      
1108             if (!fm->Merge()) {
1109                Error("MergeOutputs", "Could not merge all <%s> files", output_file.Data());
1110                delete res;
1111                delete fm;
1112                merged = kFALSE;
1113                break;
1114             } else {
1115                Info("MergeOutputs", "\n#####   Merged %d output files to <%s>", fm->GetMergeList()->GetSize(), output_chunk.Data());
1116             }
1117             if (map == res->Last()) {
1118                delete res;
1119                delete fm;
1120                break;
1121             }      
1122             count_chunk++;
1123             count_zero = fMaxMergeFiles;
1124             previous_chunk = output_chunk;
1125          }
1126       }
1127    } 
1128    if (!merged) {
1129       Error("MergeOutputs", "Terminate() will  NOT be executed");
1130    }  
1131    return merged;
1132 }   
1133
1134 //______________________________________________________________________________
1135 void AliAnalysisAlien::SetDefaultOutputs(Bool_t flag)
1136 {
1137 // Use the output files connected to output containers from the analysis manager
1138 // rather than the files defined by SetOutputFiles
1139    if (flag && !TObject::TestBit(AliAnalysisGrid::kDefaultOutputs))
1140       Info("SetDefaultOutputs", "Plugin will use the output files taken from \
1141       analysis manager");
1142    TObject::SetBit(AliAnalysisGrid::kDefaultOutputs, flag);
1143 }
1144       
1145 //______________________________________________________________________________
1146 void AliAnalysisAlien::StartAnalysis(Long64_t /*nentries*/, Long64_t /*firstEntry*/)
1147 {
1148 // Start remote grid analysis.
1149    
1150    // Check if output files have to be taken from the analysis manager
1151    if (TestBit(AliAnalysisGrid::kDefaultOutputs)) {
1152       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1153       if (!mgr || !mgr->IsInitialized()) {
1154          Error("StartAnalysis", "You need an initialized analysis manager for this");
1155          return;
1156       }
1157       fOutputFiles = "";
1158       TIter next(mgr->GetOutputs());
1159       AliAnalysisDataContainer *output;
1160       while ((output=(AliAnalysisDataContainer*)next())) {
1161          const char *filename = output->GetFileName();
1162          if (!(strcmp(filename, "default"))) {
1163             if (!mgr->GetOutputEventHandler()) continue;
1164             filename = mgr->GetOutputEventHandler()->GetOutputFileName();
1165          }
1166          if (fOutputFiles.Length()) fOutputFiles += " ";
1167          fOutputFiles += filename;
1168       }
1169       // Add extra files registered to the analysis manager
1170       if (mgr->GetExtraFiles().Length()) {
1171          if (fOutputFiles.Length()) fOutputFiles += " ";
1172          fOutputFiles += mgr->GetExtraFiles();
1173       }   
1174    }
1175 //   if (!fCloseSE.Length()) fCloseSE = gSystem->Getenv("alien_CLOSE_SE");
1176    if (TestBit(AliAnalysisGrid::kOffline)) {
1177       Info("StartAnalysis","\n##### OFFLINE MODE ##### Files to be used in GRID are produced but not copied \
1178       \n                         there nor any job run. You can revise the JDL and analysis \
1179       \n                         macro then run the same in \"submit\" mode.");
1180    } else if (TestBit(AliAnalysisGrid::kTest)) {
1181       Info("StartAnalysis","\n##### LOCAL MODE #####   Your analysis will be run locally on a subset of the requested \
1182       \n                         dataset.");
1183    } else if (TestBit(AliAnalysisGrid::kSubmit)) {
1184       Info("StartAnalysis","\n##### SUBMIT MODE #####  Files required by your analysis are copied to your grid working \
1185       \n                         space and job submitted.");
1186    } else if (TestBit(AliAnalysisGrid::kMerge)) {
1187       Info("StartAnalysis","\n##### MERGE MODE #####   The registered outputs of the analysis will be merged");
1188       return;
1189    } else {
1190       Info("StartAnalysis","\n##### FULL ANALYSIS MODE ##### Producing needed files and submitting your analysis job...");   
1191    }   
1192       
1193    if (!Connect()) {
1194       Error("StartAnalysis", "Cannot start grid analysis without grid connection");
1195       return;
1196    }
1197    Print();   
1198    if (!CheckInputData()) {
1199       Error("StartAnalysis", "There was an error in preprocessing your requested input data");
1200       return;
1201    }   
1202    CreateDataset(fDataPattern);
1203    WriteAnalysisFile();   
1204    WriteAnalysisMacro();
1205    WriteExecutable();
1206    WriteValidationScript();
1207    if (!CreateJDL()) return;
1208    if (TestBit(AliAnalysisGrid::kOffline)) return;
1209    if (TestBit(AliAnalysisGrid::kTest)) {
1210       // Locally testing the analysis
1211       Info("StartAnalysis", "\n_______________________________________________________________________ \
1212       \n   Running analysis script in a daughter shell as on a worker node \
1213       \n_______________________________________________________________________");
1214       TObjArray *list = fOutputFiles.Tokenize(" ");
1215       TIter next(list);
1216       TObjString *str;
1217       TString output_file;
1218       while((str=(TObjString*)next())) {
1219          output_file = str->GetString();
1220          Int_t index = output_file.Index("@");
1221          if (index > 0) output_file.Remove(index);         
1222          if (!gSystem->AccessPathName(output_file)) gSystem->Exec(Form("rm %s", output_file.Data()));
1223       }
1224       delete list;
1225       gSystem->Exec(Form("bash %s 2>stderr", fExecutable.Data()));
1226       gSystem->Exec("bash validate.sh");
1227 //      gSystem->Exec("cat stdout");
1228       return;
1229    }
1230    // Submit AliEn job(s)
1231    CdWork();
1232    TGridResult *res;
1233    TString jobID = "";
1234    if (!fRunRange[0]) {
1235       // Submit a given xml or a set of runs
1236       res = gGrid->Command(Form("submit %s", fJDLName.Data()));
1237       printf("*************************** %s\n",Form("submit %s", fJDLName.Data()));
1238       if (res) {
1239          const char *cjobId = res->GetKey(0,"jobId");
1240          if (!cjobId) {
1241             Error("StartAnalysis", "Your JDL %s could not be submitted", fJDLName.Data());
1242             return;
1243          } else {
1244             Info("StartAnalysis", "\n_______________________________________________________________________ \
1245             \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1246             \n_______________________________________________________________________",
1247                    fJDLName.Data(), cjobId);
1248             jobID = cjobId;      
1249          }          
1250          delete res;
1251       }   
1252    } else {
1253       // Submit for a range of runs.
1254       TString sjdl;
1255       for (Int_t irun=fRunRange[0]; irun<=fRunRange[1]; irun++) {
1256          if (!fInputFiles->At(irun-fRunRange[0])) break;
1257          sjdl = fJDLName;
1258          sjdl.ReplaceAll(".jdl", Form("_%03d.jdl", irun-fRunRange[0]));
1259          res = gGrid->Command(Form("submit %s", sjdl.Data()));
1260          printf("*************************** %s\n",Form("submit %s", sjdl.Data()));
1261          if (res) {
1262             const char *cjobId1 = res->GetKey(0,"jobId");
1263             if (!cjobId1) {
1264                Error("StartAnalysis", "Your JDL %s could not be submitted", sjdl.Data());
1265                return;
1266             } else {
1267                Info("StartAnalysis", "\n_______________________________________________________________________ \
1268                \n#####   Your JDL %s was successfully submitted. \nTHE JOB ID IS: %s \
1269                \n_______________________________________________________________________",
1270                    sjdl.Data(), cjobId1);
1271                jobID += cjobId1;
1272                jobID += " ";
1273             }          
1274             delete res;
1275          }   
1276       }
1277    }   
1278          
1279    Info("StartAnalysis", "\n#### STARTING AN ALIEN SHELL FOR YOU. EXIT WHEN YOUR JOB %s HAS FINISHED. #### \
1280    \n You may exit at any time and terminate the job later using the option <terminate> \
1281    \n ##################################################################################", jobID.Data());
1282    gSystem->Exec("aliensh");
1283 }
1284
1285 //______________________________________________________________________________
1286 void AliAnalysisAlien::WriteAnalysisFile()
1287 {
1288 // Write current analysis manager into the file analysis.root
1289    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1290       AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
1291       if (!mgr || !mgr->IsInitialized()) {
1292          Error("WriteAnalysisFile", "You need an initialized analysis manager for this");
1293          return;
1294       }
1295       // Check analysis type
1296       TObject *handler;
1297       if (mgr->GetMCtruthEventHandler()) TObject::SetBit(AliAnalysisGrid::kUseMC);
1298       handler = (TObject*)mgr->GetInputEventHandler();
1299       if (handler) {
1300          if (handler->InheritsFrom("AliESDInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseESD);
1301          if (handler->InheritsFrom("AliAODInputHandler")) TObject::SetBit(AliAnalysisGrid::kUseAOD);
1302       }
1303       TDirectory *cdir = gDirectory;
1304       TFile *file = TFile::Open("analysis.root", "RECREATE");
1305       if (file) {
1306          mgr->Write();
1307          delete file;
1308       }
1309       if (cdir) cdir->cd();
1310       Info("WriteAnalysisFile", "\n#####   Analysis manager: %s wrote to file <analysis.root>\n", mgr->GetName());
1311    }   
1312    Bool_t copy = kTRUE;
1313    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1314    if (copy) {
1315       CdWork();
1316       TString workdir = gGrid->GetHomeDirectory();
1317       workdir += fGridWorkingDir;
1318       Info("CreateJDL", "\n#####   Copying file <analysis.root> containing your initialized analysis manager to your alien workspace");
1319       if (FileExists("analysis.root")) gGrid->Rm("analysis.root");
1320       TFile::Cp("file:analysis.root", Form("alien://%s/analysis.root", workdir.Data()));
1321    }   
1322 }
1323
1324 //______________________________________________________________________________
1325 void AliAnalysisAlien::WriteAnalysisMacro()
1326 {
1327 // Write the analysis macro that will steer the analysis in grid mode.
1328    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1329       ofstream out;
1330       out.open(fAnalysisMacro.Data(), ios::out);
1331       if (!out.good()) {
1332          Error("WriteAnalysisMacro", "could not open file %s for writing", fAnalysisMacro.Data());
1333          return;
1334       }
1335       TString func = fAnalysisMacro;
1336       TString type = "ESD";
1337       TString comment = "// Analysis using ";
1338       if (TObject::TestBit(AliAnalysisGrid::kUseESD)) comment += "ESD";
1339       if (TObject::TestBit(AliAnalysisGrid::kUseAOD)) {
1340          type = "AOD";
1341          comment += "AOD";
1342       }   
1343       if (type!="AOD" && fFriendChainName!="") {
1344          Error("WriteAnalysisMacro", "Friend chain can be attached only to AOD");
1345          return;
1346       }
1347       if (TObject::TestBit(AliAnalysisGrid::kUseMC)) comment += "/MC";
1348       else comment += " data";
1349       out << "const char *anatype = \"" << type.Data() << "\";" << endl << endl;
1350       func.ReplaceAll(".C", "");
1351       out << "void " << func.Data() << "()" << endl; 
1352       out << "{" << endl;
1353       out << comment.Data() << endl;
1354       out << "// Automatically generated analysis steering macro executed in grid subjobs" << endl << endl;
1355       out << "   TStopwatch timer;" << endl;
1356       out << "   timer.Start();" << endl << endl;
1357       out << "// load base root libraries" << endl;
1358       out << "   gSystem->Load(\"libTree\");" << endl;
1359       out << "   gSystem->Load(\"libGeom\");" << endl;
1360       out << "   gSystem->Load(\"libVMC\");" << endl;
1361       out << "   gSystem->Load(\"libPhysics\");" << endl << endl;
1362       out << "// Load analysis framework libraries" << endl;
1363       if (!fPackages) {
1364          out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1365          out << "   gSystem->Load(\"libESD\");" << endl;
1366          out << "   gSystem->Load(\"libAOD\");" << endl;
1367          out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1368          out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1369          out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1370       } else {
1371          TIter next(fPackages);
1372          TObject *obj;
1373          TString pkgname;
1374          Bool_t hasSTEERBase = kFALSE;
1375          Bool_t hasESD = kFALSE;
1376          Bool_t hasAOD = kFALSE;
1377          Bool_t hasANALYSIS = kFALSE;
1378          Bool_t hasANALYSISalice = kFALSE;
1379          Bool_t hasCORRFW = kFALSE;
1380          while ((obj=next())) {
1381             pkgname = obj->GetName();
1382             if (pkgname == "STEERBase" ||
1383                 pkgname == "STEERBase.par") hasSTEERBase = kTRUE;
1384             if (pkgname == "ESD" ||
1385                 pkgname == "ESD.par")       hasESD = kTRUE;
1386             if (pkgname == "AOD" ||
1387                 pkgname == "AOD.par")       hasAOD = kTRUE;
1388             if (pkgname == "ANALYSIS" ||
1389                 pkgname == "ANALYSIS.par")  hasANALYSIS = kTRUE;
1390             if (pkgname == "ANALYSISalice" ||
1391                 pkgname == "ANALYSISalice.par") hasANALYSISalice = kTRUE;
1392             if (pkgname == "CORRFW" ||
1393                 pkgname == "CORRFW.par")    hasCORRFW = kTRUE;
1394          }   
1395          if (!hasSTEERBase) out << "   gSystem->Load(\"libSTEERBase\");" << endl;
1396          else out << "   if (!SetupPar(\"STEERBase\")) return;" << endl;
1397          if (!hasESD)       out << "   gSystem->Load(\"libESD\");" << endl;
1398          else out << "   if (!SetupPar(\"ESD\")) return;" << endl;
1399          if (!hasAOD)       out << "   gSystem->Load(\"libAOD\");" << endl;
1400          else out << "   if (!SetupPar(\"AOD\")) return;" << endl;
1401          if (!hasANALYSIS)  out << "   gSystem->Load(\"libANALYSIS\");" << endl;
1402          else out << "   if (!SetupPar(\"ANALYSIS\")) return;" << endl;
1403          if (!hasANALYSISalice)   out << "   gSystem->Load(\"libANALYSISalice\");" << endl;
1404          else out << "   if (!SetupPar(\"ANALYSISalice\")) return;" << endl;
1405          if (!hasCORRFW)    out << "   gSystem->Load(\"libCORRFW\");" << endl << endl;
1406          else out << "   if (!SetupPar(\"CORRFW\")) return;" << endl << endl;
1407          out << "// Compile other par packages" << endl;
1408          next.Reset();
1409          while ((obj=next())) {
1410             pkgname = obj->GetName();
1411             if (pkgname == "STEERBase" ||
1412                 pkgname == "STEERBase.par" ||
1413                 pkgname == "ESD" ||
1414                 pkgname == "ESD.par" ||
1415                 pkgname == "AOD" ||
1416                 pkgname == "AOD.par" ||
1417                 pkgname == "ANALYSIS" ||
1418                 pkgname == "ANALYSIS.par" ||
1419                 pkgname == "ANALYSISalice" ||
1420                 pkgname == "ANALYSISalice.par" ||
1421                 pkgname == "CORRFW" ||
1422                 pkgname == "CORRFW.par") continue;
1423             out << "   if (!SetupPar(\"" << obj->GetName() << "\")) return;" << endl;
1424          }   
1425       }   
1426       out << "// include path" << endl;
1427       if (fIncludePath.Length()) out << "   gSystem->AddIncludePath(\"" << fIncludePath.Data() << "\");" << endl;
1428       out << "   gSystem->AddIncludePath(\"-I$ALICE_ROOT/include\");" << endl << endl;
1429       if (fAdditionalLibs.Length()) {
1430          out << "// Add aditional AliRoot libraries" << endl;
1431          TObjArray *list = fAdditionalLibs.Tokenize(" ");
1432          TIter next(list);
1433          TObjString *str;
1434          while((str=(TObjString*)next())) {
1435             if (str->GetString().Contains(".so"))
1436                out << "   gSystem->Load(\"" << str->GetString().Data() << "\");" << endl;
1437          }
1438          if (list) delete list;
1439       }
1440       out << endl;
1441       out << "// analysis source to be compiled at runtime (if any)" << endl;
1442       if (fAnalysisSource.Length()) {
1443          TObjArray *list = fAnalysisSource.Tokenize(" ");
1444          TIter next(list);
1445          TObjString *str;
1446          while((str=(TObjString*)next())) {
1447             out << "   gROOT->ProcessLine(\".L " << str->GetString().Data() << "+g\");" << endl;
1448          }   
1449          if (list) delete list;
1450       }
1451       out << endl;
1452       out << "// connect to AliEn and make the chain" << endl;
1453       out << "   if (!TGrid::Connect(\"alien://\")) return;" << endl;
1454       if (IsUsingTags()) {
1455          out << "   TChain *chain = CreateChainFromTags(\"wn.xml\", anatype);" << endl << endl;
1456       } else {
1457          out << "   TChain *chain = CreateChain(\"wn.xml\", anatype);" << endl << endl;      
1458       }   
1459       out << "// read the analysis manager from file" << endl;
1460       out << "   TFile *file = TFile::Open(\"analysis.root\");" << endl;
1461       out << "   if (!file) return;" << endl; 
1462       out << "   TIter nextkey(file->GetListOfKeys());" << endl;
1463       out << "   AliAnalysisManager *mgr = 0;" << endl;
1464       out << "   TKey *key;" << endl;
1465       out << "   while ((key=(TKey*)nextkey())) {" << endl;
1466       out << "      if (!strcmp(key->GetClassName(), \"AliAnalysisManager\"))" << endl;
1467       out << "         mgr = (AliAnalysisManager*)file->Get(key->GetName());" << endl;
1468       out << "   };" << endl;
1469       out << "   if (!mgr) {" << endl;
1470       out << "      ::Error(\"" << func.Data() << "\", \"No analysis manager found in file analysis.root\");" << endl;
1471       out << "      return;" << endl;
1472       out << "   }" << endl << endl;
1473       out << "   mgr->PrintStatus();" << endl;
1474       out << "   mgr->StartAnalysis(\"localfile\", chain);" << endl;
1475       out << "   timer.Stop();" << endl;
1476       out << "   timer.Print();" << endl;
1477       out << "}" << endl << endl;
1478       if (IsUsingTags()) {
1479          out << "TChain* CreateChainFromTags(const char *xmlfile, const char *type=\"ESD\")" << endl;
1480          out << "{" << endl;
1481          out << "// Create a chain using tags from the xml file." << endl;
1482          out << "   TAlienCollection* coll = TAlienCollection::Open(xmlfile);" << endl;
1483          out << "   if (!coll) {" << endl;
1484          out << "      ::Error(\"CreateChainFromTags\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1485          out << "      return NULL;" << endl;
1486          out << "   }" << endl;
1487          out << "   TGridResult* tagResult = coll->GetGridResult(\"\",kFALSE,kFALSE);" << endl;
1488          out << "   AliTagAnalysis *tagAna = new AliTagAnalysis(type);" << endl;
1489          out << "   tagAna->ChainGridTags(tagResult);" << endl << endl;
1490          out << "   AliRunTagCuts      *runCuts = new AliRunTagCuts();" << endl;
1491          out << "   AliLHCTagCuts      *lhcCuts = new AliLHCTagCuts();" << endl;
1492          out << "   AliDetectorTagCuts *detCuts = new AliDetectorTagCuts();" << endl;
1493          out << "   AliEventTagCuts    *evCuts  = new AliEventTagCuts();" << endl;
1494          out << "   // Check if the cuts configuration file was provided" << endl;
1495          out << "   if (!gSystem->AccessPathName(\"ConfigureCuts.C\")) {" << endl;
1496          out << "      gROOT->LoadMacro(\"ConfigureCuts.C\");" << endl;
1497          out << "      ConfigureCuts(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1498          out << "   }" << endl;
1499          if (fFriendChainName=="") {
1500             out << "   TChain *chain = tagAna->QueryTags(runCuts, lhcCuts, detCuts, evCuts);" << endl;
1501          } else {
1502             out << "   TString tmpColl=\"tmpCollection.xml\";" << endl;
1503             out << "   tagAna->CreateXMLCollection(tmpColl.Data(),runCuts, lhcCuts, detCuts, evCuts);" << endl;
1504             out << "   TChain *chain = CreateChain(tmpColl.Data(),type);" << endl;
1505          }
1506          out << "   if (!chain || !chain->GetNtrees()) return NULL;" << endl;
1507          out << "   chain->ls();" << endl;
1508          out << "   return chain;" << endl;
1509          out << "}" << endl << endl;
1510          if (gSystem->AccessPathName("ConfigureCuts.C")) {
1511             TString msg = "\n#####   You may want to provide a macro ConfigureCuts.C with a method:\n";
1512             msg += "   void ConfigureCuts(AliRunTagCuts *runCuts,\n";
1513             msg += "                      AliLHCTagCuts *lhcCuts,\n";
1514             msg += "                      AliDetectorTagCuts *detCuts,\n";
1515             msg += "                      AliEventTagCuts *evCuts)";
1516             Info("WriteAnalysisMacro", msg.Data());
1517          }
1518       } 
1519       if (!IsUsingTags() || fFriendChainName!="") {
1520          out <<"//________________________________________________________________________________" << endl;
1521          out << "TChain* CreateChain(const char *xmlfile, const char *type=\"ESD\")" << endl;
1522          out << "{" << endl;
1523          out << "// Create a chain using url's from xml file" << endl;
1524          out << "   TString treename = type;" << endl;
1525          out << "   treename.ToLower();" << endl;
1526          out << "   treename += \"Tree\";" << endl;
1527          out << "   printf(\"***************************************\\n\");" << endl;
1528          out << "   printf(\"    Getting chain of trees %s\\n\", treename.Data());" << endl;
1529          out << "   printf(\"***************************************\\n\");" << endl;
1530          out << "   TAlienCollection *coll = TAlienCollection::Open(xmlfile);" << endl;
1531          out << "   if (!coll) {" << endl;
1532          out << "      ::Error(\"CreateChain\", \"Cannot create an AliEn collection from %s\", xmlfile);" << endl;
1533          out << "      return NULL;" << endl;
1534          out << "   }" << endl;
1535          out << "   TChain *chain = new TChain(treename);" << endl;
1536          if(fFriendChainName!="") {
1537             out << "   TChain *chainFriend = new TChain(treename);" << endl;
1538          }
1539          out << "   coll->Reset();" << endl;
1540          out << "   while (coll->Next()) {" << endl;
1541          out << "      chain->Add(coll->GetTURL(\"\"));" << endl;
1542          if(fFriendChainName!="") {
1543             out << "      TString fileFriend=coll->GetTURL(\"\");" << endl;
1544             out << "      fileFriend.ReplaceAll(\"AliAOD.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1545             out << "      fileFriend.ReplaceAll(\"AliAODs.root\",\""<<fFriendChainName.Data()<<"\");" << endl;
1546             out << "      chainFriend->Add(fileFriend.Data());" << endl;
1547          }
1548          out << "   }" << endl;
1549          out << "   if (!chain->GetNtrees()) {" << endl;
1550          out << "      ::Error(\"CreateChain\", \"No tree found from collection %s\", xmlfile);" << endl;
1551          out << "      return NULL;" << endl;
1552          out << "   }" << endl;
1553          if(fFriendChainName!="") {
1554             out << "   chain->AddFriend(chainFriend);" << endl;
1555          }
1556          out << "   return chain;" << endl;
1557          out << "}" << endl << endl;
1558       }   
1559       if (fPackages) {
1560          out <<"//________________________________________________________________________________" << endl;
1561          out << "Bool_t SetupPar(const char *package) {" << endl;
1562          out << "// Compile the package and set it up." << endl;
1563          out << "   TString pkgdir = package;" << endl;
1564          out << "   pkgdir.ReplaceAll(\".par\",\"\");" << endl;
1565          out << "   gSystem->Exec(Form(\"tar xvzf %s.par\", pkgdir.Data()));" << endl;
1566          out << "   TString cdir = gSystem->WorkingDirectory();" << endl;
1567          out << "   gSystem->ChangeDirectory(pkgdir);" << endl;
1568          out << "   // Check for BUILD.sh and execute" << endl;
1569          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/BUILD.sh\")) {" << endl;
1570          out << "      printf(\"*******************************\\n\");" << endl;
1571          out << "      printf(\"*** Building PAR archive    ***\\n\");" << endl;
1572          out << "      printf(\"*******************************\\n\");" << endl;
1573          out << "      if (gSystem->Exec(\"PROOF-INF/BUILD.sh\")) {" << endl;
1574          out << "         ::Error(\"SetupPar\", \"Cannot build par archive %s\", pkgdir.Data());" << endl;
1575          out << "         gSystem->ChangeDirectory(cdir);" << endl;
1576          out << "         return kFALSE;" << endl;
1577          out << "      }" << endl;
1578          out << "   } else {" << endl;
1579          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/BUILD.sh for package %s\", pkgdir.Data());" << endl;
1580          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1581          out << "      return kFALSE;" << endl;
1582          out << "   }" << endl;
1583          out << "   // Check for SETUP.C and execute" << endl;
1584          out << "   if (!gSystem->AccessPathName(\"PROOF-INF/SETUP.C\")) {" << endl;
1585          out << "      printf(\"*******************************\\n\");" << endl;
1586          out << "      printf(\"***    Setup PAR archive    ***\\n\");" << endl;
1587          out << "      printf(\"*******************************\\n\");" << endl;
1588          out << "      gROOT->Macro(\"PROOF-INF/SETUP.C\");" << endl;
1589          out << "   } else {" << endl;
1590          out << "      ::Error(\"SetupPar\",\"Cannot access PROOF-INF/SETUP.C for package %s\", pkgdir.Data());" << endl;
1591          out << "      gSystem->ChangeDirectory(cdir);" << endl;
1592          out << "      return kFALSE;" << endl;
1593          out << "   }" << endl;
1594          out << "   // Restore original workdir" << endl;
1595          out << "   gSystem->ChangeDirectory(cdir);" << endl;
1596          out << "   return kTRUE;" << endl;
1597          out << "}" << endl;
1598       }
1599       Info("WriteAnalysisMacro", "\n#####   Analysis macro to run on worker nodes <%s> written",fAnalysisMacro.Data());
1600    }   
1601    Bool_t copy = kTRUE;
1602    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1603    if (copy) {
1604       CdWork();
1605       TString workdir = gGrid->GetHomeDirectory();
1606       workdir += fGridWorkingDir;
1607       if (FileExists(fAnalysisMacro)) gGrid->Rm(fAnalysisMacro);
1608       if (IsUsingTags() && !gSystem->AccessPathName("ConfigureCuts.C")) {
1609          if (FileExists("ConfigureCuts.C")) gGrid->Rm("ConfigureCuts.C");
1610          Info("WriteAnalysisMacro", "\n#####   Copying cuts configuration macro: <ConfigureCuts.C> to your alien workspace");
1611          TFile::Cp("file:ConfigureCuts.C", Form("alien://%s/ConfigureCuts.C", workdir.Data()));
1612       }   
1613       Info("WriteAnalysisMacro", "\n#####   Copying analysis macro: <%s> to your alien workspace", fAnalysisMacro.Data());
1614       TFile::Cp(Form("file:%s",fAnalysisMacro.Data()), Form("alien://%s/%s", workdir.Data(), fAnalysisMacro.Data()));
1615    }
1616 }
1617
1618 //______________________________________________________________________________
1619 void AliAnalysisAlien::WriteExecutable()
1620 {
1621 // Generate the alien executable script.
1622    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1623       ofstream out;
1624       out.open(fExecutable.Data(), ios::out);
1625       if (out.bad()) {
1626          Error("CreateJDL", "Bad file name for executable: %s", fExecutable.Data());
1627          return;
1628       }
1629       out << "#!/bin/bash" << endl;
1630       out << "export GCLIENT_SERVER_LIST=\"pcapiserv04.cern.ch:10000|pcapiserv05.cern.ch:10000|pcapiserv06.cern.ch:10000|pcapiserv07.cern.ch:10000\"" << endl;
1631       out << "echo \"=========================================\"" << endl; 
1632       out << "echo \"############## PATH : ##############\"" << endl;
1633       out << "echo $PATH" << endl;
1634       out << "echo \"############## LD_LIBRARY_PATH : ##############\"" << endl;
1635       out << "echo $LD_LIBRARY_PATH" << endl;
1636       out << "echo \"############## ROOTSYS : ##############\"" << endl;
1637       out << "echo $ROOTSYS" << endl;
1638       out << "echo \"############## which root : ##############\"" << endl;
1639       out << "which root" << endl;
1640       out << "echo \"############## ALICE_ROOT : ##############\"" << endl;
1641       out << "echo $ALICE_ROOT" << endl;
1642       out << "echo \"############## which aliroot : ##############\"" << endl;
1643       out << "which aliroot" << endl;
1644       out << "echo \"=========================================\"" << endl << endl;
1645 //      if (TestBit(AliAnalysisGrid::kTest)) out << "root ";
1646       out << "root -b -q "; 
1647       out << fAnalysisMacro.Data() << endl << endl;
1648       out << "echo \"======== " << fAnalysisMacro.Data() << " finished ========\"" << endl;
1649    }   
1650    Bool_t copy = kTRUE;
1651    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1652    if (copy) {
1653       CdWork();
1654       TString workdir = gGrid->GetHomeDirectory();
1655       workdir += fGridWorkingDir;
1656       TString executable = Form("%s/bin/%s", gGrid->GetHomeDirectory(), fExecutable.Data());
1657       if (FileExists(executable)) gGrid->Rm(executable);
1658       Info("CreateJDL", "\n#####   Copying executable file <%s> to your AliEn bin directory", fExecutable.Data());
1659       TFile::Cp(Form("file:%s",fExecutable.Data()), Form("alien://%s", executable.Data()));
1660    } 
1661 }
1662
1663 //______________________________________________________________________________
1664 void AliAnalysisAlien::WriteValidationScript()
1665 {
1666 // Generate the alien validation script.
1667    // Generate the validation script
1668    TObjString *os;
1669    if (!Connect()) {
1670       Error("WriteValidationScript", "Alien connection required");
1671       return;
1672    }
1673    TString out_stream = "";
1674    if (!TestBit(AliAnalysisGrid::kTest)) out_stream = " >> stdout";
1675    if (!TestBit(AliAnalysisGrid::kSubmit)) {  
1676       ofstream out;
1677       out.open("validate.sh", ios::out);
1678       out << "#!/bin/bash" << endl;
1679       out << "##################################################" << endl;
1680       out << "validateout=`dirname $0`" << endl;
1681       out << "validatetime=`date`" << endl;
1682       out << "validated=\"0\";" << endl;
1683       out << "error=0" << endl;
1684       out << "if [ -z $validateout ]" << endl;
1685       out << "then" << endl;
1686       out << "    validateout=\".\"" << endl;
1687       out << "fi" << endl << endl;
1688       out << "cd $validateout;" << endl;
1689       out << "validateworkdir=`pwd`;" << endl << endl;
1690       out << "echo \"*******************************************************\"" << out_stream << endl;
1691       out << "echo \"* Automatically generated validation script           *\""  << out_stream << endl;
1692       out << "" << endl;
1693       out << "echo \"* Time:    $validatetime \""  << out_stream << endl;
1694       out << "echo \"* Dir:     $validateout\""  << out_stream << endl;
1695       out << "echo \"* Workdir: $validateworkdir\""  << out_stream << endl;
1696       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1697       out << "ls -la ./"  << out_stream << endl;
1698       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl << endl;
1699       out << "##################################################" << endl;
1700
1701       out << "" << endl;
1702       out << "parArch=`grep -Ei \"Cannot Build the PAR Archive\" stderr`" << endl;
1703       out << "segViol=`grep -Ei \"Segmentation violation\" stderr`" << endl;
1704       out << "segFault=`grep -Ei \"Segmentation fault\" stderr`" << endl;
1705       out << "" << endl;
1706
1707       out << "if [ ! -f stderr ] ; then" << endl;
1708       out << "   error=1" << endl;
1709       out << "   echo \"* ########## Job not validated - no stderr  ###\" " << out_stream << endl;
1710       out << "   echo \"Error = $error\" " << out_stream << endl;
1711       out << "fi" << endl;
1712
1713       out << "if [ \"$parArch\" != \"\" ] ; then" << endl;
1714       out << "   error=1" << endl;
1715       out << "   echo \"* ########## Job not validated - PAR archive not built  ###\" " << out_stream << endl;
1716       out << "   echo \"$parArch\" " << out_stream << endl;
1717       out << "   echo \"Error = $error\" " << out_stream << endl;
1718       out << "fi" << endl;
1719
1720       out << "if [ \"$segViol\" != \"\" ] ; then" << endl;
1721       out << "   error=1" << endl;
1722       out << "   echo \"* ########## Job not validated - Segment. violation  ###\" " << out_stream << endl;
1723       out << "   echo \"$segViol\" " << out_stream << endl;
1724       out << "   echo \"Error = $error\" " << out_stream << endl;
1725       out << "fi" << endl;
1726
1727       out << "if [ \"$segFault\" != \"\" ] ; then" << endl;
1728       out << "   error=1" << endl;
1729       out << "   echo \"* ########## Job not validated - Segment. fault  ###\" " << out_stream << endl;
1730       out << "   echo \"$segFault\" " << out_stream << endl;
1731       out << "   echo \"Error = $error\" " << out_stream << endl;
1732       out << "fi" << endl;
1733
1734       // Part dedicated to the specific analyses running into the train
1735
1736       TObjArray *arr = fOutputFiles.Tokenize(" ");
1737       TIter next1(arr);
1738       TString output_file;
1739       while ((os=(TObjString*)next1())) { 
1740          output_file = os->GetString();
1741          Int_t index = output_file.Index("@");
1742          if (index > 0) output_file.Remove(index);
1743          out << "if ! [ -f " << output_file.Data() << " ] ; then" << endl;
1744          out << "   error=1" << endl;
1745          out << "   echo \"Output file(s) not found. Job FAILED !\""  << out_stream << endl;
1746          out << "   echo \"Output file(s) not found. Job FAILED !\" >> stderr" << endl;
1747          out << "fi" << endl;
1748       }   
1749       delete arr;
1750       out << "if [ $error = 0 ] ; then" << endl;
1751       out << "   echo \"* ----------------   Job Validated  ------------------*\""  << out_stream << endl;
1752       out << "fi" << endl;
1753
1754       out << "echo \"* ----------------------------------------------------*\""  << out_stream << endl;
1755       out << "echo \"*******************************************************\""  << out_stream << endl;
1756       out << "cd -" << endl;
1757       out << "exit $error" << endl;
1758    }    
1759    Bool_t copy = kTRUE;
1760    if (TestBit(AliAnalysisGrid::kOffline) || TestBit(AliAnalysisGrid::kTest)) copy = kFALSE;
1761    if (copy) {
1762       CdWork();
1763       TString workdir = gGrid->GetHomeDirectory();
1764       workdir += fGridWorkingDir;
1765       Info("CreateJDL", "\n#####   Copying validation script <validate.sh> to your AliEn working space");
1766       if (FileExists("validate.sh")) gGrid->Rm("validate.sh");
1767       TFile::Cp("file:validate.sh", Form("alien://%s/validate.sh", workdir.Data()));
1768    } 
1769 }